此蓝桥杯嵌入式系列将加班加点的更新下去并且完全免费。
希望大家给一个免费的赞和收藏。
❤️❤️❤️❤️❤️❤️祝大家在比赛中取得好成绩❤️❤️❤️❤️❤️❤️
大家如果有什么 好的建议 或者 不懂的 都可以一起在评论区讨论,看到了会尽快回答的;
本套源文件在文末有链接,想直接的看的可以直接到文末下载
1.cubemx配置
2.文件配置
3.题目分析
一、核心做题思路(按步骤推进,避免遗漏需求)
核心原则:先搭框架,再分模块,最后整合调试,优先实现基础功能(LCD显示、按键防抖),再完成核心功能(E2PROM存储、串口打印),最后优化性能和规范提交,确保不丢基础分。
步骤1:前期准备(5分钟,定基础)
确认硬件平台:题目支持STM32G431RBT6(新版本)和STM32F103RBT6(旧版本),优先按G431配置(80MHz主频,题目明确要求)。
梳理题目核心需求:明确3大界面、4个按键功能、E2PROM存储地址、串口打印要求、性能指标(按键响应≤0.1s,LED≤0.2s)。
搭建工程框架:新建HAL库工程,配置系统时钟(80MHz),导入必要的驱动文件(LCD、GPIO、I2C、USART),创建头文件汇总(整合全局变量和函数声明)。
步骤2:分模块开发(重点,占70%工作量)
模块1:LCD显示模块(基础得分点)
初始化:设置背景色(黑色)、前景色(白色),清除屏幕,确认LCD行列对应(题目1-10行→代码0-9行,1-20列→代码0-19列)。
界面实现:分别编写3个界面的显示函数(SHOP、PRICE、REP),严格按题目图示的行列位置显示界面名称、商品信息,避免字母大小写错误(如PRICE不能写成PRISE)。
界面切换:配合B1按键,实现3个界面往复切换,切换时清除上一界面内容,避免字符残留。
模块2:按键驱动模块(易错点)
初始化:配置B1-B4为上拉输入(蓝桥杯按键常规接法),对应GPIO引脚(需结合竞赛板原理图,通常为PA0-PA3或PB0-PB3)。
防抖处理:采用软件防抖(延时20ms或计数防抖),确保按键响应时间≤0.1s,避免一次按下触发多次功能。
功能实现:按题目要求编写每个按键在不同界面的功能,重点注意边界控制(如购买数量≤库存、单价1.0-2.0循环)。
模块3:E2PROM(A24C02)模块(核心考点)
初始化:配置I2C通信(蓝桥杯竞赛板A24C02通常挂在I2C1上),编写I2C读写函数。
存储逻辑:严格按题目指定地址存储(X库存→0地址,Y库存→1地址,X单价→2地址,Y单价→3地址),注意数据类型匹配(库存为整数,单价为浮点型,需进行进制转换)。
上电读取:系统上电时,从E2PROM读取库存和单价数据,赋值给全局变量,确保掉电后数据不丢失。
数据更新:当单价、库存发生变化(如B2/B3调整、B4确认购买)时,及时写入E2PROM,避免数据同步错误。
模块4:串口通信模块(基础功能)
初始化:配置USART(如USART1),设置波特率(常规9600或115200,题目未指定则任选,确保电脑串口助手匹配),开启收发功能。
打印功能:在B4确认购买后,串口打印购买数量、总金额等信息(格式清晰,符合题目要求即可)。
模块5:LED指示灯模块(辅助功能,易忽略)
初始化:配置PC0-PC7(LED1-LED8)和PD2(锁存器),确保LED动作响应时间≤0.2s。
功能实现:可根据题目隐含需求(如确认购买成功时点亮LED1,界面切换时点亮LED2),无需额外复杂逻辑,确保响应及时即可。
步骤3:整合调试(10分钟,查错补漏)
单个模块调试:先调试LCD和按键,确保界面切换正常、按键防抖有效;再调试E2PROM,验证掉电数据是否保存;最后调试串口打印。
功能联调:模拟实际操作(切换界面、调整数量/单价、确认购买),检查数据同步(E2PROM、LCD、串口)是否正常,边界条件是否满足(如库存为0时无法购买)。
性能优化:确保按键响应≤0.1s、LED响应≤0.2s,LCD无闪烁、无字符残留,串口打印无乱码。
步骤4:规范提交(关键,避免零分)
文件整理:仅提交自行编写/修改的.c、.h文件(无需提交库文件),以及编译生成的.hex文件。
hex命名:按题目要求,新版本(G431)命名为“G+准考证号.hex”,旧版本(F103)命名为“F+准考证号.hex”,避免命名错误。
二、核心知识点(必掌握,贴合蓝桥杯考点)
1. STM32基础知识点
系统时钟配置:80MHz主频(G431),HSI或HSE时钟配置,HAL库时钟初始化函数(SystemClock_Config)。
GPIO配置:输入模式(按键,上拉输入)、输出模式(LED,推挽输出),HAL_GPIO_Init、HAL_GPIO_ReadPin、HAL_GPIO_WritePin函数使用。
中断(可选):若采用中断方式实现按键,需掌握外部中断配置(EXTI)、中断服务函数编写(避免防抖问题)。
2. LCD驱动知识点
蓝桥杯官方LCD驱动函数使用:LCD_Init、LCD_SetBackColor、LCD_SetTextColor、LCD_Clear、LCD_DisplayStringLine、LCD_DisplayChar。
LCD行列坐标对应:题目1-10行对应代码Line0-Line9,1-20列对应每个字符16个像素,需精准匹配题目图示位置。
3. 按键防抖知识点
软件防抖原理:通过延时(20ms)或计数(连续检测2次相同电平),过滤按键抖动带来的误触发。
按键状态机:常用“空闲-按下-防抖-确认-松开”状态机,确保按键响应稳定,符合≤0.1s的性能要求。
4. E2PROM(A24C02)知识点
I2C通信协议:掌握I2C起始信号、停止信号、应答信号的发送与接收,HAL库I2C函数(HAL_I2C_Master_Transmit、HAL_I2C_Master_Receive)。
A24C02读写逻辑:页写、随机读、顺序读的实现,注意地址字节的拼接(器件地址+片内地址)。
数据类型转换:浮点型单价(如1.0)存储到E2PROM时,需转换为整数(如10),读取时再转换回浮点型(10/10.0),避免浮点型直接存储的误差。
5. USART串口知识点
USART初始化:配置波特率、数据位(8位)、停止位(1位)、校验位(无校验),HAL库USART初始化函数(MX_USART1_UART_Init)。
串口打印:使用HAL_UART_Transmit函数,将字符串(如购买信息)发送到电脑,注意字符串格式拼接(sprintf函数)。
6. 模块化编程知识点
头文件汇总:创建全局头文件(如headfile.h),整合所有模块的头文件、宏定义、全局变量声明,避免重复包含。
函数封装:每个模块独立编写.c和.h文件(如lcd.c/lcd.h、eeprom.c/eeprom.h),函数功能单一,便于调试和修改。
三、高频考点(蓝桥杯重点,扣分点预警)
1. 核心考点(占分60%,必拿)
E2PROM读写与数据存储:重点考查I2C通信实现、指定地址存储、掉电数据保存,是本题核心得分点(对应题目3.5要求)。
LCD界面设计与切换:考查LCD驱动使用、行列位置匹配、界面切换逻辑,严格按题目图示要求,字母大小写、显示内容不能出错(对应3.3要求)。
按键功能实现与防抖:考查GPIO输入配置、防抖处理、不同界面下的按键功能切换,边界控制(数量、单价范围)是重点(对应3.4要求)。
2. 基础考点(占分25%,不丢基础分)
STM32系统时钟配置:80MHz主频,HAL库时钟函数的正确编写(题目明确要求)。
串口打印功能:考查USART初始化和数据发送,确保打印信息准确(对应3.1要求)。
LED指示灯响应:考查GPIO输出配置,确保响应时间≤0.2s(对应3.2要求)。
3. 易错考点(扣分重灾区,重点规避)
E2PROM地址错误:严格按题目指定地址存储(X库存→0,Y库存→1,X单价→2,Y单价→3),地址混淆会导致数据存储/读取错误。
按键防抖失效:未做防抖处理或防抖时间不足,导致一次按下触发多次功能,直接影响评测结果。
边界控制缺失:购买数量超过库存、单价超出1.0-2.0范围,未做限制,会导致功能逻辑错误。
提交规范错误:hex文件命名错误、提交多余文件(库文件),会直接被判零分(对应题目1.3、1.4要求)。
LCD显示错误:界面名称大小写错误(如PRICE写成PRISE)、行列位置偏差,会丢基础分。
4.headfile.h
#ifndef _HEADFILE_H__ #define _HEADFILE_H__ #include "stdio.h" #include "stdint.h" #include "string.h" #include "main.h" #include "tim.h" #include "usart.h" #include "gpio.h" #include "key.h" #include "handler.h" #include "fun.h" #include "lcd.h" #include "i2c_hal.h" extern uint8_t g_X_cnt ; extern uint8_t g_Y_cnt ; extern float g_X_price; extern float g_Y_price; extern uint8_t g_X_rep ; extern uint8_t g_Y_rep ; extern uint8_t g_lcd_mode; extern uint8_t g_lcd_rep_0_flag; extern uint8_t g_lcd_B4_flag_5s; extern uint8_t g_timer_5s; extern uint8_t g_rx_data; extern char g_send_buf[20]; #endif5.fun.c
#include "headfile.h" char text[21] = {0}; /** * @brief LED显示控制函数 * @param lcd LED编号(1-8),对应GPIOC的引脚8-15 * @param mode 控制模式:1=点亮LED,其他=熄灭LED * @retval 无 * @note 该函数通过74HC595锁存器控制LED显示,使用PD2作为锁存信号 */ void Led_Show(uint8_t lcd, uint8_t mode) { // 拉高锁存信号,准备数据传输 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET); if(mode == 1) { // 点亮模式:将对应LED引脚置低电平(低电平点亮) // GPIO_PIN_8<<(lcd-1) 计算对应LED的引脚位 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (lcd - 1), GPIO_PIN_RESET); } else { // 熄灭模式:将对应LED引脚置高电平 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 << (lcd - 1), GPIO_PIN_SET); } // 拉低锁存信号,锁存数据到输出端 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); } /** * @brief 商店界面显示函数 * @param 无 * @retval 无 * @note 在LCD屏幕上显示商店界面,包括标题和X、Y坐标计数 */ void Shop_Show() { // 显示商店标题,居中对齐 sprintf(text, " SHOP "); LCD_DisplayStringLine(Line1, (uint8_t *)text); // 显示X轴计数器值,格式化显示为" X:数值 " sprintf(text, " X:%d ", g_X_cnt); LCD_DisplayStringLine(Line3, (uint8_t *)text); // 显示Y轴计数器值,格式化显示为" Y:数值 " sprintf(text, " Y:%d ", g_Y_cnt); LCD_DisplayStringLine(Line4, (uint8_t *)text); } /** * @brief 价格显示函数 * @param 无 * @retval 无 * @note 在LCD屏幕上显示价格界面,包括标题和X、Y价格信息 */ void Price_Show() { // 显示价格标题,居中对齐 sprintf(text ," PRICE "); LCD_DisplayStringLine(Line1,(uint8_t *)text); // 显示X轴价格,保留1位小数 sprintf(text ," X:%.1f ",g_X_price); LCD_DisplayStringLine(Line3,(uint8_t *)text); // 显示Y轴价格,保留1位小数 sprintf(text ," Y:%.1f ",g_Y_price); LCD_DisplayStringLine(Line4,(uint8_t *)text); } /** * @brief 补货界面显示函数 * @param 无 * @retval 无 * @note 在LCD屏幕上显示补货界面,包括标题和X、Y轴补货数量 */ void Rep_Show() { // 显示补货标题,居中对齐 sprintf(text ," REP "); LCD_DisplayStringLine(Line1,(uint8_t *)text); // 显示X轴补货数量 sprintf(text ," X:%d ",g_X_rep); LCD_DisplayStringLine(Line3,(uint8_t *)text); // 显示Y轴补货数量 sprintf(text ," Y:%d ",g_Y_rep); LCD_DisplayStringLine(Line4,(uint8_t *)text); } /** * @brief LCD显示模式切换函数 * @param 无 * @retval 无 * @note 根据全局变量g_lcd_mode的值,调用对应的界面显示函数 * g_lcd_mode=0: 商店界面 * g_lcd_mode=1: 价格界面 * g_lcd_mode=2: 补货界面 */ void Lcd_Show() { // 根据当前显示模式选择对应的界面显示函数 switch(g_lcd_mode) { case 0: // 模式0:显示商店界面 Shop_Show(); break; case 1: // 模式1:显示价格界面 Price_Show(); break; case 2: // 模式2:显示补货界面 Rep_Show(); break; default: // 其他模式:不执行任何操作 break; } } /** * @brief EEPROM单字节写入函数 * @param addr EEPROM内部地址(0-255),指定写入位置 * @param data 要写入的数据(0-255) * @retval 无 * @note 使用I2C总线向AT24C02 EEPROM写入单个字节数据 * 写入完成后需要等待20ms,确保数据写入完成 */ void eeprom_write(uint8_t addr, uint8_t data) { I2CStart(); // 启动I2C总线通信 I2CSendByte(0xA0); // 发送设备地址+写模式(0xA0),AT24C02的7位地址为0x50,左移1位后加上写位0 I2CWaitAck(); // 等待从机应答 I2CSendByte(addr); // 发送目标地址,指定EEPROM内部写入位置 I2CWaitAck(); // 等待从机应答 I2CSendByte(data); // 发送要写入的数据 I2CWaitAck(); // 等待从机应答 I2CStop(); // 停止I2C总线通信 HAL_Delay(20); // 写入延时,AT24C02页写周期约5ms,20ms确保写入完成 } /** * @brief EEPROM单字节读取函数 * @param addr EEPROM内部地址(0-255),指定读取位置 * @retval 读取到的数据(0-255) * @note 使用I2C总线从AT24C02 EEPROM读取单个字节数据 * 读取过程需要两次I2C通信:第一次设置地址,第二次读取数据 */ uint8_t eeprom_read(uint8_t addr) { I2CStart(); // 启动I2C总线通信 I2CSendByte(0xA0); // 发送设备地址+写模式(0xA0),用于设置读取地址 I2CWaitAck(); // 等待从机应答 I2CSendByte(addr); // 发送目标地址,指定EEPROM内部读取位置 I2CWaitAck(); // 等待从机应答 I2CStart(); // 重新启动I2C总线,切换到读模式 I2CSendByte(0xA1); // 发送设备地址+读模式(0xA1),准备读取数据 I2CWaitAck(); // 等待从机应答 uint8_t data = I2CReceiveByte(); // 接收1字节数据 I2CSendNotAck(); // 发送非应答信号,表示读取结束 I2CStop(); // 停止I2C总线通信 return data; // 返回读取到的数据 } /** * @brief 状态更新显示函数 * @param 无 * @retval 无 * @note 更新LCD显示界面和LED指示灯状态 * 通常在主循环或定时器中断中调用,实现界面和LED的实时更新 */ void Change() { // 更新LCD显示界面,根据g_lcd_mode显示对应的界面(商店/价格/补货) Lcd_Show(); // 控制LED2显示补货标志状态 // g_lcd_rep_0_flag=1时点亮LED2,表示补货模式激活 Led_Show(2, g_lcd_rep_0_flag); // 控制LED1显示5秒标志状态 // g_lcd_B4_flag_5s=1时点亮LED1,表示5秒定时器激活 Led_Show(1, g_lcd_B4_flag_5s); }6.key.c
#include "headfile.h" /* ==================== 按键状态变量(static,仅本文件可见) ==================== */ static uint8_t B1_state ; // B1按键当前状态(PB0),0=按下,1=释放 static uint8_t B2_state ; // B2按键当前状态(PB1),0=按下,1=释放 static uint8_t B3_state ; // B3按键当前状态(PB2),0=按下,1=释放 static uint8_t B4_state ; // B4按键当前状态(PA0),0=按下,1=释放 /* ==================== 按键上一次状态变量(static,用于下降沿检测) ==================== */ static uint8_t B1_last_state ; // B1按键上一次状态,用于检测按键按下(下降沿) static uint8_t B2_last_state ; // B2按键上一次状态,用于检测按键按下(下降沿) static uint8_t B3_last_state ; // B3按键上一次状态,用于检测按键按下(下降沿) static uint8_t B4_last_state ; // B4按键上一次状态,用于检测按键按下(下降沿) /* ==================== 按键去抖动时间变量(static) ==================== */ static uint32_t tick ; // 当前系统时间(毫秒),通过HAL_GetTick()获取 static uint32_t last_tick; // 上次按键扫描时间(毫秒),用于20ms去抖动判断 /* ==================== 商店计数器变量(全局,可被其他文件访问) ==================== */ uint8_t g_X_cnt = 0; // X商品计数器,记录X已购买数量(0-补货数量) uint8_t g_Y_cnt = 0; // Y商品计数器,记录Y已购买数量(0-补货数量) /* ==================== 商品价格变量(全局,可被其他文件访问) ==================== */ float g_X_price = 1.0f; // X商品单价(元),范围1.0-2.0,步进0.1 float g_Y_price = 1.0f; // Y商品单价(元),范围1.0-2.0,步进0.1 /* ==================== 补货数量变量(全局,可被其他文件访问) ==================== */ uint8_t g_X_rep = 10; // X补货数量,记录X库存数量(默认10) uint8_t g_Y_rep = 10; // Y补货数量,记录Y库存数量(默认10) /* ==================== LCD显示模式变量(全局,可被其他文件访问) ==================== */ uint8_t g_lcd_mode = 0; // LCD显示模式:0=商店界面,1=价格界面,2=补货界面 /** * @brief 按键扫描函数 * @param 无 * @retval 无 * @note 扫描4个按键状态,根据按键和当前LCD模式执行相应操作 * 包含按键去抖动处理(20ms) */ void Key_Scan() { // 获取当前系统时间(毫秒) tick = HAL_GetTick(); // 按键去抖动处理:距离上次扫描不足20ms则返回 if(tick-last_tick<=20) return; // 更新上次扫描时间 last_tick = tick; // 读取4个按键的当前状态(低电平有效) B1_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); B2_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); B3_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2); B4_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); // B1按键:切换LCD显示模式(商店/价格/补货) if(B1_state == 0 && B1_last_state == 1) { g_lcd_mode++; // 模式递增 g_lcd_mode %= 3; // 模式在0-2之间循环 } // B2按键:X轴操作 if(B2_state == 0 && B2_last_state == 1) { if(g_lcd_mode == 0) // 商店模式:增加X轴计数 { g_X_cnt++; if(g_X_cnt > g_X_rep) g_X_cnt = 0; // 超过补货数量则归零 } if(g_lcd_mode == 1) // 价格模式:增加X轴价格 { g_X_price += 0.1f; if(g_X_price >= 2.1f) g_X_price = 1.0f; // 价格在1.0-2.0之间循环 eeprom_write(2, g_X_price * 10); // 保存价格到EEPROM(地址2) } if(g_lcd_mode == 2) // 补货模式:增加X轴补货数量 { g_X_rep++; eeprom_write(0, g_X_rep); // 保存补货数量到EEPROM(地址0) } } // B3按键:Y轴操作 if(B3_state == 0 && B3_last_state == 1) { if(g_lcd_mode == 0) // 商店模式:增加Y轴计数 { g_Y_cnt++; if(g_Y_cnt > g_Y_rep) g_Y_cnt = 0; // 超过补货数量则归零 } if(g_lcd_mode == 1) // 价格模式:增加Y轴价格 { g_Y_price += 0.1f; if(g_Y_price >= 2.1f) g_Y_price = 1.0f; // 价格在1.0-2.0之间循环 eeprom_write(3, g_Y_price * 10); // 保存价格到EEPROM(地址3) } if(g_lcd_mode == 2) // 补货模式:增加Y轴补货数量 { g_Y_rep++; eeprom_write(1, g_Y_rep); // 保存补货数量到EEPROM(地址1) } } // B4按键:确认购买(仅在商店模式有效) if(B4_state == 0 && B4_last_state == 1) { if(g_lcd_mode == 0) { // 扣减补货数量 g_X_rep -= g_X_cnt; g_Y_rep -= g_Y_cnt; // 保存更新后的补货数量到EEPROM eeprom_write(0, g_X_rep); eeprom_write(1, g_Y_rep); // 激活5秒标志和定时器 g_lcd_B4_flag_5s = 1; g_timer_5s = 0; // 设置PWM占空比(30%) TIM2->CCR2 = 30 - 1; // 计算总价格并通过串口发送 sprintf(g_send_buf, "X:%d,Y:%d,Z:%.1f", \ g_X_cnt, \ g_Y_cnt, \ g_X_cnt * g_X_price + g_Y_cnt * g_Y_price \ ); HAL_UART_Transmit(&huart1, (uint8_t *)g_send_buf, strlen(g_send_buf), 50); // 清零计数器 g_X_cnt = 0; g_Y_cnt = 0; } } // 保存当前按键状态,用于下次检测按键按下(下降沿检测) B1_last_state = B1_state; B2_last_state = B2_state; B3_last_state = B3_state; B4_last_state = B4_state; }7.handler.c
#include "headfile.h" /* ==================== 补货标志变量(全局,可被其他文件访问) ==================== */ uint8_t g_lcd_rep_0_flag; // 补货标志:1=需要补货,0=库存充足 // 当X和Y补货数量都为0时,每100ms翻转一次(LED2闪烁) // 用于提醒用户需要补货 /* ==================== 5秒定时标志变量(全局,可被其他文件访问) ==================== */ uint8_t g_lcd_B4_flag_5s; // 5秒定时标志:1=定时器运行中,0=定时器停止 // 按下B4确认购买后激活,持续5秒 // 用于控制PWM占空比(30%)持续5秒后恢复默认(5%) /* ==================== 5秒定时器计数变量(全局,可被其他文件访问) ==================== */ uint8_t g_timer_5s; // 5秒定时器计数器(0-50) // TIM6定时周期100ms,50次中断=5秒 // 达到50时关闭5秒标志并恢复PWM默认占空比 /* ==================== 串口接收数据变量(全局,可被其他文件访问) ==================== */ uint8_t g_rx_data; // 串口接收缓冲区,存储接收到的单个字节 // 用于USART1中断接收,接收完成后触发回调函数 // 当接收到'?'字符时,返回价格信息 /* ==================== 串口发送缓冲区(全局,可被其他文件访问) ==================== */ char g_send_buf[20]={0}; // 串口发送缓冲区,最大20字节 // 用于存储格式化后的响应字符串 // 格式:"X:价格1,Y:价格2",例如"X:1.5,Y:2.0" /** * @brief 定时器周期中断回调函数 * @param htim 定时器句柄指针 * @retval 无 * @note 处理TIM6定时器的周期中断,实现补货标志闪烁和5秒定时功能 * TIM6定时周期为100ms,因此50次中断对应5秒 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // 判断是否为TIM6定时器中断 if(htim->Instance==TIM6) { // 补货标志闪烁逻辑 if(g_X_rep==0 && g_Y_rep==0) { // 当X和Y轴补货数量都为0时,补货标志每100ms翻转一次(闪烁效果) g_lcd_rep_0_flag=!g_lcd_rep_0_flag; } else { // 当补货数量不为0时,关闭补货标志 g_lcd_rep_0_flag=0; } // 5秒定时器逻辑 if(g_lcd_B4_flag_5s==1) { // 5秒标志激活时,每100ms计数器加1 g_timer_5s++; // 判断是否达到5秒(50次中断 × 100ms = 5000ms) if(g_timer_5s>=50) { // 关闭5秒标志 g_lcd_B4_flag_5s=0; // 清零定时器计数器 g_timer_5s=0; // 恢复PWM占空比为5%(购买完成后的默认状态) TIM2->CCR2 = 5-1; } } } } /** * @brief UART接收完成中断回调函数 * @param huart UART句柄指针 * @retval 无 * @note 处理USART1的接收完成中断,实现串口命令响应功能 * 当接收到'?'字符时,返回当前X和Y轴的价格信息 */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { // 判断是否为USART1的接收完成中断 if(huart->Instance == USART1) { // 检查接收到的数据是否为查询命令'?' if(g_rx_data == '?') { // 格式化价格信息字符串 // 格式:"X:价格1,Y:价格2",价格保留1位小数 sprintf(g_send_buf, "X:%.1f,Y:%.1f", g_X_price, g_Y_price); // 通过USART1发送价格信息 // 参数:UART句柄、发送缓冲区、发送长度、超时时间(50ms) HAL_UART_Transmit(&huart1, (uint8_t *)g_send_buf, strlen(g_send_buf), 50); } // 重新启动USART1接收中断,准备接收下一个字节 // 参数:UART句柄、接收缓冲区地址、接收字节数(1) HAL_UART_Receive_IT(&huart1, &g_rx_data, 1); } }8.main.c
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "headfile.h" /* USER CODE END Includes */ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.............................<<<<<<<<<<<<<<<<<<<<< /** * @brief The application entry point. * @retval int */ 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(); // 初始化GPIO外设,配置引脚模式(输入/输出/复用等) MX_TIM2_Init(); // 初始化TIM2定时器,配置为PWM模式(用于LED亮度控制) MX_TIM6_Init(); // 初始化TIM6定时器,配置为基本定时器(用于补货标志闪烁和5秒定时) MX_USART1_UART_Init(); // 初始化USART1串口,配置波特率等参数(用于串口通信) /* USER CODE BEGIN 2 */ // 用户代码开始区域,以下为用户自定义初始化代码 LCD_Init(); // 初始化LCD显示屏,配置LCD控制器 LCD_SetBackColor(Black); // 设置LCD背景色为黑色 LCD_SetTextColor(White); // 设置LCD文字颜色为白色 LCD_Clear(Black); // 清屏,用黑色填充整个屏幕 HAL_TIM_Base_Start_IT(&htim6); // 启动TIM6定时器并使能中断(周期100ms) HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); // 启动TIM2的PWM输出通道2(用于LED亮度控制) I2CInit(); // 初始化I2C总线(用于AT24C02 EEPROM通信) HAL_UART_Receive_IT(&huart1, &g_rx_data, 1); // 启动USART1接收中断,每次接收1字节到g_rx_data /** * @brief EEPROM参数初始化 * @note 检查首次运行标志,决定是从EEPROM读取参数还是写入默认值 * EEPROM地址分配: * - 地址0:X补货数量 * - 地址1:Y补货数量 * - 地址2:X价格(整数存储,实际值=读取值/10) * - 地址3:Y价格(整数存储,实际值=读取值/10) * - 地址4:首次运行标志(0xAA表示已初始化) */ if(eeprom_read(4) == 0xAA) // 检查地址4的首次运行标志是否为0xAA,非首次运行校验 { // 从EEPROM读取已保存的参数 g_X_rep = eeprom_read(0); // 读取X轴补货数量(地址0) g_Y_rep = eeprom_read(1); // 读取Y轴补货数量(地址1) g_X_price = eeprom_read(2) / 10.0f; // 读取X轴价格,存储时放大10倍,读取时除以10恢复 g_Y_price = eeprom_read(3) / 10.0f; // 读取Y轴价格,存储时放大10倍,读取时除以10恢复 } else // 首次运行校验,写入默认值 { // 写入默认参数值 eeprom_write(0, 10); // X轴补货数量初始值10 eeprom_write(1, 10); // Y轴补货数量初始值10 eeprom_write(2, 10); // X轴价格初始值1.0(存储10,实际值=10/10) eeprom_write(3, 10); // Y轴价格初始值1.0(存储10,实际值=10/10) eeprom_write(4, 0xAA); // 写入首次运行标志位,标记已初始化 } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Key_Scan(); Change(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }9.lcd.c 修改部分
void LCD_Init(void) { uint16_t temp = GPIOC->ODR & 0xff00; //此处修改 LCD_CtrlLinesConfig(); dummy = LCD_ReadReg(0); if(dummy == 0x8230) { REG_8230_Init(); } else { REG_932X_Init(); } dummy = LCD_ReadReg(0); GPIOC->ODR = (GPIOC->ODR & 0x00ff) | temp; //此处修改 } void LCD_Clear(u16 Color) { uint16_t temp = GPIOC->ODR & 0xff00; //此处修改 u32 index = 0; LCD_SetCursor(0x00, 0x0000); LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */ for(index = 0; index < 76800; index++) { LCD_WriteRAM(Color); } GPIOC->ODR = (GPIOC->ODR & 0x00ff) | temp; //此处修改 } void LCD_DisplayStringLine(u8 Line, u8 *ptr) { uint16_t temp = GPIOC->ODR & 0xff00; //此处修改 u32 i = 0; u16 refcolumn = 319;//319; while ((*ptr != 0) && (i < 20)) // 20 { LCD_DisplayChar(Line, refcolumn, *ptr); refcolumn -= 16; ptr++; i++; } GPIOC->ODR = (GPIOC->ODR & 0x00ff) | temp; //此处修改 }10.源文件(含题目)
通过网盘分享的文件:13届蓝桥杯嵌入式省赛真题二
链接: https://pan.baidu.com/s/1CxVtIgld-ZVrM6hKhON03w?pwd=i4e7 提取码: i4e7