第十三届蓝桥杯嵌入式省赛真题演练 |
您所在的位置:网站首页 › 按键式6位密码门锁怎么改密码 › 第十三届蓝桥杯嵌入式省赛真题演练 |
题目分析
led.c文件,用一个函数来指定对应led亮灭 #include "led.h" void led_dis(uint8_t num) //定义一个选中led亮灯的函数,num为8位 { HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET); //拉高全部引脚,让led都熄灭 HAL_GPIO_WritePin(GPIOC,num 0}; void dis_pro() { if(view == 0) //通过按键来切换 { sprintf((char *)temp," P S D"); //将待显示数据放入数组 LCD_DisplayStringLine(Line2,temp); //显示数组中的数据 sprintf((char *)temp," B 1 :"); LCD_DisplayStringLine(Line4,temp); sprintf((char *)temp," B 2 :"); LCD_DisplayStringLine(Line5,temp); sprintf((char *)temp," B 3 :"); LCD_DisplayStringLine(Line6,temp); } if(view == 1) { sprintf((char *)temp," S T A"); LCD_DisplayStringLine(Line2,temp); sprintf((char *)temp," F :"); LCD_DisplayStringLine(Line4,temp); sprintf((char *)temp," D :"); } } #ifndef _DIS_PRO_H #define _DIS_PRO_H #include "stdio.h" #include "main.h" #include "lcd.h" void dis_pro(void); #endif当然,如果有报错说某某函数或变量没有定义,那就在相应的.h文件中添加相关声明或即可。当然在key.c中还定义了一个按键功能函数 void key_pro() { if(key_sta[3].flag == 1) { view ++; if(view > 1) view = 0; LCD_Clear(Black); key_sta[3].flag = 0; } }下载验证,结果可观。 接下来写串口通信模块。 #include "uart.h" uint8_t dat = 0; //创建变量来接收单个数据 uint8_t data[30] = {0}; //创建数组来储存接收的数据 uint8_t pointer = 0; //创建一个光标来指示当前所在数组的位置 uint8_t a[2] = {'1'}; //接收串口设置的密码的第一位 uint8_t b[2] = {'2'}; //接收串口设置的密码的第二位 uint8_t c[2] = {'3'}; //接收串口设置的密码的第三位 uint8_t d[5] = {0}; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //串口接收中断回调函数 { data[pointer++] = dat; //将当前接收到的单个数据存入数组 HAL_UART_Receive_IT(huart,&dat,1); //开启串口接收中断继续接收 } void uart_pro() //定义一个函数实现串口的具体功能 { if(pointer > 0) { if(pointer == 7) //若接收到七个数据,就把数据分放便于后续比较 { sscanf((char*)data,"%3s-%1s%1s%1s",d,a,b,c); //将data这个数组中的数据按照后面定义的格式分别放入dabc四个数组中 } else { char text[30]; sprintf(text,"ERROR"); HAL_UART_Transmit(&huart1,(uint8_t *)text,strlen(text),50);//若未接收完则向用户发送一个erro } pointer = 0; //光标回首位 memset(data,0,30); //数组归零 } } #ifndef _UART_H #define _UART_H #include "main.h" #include "stdio.h" #include "usart.h" #include "string.h" void uart_pro(void); #endif前面分析的基本模块现已基本实现,接下来仔细去看题目的要求,对各模块的具体功能要求。 首先,按键输入@,0-9几个数来模拟输入密码的过程,与串口设置的密码进行比对,B4按下时若密码输入正确,则切换界面。初始状态下三位密码显示皆为@。主要需要修改的就是按键模块。 void key_pro() { if(key_sta[0].flag == 1) //B1按键 { if(n_1[0] == '@') //根据ASCII码表先将字符@改为0 n_1[0] -= 17; n_1[0]++; //按键自增 if(n_1[0]>57) //超过9后变回@,@-0-9 n_1[0] = '@'; key_sta[0].flag = 0; //标志位归零 } if(key_sta[1].flag == 1) //B2 { if(n_2[0] == '@') n_2[0] -= 17; n_2[0]++; if(n_2[0]>57) n_2[0] = '@'; key_sta[1].flag = 0; } if(key_sta[2].flag == 1) //B3 { if(n_3[0] == '@') n_3[0] -= 17; n_3[0]++; if(n_3[0]>57) n_3[0] = '@'; key_sta[2].flag = 0; } if(key_sta[3].flag == 1) //B4 { if((a[0] == n_1[0]) && (b[0] == n_2[0]) && (c[0] == n_3[0])) //判断密码是否输入正确 { view ++; //切换界面 if(view > 1) view = 0; LCD_Clear(Black); key_sta[3].flag = 0; } } }下载发现初始密码可以解锁,但无法通过按键进行修改。问题出在写串口的时候,没有在main.c中开启串口接收中断,在/* USER CODE BEGIN 2 */ 下加入HAL_UART_Receive_IT(&huart1,&dat,1);开启即可。验证无误。 题目要求,输入密码成功后要有信号输出,前面看不懂的那个模块用处就在于此。使用PA1完成脉冲输出功能,没输入正确密码前PA1输出的是1KHz的方波信号,密码正确则变为2KHz 占空比为10%的方波信号。持续五秒后,又变回原来的信号以及密码输入界面。 那我们去cube中先配置PA1为TIM_CH2。因为初始为1KHz,分频80,重装载1000。而因为我们要在LCD上显示频率和占空比,计算频率可以随便用上升沿或下降沿,捕获到的相当于PWM波一个周期的时间,用80000000(时钟频率)/80(分频系数)/time(捕获到的时间)=频率。而占空比则是利用下降沿的时间除以整个周期时间,则为占空比。所以可以配置一个输入捕获(如PB4),利用其中两个通道来分别捕获上升沿和下降沿的时间来计算频率值。 再次生成代码并打开工程文件。在key.c中写入输入捕获中断回调函数。 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) //输入捕获中断回调函数 { if(htim->Instance == TIM3) { time_1 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); //读出计时值 time_2 = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2); __HAL_TIM_SetCounter(htim,0); //计时值归零 frq_1 = (80000000/80)/time_1; //计算当前频率 zk = (time_2/time_1)*100; //计算占空比(下降沿时间除以上升沿时间) HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_1); //打开输入捕获定时器 HAL_TIM_IC_Start_IT(htim,TIM_CHANNEL_2); } }有了之前的教训,不要忘记在主函数中分别开启PWM信号和输入捕获中断。这里先不去管具体的功能,将frq_1和zk放入dis_pro.c中显示,想测试一下这个信号输出模块是否能成功。果不其然,代码逻辑是1000hz的频率,但显示出来就是233这个数,占空比为0。结果问题出在对变量的定义上,这里的代码没有给出变量定义,但文末我会附上整个工程文件。我写代码有个问题是在变量的定义上,不会去细想,这个数据的本质,只一心想着这个代码逻辑,问就是uint8_t类型,也不会报错,但出了问题也确实给我整嘛了。这里,time应该是double类型,而频率应该是uint16_t类型。 根据题目要求,密码输入正确后,频率会从4k变为2k且占空比为10%。在key_pro()函数中增改如下代码 if(key_sta[3].flag == 1) //B4 { if((a[0] == n_1[0]) && (b[0] == n_2[0]) && (c[0] == n_3[0])) //判断密码是否输入正确 { LCD_Clear(Black); //输入正确则清屏切换界面 view ++; __HAL_TIM_SET_AUTORELOAD(&htim2,530); //设置频率为2k __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50); //设置占空比 HAL_Delay(5000); __HAL_TIM_SET_AUTORELOAD(&htim2,999); //恢复频率为1k if(view > 1) view = 0; key_sta[3].flag = 0; } }编译无误,下载验证。再有,题目有信号输出精度要求,但是我按照这样的思路写出来他的频率已经超出精度范围了。我猜测是因为tim3开了两个通道的的缘故,因为一开始我没写占空比的测量,也就只开了一个捕获上升沿的通道,频率精度是正常的。这里可以调高函数中的参数值(如上面的代码__HAL_TIM_SET_AUTORELOAD的参数我设置为了530)。 最后,LED功能部分。题目要求密码验证成功,LED1点亮五秒后熄灭,而如果暑促密码>=3次,LED2以100毫秒的间隔闪烁,五秒后熄灭。在key_pro()函数中增改如下代码 if(key_sta[3].flag == 1) //B4 { if((a[0] == n_1[0]) && (b[0] == n_2[0]) && (c[0] == n_3[0])) //判断密码是否输入正确 { LCD_Clear(Black); //输入正确则清屏切换界面 view ++; __HAL_TIM_SET_AUTORELOAD(&htim2,530); //设置频率为2k __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50); //设置占空比 led_dis(0x01); //LED1亮5s HAL_Delay(5000); __HAL_TIM_SET_AUTORELOAD(&htim2,999); //恢复频率为1k led_dis(0x00); if(view > 1) view = 0; } else { wrong ++; //错误次数 if(wrong >= 3) { for(uint8_t i = 0; i if((a[0] == n_1[0]) && (b[0] == n_2[0]) && (c[0] == n_3[0])) //判断密码是否输入正确 { wrong = 0; __HAL_TIM_SET_AUTORELOAD(&htim2,530); //设置频率为2k __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50); //设置占空比 led_dis(0x01); //LED1亮5s view ++; LCD_Clear(Black); //输入正确则清屏切换界面 uwTick_pwm = uwTick; while(uwTick - uwTick_pwm wrong ++; //错误次数 if(wrong >= 3) { for(uint8_t i = 0; i |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |