后面有时间的话,会不断更新各届真题,现在2022年的第一场省赛测试基本完成所有功能,注释掉的代码有解释,不看也没有影响。
提示:以下是本篇文章正文内容,下面案例可供参考
进行按键扫描,置位相应标志位
代码如下(示例):
//按键标志位
uint8_t key1_flag = 0;
uint8_t key2_flag = 0;
uint8_t key3_flag = 0;
uint8_t key4_flag = 0;
//读取当前状态
uint8_t key1_state = 1;
uint8_t key2_state = 1;
uint8_t key3_state = 1;
uint8_t key4_state = 1;
//保存上一次状态
uint8_t key1_state_last = 1;
uint8_t key2_state_last = 1;
uint8_t key3_state_last = 1;
uint8_t key4_state_last = 1;
/*
*@函 数: Key_Scan
*@功 能: 进行按键扫描
*/
void Key_Scan(void)
{
//读取当前电压
key1_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key2_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key3_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key4_state = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
//检测按键按下1-->0 下降沿
if(key1_state_last && !key1_state ) key1_flag = 1;
if(key2_state_last && !key2_state ) key2_flag = 1;
if(key3_state_last && !key3_state ) key3_flag = 1;
if(key4_state_last && !key4_state ) key4_flag = 1;
//保存当前状态用于下一次判断
key1_state_last = key1_state ;
key2_state_last = key2_state ;
key3_state_last = key3_state ;
key4_state_last = key4_state ;
}
代码如下(示例):
/*
*@函 数: LED_Disp
*@功 能: LED显示
*/
void LED_Disp(uint8_t ucLed)
{
HAL_GPIO_WritePin(GPIOC,0xff<<8,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC,ucLed<<8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "lcd.h"
#include
#include
void SystemClock_Config(void);
uint8_t UART_Receive_Buff;//串口每次中断接收变量存储
uint8_t Receive_Password[7];//将接收的七次的数据存储
uint8_t Index = 0;
//LED 变量
uint8_t ucled = 0;
//延时 变量
uint32_t uwTick_Key_Wait_Time = 0;//按键扫描延时
uint32_t uwTick_Page_Wait_Time = 0;//输出界面2切换延时
uint32_t uwTick_LED_Wait_Time = 0;//密码错误 LED 0.1s闪烁延时
//LCD 变量
uint8_t LCD_Buff[20];
uint8_t Page = 1;//界面切换变量
//定时器变量
float PA1_Fre = 0;
float PA1_Duty = 0;
//储存正确密码
uint8_t Right_Password[3] = {1,2,3};
//密码结构体
typedef struct
{
int8_t Word1;//第一位密码
int8_t Word2;//第二位密码
int8_t Word3;//第三位密码
uint8_t Input_Error_Cnt;//记录输入错误次数
bool NoDisp_Flag[3];//B1 B2 B3 不显示密码标志
bool Input_Right_Flag;//输入正确标志
}Password;
Password PSD = {-1,-1,-1,0,{1,1,1},0};
//函数声明
void KEY_Process(void);
void LED_Process(void);
void LCD_UI(void);
//主函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
//关闭所有LED
LED_Disp(0x00);
//LCD 初始化
LCD_Init();
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
LCD_Clear(Black);
//定时器初始化
__HAL_TIM_SET_AUTORELOAD(&htim2,999);//默认1KHz 1M/1000 = 1K
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,500);//占空比 500/(999+1)
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
//开启串口
HAL_UART_Receive_IT(&huart1,&UART_Receive_Buff,1);
//默认上电不显示密码
PSD.NoDisp_Flag[0] = 1;//B1不显示
PSD.NoDisp_Flag[1] = 1;//B2不显示
PSD.NoDisp_Flag[2] = 1;//B3不显示
//主循环
while (1)
{
KEY_Process();//按键处理
LED_Process();//led处理
LCD_UI();//显示界面
}
}
/*
*@函 数: KEY_Process
*@功 能: 按键处理
*/
void KEY_Process(void)
{
if((uwTick - uwTick_Key_Wait_Time)<50) return;
uwTick_Key_Wait_Time = uwTick;
//按键扫描,只有在输入界面才允许按键扫描
if(Page==1) { Key_Scan();}
if(key1_flag)
{
key1_flag = 0;
PSD.NoDisp_Flag[0] = 0;//允许显示输入的密码
PSD.Word1 ++;
if(PSD.Word1>=10) { PSD.Word1=0; }//限幅
}
else if(key2_flag)
{
key2_flag = 0;
PSD.NoDisp_Flag[1] = 0;//允许显示输入的密码
PSD.Word2 ++;
if(PSD.Word2>=10) { PSD.Word2=0; }
}
else if(key3_flag)
{
key3_flag = 0;
PSD.NoDisp_Flag[2] = 0;//允许显示输入的密码
PSD.Word3 ++;
if(PSD.Word3>=10) { PSD.Word3=0; }
}
else if(key4_flag)
{
key4_flag = 0;
//开始比对密码
if((PSD.Word1 == Right_Password[0]) && (PSD.Word2 == Right_Password[1]) &&
(PSD.Word3 == Right_Password[2]))
{
//修改PWM参数
__HAL_TIM_SET_AUTORELOAD(&htim2,499);//2KHz 1M/500 = 2K
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50);//占空比 50/(499+1)= 10%
HAL_TIM_PWM_Init(&htim2);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
if(__HAL_TIM_GET_AUTORELOAD(&htim2))
PA1_Fre = 1000000.0f/(__HAL_TIM_GET_AUTORELOAD(&htim2)+1);//2000Hz
if(__HAL_TIM_GET_COMPARE(&htim2,TIM_CHANNEL_2))
PA1_Duty = __HAL_TIM_GET_COMPARE(&htim2,TIM_CHANNEL_2)*100.0f/(__HAL_TIM_GET_AUTORELOAD(&htim2)+1);
PSD.Input_Right_Flag = 1;//密码输入正确
Page = 2;//切换显示界面
uwTick_Page_Wait_Time = uwTick;//输出显示界面延时
ucled = 0x01 ;//密码输入正确,LED1亮
}else{
Page = 1;//仍然处于输入界面
//密码输入错误
PSD.Input_Error_Cnt ++;
//显示界面显示@
PSD.NoDisp_Flag[0] = 1;//隐藏第一位密码
PSD.NoDisp_Flag[1] = 1;//隐藏第二位密码
PSD.NoDisp_Flag[2] = 1;//隐藏第三位密码
//密码设置初始化,每按一次加一,从-1开始
PSD.Word1 = -1; PSD.Word2 = -1; PSD.Word3 = -1;
}
}
}
/*
*@函 数: LED_Process
*@功 能: LED处理
*/
void LED_Process(void)
{
static uint8_t led_cnt = 0;
if(PSD.Input_Error_Cnt>=3)//错误次数达到三次时
{
if((uwTick - uwTick_LED_Wait_Time)>=100)//控制100ms闪烁
{
uwTick_LED_Wait_Time = uwTick;
led_cnt ++;//0.1s*(51-1) = 0.1*50 = 5s
ucled ^= 0x02;
}
if(led_cnt>=51)
{//清除标志位
led_cnt = 0;
ucled = 0x00;
uwTick_LED_Wait_Time = 0;
PSD.Input_Error_Cnt = 0;
}
}
LED_Disp(ucled);
}
/*
*@函 数: LCD_UI
*@功 能: UI界面
*/
void LCD_UI(void)
{
switch(Page)
{
case 1://输入界面
LCD_DisplayStringLine(Line1,(uint8_t*)" PSD ");
if(PSD.NoDisp_Flag[0]==1)//密码隐藏则显示@
{
sprintf((char*)LCD_Buff," B1:%c ",'@');
LCD_DisplayStringLine(Line3,LCD_Buff);
}else{
sprintf((char*)LCD_Buff," B1:%d ",PSD.Word1);
LCD_DisplayStringLine(Line3,LCD_Buff);
}
if(PSD.NoDisp_Flag[1]==1)//密码隐藏则显示@
{
sprintf((char*)LCD_Buff," B2:%c ",'@');
LCD_DisplayStringLine(Line4,LCD_Buff);
}else{
sprintf((char*)LCD_Buff," B2:%d ",PSD.Word2);
LCD_DisplayStringLine(Line4,LCD_Buff);
}
if(PSD.NoDisp_Flag[2]==1)//密码隐藏则显示@
{
sprintf((char*)LCD_Buff," B3:%c ",'@');
LCD_DisplayStringLine(Line5,LCD_Buff);
}else{
sprintf((char*)LCD_Buff," B3:%d ",PSD.Word3);
LCD_DisplayStringLine(Line5,LCD_Buff);
}
break;
case 2://输出界面
LCD_DisplayStringLine(Line1,(uint8_t*)" STA ");
sprintf((char*)LCD_Buff," F:%.0fHz ",PA1_Fre);
LCD_DisplayStringLine(Line3,LCD_Buff);
sprintf((char*)LCD_Buff," D:%.0f%% ",PA1_Duty);
LCD_DisplayStringLine(Line4,LCD_Buff);
LCD_ClearLine(Line5);
break;
}
//处于界面2
if(Page==2)
{
if((uwTick - uwTick_Page_Wait_Time)>5000)//5s后
{
ucled = 0x00;//5s后 关闭LED
//这句话很重要,如果直接使用下面频率和占空比的配置会出问题
MX_TIM2_Init(); //配置后 ,默认的输出就是1KHz,50%,因此下面 的操作都可以不用,除非需要改到其他值
//寄存器和库函数操作用的话 两者选其一,不用没用影响,MX_TIM2_Init已经配置好了
//寄存器操作
//htim2.Instance->ARR = 999;//默认1KHz 1M/1000 = 1K
//htim2.Init.Period = 999; //占空比 500/(999+1)=50%
//htim2.Instance->CCR2 = 300; //操作寄存器修改比较值
//库函数操作
//__HAL_TIM_SET_AUTORELOAD(&htim2,999);//默认1KHz 1M/1000 = 1K
//__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,500);//占空比 500/(999+1)=50%
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
Page = 1;//切换界面
//显示界面显示@
PSD.NoDisp_Flag[0] = 1;//隐藏第一位密码
PSD.NoDisp_Flag[1] = 1;//隐藏第二位密码
PSD.NoDisp_Flag[2] = 1;//隐藏第三位密码
//密码设置初始化
PSD.Word1 = -1; PSD.Word2 = -1; PSD.Word3 = -1;
}
}
}
/*
*@函 数: HAL_UART_RxCpltCallback
*@功 能: 串口接收中断回调函数
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
Receive_Password[Index++] = UART_Receive_Buff;
if(Index==7)//接收到七个字符后
{
Index = 0;
Receive_Password[0] = Receive_Password[0] - '0';
Receive_Password[1] = Receive_Password[1] - '0';
Receive_Password[2] = Receive_Password[2] - '0';
if((Right_Password[0] == Receive_Password[0]) && (Right_Password[1] == Receive_Password[1]) &&
(Right_Password[2] == Receive_Password[2]))//密码正确修改密码
{//更新密码
Right_Password[0] = Receive_Password[4] - '0';
Right_Password[1] = Receive_Password[5] - '0';
Right_Password[2] = Receive_Password[6] - '0';
}
}
HAL_UART_Receive_IT(&huart1,&UART_Receive_Buff,1);//进行下一次接收
}
代码链接就放在下面了,需要的可以自己提取:
https://www.aliyundrive.com/s/yt8cDeNM1y6
提取码: hq40