蓝桥杯嵌入式(HAL库版)省赛系列文章
第六届蓝桥杯嵌入式省赛程序设计题(HAL库版)
第九届蓝桥杯嵌入式省赛程序设计题(HAL库版)
第十一届蓝桥杯嵌入式省赛程序设计题(HAL库版)
第十三届蓝桥杯嵌入式省赛程序设计题(HAL库版)
第十届蓝桥杯嵌入式省赛程序设计题(HAL库版)
前言
报名参加蓝桥杯嵌入式组别,通过做往年省赛例题的方式进行能力整体提升,需要的小伙伴可以简单看一下哈,写的不好,还请大家多多包涵,欢迎大佬指出问题!
需要其他届赛题的朋友可以从顶部链接直达喔!
闲话少说,进入正题!
一、赛题要求
1.硬件框图
2.功能描述
初始状态:
- 默认输出提醒指示灯。
超过上限提醒指示灯:LD1
低于下限提醒指示灯:LD2 - 默认电压阈值参数。
电压的上限值:2.4V
电压的下限值:1.2V
根据上述任务要求,使用STM32CubeMX生成Keil文件进行程序编写。
二、配置工程
1.配置流程
使用STM32CubeMX的流程可以概括为四个步骤,分别为:选择芯片、配置引脚、配置时钟、建立工程
1.1选择芯片
蓝桥杯嵌入式平台所使用的芯片为STM32G431RBTx,故我们进行搜索并建立工程。
1.2配置引脚
LED灯由PC8-PC15控制,低电平点亮,由PD2引脚控制锁存,低电平变为高电平开锁,高电平变为低电平上锁,设置引脚模式为输出模式。
开发板上共配备了4个按键,分别连接在PB0,PB1,PB2,PA0引脚上,设置引脚模式为输入模式。
由于题目中设计电压测量,故需要配置ADC,参考原理图可知,R37与PB15相连,PB15为ADC2_IN15
1.3配置时钟
时钟配置这里考虑到芯片最高频率为170MHz,所以我直接选择将HCLK一栏设置为最大值170MHz
1.4建立工程
一定要将Toolchain/IDE更改为MDK-ARM,版本号根据大家的实际情况确定即可
这里我勾选的是只将必要的库文件粘贴过来,可以减小工程建立的大小。
至此,建立工程阶段结束,可以开始写代码啦!
三、软件实现(模块化编程)
1. 按键扫描
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_PIN)
{
if(HAL_GPIO_ReadPin(GPIOx,GPIO_PIN) == RESET)
{
while(HAL_GPIO_ReadPin(GPIOx,GPIO_PIN) == RESET)
;
return 2;
}
else
return 1;
}
2. 按键控制电压参数改变(配合扫描函数使用)
void Key_Volt_Change(double *Volt)
{
if (Key_Scan(B3_Plus_GPIO_Port,B3_Plus_Pin) == 2)
{
*Volt += 0.3;
if(*Volt >= 3.3)
*Volt = 3.3;
}
if(Key_Scan(B4_Minus_GPIO_Port,B4_Minus_Pin) == 2)
{
*Volt -= 0.3;
if(*Volt <= 0)
*Volt = 0;
}
}
3. 按键控制指示灯序号改变(配合扫描函数使用)
void Key_LD_Change(uint16_t *LD)
{
if (Key_Scan(B3_Plus_GPIO_Port,B3_Plus_Pin) == 2)
{
*LD += 1;
if(*LD >= 8)
*LD = 8;
}
if(Key_Scan(B4_Minus_GPIO_Port,B4_Minus_Pin) == 2)
{
*LD -= 1;
if(*LD <= 1)
*LD = 1;
}
}
4. 读取ADC数值(启动->读取->返回)
double Get_ADC(void)
{
HAL_ADC_Start(&hadc2); //启动ADC2
adc = HAL_ADC_GetValue(&hadc2); //定义变量adc,用于获取ADC2的值
return (adc*3.3/4096); //函数返回值为adc*3.3/4096,3.3V为最大电压值,4096为12位的LSB
}
5. 上限报警
void LD_Upper_Warning(uint8_t Upper)
{
GPIOC -> ODR = ~(0x0001 << (Upper + 7));
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_RESET);
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_RESET);
}
6. 下限报警
void LD_Lower_Warning(uint8_t Lower)
{
GPIOC -> ODR = ~(0x0001 << (Lower + 7));
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_RESET);
HAL_Delay(200);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_RESET);
}
7. 正常工作情况
void LD_Normal()
{
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(LD_Control_GPIO_Port,LD_Control_Pin,GPIO_PIN_RESET);
}
8. 数据显示界面
if(KEYB1_FLAG == 0)
{
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line0,(uint8_t*)" ");
LCD_DisplayStringLine(Line1,(uint8_t*)" Main ");
LCD_DisplayStringLine(Line2,(uint8_t*)" ");
LCD_DisplayStringLine(Line3,(uint8_t*)" ");
LCD_DisplayStringLine(Line4,(uint8_t*)" Volt: ");
LCD_DisplayStringLine(Line5,(uint8_t*)" ");
LCD_DisplayStringLine(Line6,(uint8_t*)" ");
LCD_DisplayStringLine(Line7,(uint8_t*)" ");
LCD_DisplayStringLine(Line8,(uint8_t*)" ");
LCD_DisplayStringLine(Line9,(uint8_t*)" ");
V = Get_ADC();
sprintf(ADC_TEXT," Volt:%.2fV ",V);
LCD_DisplayStringLine(Line4,(uint8_t*)ADC_TEXT);
if( V >= Max_Volt)
{
LCD_DisplayStringLine(Line6,(uint8_t*)" Status:Upper ");
LD_Upper_Warning();
}
if( V < Max_Volt && V > Min_Volt)
{
LCD_DisplayStringLine(Line6,(uint8_t*)" Status:Normal ");
LD_Normal();
}
if( V <= Min_Volt)
{
LCD_DisplayStringLine(Line6,(uint8_t*)" Status:Lower ");
LD_Lower_Warning();
}
if(Key_Scan(B1_Setting_GPIO_Port,B1_Setting_Pin) ==2)
{
KEYB1_FLAG += 1;
}
}
9. 参数设置界面
else
{
if(Key_Scan(B2_Selection_GPIO_Port,B2_Selection_Pin) == 2)
KEYB2_FLAG += 1;
if(KEYB2_FLAG > 4)
KEYB2_FLAG = 0;
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
LCD_DisplayStringLine(Line0,(uint8_t*)" ");
LCD_DisplayStringLine(Line1,(uint8_t*)" Setting ");
LCD_DisplayStringLine(Line2,(uint8_t*)" ");
LCD_DisplayStringLine(Line5,(uint8_t*)" ");
LCD_DisplayStringLine(Line8,(uint8_t*)" ");
LCD_DisplayStringLine(Line9,(uint8_t*)" ");
sprintf(LCD_TEXT," Max Volt:%.2fV ",Max_Volt);
if(KEYB2_FLAG == 1)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line3,(uint8_t*)LCD_TEXT);
LCD_SetBackColor(White);
Key_Volt_Change(&Max_Volt);
}
else
LCD_DisplayStringLine(Line3,(uint8_t*)LCD_TEXT);
sprintf(LCD_TEXT," Min Volt:%.2fV ",Min_Volt);
if(KEYB2_FLAG == 2)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line4,(uint8_t*)LCD_TEXT);
LCD_SetBackColor(White);
Key_Volt_Change(&Min_Volt);
}
else
LCD_DisplayStringLine(Line4,(uint8_t*)LCD_TEXT);
sprintf(LD_TEXT," Upper:LD%d ",Upper);
if(KEYB2_FLAG == 3)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line6,(uint8_t*)LD_TEXT);
LCD_SetBackColor(White);
Key_LD_Change(&Upper);
}
else
LCD_DisplayStringLine(Line6,(uint8_t*)LD_TEXT);
sprintf(LD_TEXT," Lower:LD%d ",Lower);
if(KEYB2_FLAG == 4)
{
LCD_SetBackColor(Green);
LCD_DisplayStringLine(Line7,(uint8_t*)LD_TEXT);
LCD_SetBackColor(White);
Key_LD_Change(&Lower);
}
else
LCD_DisplayStringLine(Line7,(uint8_t*)LD_TEXT);
if(Key_Scan(B1_Setting_GPIO_Port,B1_Setting_Pin) ==2)
{
KEYB1_FLAG += 1;
}
if(Upper == Lower)
{
LCD_SetTextColor(Red);
LCD_DisplayStringLine(Line5,(uint8_t*)" LD Conflicted! ");
}
else
LCD_DisplayStringLine(Line5,(uint8_t*)" ");
}
10. 界面切换
if(KEYB1_FLAG >1)
KEYB1_FLAG = 0;
总结
通过上述代码基本可以实现任务的全部要求,但存在频繁闪烁的问题,我也不是很清楚是因为硬件原因还是软件原因,还望各路大佬指出!
如果需要全部代码可以直接私信我哈,文章已经很长啦,就不放全部代码啦!希望与各位小伙伴一同进步呀!