蓝桥杯嵌入式十三届第二场
前言:使用新板子stm32G431,由于笨人大概属于偏业余,全部使用HAL库函数实现,可读性应该蛮高的,最后写完没认真检查,如有问题欢迎指正。
所有变量、结构体以及功能实现函数
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "lcd.h"
#include "i2c.h"
#include "stdbool.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef struct keys
{
uint8_t step; //按键的步骤
bool key_state; //按键的状态
bool single_flag; //按键单击标志
}KEY;
KEY key[4]={0,0,0};
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LED1 GPIO_PIN_8
#define LED2 GPIO_PIN_9
#define LED3 GPIO_PIN_10
#define LED4 GPIO_PIN_11
#define LED5 GPIO_PIN_12
#define LED6 GPIO_PIN_13
#define LED7 GPIO_PIN_14
#define LED8 GPIO_PIN_15
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
char text[30];
int x_purchase=0; //x购买数量
int x_count=10; //x库存
double x_price=1.0; //x单价
int y_purchase=0;
int y_count=10;
double y_price=1.0;
uint8_t view_flag=0; //显示界面标志
uint8_t rx[20];
uint8_t data;
__IO uint32_t LEDuwTick1=0xffffff,LEDuwTick2,PWMuwTick=0xffffff;
uint8_t eeprom_read(uint8_t addr);
void eeprom_write(uint8_t addr,uint8_t data);
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
//重写printf函数
int fputc(int c,FILE* Stream)
{
HAL_UART_Transmit(&huart1,(unsigned char *)&c,1,1000);
return 1;
}
//关闭所有LED灯
void LED_OFF(void)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
//控制LED开关
void LED_Control(uint16_t LED,uint8_t LED_Status)
{
if(LED_Status==0)
{
HAL_GPIO_WritePin(GPIOC,LED,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOC,LED,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
}
//翻转LED
void LED_Toggle(uint16_t LED)
{
HAL_GPIO_TogglePin(GPIOC,LED);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void LED_proc()
{
if(uwTick-LEDuwTick1<5000)
LED_Control(LED1,1);
else
LED_Control(LED1,0);
if(x_count==0&&y_count==0)
{
if(uwTick-LEDuwTick2>100)
{
LEDuwTick2=uwTick;
LED_Toggle(LED2);
}
}
else LED_Control(LED2,0);
}
//显示屏清除
void view_clear()
{
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
}
//商品购买界面
void view_SHOP()
{
sprintf(text," SHOP");
LCD_DisplayStringLine(Line2,(uint8_t *)text);
sprintf(text," X:%d",x_purchase);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
sprintf(text," Y:%d",y_purchase);
LCD_DisplayStringLine(Line5,(uint8_t *)text);
}
//商品价格界面
void view_PRICE()
{
sprintf(text," PRICE");
LCD_DisplayStringLine(Line2,(uint8_t *)text);
sprintf(text," X:%.1f",x_price);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
sprintf(text," Y:%.1f",y_price);
LCD_DisplayStringLine(Line5,(uint8_t *)text);
}
//库存信息界面
void view_REP()
{
sprintf(text," PER");
LCD_DisplayStringLine(Line2,(uint8_t *)text);
sprintf(text," X:%d",x_count);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
sprintf(text," Y:%d",y_count);
LCD_DisplayStringLine(Line5,(uint8_t *)text);
}
//重写TIM3的中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
//读取每个按键当前的状态
key[0].key_state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_state=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_state=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++)
{
switch(key[i].step)
{
case 0:
//如果按键现在为低电平,则进入下一步继续判断(按键消抖)
if(key[i].key_state==0)
key[i].step=1;
break;
case 1:
//如果按键现在仍为低电平,则判断按键被按键,否则视为抖动,返回上一步
if(key[i].key_state==0)
{
key[i].single_flag=1;
key[i].step=2;
}
else key[i].step=0;
break;
case 2:
//按键被松开,返回第一步
if(key[i].key_state==1)
key[i].step=0;
break;
}
}
}
}
void KEY_proc()
{
if(key[0].single_flag==1)
{
if(view_flag==0)
{
x_purchase=0;
y_purchase=0;
}
view_flag=(view_flag+1)%3;
view_clear();
switch(view_flag)
{
case 0:
view_SHOP();
break;
case 1:
view_PRICE();
break;
case 2:
view_REP();
break;
}
key[0].single_flag=0;
}
if(key[1].single_flag==1)
{
switch(view_flag)
{
case 0:
if(x_purchase==x_count)
x_purchase=0;
else
x_purchase++;
view_SHOP();
break;
case 1:
if(x_price>=2.0)
x_price=1.0;
else
x_price+=0.1;
view_PRICE();
eeprom_write(0x02,x_price*10.0); //注意此处若*10小数点后一位会被吞掉
break;
case 2:
x_count++;
view_REP();
eeprom_write(0x00,x_count);
break;
}
key[1].single_flag=0;
}
if(key[2].single_flag==1)
{
switch(view_flag)
{
case 0:
if(y_purchase==y_count)
y_purchase=0;
else
y_purchase++;
view_SHOP();
break;
case 1:
if(y_price>=2.0)
y_price=1.0;
else
y_price+=0.1;
view_PRICE();
eeprom_write(0x03,y_price*10.0);
break;
case 2:
y_count++;
view_REP();
eeprom_write(0x01,y_count);
break;
}
key[2].single_flag=0;
}
if(key[3].single_flag==1)
{
if(view_flag==0)
{
x_count-=x_purchase;
y_count-=y_purchase;
printf("X:%d,Y:%d,Z=%.1f\n",x_purchase,y_purchase,(x_purchase*x_price)+(y_price*y_price));
x_purchase=0;
y_purchase=0;
LEDuwTick1=uwTick; //计时触发
PWMuwTick=uwTick;
}
view_clear();
view_SHOP();
eeprom_write(0x00,x_count);
HAL_Delay(10);
eeprom_write(0x01,y_count);
HAL_Delay(10);
key[3].single_flag=0;
}
}
//uart_receive的回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART1)
{
if(rx[0]=='?')
printf("X:%.1f,Y:%.1f\n",x_price,y_price);
}
HAL_UART_Receive_IT(&huart1,rx,1); //注意此处需要再开启接收中断,否则无法继续接收
}
void PWM_proc()
{
if(uwTick-PWMuwTick<5000)
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,30); //调整占空比为30% 前提:htim2.Init.Period = 99;
}
else
{
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,5); //调整占空比为5%
}
}
void ee_proc()
{
data=eeprom_read(0x08); //判断是否为第一次上电
if(data!=0x99) //如果为第一次上电 将数据写入eeprom
{
data=0x99;
eeprom_write(0x08,data);
eeprom_write(0x00,x_count);
eeprom_write(0x01,y_count);
eeprom_write(0x02,x_price*10.0);
eeprom_write(0x03,y_price*10.0);
}
else //如果不是第一次上电 从eeprom读取数据
{
x_count=eeprom_read(0);
y_count=eeprom_read(1);
x_price=eeprom_read(2)/10.0;
y_price=eeprom_read(3)/10.0;
}
}
/* USER CODE END PFP */
main函数
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
I2CInit();
LCD_Init(); //初始化LCD
view_clear();//清屏
view_SHOP(); //上电默认处于商品购买界面
LED_OFF(); //初始化关闭所有LED灯
HAL_TIM_Base_Start_IT(&htim3); //打开TIM3 用于按键
HAL_UART_Receive_IT(&huart1,rx,1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); //开启PWM
ee_proc(); //eeprom操作
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LED_proc();
KEY_proc();
PWM_proc();
}
/* USER CODE END 3 */
}
eeprom的读写函数
uint8_t eeprom_read(uint8_t addr)
{
uint8_t data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
data=I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return data;
}
void eeprom_write(uint8_t addr,uint8_t data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
HAL_Delay(10);
}