蓝桥杯嵌入式13届第一场赛题
提示:本文描述赛题是关于蓝桥杯嵌入式第十三届省赛第一场:
话少,是不可能的,下面是对上述赛题的的一些讲解(不能算讲解,称之为理解吧)
首先来说说我程序的实现步骤吧:
- 实现密码输入与判断密码的正误
- 使用串口实现密码的更改
- 实现PWM的输出
- 实现题目中其他外设
- 调试程序bug,并完善程序
时钟配置
上面是关于赛题的时钟配置,我们在学习F1平台的时候会配置HCLK为72MHz(这里我理解是将时钟配置成最大,速度快一点),这里配置80MHz我也不知道为啥,对这方面有兴趣的朋友可以分享分享。在debug配置的时候,最好将SW选上,在使用F1平台时候,刚开始使用hal库,由于debug未勾选上,导致芯片下不了程序,但在G4平台中网上的一些视频也没有勾选debug配置,并不会导致芯片锁死。官方给的驱动代码也没有选择。所以对G4来说并没有什么影响,各位兄弟在配置时候还是住点意吧。也有可能芯片是盗版才导致锁死的。
三行按键的理解
uc_KeyDown = uc_KeyVal & (uc_KeyOld ^ uc_KeyVal); // Press the key value
uc_KeyUp = ~ uc_KeyVal & (uc_KeyOld ^ uc_KeyVal); // Press the key to lift the key value
uc_KeyOld = uc_KeyVal;
现在我们开始假设
过程1:假设第4个被按下也就是’uc_KeyVal = 4(0000 0100)’ 经过’uc_KeyDown’ 中的运算,使得’uc_KeyDown’ 变成了4(0000 0100) uc_KeyUp为0,uc_KeyOld = 4(0000 0100)
过程2:当第4个按键产生下降沿时,按键一直被按下(注意此时的状态是按下,并非按键的不定态)。此时uc_KeyVal 仍然为4(0000 0100)由于在uc_KeyOld 在上一次值的变换,当前的uc_KeyDown变成了0,uc_KeyUp也变成了0,uc_KeyOld还是4
过程3:第4个按键一直按下随后弹起,uc_KeyVal 变为0 。uc_KeyDown变为0,uc_KeyUp变成了4,uc_KeyOld 变为了0。按键识别结束。
定时器的配置
- 定时器6用于计时5s
- 定时器2用来产生PWM脉冲
初始设置频率是1000Hz = 80MHz x106 /[(79 + 1) + (999 + 1)]
对于上述定时器,6开中断进行精准定时,2不需要开启中断。
下面是定时器2设置PWM输出所用的函数。
__HAL_TIM_SET_AUTORELOAD(&htim2, 999); /* 设置频率1Khz */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */
到这里我们就结束了,代码里有详细的注释,可以直接下载进行参考,欢迎各位Up进行评论和指正。评论还是在csdn吧,GitHub还是个小白,不咋玩的明白。
下面是部分函数:
- 定时器6处理
static uint16_t u16_ms = 0;
static uint16_t u16_100ms = 0;
static uint16_t u16_5000ms = 0;
if(htim->Instance == TIM6) {
if(right_flag) { /* 密码输入正确开始计时 */
u16_ms++;
if(u16_ms == 5000) {
right_flag = 0;
PSD_STA = 0; /* 切回界面 */
mima[0] = mima[1] = mima[2] = '@';
lcd_flag_show = 1; /* LCD清屏 */
u16_ms = 0;
}
}
if(ld2_YN_flag) {
u16_5000ms++;
if(u16_5000ms == 5000) {
ld2_YN_flag = 0;
u16_5000ms = 0;
}
}
if(++u16_100ms == 100) {
flag ^= 1;
u16_100ms = 0;
}
}
HAL_TIM_Base_Start_IT(&htim6)
- 串口处理函数
int isRxCplt(void) {
uint8_t i;
if(dex == 0) /* 没有接受到数据 */
return 0;
else if(dex != 7) { /* 接收不满7位数据 */
return -1;
}
if(rx_buf[3] == '-') { /* 接收密码数据正确 */
for(i = 0; i < 3; i++) {
if(rx_buf[i] < '0' || rx_buf[i] > '9') /* 前三位接收合法返回错误 */
return -1;
}
for(i = 4; i < 7; i++) {
if(rx_buf[i] < '0' || rx_buf[i] > '9') /* 后三位接收合法返回错误 */
return -1;
}
return 1;
}
else return -1; /* 接收到第三个数据不为 '-' 返回错误 */
return 0;
}
void Uart_Proc(void) {
static __IO uint32_t uwTick_UART_Speed;
uint8_t tx[21];
if((uwTick - uwTick_UART_Speed) < 100) return;
uwTick_UART_Speed = uwTick;
if(isRxCplt() == 1) {
if((rx_buf[0] == right_mima[0])&&(rx_buf[1] == right_mima[1])&&(rx_buf[2] == right_mima[2])) { /* 发送前三位密码与原始密码相同。则密码正确 */
/* 修改密码 */
right_mima[0] = rx_buf[4];
right_mima[1] = rx_buf[5];
right_mima[2] = rx_buf[6];
sprintf((char* )tx, "OK\r\n");
HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送OK表示修改成功 */
}
else { /* 输入原始密码错误 */
sprintf((char* )tx, "ERROR\r\n");
HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送错误 */
}
}
else if(isRxCplt() == -1){ /* 接受数据不合法 */
sprintf((char* )tx, "ERROR\r\n");
HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送错误 */
}
dex = 0; /* 清除串口接收数组索引 */
}
- LED处理函数
void LED_Proc(void) {
static __IO uint32_t uwTick_LED_Speed;
if((uwTick - uwTick_LED_Speed) < 100) return;
uwTick_LED_Speed = uwTick;
LED_CLOSE(); // 关灯
if(right_flag) { /* 密码输入正确 */
LED_Disp_OP(LD1);
pwm_flag = 1; /* 输出脉冲 */
}
else {
LED_Disp_CL(LD1);
pwm_flag = 0; /* 输出脉冲 */
}
if(ld2_YN_flag) {
if(flag)
LED_Disp_OP(LD2);
else
LED_Disp_CL(LD2);
}
else LED_Disp_CL(LD2);
}
- LCD 处理函数
void LCD_Proc(void) {
static __IO uint32_t uwTick_LCD_Speed = 0;
if(uwTick - uwTick_LCD_Speed < 100) return; /* 函数刷新频率 */
uwTick_LCD_Speed = uwTick;
if(lcd_flag_show == 1) { /* 从STA界面切回PSD界面 需要清屏一次 */
lcd_flag_show = 0;
LCD_Clear(White);
}
/* 默认输出方波,占空比为50% */
/* 在LED_Proc()中实现pwm_flag的控制 */
if(pwm_flag == 0) { /* 输出方波,占空比为50% */
__HAL_TIM_SET_AUTORELOAD(&htim2, 999); /* 设置频率1Khz */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */
}
else if(pwm_flag == 1) { /* 密码正确输出脉冲,占空比为50% */
__HAL_TIM_SET_AUTORELOAD(&htim2, 499); /* 设置频率2Khz = 80Mhz/[(AUTORELOAD+1) + 80] 其中80为cubemx配置 */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 50); /* 设置占空比为10% = 50/500*/
}
if(PSD_STA == 0) { /* 在PSD界面 */
sprintf((char* )Lcd_Disp_String, (const char* )" P S D ");
LCD_DisplayStringLine(Line2, Lcd_Disp_String);
sprintf((char* )Lcd_Disp_String, (const char* )" B1 : %c", mima[0]);
LCD_DisplayStringLine(Line4, Lcd_Disp_String);
sprintf((char* )Lcd_Disp_String, (const char* )" B2 : %c", mima[1]);
LCD_DisplayStringLine(Line5, Lcd_Disp_String);
sprintf((char* )Lcd_Disp_String, (const char* )" B3 : %c", mima[2]);
LCD_DisplayStringLine(Line6, Lcd_Disp_String);
}
else if(PSD_STA == 1) { /* 在STA界面 */
memset(Lcd_Disp_String, '\0', sizeof(Lcd_Disp_String));
sprintf((char* )Lcd_Disp_String, (const char* )" S T A ");
LCD_DisplayStringLine(Line2, Lcd_Disp_String);
if(pwm_flag == 1) { freq = 2000; D_Pwm = 10; } /* 密码正确后输出脉冲,占空比为10% */
else { freq = 1000; D_Pwm = 50; } /* 5s后输出方波,占空比为50% */
sprintf((char* )Lcd_Disp_String, (const char* )" F : %04dHz", freq);
LCD_DisplayStringLine(Line4, Lcd_Disp_String);
sprintf((char* )Lcd_Disp_String, (const char* )" D : %02d%%", D_Pwm);
LCD_DisplayStringLine(Line5, Lcd_Disp_String);
}
}
- 按键处理
void B4(void) {
if(PSD_STA == 0) {
if((right_mima[0] == mima[0])&&(right_mima[1] == mima[1])&&(right_mima[2] == mima[2])) { /* 密码正确 */
error_num = 0;
right_flag = 1;
PSD_STA = 1; // 密码正确进入界面二
LCD_Clear(White); /* 密码正确进行清屏 */
}
else { /* 密码错误 */
if(++error_num >= 3) { /* 密码错误大于3次 */
ld2_YN_flag = 1; /* LD2闪烁报警 */
}
right_flag = 0;
mima[0] = mima[1] = mima[2] = '@';
}
}
}
void B3(void) {
if(PSD_STA == 0) {
if(++mima[0] > '9')
mima[0] = '0';
}
}
void B2(void) {
if(PSD_STA == 0) {
if(++mima[1] > '9')
mima[1] = '0';
}
}
void B1(void) {
if(PSD_STA == 0) {
if(++mima[2] > '9')
mima[2] = '0';
}
}
- 主函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_TIM6_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
LCD_Init(); /* LCD初始化 */
LCD_Clear(White);
LCD_SetBackColor(White); // 背景颜色
LCD_SetTextColor(Blue); // 文本颜色
HAL_TIM_Base_Start_IT(&htim6); /* 基础定时器6(1ms)中断开启 */
HAL_UART_Receive_IT(&huart1, &rx, 1); /* 打开异步串口1通信 */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
__HAL_TIM_SET_AUTORELOAD(&htim2, 999); /* 设置频率1Khz */
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */
while (1)
{
LED_Proc();
LCD_Proc();
Key_Proc();
Uart_Proc();
}
return 0;
}
下面是关与源代码的链接:
13届省赛第一场
希望可以帮助到大家。