目录

一.题目要求

1.功能要求

2.界面显示

​编辑​编辑​编辑3.按键

4.EEP存储

5.串口发送接收

​编辑​编辑

6.LED和PWM,及初始化

二.main中

三.user.c中

四.user.h中

五.总结


一.题目要求

1.功能要求

2.界面显示

3.按键

4.EEP存储

注意:可以不在CubeMX配置PB6和PB7为ouput (配置的话可以不调用),但一定不要忘记在main中调用IIC初始化函数。此外要注意EEP不能直接存浮点数

5.串口发送接收

注意:不要用成中文的问号

6.LED和PWM,及初始化

二.main中

#include "user.h"

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();

	
	LCD_Init();						//一定要加,不然LCD不能用
	I2CInit();						//一定要加,不然IIC不能用

	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	
	XY_Init();                                      //商品信息初始化
	HAL_UART_Receive_IT(&huart1,&rx_data,1);		//串口接收中断
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);		//输出PWM
	HAL_TIM_Base_Start_IT(&htim3);					//定时
	
  while (1)
  {
	  key_proc();
	  lcd_proc();
	  uart_rx_proc();
	  led_proc();
	  pwm_proc();
  }
 
}

三.user.c中

#include "user.h"

extern UART_HandleTypeDef huart1;
extern TIM_HandleTypeDef htim2;				//生成PWM,CCR2
extern TIM_HandleTypeDef htim3;				//定时

void AT24C02_Write(uint8_t address,uint8_t data)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	I2CStop();
}

uint8_t AT24C02_Read(uint8_t address)
{
	uint8_t data;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	data = I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
	return data;
}

uint8_t key_value,key_down,key_up,key_old = 0;
void key_scan(void)
{
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == RESET)
		key_value = 1;
	else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == RESET)
		key_value = 2;
	else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == RESET)
		key_value = 3;
	else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
		key_value = 4;
	else key_value = 0;
	
	key_down = key_value & (key_value ^ key_old);
	key_up = ~key_value & (key_value ^ key_old);
	key_old = key_value;
}

uint8_t X_Stock = 10,Y_Stock = 10;		//库存数量
uint8_t X_Shop = 0,Y_Shop = 0;			//购买数量
double X_Price = 1.0,Y_Price = 1.0;		//商品价格
uint8_t page_index = 1;					//页面
struct Shop Shop_info = {0};			//购买信息结构体变量
uint8_t led_flag[2] = {0,0};			//两个灯的标志位,0灭1亮
uint8_t pwm_mode = 0;					//pwm调占空比,0输出5%,1输出30%
uint32_t key_tick = 0;
void key_proc(void)
{
	if(uwTick - key_tick < 10)
		return;
	key_tick = uwTick;
	key_scan();
	
	if(key_down == 1)					//页面切换
	{
		page_index ++;
		LCD_Clear(Black);
		if(page_index == 4)page_index = 1;
	}
	else if(key_down == 2)				//X
	{
		switch(page_index)
		{
			case 1:
			{
				if(X_Shop < X_Stock)
				{
					X_Shop ++;
					if(X_Shop == X_Stock)X_Shop = X_Stock;
				}
				else if(X_Shop >= X_Stock)X_Shop = 0;
				
			}break;
			
			case 2:
			{
				if(X_Price < 2.0)X_Price += 0.1;
				else if(X_Price >= 2.0)X_Price = 1.0;
				AT24C02_Write(0x02,(uint8_t)(X_Price * 10));
				HAL_Delay(5);
				
			}break;
			
			case 3:
			{
				X_Stock ++;
				led_flag[1] = 0;
				AT24C02_Write(0x00,X_Stock);
				HAL_Delay(5);
				
			}break;
		}
	}
	else if(key_down == 3)					//Y
	{
		switch(page_index)
		{
			case 1:
			{
				if(Y_Shop < Y_Stock)
				{
					Y_Shop ++;
					if(Y_Shop == Y_Stock)Y_Shop = Y_Stock;
				}
				else if(Y_Shop >= Y_Stock)Y_Shop = 0;
				
			}break;
			
			case 2:
			{
				if(Y_Price < 2.0)Y_Price += 0.1;
				else if(Y_Price >= 2.0)Y_Price = 1.0;
				AT24C02_Write(0x03,(uint8_t)(Y_Price * 10));		
				HAL_Delay(5);
				
			}break;
			
			case 3:
			{
				Y_Stock ++;
				led_flag[1] = 0;					//有库存
				AT24C02_Write(0x01,Y_Stock);
				HAL_Delay(5);
				
			}break;
		}
	}
	//按下,有购买的商品(库存肯定有),在页面一
	else if(key_down == 4 && (X_Shop > 0 || Y_Shop > 0) && page_index == 1)
	{			
		//确认购买的信息
		Shop_info.Shop_Quantity[0]= X_Shop;
		Shop_info.Shop_Quantity[1]= Y_Shop;
		Shop_info.Shop_Price[0] = X_Price;
		Shop_info.Shop_Price[1] = Y_Price;
		
		//算总价格
		Shop_info.All_Price = Shop_info.Shop_Quantity[0] * Shop_info.Shop_Price[0] +
							  Shop_info.Shop_Quantity[1] * Shop_info.Shop_Price[1];	
		
		//打印购买信息
		printf("X:%d,Y:%d,Z:%.1lf",Shop_info.Shop_Quantity[0],Shop_info.Shop_Quantity[1],Shop_info.All_Price);
		
		//库存有变
		X_Stock -= X_Shop;
		Y_Stock -= Y_Shop;
		AT24C02_Write(0x00,X_Stock);
		HAL_Delay(5);
		AT24C02_Write(0x01,Y_Stock);
		HAL_Delay(5);
		
		led_flag[0] = 1;				//LD1亮
		pwm_mode = 1;					//PWM输出占空比30%
		X_Shop = Y_Shop = 0;			//清除购买页面信息	
	}	
	else if(X_Stock == 0 && Y_Stock == 0)	//没有库存
	{	
		led_flag[1] = 1;
	}
}

void XY_Init(void)
{
	//地址随便读一个就行,数据随给一个,只要不超过255
	if(AT24C02_Read(123) != 125)	//第一次烧录或复位,进行变量初始化
	{
		AT24C02_Write(123,125);
		X_Stock = 10;
		Y_Stock = 10;
		X_Price = 1.0;
		Y_Price = 1.0;
		HAL_Delay(5);
		AT24C02_Write(0x00,X_Stock);
		HAL_Delay(5);
		AT24C02_Write(0x01,Y_Stock);
		HAL_Delay(5);
		AT24C02_Write(0x02,(uint8_t)(X_Price * 10));
		HAL_Delay(5);
		AT24C02_Write(0x03,(uint8_t)(Y_Price * 10));
		HAL_Delay(5);
	}
	else 							//不是第一次烧录或复位,读取上一次的数据
	{
		X_Stock = AT24C02_Read(0x00);
		HAL_Delay(5);
		Y_Stock = AT24C02_Read(0x01);
		HAL_Delay(5);
		X_Price = AT24C02_Read(0x02)/10.0;
		HAL_Delay(5);
		Y_Price = AT24C02_Read(0x03)/10.0;
		HAL_Delay(5);
	}
}

uint16_t time_ms = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim -> Instance == TIM3)
	{
		if(led_flag[0] == 1)time_ms ++;
		
		if(time_ms == 5000)					//5秒定时
		{
			time_ms = 0;
			pwm_mode = 0;			
			led_flag[0] = 0;
		}
	}
}

void led_disp(u8 ucled)
{
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,ucled << 8,GPIO_PIN_RESET);
	HAL_Delay(2);										//一定要加,不然闪烁亮度低
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

uint32_t led_tick = 0;
uint8_t lednum = 0;
void led_proc(void)
{
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
	
	if(led_flag[0] == 1)									//LD1
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);
	else
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
	
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	
	if(uwTick - led_tick < 100)
		return;
	led_tick = uwTick;
	
	if(led_flag[1] == 1)lednum |= 2;						//LD2
	else if(led_flag[1] == 0)lednum &= ~2;
	
	led_disp(lednum);
}

uint32_t pwm_tick = 0;
void pwm_proc(void)
{
	if(uwTick - pwm_tick < 100)
		return;
	pwm_tick = uwTick;
	if(pwm_mode == 1)						//30%	
		TIM2 -> CCR2 = 150;	
	else 									//5%
		TIM2 -> CCR2 = 25;
}

char buf[30];
uint32_t lcd_tick = 0;
void lcd_proc(void)
{
	if(uwTick - lcd_tick < 150)
		return;
	lcd_tick = uwTick;
	
	if(page_index == 1)
	{
		LCD_DisplayStringLine(Line1,(u8 *)"        SHOP   ");
		
		sprintf(buf,"     X:%d     ",X_Shop);
		LCD_DisplayStringLine(Line3,(u8 *)buf);
		
		sprintf(buf,"     Y:%d     ",Y_Shop);
		LCD_DisplayStringLine(Line4,(u8 *)buf);
	}
	else if(page_index == 2)
	{
		LCD_DisplayStringLine(Line1,(u8 *)"        PRICE   ");
		
		sprintf(buf,"     X:%.1lf     ",X_Price);
		LCD_DisplayStringLine(Line3,(u8 *)buf);
		
		sprintf(buf,"     Y:%.1lf     ",Y_Price);
		LCD_DisplayStringLine(Line4,(u8 *)buf);
	}
	else 
	{
		LCD_DisplayStringLine(Line1,(u8 *)"        REP   ");
		
		sprintf(buf,"     X:%d     ",X_Stock);
		LCD_DisplayStringLine(Line3,(u8 *)buf);
		
		sprintf(buf,"     Y:%d     ",Y_Stock);
		LCD_DisplayStringLine(Line4,(u8 *)buf);
	}
}

int fputc(int ch,FILE *p)
{
	uint8_t c = (uint8_t)ch;
	HAL_UART_Transmit(&huart1,&c,1,50);
	return ch;
}

#define RX_BUF_SIZE 64
#define RX_TIMEOUT 100
uint32_t last_rx_tick = 0;						//最后接收数据的时刻
uint8_t rx_pointer = 0,rx_data,rx_buf[RX_BUF_SIZE];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(rx_pointer < RX_BUF_SIZE - 1)
	{
		rx_buf[rx_pointer ++] = rx_data;
		last_rx_tick = uwTick;							//更新最后接收数据的时刻
	}
	HAL_UART_Receive_IT(&huart1,&rx_data,1);
}

void uart_rx_proc(void)
{
	//超时处理
	if((uwTick - last_rx_tick > RX_TIMEOUT) && rx_pointer > 0)
	{		
		if(rx_pointer == 1)
		{
			if(rx_buf[0] == '?')			//注意不要用到中文的问号?
			{
				printf("X:%.1lf,Y:%.1lf",X_Price,Y_Price);
			}
		}
		rx_pointer = 0;
		memset(rx_buf,0,sizeof(rx_buf));
	}
}

四.user.h中

#ifndef __USER_H
#define __USER_H

#include "main.h"
#include "stdio.h"
#include "string.h"
#include "i2c_hal.h"

void key_proc(void);
void lcd_proc(void);
void AT24C02_Write(uint8_t address,uint8_t data);
uint8_t AT24C02_Read(uint8_t address);
void XY_Init(void);
int fputc(int ch,FILE *p);
void uart_rx_proc(void);
void led_proc(void);
void pwm_proc(void);

struct Shop						//购买信息结构体
{
	uint8_t Shop_Quantity[2];
	double Shop_Price[2];
	double All_Price;
};

extern uint8_t rx_data;

#endif

五.总结

1.注意eep存浮点数的方式和不要忘记IIC初始化

2.不要打成中文下的问号

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐