赞
踩
相关说明:
开发板:CT117E-M4(STM32G431RB 蓝桥杯嵌入式比赛板)
开发环境: CubeMX+Keil5
涉及题目:STM32ADC–基于HAL库(第十届蓝桥杯嵌入式省赛-研究生组)
题目难点:LCD与LED冲突。LED3在作为Upper LED,当前电压超出阈值时闪烁时仍存在问题,其他皆正常,用的是新板,不确定是否与板子有关。
CubeMX配置、主要函数代码及说明:
1.使能外部高速时钟:
2.配置时钟树:
3.GPIO:
4.ADC(除图中配置,其他默认即可):
5.I2C(存储电压值、LED灯):
6.TIM6(0.2s中断):
void EEPROM_WriteBuff(uint8_t addr,uint8_t *writeBuff,uint32_t numToWrite); //EEPROM写数组
void EEPROM_ReadBuff(uint8_t addr,uint8_t *readBuff,uint32_t numToRead); //EEPROM读数组
double ADC_GetValue(void); //获取ADC的值
void KEY_Scan(void); //按键扫描
void Setting_Mode(void); //设置模式
void Color_change(void); //选中行高亮
void Data_change(uint8_t mode); //数据更改(max/min/led)
void Data_read(void); //从EEPROM中读取数据
void Data_save(void); //数据保存
char* GET_Statue(void); //获取当前状态(Upper/Lower/Normal)
void LCD_fresh(void); //LCD更新
void LCD_Init_Show(void); //LCD初始化
void LED_refresh(void); //LED更新
#define LED_GPIO_PORT GPIOC
#define LED1_GPIO_PIN GPIO_PIN_8
#define LED2_GPIO_PIN GPIO_PIN_9
#define LED3_GPIO_PIN GPIO_PIN_10
#define LED4_GPIO_PIN GPIO_PIN_11
#define LED5_GPIO_PIN GPIO_PIN_12
#define LED6_GPIO_PIN GPIO_PIN_13
#define LED7_GPIO_PIN GPIO_PIN_14
#define LED8_GPIO_PIN GPIO_PIN_15
#define ON GPIO_PIN_RESET
#define OFF GPIO_PIN_SET
#define TOG 2
#define LED1(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED1_GPIO_PIN,a)
#define LED2(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED2_GPIO_PIN,a)
#define LED3(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED3_GPIO_PIN,a)
#define LED4(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED4_GPIO_PIN,a)
#define LED5(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED5_GPIO_PIN,a)
#define LED6(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED6_GPIO_PIN,a)
#define LED7(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED7_GPIO_PIN,a)
#define LED8(a) HAL_GPIO_WritePin(LED_GPIO_PORT,LED8_GPIO_PIN,a)
#define LED1_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED1_GPIO_PIN)
#define LED2_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED2_GPIO_PIN)
#define LED3_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED3_GPIO_PIN)
#define LED4_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED4_GPIO_PIN)
#define LED5_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED5_GPIO_PIN)
#define LED6_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED6_GPIO_PIN)
#define LED7_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED7_GPIO_PIN)
#define LED8_TOG() HAL_GPIO_TogglePin(LED_GPIO_PORT,LED8_GPIO_PIN)
#define KEY1_GPIO_PORT GPIOB
#define KEY1_GPIO_PIN GPIO_PIN_0
#define KEY2_GPIO_PORT GPIOB
#define KEY2_GPIO_PIN GPIO_PIN_1
#define KEY3_GPIO_PORT GPIOB
#define KEY3_GPIO_PIN GPIO_PIN_2
#define KEY4_GPIO_PORT GPIOA
#define KEY4_GPIO_PIN GPIO_PIN_0
#define max 2//max数据对应行 下三个同理
#define min 4
#define upper 6
#define lower 8
#define add 1//加模式
#define sub 0//减模式
double writeBuff[1]; //EEPROM写数据数组
double readBuff[1]; //EEPROM读数据数组
uint8_t v_maxAddr=0X08; //EEPROM存储上限电压的地址
uint8_t v_minAddr=0X00; //EEPROM存储下限电压的地址
double v_max; //上限电压
double v_min; //下限电压
double v_now; //当前电压
double v_step=0.3; //电压每次改变值
double v_upper=3.3; //电压更改最大值
double v_lower=0; //电压更改最小值
uint8_t led_upAddr=0X10; //EEPROM存储Upper LED的地址
uint8_t led_lowAddr=0X18; //EEPROM存储Lower LED的地址
int led_up; //Upper对应LED
int led_low; //Lower对应LED
int led_max=8; //最大为LED8
int led_min=1; //最小为LED1
int led_step=1; //LED每次改变值
int led_statue=1; //LED灯状态(0低于下限/1正常状态/2高于上限)
int led_change=0; //LED灯状态改变标志位
uint8_t led_close[9]; //LED灯关闭数组(为1则下标对应的LED灯关闭)
uint8_t page=1; //LCD页面(1/2)
uint8_t line_now=48; //当前行对应坐标
uint8_t line_old=48; //初始行对应坐标
uint8_t line_end=192; //结束行对应坐标
uint8_t line_setp=48; //每行坐标差
uint8_t lcd_fresh_num=0; //主循环中LCD更新标志(0.4s更新一次,减小LCD更新对LED的影响)
char str[30]; //组合字符串
主循环中只有一个按键有效。
void KEY_Scan()
{
//KEY1 界面切换
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET);
page=2;//LCD页改变
LCD_fresh();//LCD更新
Setting_Mode();//进入设置模式
led_change=1;//LED更新标志,使新用新设定的LED
}
}
}
相比于之前,本次设置模式函数的编写降低了程序耦合度,将数据的增加,减小和保存都写成一个独立的函数来调用。
void Setting_Mode()//设置模式
{
uint8_t i;
line_now=line_old;//当前行更新
uint8_t lcd_change=0;//LCD更新标志位
Color_change();//当前行颜色翻转,上一行颜色恢复
while(1)
{
if(lcd_change)
{
lcd_change=0;
Color_change();//当前行颜色翻转,上一行颜色恢复
}
//KEY1 界面切换
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==GPIO_PIN_RESET);
Data_save();//将数据存储至EEPROM
for(i=1;i<9;i++)//LED关闭数组重置
{
led_close[i]=1;
}
led_close[led_up]=0;//将新设定的Upper LED对应下标改为0
led_close[led_low]=0;//将新设定的Lower LED对应下标改为0
page=1;//LCD显示页改变
LCD_fresh();//LCD更新
break;//退出循环
}
}
//KEY2 选择按键
else if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY2_GPIO_PORT,KEY2_GPIO_PIN)==GPIO_PIN_RESET);
line_now+=line_setp;//行增加
if(line_now>line_end)//如果当前行大于末尾行则回到初始行
line_now=line_old;
lcd_change=1;//LCD改变标志位置1
}
}
//KEY3 ++
else if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY3_GPIO_PORT,KEY3_GPIO_PIN)==GPIO_PIN_RESET);
Data_change(add);//当前数据以增模式改变
lcd_change=1;//LCD改变标志位置1
}
}
//KEY4 --
else if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(KEY4_GPIO_PORT,KEY4_GPIO_PIN)==GPIO_PIN_RESET);
Data_change(sub);//当前行数据以减模式改变
lcd_change=1;//LCD改变标志位置1
}
}
v_now=ADC_GetValue();//获取R37的电压值
LED_refresh();//LED动态更新
}//while
}
使用ADC时需注意,每次GetValue之前都要调用一次Start函数。
double ADC_GetValue()
{
double count;
HAL_ADC_Start(&hadc2);
count=HAL_ADC_GetValue(&hadc2);
return count*3.3/4096;
}
函数中str保存当前行显示字符串,str2保存上一行显示字符串,首行数据的上一行是末尾行。
void Color_change()
{
char str2[30];
if(line_now==line_old+line_setp*0)
{
sprintf(str," Max Volt:%.2fV ",v_max);
sprintf(str2," Lower:LD%d ",led_low);
}
else if(line_now==line_old+line_setp*1)
{
sprintf(str," Min Volt:%.2fV ",v_min);
sprintf(str2," Max Volt:%.2fV ",v_max);
}
else if(line_now==line_old+line_setp*2)
{
sprintf(str," Upper:LD%d ",led_up);
sprintf(str2," Min Volt:%.2fV ",v_min);
}
else if(line_now==line_old+line_setp*3)
{
sprintf(str," Lower:LD%d ",led_low);
sprintf(str2," Upper:LD%d ",led_up);
}
LCD_SetTextColor(Blue);//上一行颜色恢复
LCD_SetBackColor(White);
if(line_now==line_old)
LCD_DisplayStringLine(line_end,(unsigned char*)str2);
else
LCD_DisplayStringLine(line_now-line_setp,(unsigned char*)str2);
LCD_SetTextColor(White);//当前颜色翻转
LCD_SetBackColor(Blue);
LCD_DisplayStringLine(line_now,(unsigned char*)str);
}
LED关闭数组中,若值为1,则下标对应LED灯关闭。
void LED_AllClose()//LED关闭数组中,若值为1,则下标对应LED灯关闭
{
uint8_t i;
for(i=1;i<9;i++)
{
if(led_close[i]==1)
{
switch(i)
{
case 1:
LED1(OFF);
break;
case 2:
LED2(OFF);
break;
case 3:
LED3(OFF);
break;
case 4:
LED4(OFF);
break;
case 5:
LED5(OFF);
break;
case 6:
LED6(OFF);
break;
case 7:
LED7(OFF);
break;
case 8:
LED8(OFF);
break;
}
}
}
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
int main(void)
{
uint8_t i;
/* 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_ADC2_Init();
I2CInit();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
HAL_ADC_Start(&hadc2);//开启ADC2
LCD_Init_Show();//LCD开机界面显示
TIM6->SR=0;//中断标志位置0
Data_read();//从EEPROM中读取数据
for(i=1;i<9;i++)//初始化LED关闭数组
{
led_close[i]=1;
}
led_close[led_up]=0;//开启Upper LED
led_close[led_low]=0;//开启Lower LED
LED_AllClose();//其余灯全部关闭
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
KEY_Scan();//按键扫描
v_now=ADC_GetValue();//获取ADC的值
if(led_statue==2 ||led_statue==0)//LED状态为闪烁(Upper/Lower)
{
if(lcd_fresh_num>1)//每0.4s刷新一次LCD
{
lcd_fresh_num=0;
LCD_fresh();
}
}
else//LED为常亮
{
LCD_fresh();
}
LED_refresh();//LED更新
}
/* USER CODE END 3 */
}
以上就是全部内容,如有错误请批评指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。