蓝桥杯嵌入式STM32G431——第六届省赛真题
作者:互联网
第六届省赛真题
main.c
#include "main.h"
//使用CubeMX配置以下头文件下的模块初始化
#include "rcc.h" //时钟初始化
#include "led_key.h"
#include "lcd.h"
#include "i2c.h"
#include "uart.h"
#include "adc.h"
#include "rtc.h"
//***全局变量区
//*扫描时间速度控制变量
__IO uint32_t uwTick_LED_Set_Point; //控制LED执行一次的时间
__IO uint32_t uwTick_KEY_Set_Point; //控制KEY执行一次的时间
__IO uint32_t uwTick_LCD_Set_Point; //控制LCD执行一次的时间
__IO uint32_t uwTick_UART_Set_Point; //控制UART执行一次的时间
//*LED变量
uint8_t ucLed;
//*按键变量
uint8_t key_value,key_up,key_down; //按键的三行代码所使用的变量
static uint8_t key_old;
//*LCD变量
uint8_t LCD_Disp_String[21];
//*串口变量
uint8_t UART_Str[40]; //串口发送时用于存储发送数据的缓冲区
uint8_t rx_buffer; //串口接收数据的中间缓冲变量
//*ADC2变量
float ADC2_Voltage; //R37的电压值
//*RTC变量
RTC_TimeTypeDef T;
RTC_DateTypeDef D;
//***用户自定义变量区
uint8_t Interface_ctrl;// 0x00-界面选择 0x11-小时控制 0x12-分钟控制 0x13-秒控制
uint8_t k_value = 1; //k初始值为1
uint8_t LED_ctrl;; //0x00-打开 0x01-关闭
uint8_t Clock_Comp_Disp[3]={0,0,0}; //时钟对比值 显示
uint8_t Clock_Comp_Ctrl[3]; //时钟对比值 控制
__IO uint32_t uwTick_Clock_Time_Set_Point; //时钟时间控制变量
uint8_t Time_Set_Ctrl; //0不灭 1灭
uint8_t Uart_Transmit_Times_Ctrl; //串口发送次数控制
uint8_t rx_Buf[100]; //接收数据缓存区
uint8_t rx_Buf_index; //接收数据的位置
__IO uint32_t uwTick_RX_Dealy_Time; //用于对接收时间的判断
_Bool Start_Flag = 0; //起始位判断
__IO uint32_t uwTick_LED_Light_Time; //用于控制LED闪烁时间
//***子函数声明区
void SystemClock_Config(void);
void LED_Proc(void);
void KEY_Proc(void);
void LCD_Proc(void);
void UART_Proc(void);
//***主函数区
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
//*初始化区
//LED和按键的初始化
LED_KEY_Init();
//LCD的初始化
LCD_Init();
LCD_Clear(Black); //清屏
LCD_SetBackColor(Black); //设置背景颜色
LCD_SetTextColor(Magenta); //设置文本颜色
//I2C初始化
I2CInit();
I2C_24c02_read(&k_value , 0 , 1); //EEPROM读数据
//串口初始化
UART1_Init();
HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1); //打开串口接收中断 进入串口中断回调函数
//ADC2初始化
ADC2_Init();
//RTC实时时钟初始化
RTC_Init();
while (1)
{
LED_Proc();
KEY_Proc();
LCD_Proc();
UART_Proc();
}
}
//***子函数区
//*LED处理函数
void LED_Proc(void)
{
if((uwTick - uwTick_LED_Set_Point)<50) return;
uwTick_LED_Set_Point = uwTick; //每50ms执行一次
if(LED_ctrl == 0x00) //打开LED每200ms闪烁功能
{
if(ADC2_Voltage > (3.3*k_value*0.1)) //V1>VDD*k VDD=3.3V
{
if((uwTick - uwTick_LED_Light_Time)>=200) //LED每200ms闪烁一次
{
uwTick_LED_Light_Time = uwTick;
ucLed ^= 0x01;
}
}
else
ucLed = 0x00; //V1<=3.3*k 关闭LED
}
else
{
ucLed = 0x00; //LED为OFF 关闭LED
}
LED_Disp(ucLed); //LED显示函数
}
//*按键处理函数
void KEY_Proc(void)
{
if((uwTick - uwTick_KEY_Set_Point)<100) return;
uwTick_KEY_Set_Point = uwTick; //每100ms执行一次
//按键的三行代码
key_value = KEY_Scan();
key_up = key_value & (key_value ^ key_old);
key_down = ~key_value & (key_value ^ key_old);
key_old = key_value;
if(key_down == 1) //按键B1控制LED打开或关闭
{
LED_ctrl ^= 0x01;
}
if(key_down == 2) //按键2控制界面的切换
{
Interface_ctrl ^= 0x10;
LCD_Clear(Black); //每次切换界面时需清屏
if((Interface_ctrl>>4) == 0) //当返回主界面时,将将设定的闹钟值赋给闹钟控制值用于判断是否上报
{
Clock_Comp_Ctrl[0]=Clock_Comp_Disp[0];
Clock_Comp_Ctrl[1]=Clock_Comp_Disp[1];
Clock_Comp_Ctrl[2]=Clock_Comp_Disp[2];
}
}
if((Interface_ctrl>>4) == 0x1) //在设置上报时间界面下
{
if(key_down == 3) //按键B3实现时分秒的切换
{
Interface_ctrl +=1;
if(Interface_ctrl == 0x14)
Interface_ctrl = 0x10;
}
}
if(key_down ==4) //按键B4实现时分秒时间的调整
{
if(Interface_ctrl == 0x11)
{
Clock_Comp_Disp[0]++;
if(Clock_Comp_Disp[0] == 24)
{
Clock_Comp_Disp[0] = 0;
}
}
if(Interface_ctrl == 0x12)
{
Clock_Comp_Disp[1]++;
if(Clock_Comp_Disp[1] == 60)
{
Clock_Comp_Disp[1] = 0;
}
}
if(Interface_ctrl == 0x13)
{
Clock_Comp_Disp[2]++;
if(Clock_Comp_Disp[2] == 60)
{
Clock_Comp_Disp[2] = 0;
}
}
}
}
//*LCD处理函数
void LCD_Proc(void)
{
if((uwTick - uwTick_LCD_Set_Point)<100) return;
uwTick_LCD_Set_Point = uwTick; //每100ms执行一次
if((Interface_ctrl>>4) == 0x0) //主界面显示下
{
ADC2_Voltage = ADC2_Get_Value()*(3.3/4096); //ADC2的电压值转换
HAL_RTC_GetTime(&hrtc , &T ,RTC_FORMAT_BIN); //打开RTC实时时钟 需要同时获取时间与日期才有效
HAL_RTC_GetDate(&hrtc , &D ,RTC_FORMAT_BIN);
//*LCD显示
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String)); //清空字符串
sprintf((char*)LCD_Disp_String , " V1:%4.2fV ", ADC2_Voltage); //打印字符串
LCD_DisplayStringLine(Line2 , LCD_Disp_String); //将字符串中的数据打印到屏幕上对应位置
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " k:%3.1f ", k_value*0.1);
LCD_DisplayStringLine(Line4 , LCD_Disp_String);
if(LED_ctrl == 0x00) //打开LED
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " LED:ON ");
LCD_DisplayStringLine(Line6 , LCD_Disp_String);
}
else //关闭LED
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " LED:OFF");
LCD_DisplayStringLine(Line6 , LCD_Disp_String);
}
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " T:%02d-%02d-%02d",T.Hours,T.Minutes,T.Seconds);
LCD_DisplayStringLine(Line8 , LCD_Disp_String);
}
else if((Interface_ctrl>>4) == 0x01) //上报时间设置界面
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " Setting");
LCD_DisplayStringLine(Line2 , LCD_Disp_String);
if(Time_Set_Ctrl == 0x00)
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " %02d-%02d-%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
LCD_DisplayStringLine(Line5 , LCD_Disp_String);
}
if((uwTick - uwTick_Clock_Time_Set_Point)>=500) //实现设置时或分或秒时的闪烁功能 每500ms闪烁
{
uwTick_Clock_Time_Set_Point = uwTick;
Time_Set_Ctrl ^= 0x01;
}
if(Time_Set_Ctrl == 0x01) //时间设置控制为0x01为关闭对应位
{
if(Interface_ctrl == 0x11) //小时控制
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " -%02d-%02d",Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
}
else if(Interface_ctrl == 0x12) //分钟控制
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " %02d- -%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[2]);
}
else if(Interface_ctrl == 0x13) //秒控制
{
memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
sprintf((char*)LCD_Disp_String , " %02d-%02d- ",Clock_Comp_Disp[0],Clock_Comp_Disp[1]);
}
else //时间设置完成 都不闪烁
{
sprintf((char*)LCD_Disp_String , " %02d-%02d-%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
}
LCD_DisplayStringLine(Line5 , LCD_Disp_String);
}
}
}
//*串口处理
void UART_Proc(void)
{
if((uwTick - uwTick_UART_Set_Point)<50) return;
uwTick_UART_Set_Point = uwTick; //每50ms执行一次
//当实时时钟的数值与设置的上报时间相等
if((T.Hours==Clock_Comp_Ctrl[0])&&(T.Minutes==Clock_Comp_Ctrl[1])&&(T.Seconds==Clock_Comp_Ctrl[2]))
{
if(Uart_Transmit_Times_Ctrl == 0)
{
Uart_Transmit_Times_Ctrl = 1; //对每秒钟只上报一次数据的处理 每秒钟只传送一次数据 如果不做处理每秒钟会发送20次
sprintf((char*)UART_Str , "%4.2f+%3.1f+%02d%02d%02d\n",ADC2_Voltage,k_value*0.1,T.Hours,T.Minutes,T.Seconds);
HAL_UART_Transmit(&huart1 , UART_Str , strlen((char*)UART_Str) ,50);
}
}
else
{
Uart_Transmit_Times_Ctrl = 0; //串口每秒钟输出数据次数标志位清零以便于修改完上报时间后再次做上面的处理
}
//*串口接收数据处理
if((uwTick - uwTick_RX_Dealy_Time)>=200 && (uwTick - uwTick_RX_Dealy_Time)<=300) //200ms~300ms之内处理一次
{
if(rx_Buf_index == 6)//接收到6个数据
{
//判断接收的数据是否正确 如果正确通过串口发送OK 不正确不发送
if((rx_Buf[0]==0x6B) && (rx_Buf[1]==0x30) && (rx_Buf[2]==0x2E) && (rx_Buf[4]==0x5C) && (rx_Buf[5]==0x6E))
{
if((rx_Buf[3]<=0x39) && (rx_Buf[3]>=0x31))
{
k_value = rx_Buf[3] - 0x30; //串口修改后k_value的值
sprintf((char*)UART_Str , "ok\n");
HAL_UART_Transmit(&huart1 , UART_Str , strlen((char*)UART_Str) ,50);
I2C_24c02_write(&k_value , 0 , 1); //EEPROM写数据 将通过串口修改的k_value的值存入EEPROM中
}
}
}
rx_Buf_index = 0;
Start_Flag = 0;
}
}
//*串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if((rx_buffer == 0x6B) && (rx_Buf_index == 0))
{
uwTick_RX_Dealy_Time = uwTick; //接收到第一个数据开始计数的时间
Start_Flag = 1; //接收开始标志位
}
if(Start_Flag == 1)
{
rx_Buf[rx_Buf_index] = rx_buffer; //每一位接收到的数存入接收缓冲区中
rx_Buf_index++;
}
HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1);
}
标签:Disp,uwTick,String,真题,Comp,Clock,STM32G431,蓝桥,LCD 来源: https://blog.csdn.net/qq_52542756/article/details/122867866