蓝桥杯嵌入式第12届模拟赛
按键模块
使用的是状态机消抖
#define KB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define key_input ((KB1)|(KB2<<1)|(KB3<<2)|(KB4<<3)|0XF0)
#define KB1_PRESS 1
#define KB2_PRESS 2
#define KB3_PRESS 3
#define KB4_PRESS 4
uint8_t key_read(void)
{
static int key_state = 0;
unsigned char key_return = 0;
switch(key_state)
{
case 0:
if(key_input != 0xff) key_state = 1;
break;
case 1:
if(key_input == 0xff)key_state = 0;
else
{
switch(key_input)
{
case 0xfe:key_return = KB1_PRESS;break;
case 0xfd:key_return = KB2_PRESS;break;
case 0xfb:key_return = KB3_PRESS;break;
case 0xf7:key_return = KB4_PRESS;break;
}
key_state = 2;
}
break;
case 2:
if(key_input == 0xff) key_state = 0;
break;
}
return key_return;
}
主函数按键处理代码
if(key_flag)
{
key_flag=0;
key_val = key_read();
if(key_val == KB1_PRESS)
{
mode_flag++;
if(mode_flag == 2)
{
mode_flag = 0;
if(Volmax < (Volmin + 5))
{
Volmax = temp_Volmax;
Volmin = temp_Volmin;
}
}
if(mode_flag == 1)
{
temp_Volmax = Volmax;
temp_Volmin = Volmin;
}
}
if(key_val == KB2_PRESS)
{
if(mode_flag == 1)
{
Volmax -=1;
if(Volmax == -1) Volmax = 33;
}
}
if(key_val == KB3_PRESS)
{
if(mode_flag == 1)
{
Volmin +=1;;
if(Volmin == 34) Volmin = 0;
}
}
}
由于float的问题,所以不能直接判断 Vmax==0.0f以及Vmin == 3.3f,所以这里选用了使用整型数,方便判断。
PWM输出模块
这里是通过PA0输出PWM波。将TIM2的CHANNEL2设置为PWM输出模式。
void PWM_OUTPUT(unsigned char state)
{
switch(state)
{
case 1:
TIM2->ARR=9999;
//TIM2->CCR2=5000;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,5000);
TIM2->EGR=TIM_EGR_UG;
break;
case 2:
TIM2->ARR=999;
//TIM2->CCR2=500;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,500);
TIM2->EGR=TIM_EGR_UG;
break;
case 3:
TIM2->ARR=99;
//TIM2->CCR2=50;
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50);
TIM2->EGR=TIM_EGR_UG;
break;
}
}
注释掉的部分和_HAL_TIM_SET_COMPARE();函数是一个效果。
定时器模块
使用TIM3作为通用定时器,调用回执函数,在定时器中断内设置adc读取间隔实践以及按键时间。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM3)
{
static int key_count = 0, adc_count = 0;
key_count++;
if(key_count==10)
{
key_count=0;
key_flag=1;
}
if(Adc_flag == 0)
{
adc_count++;
if(adc_count == 50)
{
adc_count = 0;
adc_flag=1;
}
}
}
}
LCD显示模块
通过mode_flag的不同值作为数据页面与设置页面的判断。
if(mode_flag == 0)
{
LCD_DisplayStringLine(Line1,data_str);
sprintf((char *)show_str,"V:%.2fV ",adc_ana_val);
LCD_DisplayStringLine(Line3,show_str);
sprintf((char *)show_str,"A:%d ",Vol_State);
LCD_DisplayStringLine(Line4,show_str);
}
else
{
LCD_DisplayStringLine(Line1,para_str);
sprintf((char *)show_str,"Vmax:%d.%dV ",Volmax/10,Volmax%10);
LCD_DisplayStringLine(Line3,show_str);
sprintf((char *)show_str,"Vmin:%d.%dV ",Volmin/10,Volmin%10);
LCD_DisplayStringLine(Line4,show_str);
}
关于LED与LCD冲突的内容,可以看一下这篇文章。
void LEDx_ON(unsigned char led_pin)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7<<(led_pin),GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}