前言
我在HC05的文章里面已经做了串口收发的实验。但是如果在实际项目中使用的话,会出现一些问题。
比如,程序会一直停留在检测串口的函数中,如果HC05不发送数据,那么程序会因为一直没有接收到数据,导致程序卡死。
当数据发送过来,而单片机在进行其他的操作时,会来不及更新接收到的数据,导致数据丢包。
所以在实际操作中,会对串口接收开启中断,并在中断函数内,做数据的解算并对单片机发送指令。
当然你还可以开启DMA来降低CPU的功耗,让你的单片机可以做更多的事情,但是对于一个小车来说,没有那个必要。
完成项目需求比炫技重要。后续更新了DMA我会在这里转载
准备及硬件调试
这里我就不多作解释了,不清楚的可以跳转到我之前的文章观看
stm32__hc05链接
CubeMX配置
按照之前文章的方式配置,注意你的晶振频率。完成前面的配置之后只需要再开启接收中断即可
keil软件编写
/* USER CODE BEGIN 0 */
#include "stdio.h"
#include "string.h"
#define RXBUFFERSIZE 256 //最大接收字节数
char RxBuffer[RXBUFFERSIZE]; //接收数据
uint8_t aRxBuffer; //接收中断缓冲
uint8_t Uart2_Rx_Cnt = 0; //接收缓冲计数
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
if(Uart1_Rx_Cnt >= 255) //溢出判断
{
Uart1_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);
}
else
{
RxBuffer[Uart1_Rx_Cnt++] = aRxBuffer; //
if(RxBuffer[0] == 'c'&&RxBuffer[1] == 'm')//当发送1时,cm
{
unit_change = 0;
}
else if(RxBuffer[0] == '+'&&RxBuffer[1] == 'm')//当发送2时,m
{
unit_change = 1;
}
if((RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
{
HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
Uart1_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1); //因为接收中断使用了一次即关闭,所以在最后加入这行代码即可实现无限使用
}
/* USER CODE END 1 */
在usart.c中添加上面两段代码
HAL_UART_RxCpltCallback()函数是一个弱函数,所以我们直接重新写一个HAL_UART_RxCpltCallback()函数来写中断回调
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
在main函数中开启中断
注解
在这个回调函数里面,首先是if语句来检测是否数据溢出
然后将寄存器aRxBuffer的值传给RxBuffer[]
if(RxBuffer[0] == 'c'&&RxBuffer[1] == 'm')//当发送1时,cm
{
unit_change = 0;
}
else if(RxBuffer[0] == '+'&&RxBuffer[1] == 'm')//当发送2时,m
{
unit_change = 1;
}
这一部分是我对接收到的数据作的解析判断,写在中断回调函数里的好处就是,每一次接收到数据,都能作一次解析判断,不会因为串口发送的频率过快导致指令更新不及时
if((RxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
{
HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
Uart1_Rx_Cnt = 0;
memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
}
判断结束位,数据接收完毕之后,将接收到的数据在发送回去,我这里串口连接的是电脑XCOM,所以XCOM发送什么数据过来,它会再显示一遍接收到的数据。
当然你也可以用蓝牙模块来代替XCOM这样就是手机端发送数据,然后手机端再接收一遍。
原理都是一样的,不过是发送和接收的平台变了而已
这里可以用来检测我们的数据有没有发错,可以把这儿的发送删掉,只保留memset()函数来清空数组
当然你也可以不清空或者不在这个地方清空,代码是死的,人是活的,一切看你自己的想法