一、题目分析
考察内容:
- led
- 按键(短按)
- PWM输出(PA1)
- 串口接收
- lcd显示
根据PWM输出占空比调节,高频与低频切换
串口接收(指令解析)【中断接收】
2个显示界面
led灯闪烁定时器
二、Usr.c
/* Includes ------------------------------------------------------------------*/
#include "usr.h"
#include "usart.h"
/* values --------------------------------------------------------------------*/
struct keys key[4]={0,0,0,0};
uint8_t menu = 0;
uint8_t password_valid = 0;//密码有效信号
uint8_t password_err_3 = 0;//密码3次及以上输入错误信号
uint8_t password_err_time = 0;//密码3次及以上输入错误次数
uint8_t B1 = '@';
uint8_t B2 = '@';
uint8_t B3 = '@';
uint16_t F = 1000;
uint16_t D = 50;
uint16_t password = 123;//密码
/* define --------------------------------------------------------------------*/
#define MENU_PSD 0
#define MENU_STA 1
/*----------------------------------------------------------------------------*/
void led_set(uint8_t led_dis)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//关闭所有led
HAL_GPIO_WritePin(GPIOC,led_dis<<8,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void led_2_toggle(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_9);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
//key_control
void key_control(void)
{
if(key[0].single_flag == 1){
key[0].single_flag = 0;
//仅在PSD有效
if(menu == MENU_PSD){
if(B1 == '@'){
B1 = '0';
}else{
B1++;
if(B1>'9'){
B1 = '0';
}
}
}
}else if(key[1].single_flag == 1){
key[1].single_flag = 0;
if(menu == MENU_PSD){
if(B2 == '@'){
B2 = '0';
}else{
B2++;
if(B2>'9'){
B2 = '0';
}
}
}
}else if(key[2].single_flag == 1){
key[2].single_flag = 0;
if(menu == MENU_PSD){
if(B3 == '@'){
B3 = '0';
}else{
B3++;
if(B3>'9'){
B3 = '0';
}
}
}
}else if(key[3].single_flag == 1){ //密码输入完成确认
key[3].single_flag = 0;
//此处要写密码判断
if((B1-'0')*100+(B2-'0')*10+(B3-'0') == password){
password_valid = 1;
}else{
password_err_time ++;
}
if(password_valid == 1){
menu = MENU_STA;
password_err_3 = 0;
password_err_time = 0;//输入成功将err次数清0
}else{
B1 ='@';
B2 ='@';
B3 ='@';
if(password_err_time >= 3){
password_err_3 = 1;
}
}
}else{
key[0].long_flag = 0;
key[1].long_flag = 0;
key[2].long_flag = 0;
key[3].long_flag = 0;
}
}
void dispaly_init(void){
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
}
void menu_display(void)
{
char text[30]={NULL};
if(menu == MENU_PSD){
sprintf(text," PSD ");
LCD_DisplayStringLine(Line1,(u8*)text);
sprintf(text," B1:%c ",B1);
LCD_DisplayStringLine(Line3,(u8*)text);
sprintf(text," B2:%c ",B2);
LCD_DisplayStringLine(Line4,(u8*)text);
sprintf(text," B3:%c ",B3);
LCD_DisplayStringLine(Line5,(u8*)text);
}else{
fre_2hz_duty_10_set();
sprintf(text," STA ");
LCD_DisplayStringLine(Line1,(u8*)text);
sprintf(text," F:%d",F);
LCD_DisplayStringLine(Line3,(u8*)text);
sprintf(text," D:%d",D);
LCD_DisplayStringLine(Line4,(u8*)text);
LCD_ClearLine(Line5);
}
}
//2hz
void fre_2hz_duty_10_set(void)
{
F= 2000;
D =10;
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,100-1);//占空比百分之10
__HAL_TIM_SET_PRESCALER(&htim2,40-1);//2hz
}
//1hz 50%
void fre_1hz_duty_50_set(void){
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,500-1);//占空比百分之50
__HAL_TIM_SET_PRESCALER(&htim2,80-1);//1hz
F= 2000;
D = 50;
}
//定时器中断服务函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
key[0].key_sta = HAL_GPIO_ReadPin(B1_Port,B1_Pin);
key[1].key_sta = HAL_GPIO_ReadPin(B2_Port,B2_Pin);
key[2].key_sta = HAL_GPIO_ReadPin(B3_Port,B3_Pin);
key[3].key_sta = HAL_GPIO_ReadPin(B4_Port,B4_Pin);
for(uint8_t i =0;i<4;i++){
switch(key[i].judge_sta){
case 0:{
if(key[i].key_sta == 0){
key[i].judge_sta = 1;
key[i].key_time = 0;
}else {
key[i].judge_sta = 0;
}
}break;
case 1:{
if(key[i].key_sta == 0){
key[i].judge_sta = 2;
}else{
key[i].judge_sta = 0;
}
}break;
case 2:{
if(key[i].key_sta == 1){
if(key[i].key_time< Short_time){
key[i].single_flag = 1;
key[i].judge_sta = 0;
}
}else{
key[i].key_time++;
if(key[i].key_time > Long_time){
key[i].long_flag = 1;
key[i].judge_sta = 0;
}
}
}break;
}
}
}
if(htim->Instance == TIM7){
static uint16_t time = 0;
if(password_valid == 1){
password_err_3 = 0;
led_set(0x01);
F= 2000;
fre_2hz_duty_10_set();
if(time>= 50-1){
password_valid = 0;
led_set(0x00);
time = 0;
menu = MENU_PSD;
B1 = '@';
B2 = '@';
B3 = '@';
}else{
time ++;
}
}else if(password_err_3 == 1){
//led2翻转
led_2_toggle();
//5s后接触报警
if(time>= 50-1){
password_err_3 = 0;
led_set(0x00);
time = 0; //5s计时清零
}else{
time ++; //计时++
}
F= 1000;
fre_1hz_duty_50_set();//方波1hz
}else{
time = 0;
fre_1hz_duty_50_set();//方波1hz
}
}
}
//串口接收完成中断回调服务函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
led_set(0xaa);
if(((recevie[0]-'0')*100+(recevie[1]-'0')*10+(recevie[2]-'0') == password)&&(recevie[3]) == '-'){
password = (recevie[4]-'0')*100+(recevie[5]-'0')*10+(recevie[6]-'0');
}
HAL_UART_Receive_IT(&huart1,recevie,7);
}
}
三、Usr.h
#ifndef __USR_H__
#define __USR_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "lcd.h"
#include "stdio.h"
#include "tim.h"
/* extern --------------------------------------------------------------------*/
extern uint8_t recevie[7];
//key
struct keys{
uint8_t judge_sta;
uint8_t key_sta;
uint8_t single_flag;
uint8_t long_flag;
uint8_t key_time;
};
/*key define-------------------------------------------------------------------*/
#define B1_Port GPIOB
#define B2_Port GPIOB
#define B3_Port GPIOB
#define B4_Port GPIOA
#define B1_Pin GPIO_PIN_0
#define B2_Pin GPIO_PIN_1
#define B3_Pin GPIO_PIN_2
#define B4_Pin GPIO_PIN_0
#define Long_time 200 //2s
#define Short_time 50 //0.5s
//led
void led_set(uint8_t led_dis);
void led_2_toggle(void);
//key_control
void key_control(void);
void dispaly_init(void);
void menu_display(void);
void fre_2hz_duty_10_set(void);
#ifdef __cplusplus
}
#endif
#endif
四、串口中断接收
本题目要求接收7个ASCII码字符
定义uint8_t 类型接收数组
uint8_t recevie[7];
在while(1)前开启串口接收中断函数,接收7个字符后进入中断服务函数
HAL_UART_Receive_IT(&huart1,recevie,7);
根据中断类型,调用中断回调函数
下面展示中断服务函数
//串口接收完成中断回调服务函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
led_set(0xaa);
if(((recevie[0]-'0')*100+(recevie[1]-'0')*10+(recevie[2]-'0') == password)&&(recevie[3]) == '-'){
password = (recevie[4]-'0')*100+(recevie[5]-'0')*10+(recevie[6]-'0');
}
HAL_UART_Receive_IT(&huart1,recevie,7);
}
}
五、LED灯闪烁问题解决??
计时应该是正确的5s,但是感觉led灯闪烁时间不够
if(htim->Instance == TIM7){
static uint16_t time = 0;
if(password_valid == 1){
password_err_3 = 0;
led_set(0x01);
F= 2000;
fre_2hz_duty_10_set();
if(time>= 50-1){
password_valid = 0;
led_set(0x00);
time = 0;
menu = MENU_PSD;
B1 = '@';
B2 = '@';
B3 = '@';
}else{
time ++;
}
}else if(password_err_3 == 1){
//led2翻转
led_2_toggle();
//5s后接触报警
if(time>= 50-1){
password_err_3 = 0;
led_set(0x00);
time = 0; //5s计时清零
}else{
time ++; //计时++
}
F= 1000;
fre_1hz_duty_50_set();//方波1hz
}else{
time = 0;
fre_1hz_duty_50_set();//方波1hz
}
}
六、 总结
本次只写一个usr.c usr.h,发现确实方便了许多!!相较于14届难度较小
比照LCD的cubemx配置引脚的时候,记得配置PD2(led锁存器引脚)
复制其他.h时后记得更改预编译
#ifndef __USR_H__ //记得更改
#define __USR_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#ifdef __cplusplus
}
#endif
#endif
如果没有改为__USR_H__,跳转函数跳转不进去usr.c文件,会显示C99_warning