你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32基于CubeMX的高速串口收发程序(中断模式)  

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑

看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
简单的要求是,USART1和USART2之间互相转发
发现使用CubeMX平台,建立测试工程没有难度,情况如下:

1. 配置管脚,使用BluePill最小板,PC13接有LED:
MCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
0.JPG

2. 配置时钟,重点已经标出:
1.jpg

3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
(USART2也要同样配置)
2.jpg

(然后,生成工程代码)

4. 添加代码
4.1 在main的初始化部分,添加接收中断使能:
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码


4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
  1. /* USER CODE BEGIN 0 */
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
  3. struct bufer_st {
  4.   unsigned int in;                // Next In Index
  5.   unsigned int out;               // Next Out Index
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer
  7. };
  8. static struct bufer_st uart1buffer = { 0, 0, };
  9. static struct bufer_st uart2buffer = { 0, 0, };
  10. /* USER CODE END 0 */
复制代码



4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**
  2. * @brief This function handles USART1 global interrupt.
  3. */
  4. void USART1_IRQHandler(void)
  5. {
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
  7.   struct bufer_st *p;
  8.   /* USER CODE END USART1_IRQn 0 */
  9.   HAL_UART_IRQHandler(&huart1);
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
  11.   p = &uart1buffer; //use UART1 buffer
  12.   
  13.   //raed UART1
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
  15.   {                  
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt

  17.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
  18.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
  19.       p->in++;
  20.     }
  21.   }
  22.   //send to UART2
  23.   if (p->in != p->out)
  24.   {
  25.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
  26.     p->out++;
  27.   }
  28.   /* USER CODE END USART1_IRQn 1 */
  29. }

  30. /**
  31. * @brief This function handles USART2 global interrupt.
  32. */
  33. void USART2_IRQHandler(void)
  34. {
  35.   /* USER CODE BEGIN USART2_IRQn 0 */
  36.   struct bufer_st *p;
  37.   /* USER CODE END USART2_IRQn 0 */
  38.   HAL_UART_IRQHandler(&huart2);
  39.   /* USER CODE BEGIN USART2_IRQn 1 */
  40.   p = &uart2buffer; //use UART2 buffer
  41.   
  42.   //raed UART2
  43.   if (USART2->SR & UART_IT_RXNE) // read interrupt
  44.   {                  
  45.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt

  46.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
  47.     {
  48.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
  49.       p->in++;
  50.     }
  51.   }
  52.   //send to UART1
  53.   if (p->in != p->out)
  54.   {
  55.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
  56.     p->out++;
  57.   }
  58.   /* USER CODE END USART2_IRQn 1 */
  59. }
复制代码

(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)

大功告成了!! 编译后烧录。

测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。
测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。
(高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)

最后,完整的工程见附件。

STM32F103-USART-CUBE.rar

下载

599.08 KB, 下载次数: 503

评分

参与人数 1 ST金币 +12 收起 理由
g921002 + 12 很给力!

查看全部评分

收藏 10 评论21 发布时间:2018-7-14 21:15

举报

21个回答
yesterdat 回答时间:2018-8-3 07:39:01
本帖最后由 yesterdat 于 2018-8-3 08:35 编辑

谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
  • void USART1_IRQHandler(void)
  • {
  •   /* USER CODE BEGIN USART1_IRQn 0 */
  •   struct bufer_st *p;
  •   /* USER CODE END USART1_IRQn 0 */
  •   HAL_UART_IRQHandler(&huart1);
  •   /* USER CODE BEGIN USART1_IRQn 1 */
  •   p = &uart1buffer; //use UART1 buffer
  •   //raed UART1
  •   if (USART1->SR & UART_IT_RXNE) // read interrupt
  •   {
  •     USART1->SR &= ~UART_IT_RXNE; // clear interrupt
  •     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
  •       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
  •       p->in++;
  •     }
  •   }
  •   //send to UART2
  •   if (p->in != p->out)
  •   {
  •     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收发
  •     p->out++;
  •   }
  •   /* USER CODE END USART1_IRQn 1 */
  • }



radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存 ...

1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。

ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
...

1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存器很快,但是发送完成又是另外一会事情
zero99 回答时间:2018-7-16 17:11:27
学习了
yuyuswh 回答时间:2018-7-21 21:45:32
谢谢分享!
annQian 回答时间:2018-7-30 17:00:14
不错
STM1024 回答时间:2018-8-3 08:53:34
看标题以为采用DMA
ssssss 回答时间:2018-8-13 17:22:46
USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收发

当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:22
USART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...

不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度 ...

我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞
zmingwang-34437 回答时间:2018-8-15 09:57:14
你这个方案有两个地方可以讨论下,一是转发双方如果速率不同,就需要进行流控制管理;二是如果速率过高,中断会很频繁,这将导致系统中其他程序的实时性变差,最好用DMA
Kevin_G 回答时间:2019-3-25 12:51:50
收藏
lorabbitve 回答时间:2019-9-9 00:15:08
学习了
generalcircuits 回答时间:2019-9-9 10:42:31
学习一下,谢谢
12下一页

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版