串口中断方式的特点
中断代码如下
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
{
if (rxReceiveCount1 < 20)
{
rxBuffer1[rxReceiveCount1]=(uint8_t)(huart1.Instance->DR);
++rxReceiveCount1;
}
else
{
rxReceiveCount1 = 0;
}
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
}
else if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
uint32_t tmp1;
tmp1 = huart1.Instance->SR;
tmp1 = huart1.Instance->DR;
rxFrameFlag1 = 1;
}
/* USER CODE END USART1_IRQn 0 */
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/**
HAL_UART_Receive_IT(&huart1, (uint8_t *)&rc_data, 1)
的作用是:
启动UART1的中断接收模式:该代码将启动UART1的中断接收模式,使UART1开始等待接收数据。
指定接收缓冲区:将rc_data
变量的地址作为接收数据的缓冲区地址。这意味着当UART1接收到数据时,数据将存储在rc_data
变量中。
指定缓冲区大小:1
表示接收数据的大小为1个字节。这意味着当UART1接收到1个字节的数据时,将触发一个接收中断,并将数据存储在rc_data
变量中。
需要注意的是,在初始化UART1时,需要先调用一次该函数,来启动UART1的中断接收模式;再接受完一个数据后,也需要再调用该函数来重新启动UART1的中断接收模式,以等待接收下一个字节的数据。
空闲中断接收,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。
DMA用在只需要传输数据,不需要处理数据的地方,有三种传输方式:
在传输数据时,可以配置指向传输双方数据的指针是否自动向后递增。通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用。
通常如下图配置:
最后直接生成文件
定义变量
/* USER CODE BEGIN 0 */
volatile uint8_t rx_len=0; //接收到的数据长度
volatile uint8_t recv_end_flag=0;//接收完成标志
uint8_t rx_buffer[200];//缓存数组
/* USER CODE END 0 */
开启空闲中断和dma接收
/* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能空闲中断
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,200); //开启DMA接收
/* USER CODE END USART1_Init 2 */
重定义fputc,是为了能使用printf函数
/* USER CODE BEGIN 1 */
//重定向fputc函数
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 1 */
#include
/* USER CODE BEGIN Includes */
extern volatile uint8_t rx_len ; //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern uint8_t rx_buffer[200]; //接收数据缓存数组
注意这里的#include
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t tmp_flag = 0;
uint32_t temp;
tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
if((tmp_flag != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//
temp = huart1.Instance->SR;
temp = huart1.Instance->DR;
HAL_UART_DMAStop(&huart1);
temp = hdma_usart1_rx.Instance->CNDTR;//获取此时DMA中未传输的数据个数
rx_len = 200 - temp; //总计数减去未传输的数据个数,得到此次接收到的数据个数
recv_end_flag = 1;
}
HAL_UART_IRQHandler(&huart1);
/* USER CODE END USART1_IRQn 0 */
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
这里不使用回调函数
while (1)
{
/* USER CODE END WHILE */
if(recv_end_flag ==1)
{
printf("接收到的数据长度为%d\r\n",rx_len);
HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);
for(uint8_t i=0;i
这里只是测试代码,将接收到的数据再利用串口输出到串口助手
当数据接收间隔时间很短的情况下,这里是1ms,数据接收会出错;在10ms后就正常
1.程序下载到板子上没反应,只有在一步一步调试时才有输出。最后勾选了Use MicoLIB后程序就正常运行了
2.输出中文时串口助手上显示乱码,代码格式要改为GB 2312,但直接在keil上修改没什么用,我这里是在vscode上修改格式后保存,在keil上运行就行了。