【STM32】串口的阻塞、中断、DMA收发

目录

阻塞

串口阻塞发送

串口阻塞接收

中断

串口中断发送

串口中断接收

DMA

串口DMA发送

串口DMA接收

本文基于STM32F103CBT6单片机,分别使用串口的阻塞收发函数、中断收发函数、DMA收发函数进行测试

阻塞

串口阻塞发送

定义字符数组p

cpp 复制代码
char p[10] = "hello\r\n";

调试观察其地址为0x20000004

在单片机内存中如下图

主循环中进行发送

cpp 复制代码
  while (1)

  {

   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

   HAL_UART_Transmit(&huart1, p, 15, 100);

   HAL_Delay(500);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }

发15个字节,起始地址是字符数组第1个元素的地址,亦即0x20000004

打印出来的内容就是0x2000004++15这个范围的内容

当发送量巨大而超时时间又比较短时,就会超时

这种阻塞式发送,MCU会一直处理串口的发送,后续的代码只能等待发送完毕才能执行

串口的波特率是115200,5ms大概发送五十多个字节

当发送超时后,将停止串口发送,并直接执行下一条语句

串口阻塞接收

定义一个存放接收内容的数组

cpp 复制代码
char rx[10];

主循环内使用接收函数,超时时间为500ms

cpp 复制代码
  while (1)

  {

   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

   HAL_UART_Receive(&huart1, rx, 10, 500);

   HAL_Delay(500);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }

观察发现LED灯的闪烁频率由1hz变成0.5hz了,这是因为现在没有给串口发送任何东西,以至于串口一直超时,直到超时时间到达设定的500ms才会继续往下运行。

如果超时时间设置特别小,而需要接收的数据量又比较大的话,就永远也不会接收满了,就一直接收超时,跳转下一条语句

上位机不停地发送数据,但接收函数的超时时间仅设置1ms,就不能接收满预设的100字节,会一直超时,最多大概收到23个字节

如果超时时间较长,只要串口没收满设定的10字节数组,就会一直等待,后续代码无法执行

如果在等待期间有接收满10字节,就会立刻运行下面的代码,并将收到的内容存放至rx数组

中断

串口中断发送

勾选串口全局中断,生成代码

在主循环前面发送1024个字节的数据

cpp 复制代码
uartStatus = HAL_UART_Transmit_IT(&huart1, p, 1024);

  /* USER CODE END 2 */

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

   

   HAL_Delay(500);

   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

  }

并在翻转电平和中断函数内打断点,程序会先进入中断服务函数,因为发送1024字节的时间小于500ms

如果把串口发送放入主循环,且delay时间设置50ms会造成串口busy

主循环每执行一次串口发送,except++

每成功发送完毕一次,sendok++

调试发现基本有一半的时间里是处于串口发送繁忙状态而没有发出

因为发送1024字节大概需要100ms,差不多两次循环才能让串口处于发送空闲状态

中断的好处是发送过程中MCU不会一直等待直到发送完毕,可以继续执行下面的语句

只要注意不要在还没有发送完毕就继续开始新的发送

串口中断接收

在主循环前调用串口中断接收

当串口助手发送超过10字节的数据时,进入串口接收中断,切换LED亮灭,并将设定的10字节内容存放至rx数组

继续发送,将不再进入接收中断

在主循环内反复调用串口中断接收函数

串口助手不发送任何内容,串口将处于接收繁忙状态

串口助手每50ms发送一次超过10字节的数据,串口接收状态将一直处于OK

由于调用接收中断和上位机下发内容的周期都是接近50ms,那么在调用语句后不超过50ms的时间内(下一次调用语句前),上位机就能及时地发送超过10字节的内容,触发接收中断

如果串口助手发送间隔小于50ms,会触发overrun错误

串口框架图表明引脚检测到电平信号后进行转换,给移位寄存器,再给RDR寄存器

结合overrun故障的描述就是当RDR寄存器不是空的时候,移位寄存器试图给RDR寄存器transfer数据------还没来得及拿走旧的数据,新的数据又来了

当出现这个故障时,RDR寄存器的值不会丢失,只更新移位寄存器的内容

在调用接收中断函数前将overrun标志位清除,这样即便串口助手发送频率高于接收函数调用频率,也可以接收到新发的数据

DMA

串口 DMA 发送

增加发送DMA

在主循环内每隔50ms进行一次DMA发送

第一次发送成功,串口助手显示接收到1024字节

由于发送1024字节所需时间大于50ms,在第二次进入循环时就会发生busy

预期发送次数大约是实际发送完毕次数的一半,因为发送1024字节的数据,大概要100ms,每2次才能成功发送一次

DMA的好处是发送过程中MCU不会一直等待直到发送完毕,可以继续执行下面的语句

只要注意不要在还没有发送完毕就继续开始新的发送

串口 DMA 接收

增加接收DMA

串口助手每10ms发送一次数据,偶尔会有busy出现,但不会像中断接收那样overrun

参考DMA的接收机制,当出现RXNE后,数据就被搬运走了,这个过程很快

串口的DMA和串口中断有点相似,但DMA更适合处理高速,大量的数据,DMA 硬件会在同一个总线时钟周期自动把 RDR 里的数据搬到内存缓冲区。读走后,RDR 立即空闲,RXNE 被自动清零。只要 DMA 通道使能且缓冲区未满,RDR 几乎"瞬时"被取走。过程无需 CPU 参与,搬运速度远快于中断响应。

中断则靠 CPU 在中断中数据搬运,慢了就丢。

相关推荐
眰恦ゞLYF17 小时前
嵌入式硬件——基于IMX6ULL的GPT(通用定时器)实现
单片机·嵌入式硬件·gpt·imx6ull
充哥单片机设计20 小时前
【STM32项目开源】基于STM32的智能老人拐杖
stm32·单片机·嵌入式硬件
10001hours20 小时前
(基于江协科技)51单片机入门:6.串口
科技·嵌入式硬件·51单片机
眰恦ゞLYF21 小时前
嵌入式硬件——基于IMX6ULL的I2C实现
嵌入式硬件·i2c
常州晟凯电子科技1 天前
君正T32开发笔记之固件烧写
人工智能·笔记·嵌入式硬件·物联网
李永奉1 天前
51单片机-驱动LCD1602液晶显示屏教程
单片机·嵌入式硬件·51单片机
straw_hat.2 天前
PCB学习——STM32F103VET6-STM32接口部分
stm32·嵌入式硬件·学习
Hello_wshuo2 天前
记一次手机付费充电设备研究
linux·单片机
点灯小铭2 天前
基于51单片机的手机蓝牙控制8位LED灯亮灭设计
单片机·mongodb·智能手机·毕业设计·51单片机·课程设计