1.任务分析
查看第十二届的真题,有一个串口接收的任务
最后有一个任务要求为
这就需要我们考虑错误的情况,串口接收的特点为每次进入中断只能接收一个字节的数据,如果考虑错误的情况,那么有两种方法。
1.每次接收到一个字节时,就去判断这个字节是否符合要求
2.接受完全部字节,判断字符串是否符合要求
第一种方法,我们要进行很多次判断,所以不能采用
第二种方法,存在一个问题,怎么去判断接收完了所有字符
解决方法:利用定时器,处理串口接收
串口波特率 = 9600bit/s 就是1s可以传输9600bit
串口传输一次数据 包含起始位(1bit),数据位(8bit),结束位(1bit),一共10bit
10 * 1/9600 = 0.00104s = 1.04ms
串口接收两个数据的间隔为1.04ms,在接收一个数据时让定时器的计数器清零,第二个也是如此,在后面接收每个数据的时候都让计数器清零。
当接收最后一个数据的时候,进行一次判断,如果时间大于1.04ms,那就说明它不会再有下一个数据发来了,也就意味着数据接收完成。
比方说我们设置定时器的PSC + 1 = 8000。那么cnt计数器每次加一,它所需要的时间就是8000/80MHz = 1/10000 。cnt = 15 时对应的时间 t = 15 * 1/10000 = 0.0015s = 1.5ms。
这样在最后我们就可以判断cnt是否大于15。大于15说明接收完成。cnt大于15也就是说t大于1.5ms
2.CubeMX配置
USART1设置为异步通信,波特率为9600
打开TIM4的配置界面,时钟源为内部时钟,PSC设置为8000-1
配置完成点击右上角生成代码
3.代码部分
首先进行定时器的使能
HAL_TIM_Base_Start(&htim4);
编写串口接收的回调函数与接收判断函数
uint8_t rec_data, count;
uint8_t rec_flag;
char rec_buff[20];
char send_buff[20];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart -> Instance == USART1)
{
TIM4 -> CNT = 0;
rec_flag = 1;
rec_buff[count] = rec_data;
count++;
HAL_UART_Receive_IT(huart, &rec_data, 1);
}
}
void uart_data_rec(void)
{
if(rec_flag)
{
if(TIM4 -> CNT > 15)
{
if(rec_buff[0] == 'l' && rec_buff[1] == 'a' && rec_buff[2] == 'n')
{
sprintf(send_buff,"lan\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)send_buff,sizeof(send_buff),50);
}
else if(rec_buff[0] == 'q' && rec_buff[1] == 'i' && rec_buff[2] == 'a' && rec_buff[3] == 'o')
{
sprintf(send_buff,"qiao\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)send_buff,sizeof(send_buff),50);
}
else if(rec_buff[0] == 'b' && rec_buff[1] == 'e' && rec_buff[2] == 'i')
{
sprintf(send_buff,"bei\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)send_buff,sizeof(send_buff),50);
}
else
{
sprintf(send_buff,"error!\r\n");
HAL_UART_Transmit(&huart1,(uint8_t *)send_buff,sizeof(send_buff),50);
}
rec_flag = 0;
for(uint8_t i=0; i<count; i++)
rec_buff[i] = 0;
count = 0;
}
}
}
将uart_data_rec函数放在主程序的while(1)中
烧录完成开打串口助手进行试验,将波特率设为9600
实验发现,当发送lan、qiao、bei时,分别显示在了接收区,当发送haha时,显示error!