导航菜单
首页 >  蓝桥杯大赛历年真题嵌入式  > 蓝桥杯嵌入式

蓝桥杯嵌入式

题目

    十三届省赛是要制作一个可由串口设置密码的密码锁。在本场比赛中,我们将用到LED模块、按键模块、串口模块、定时器的PWM模块以及官方会提供源码的LCD模块。下面就请看原题:

在这里插入图片描述

题解

    在正式题解前,大家需要注意以下几点:

由于LCD与LED有部分引脚是共用的,因此初始化完成LCD后最好手动关闭LED;由于每次LCD显示的长度可能不同,因此在本次显示前,要不先清屏,要不跟上次显示一样长;使用CubeMX配置完成串口USART1后需要更改默认引脚为PA9、PA10;LED模块

    通过查询产品手册知,LED的引脚为PC8~PC15,外加锁存器74HC573需要用到的引脚PD2。(由于题目要求除LED1、LED2外的其他LED都处于熄灭状态,此处特意将所有的LED都初始化) CubeMX配置: 代码样例     由于G431的所有LED都跟锁存器74HC573连接,因此每次更改LED状态时都需要先打开锁存器,写入数据后再关闭锁存器。

/****************************************************** 函数功能:改变所有LED的状态* 函数参数:*char LEDSTATE: 0-表示关闭 1-表示打开* 函数返回值:无******************************************************/void changeAllLedByStateNumber(char LEDSTATE){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,(LEDSTATE==1?GPIO_PIN_RESET:GPIO_PIN_SET));//打开锁存器准备写入数据HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);//关闭锁存器 锁存器的作用为 使得锁存器输出端的电平一直维持在一个固定的状态HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}/****************************************************** 函数功能:根据LED的位置打开或者是关闭LED* 函数参数:*uint16_t LEDLOCATION:需要操作LED的位置*char LEDSTATE: 0-表示关闭 1-表示打开* 函数返回值:无******************************************************/void changeLedStateByLocation(uint16_t LEDLOCATION,char LEDSTATE){HAL_GPIO_WritePin(GPIOC,LEDLOCATION,(LEDSTATE==1?GPIO_PIN_RESET:GPIO_PIN_SET));HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);} 按键模块

    通过查询产品手册知,开发板上的四个按键引脚为PB0~PB2、PA0。 CubeMX配置 代码样例     由于G431开发板上按键数量较少以及本次按键不涉及长短按、单击双击等复杂按键的设计,因此,我们直接使用含锁机制的if判断即可。

第一步,判断按键是否按键以及锁是否处于打开状态,如果两者有一个不满足函数直接返回;否则,进入下一步;第二步,上锁,延时消抖;第三步,再次读取各个按键,判断具体是哪个按键按下;第四步,判断按键是否松开,如果松开,则开锁;否则函数直接返回。 /********************************************* * 函数功能:按键扫描 含按键消抖 无长按短按设计 * 函数参数:无 * 函数返回值:按键的位置 *返回值说明:B1-1 B2-2 B3-3 B4-4*********************************************/unsigned char scanKey(void){//按键锁static unsigned char keyLock = 1;//记录按键消抖时间// static uint16_t keyCount = 0;//按键按下if((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == RESET || HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == RESET || HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == RESET || HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)&& keyLock == 1){//给按键上锁 避免多次触发按键keyLock = 0;//按键消抖 这里最好不要使用延时函数进行消抖 会影响系统的实时性// if(++keyCount % 10 < 5) return 0;// if(HAL_GetTick()%15 < 10) return 0;HAL_Delay(10);//按键B1if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == RESET){return 1;}//按键B2if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == RESET){return 2;}//按键B3if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == RESET){return 3;}//按键B4if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET){return 4;}}//按键松开if((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == SET && HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == SET && HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == SET && HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == SET)&& keyLock == 0){//开锁keyLock = 1;}return 0;} 串口

    本次试题中,串口功能比较简单,只需要能够完成简单的接收数据即可。 CubeMX配置     配置时一定一定记得改引脚!!! 在这里插入图片描述 代码样例     HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)函数解析:

UART_HandleTypeDef *huart:串口通道;uint8_t *pData:存放数据的buff;uint16_t Size:一次接收数据的长度     不过使用时还需要初始化,否则不能够进入中断接收数据; /***使用HAL_UART_Receive_IT中断接收数据 每次接收完成数据后就会执行该函数***/void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart->Instance == USART1){// 重新使能中断HAL_UART_Receive_IT(huart,(uint8_t *)&Rxbuff,sizeof(Rxbuff)); }} 定时器输出PWM波

CubeMX配置 在这里插入图片描述 修改PWM的频率及占空比样例代码(可直接调用)

/***************************************** 函数功能:修改PWM频率工作* 函数参数:*unsigned int autoreloadDate:重装载值*unsigned int compareDate:PWM的比较值* 函数返回值:无****************************************/void pwmWorkByFre(unsigned int autoreloadDate,unsigned int compareDate){//设置重装载值__HAL_TIM_SetAutoreload(&htim2,autoreloadDate-1);__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,compareDate);HAL_TIM_GenerateEvent(&htim2, TIM_EVENTSOURCE_UPDATE);} LCD模块

    LCD模块官方会提供源码,内含初始化,大家会用即可。如下面是一段将LCD初始化成——文字颜色为白色、背景为蓝色的LCD屏:

/******************************************************************************* 函数功能:LCD初始化* 函数参数:无* 函数返回值:无*******************************************************************************/void lcdInit(void){//HAL库的初始化LCD_Init();//设置LCD的背景色LCD_Clear(Blue);//设置LCD字体颜色LCD_SetTextColor(White);//设置LCD字体的背景色LCD_SetBackColor(Blue);} 完整的配置文件

    文件说明:

sysInit()函数:自己添加的初始化配置;sysWork()函数:系统工作逻辑函数;#include "config.h"#include "stdio.h"#include "string.h"#include "stdlib.h"//外部定义变量extern TIM_HandleTypeDef htim7,htim2;extern UART_HandleTypeDef huart1;extern TIM_HandleTypeDef htim3;//记录目前LCD处于的界面 0-密码输入界面 1-显示输出界面int lcd_view_mod = 0;//定时器7计数 计数值加1表示定时器触发一次也就是过了10msint time7_count = 0;//保存上一次定时器7计数值int time7_count_start_flag = 0;//密码输入界面显示的数据char psd_txt[20];//输出状态界面显示数据char sta_txt[20];char temp[20];unsigned int crrl_t = 0;uint32_t frd = 0;//用于循环int i,j;//* 存储串口1接收的数据uint8_t Rxbuff[7];//密码锁密码 注意 这里一定一定要加上字符串结束符'\0' 否则会出现字符串拼接的情况char passwd[4] = {'1','2','3','\0'};//输入的密码char passwd_test[4] = {'0','0','0','\0'};//记录密码输错次数unsigned int passwd_wrong_count = 0;//记录是否重头开始输入密码 0-是重头开始输入且没开始输入的 1-不是重头开始输入密码char passwd_flag = 0;//记录按键的值unsigned char key_num = 0;/************************************************ 函数功能:自定义的系统初始化* 函数参数:无* 函数返回值:无***********************************************/void sysInit(void){//LCD初始化lcdInit();//关闭所有的LEDchangeAllLedByStateNumber(0);//打开定时器7中断HAL_TIM_Base_Start_IT(&htim7);//打开串口的中断接收功能HAL_UART_Receive_IT(&huart1,(uint8_t *)&Rxbuff,sizeof(Rxbuff)); //打开定时器2通道2的PWM输出功能HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);}/************************************************ 函数功能:系统工作逻辑函数* 函数参数:无* 函数返回值:无***********************************************/void sysWork(void){//更新密码getPasswdByUsart();//密码的相关操作以及显示密码界面if(lcd_view_mod == 0){keyProc();PSDViewDisplay();pwmWorkByFre(1000,400);}//显示输出界面else if(lcd_view_mod == 1){STAViewDisplay();pwmWorkByFre(500,50);passwd_flag = 0;time7_count_start_flag = 1;}//LED灯显示ledDisplay();//5秒时间到 定时器值以及标志位归零 界面显示密码界面 密码输错次数归零if(time7_count>500){time7_count = 0;time7_count_start_flag = 0;lcd_view_mod = 0;passwd_wrong_count = 0;}}/***非阻塞模式下定时器中断回调函数***/void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){//定时器7的中断回调函数if(htim->Instance == TIM7){key_num = scanKey();if(time7_count_start_flag)time7_count++;}}/***使用HAL_UART_Receive_IT中断接收数据 每次接收完成数据后就会执行该函数***/void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if(huart->Instance == USART1){// 重新使能中断HAL_UART_Receive_IT(huart,(uint8_t *)&Rxbuff,sizeof(Rxbuff)); }}/************************************************ 函数功能:显示密码输入界面* 函数参数:无* 函数返回值:无***********************************************/void PSDViewDisplay(void){LCD_DisplayStringLine(Line2,(uint8_t*)"PSD");//在第一次输入密码前显示if(passwd_flag == 0){sprintf(psd_txt,"B1 :%c",'@');LCD_DisplayStringLine(Line3,(uint8_t*)psd_txt);sprintf(psd_txt,"B2 :%c",'@');LCD_DisplayStringLine(Line4,(uint8_t*)psd_txt);sprintf(psd_txt,"B3 :%c",'@');LCD_DisplayStringLine(Line5,(uint8_t*)psd_txt);}else{sprintf(psd_txt,"B1 :%c",passwd_test[0]);LCD_DisplayStringLine(Line3,(uint8_t*)psd_txt);sprintf(psd_txt,"B2 :%c",passwd_test[1]);LCD_DisplayStringLine(Line4,(uint8_t*)psd_txt);sprintf(psd_txt,"B3 :%c",passwd_test[2]);LCD_DisplayStringLine(Line5,(uint8_t*)psd_txt);}}/************************************************ 函数功能:显示输出界面* 函数参数:无* 函数返回值:无***********************************************/void STAViewDisplay(void){LCD_DisplayStringLine(Line2,(uint8_t*)"STA");LCD_DisplayStringLine(Line3,(uint8_t*)"F :2000Hz");LCD_DisplayStringLine(Line4,(uint8_t*)"D :10%");LCD_ClearLine(Line5);}/************************************************ 函数功能:LED的相关显示* 函数参数:无* 函数返回值:无***********************************************/void ledDisplay(void){static int LED2_state = 1;//为了避免LED显示受到LCD影响 应该先关闭所有LEDchangeAllLedByStateNumber(0);//密码输入错误三次 LED2以0.1秒间隔闪烁 (5秒后熄灭)if(passwd_wrong_count>=3){time7_count_start_flag = 1;if(time7_count

相关推荐: