概述
不算客观题,4t网评测有85分(仅供参考)
1.cubemx配置
定时器2
- 注意CCR初始为500,占空比50%,之后要调整为10%
- 频率为1Khz
定时器6
- 定时器6用来每隔10ms扫描按键
串口
- 注意开启NVIC
2.代码
全局变量
/*------------------------杂区------------*/
extern struct keys Mkey[5];
uint8_t led_sta=0x00;
char str[40];
char rx_data [50];
char tx_data[50];
char m_data[50];
uint8_t view;
uint8_t error;
uint8_t confirm;
uint8_t right;
uint8_t K_first;//实现显示@
uint8_t K_second;
uint8_t K_third;
uint32_t tim_5s;
uint32_t tim_5s_ledflag;
/*------------------------数据区------------*/
//confirm=0
int b1;//按键获得值
int b2;
int b3;
char password[4]="123";//现在代码
//confirm=1
uint16_t frq;
float duty;
初始化
- 需要注意,这里的接收中断初始化最好使用(HAL_UARTEx_ReceiveToIdle_IT(&huart1,( uint8_t*)rx_data,50);)用来接收不定长的数据
void My_Init(void)
{
HAL_TIM_Base_Start_IT(&htim6);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
HAL_UART_Init(&huart1);
HAL_UARTEx_ReceiveToIdle_IT(&huart1,( uint8_t*)rx_data,50);
该函数用于在中断模式下接收数据,直到 UART 接收缓冲区空闲(即没有数据接收一段时间)。
//HAL_UART_Receive_IT(&huart1,(uint8_t *)rx_data,sizeof(rx_data));
//HAL_UART_Transmit_IT(&huart1,(uint8_t *)tx_data,sizeof(tx_data));
LCD_Init();
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
LED_Disp(0x00);
tim_5s_ledflag=uwTick;
}
LED模块
void LED_Disp(uint8_t x )
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,x<<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_sta(uint8_t num,uint8_t sta)
{
uint8_t pos=0x01<<(num-1);
led_sta=(led_sta&(~pos))|(pos*sta);
LED_Disp(led_sta);
}
void LED_proc(void)
{
if(tim_5s)
{
LED_sta(1,1);
}
else LED_sta(1,0);
static uint16_t flag,count;
if(error>=3)
{
if(uwTick-tim_5s_ledflag>100)
{
count++;
flag=!flag;
LED_sta(2,flag);
tim_5s_ledflag=uwTick;
if(count>=50)
{
LED_sta(2,0);
count=0;
error=0;
}
}
}
else LED_sta(2,0);
}
按键
struct keys
{
uint8_t press;
uint8_t flag;
uint32_t age;
uint8_t Long_flag;
};
struct keys Mkey[5];
uint8_t key_read(void)
{
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0 ) return 1;
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0) return 2;
else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==0) return 3;
else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0) return 4;
else return 0;
}
void key_serv(void)
{
uint8_t key_v =key_read();
if(key_v!=0)
{
Mkey[key_v].age++;
if(Mkey[key_v].age>2)
{
Mkey[key_v].press=1;
}
}
else
{
for(int i=0;i<5;i++)
{
if(Mkey[i].press==1&&Mkey[i].Long_flag!=1) Mkey[i].flag=1;
//if(Mkey[i].age>199&&Mkey[i].press==1) Mkey[i].Long_flag=1;
//if(Mkey[i].press==1 ) Mkey[i].flag=1;
Mkey[i].age=0;
Mkey[i].press=0;
}
}
}
void key_proc(void)
{
if((Mkey[1].flag==1)&&(view==0))//按键1
{
if(K_first==1) b1++;
b1%=10;
K_first=1;
Mkey[1].flag=0;
}
if(Mkey[2].flag==1&&(view==0))//按键2
{
if(K_second==1) b2++;
b2%=10;
K_second=1;
Mkey[2].flag=0;
}
if(Mkey[3].flag==1&&(view==0))//按键3加
{
if(K_third==1) b3++;
b3%=10;
K_third=1;
Mkey[3].flag=0;
}
if(Mkey[4].flag==1)//按键4
{
confirm=1;
if((password[0]-48) == b1 &&(password[1]-48) == b2&& (password[2]-48) == b3)//如果密码正确
//if(password[0] == b1 &&password[1] == b2&& (password[2]) == b3)//如果密码正确
{
view=1;//切换sta界面
right=1;
error=0;//次数清零
LCD_Clear(Black);
TIM2->ARR=500-1;TIM2->CCR2=50;//设置PWM 2khz 10%
}
else//不相等
{
view=0;
error++;
}
K_first=0;//更换PSD显示@
K_second=0;
K_third=0;
b1=b2=b3=0;
// memset(rx_data,0,sizeof(rx_data));//确认按下,每一位都置0
Mkey[4].flag=0;
}
}
LCD
void LCD_proc(void)
{
if(view==0)
{
sprintf(str," PSD ");
LCD_DisplayStringLine(Line1,(u8 *)str);
if(K_first==1)
{
sprintf(str," B1:%d ",b1);
LCD_DisplayStringLine(Line3,(u8 *)str);
}
else
{
sprintf(str," B1:@ ");
LCD_DisplayStringLine(Line3,(u8 *)str);
}
if(K_second==1)
{
sprintf(str," B2:%d ",b2);
LCD_DisplayStringLine(Line4,(u8 *)str);
}
else
{
sprintf(str," B2:@ ");
LCD_DisplayStringLine(Line4,(u8 *)str);
}
if(K_third)
{
sprintf(str," B3:%d ",b3);
LCD_DisplayStringLine(Line5,(u8 *)str);
}
else
{
sprintf(str," B3:@ ");
LCD_DisplayStringLine(Line5,(u8 *)str);
}
}
if(view==1)
{
frq=80000000/(TIM2->PSC+1)/(TIM2->ARR+1);
duty=(TIM2->CCR2)*100.0f/(TIM2->ARR);
sprintf(str," STA ");
LCD_DisplayStringLine(Line1,(u8 *)str);
sprintf(str," F=%dHz ",frq);
LCD_DisplayStringLine(Line3,(u8 *)str);
sprintf(str," D=%.0f%% ",duty);
LCD_DisplayStringLine(Line4,(u8 *)str);
}
}
中断函数
- 需要注意char old_pswd[4]; char new_pswd[4];接收三位数据便需要4个字节后面有’\0’;
- char password[4]=“123”;也是一样(否则会出现第一位置0)
uint16_t count;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6)//按键10ms
{
key_serv( );
if(right)tim_5s++;//STA界面
if(tim_5s>500)
{
view=0;
tim_5s=0;
right=0;
TIM2->ARR=1000-1;TIM2->CCR2=500-1;
}
}
}
static uint16_t count;
char old_pswd[4];
char new_pswd[4];
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
count++;//记录进入中断的次数
if(huart->Instance==USART1)
{
//如果 old_pswd 和 new_pswd 是全局变量,并且在中断服务例程(ISR)中被修改,
//而在主程序中也被访问或修改,可能会导致数据竞争和未定义行为。
//这种情况下,主程序和中断服务例程可能会同时访问和修改这些变量,导致 password 的第一位被意外清零
// 确保数据格式为 old_pswd-new_pswd
if (sscanf(rx_data, "%3s-%3s", old_pswd, new_pswd)==2 ) // 确保成功读取两个密码
{
// 判断旧密码是否正确
if (strcmp(password,old_pswd) == 0)
{
// 密码正确,更新密码
for (int i = 0; i < 3; i++)
{
password[i] = new_pswd[i]; // 更新为新密码
}
// 返回成功信息
sprintf(tx_data, " success ");
HAL_UART_Transmit(&huart1, (const uint8_t*)tx_data, strlen(tx_data), HAL_MAX_DELAY);
}
else
{
// 旧密码不匹配
sprintf(tx_data, " fail ");
HAL_UART_Transmit(&huart1, (const uint8_t*)tx_data, strlen(tx_data), HAL_MAX_DELAY);
}
}
else
{
// 数据格式不正确
sprintf(tx_data, " invalid format ");
HAL_UART_Transmit(&huart1, (const uint8_t*)tx_data, strlen(tx_data), HAL_MAX_DELAY);
}
// 重新启动接收中断
HAL_UARTEx_ReceiveToIdle_IT(&huart1,( uint8_t*)rx_data,50);
}
}
感谢阅读,仅供参考