OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2075|回复: 17

求教关于STM32F4HAL串口发送的问题

[复制链接]

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
发表于 2023-10-17 14:28:00 | 显示全部楼层 |阅读模式
1金钱
最近在学习hal库串口问题的时候,发现了只要我开启了发送中断,就会一直进入发送中断的回调函数中,求大佬指点:


串口一直打印发送已完成。。。

最佳答案

查看完整内容[请看2#楼]

接收是接收 发送是发送 这俩不是一个东西 中断发送的一般逻辑是这样的: 1. 应用中有多个数据要发送时,先将他们一股脑的放入FIFO中,然后使能发送中断 2. 中断服务函数中发送FIFO中的一个数据,FIFO为空时,关闭发送中断
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1013
金钱
1013
注册时间
2014-4-7
在线时间
98 小时
发表于 2023-10-17 14:28:01 | 显示全部楼层
yangwang1025 发表于 2023-11-7 09:40
那意思是必须要接收到数据了不发送出去才不会进入发送中断吗?

接收是接收 发送是发送 这俩不是一个东西

中断发送的一般逻辑是这样的:
1. 应用中有多个数据要发送时,先将他们一股脑的放入FIFO中,然后使能发送中断
2. 中断服务函数中发送FIFO中的一个数据,FIFO为空时,关闭发送中断
在你没有做出成绩之前,这个世界不会在乎你的自尊。
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-10-19 09:04:46 | 显示全部楼层
确定没发?进回调后会清除中断标志的
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-10-19 11:23:14 | 显示全部楼层
阿侑kevin 发表于 2023-10-19 09:04
确定没发?进回调后会清除中断标志的

是一直在发,没发送任何数据也会进入回调函数,标志位是有清除的
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-10-19 15:55:28 | 显示全部楼层
yangwang1025 发表于 2023-10-19 11:23
是一直在发,没发送任何数据也会进入回调函数,标志位是有清除的

有点意思,关键代码贴出来看看
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-10-19 16:09:55 | 显示全部楼层
阿侑kevin 发表于 2023-10-19 15:55
有点意思,关键代码贴出来看看
  1. #include "./SYSTEM/sys/sys.h"
  2. #include "./SYSTEM/usart/usart.h"


  3. /* 如果使用os,则包括下面的头文件即可 */
  4. #if SYS_SUPPORT_OS
  5. #include "os.h"                               /* os 使用 */
  6. #endif

  7. /******************************************************************************************/
  8. /* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */

  9. #if 1
  10. #if (__ARMCC_VERSION >= 6010050)                    /* 使用AC6编译器时 */
  11. __asm(".global __use_no_semihosting\n\t");          /* 声明不使用半主机模式 */
  12. __asm(".global __ARM_use_no_argv \n\t");            /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

  13. #else
  14. /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
  15. #pragma import(__use_no_semihosting)

  16. struct __FILE
  17. {
  18.     int handle;
  19.     /* Whatever you require here. If the only file you are using is */
  20.     /* standard output using printf() for debugging, no file handling */
  21.     /* is required. */
  22. };

  23. #endif

  24. /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
  25. int _ttywrch(int ch)
  26. {
  27.     ch = ch;
  28.     return ch;
  29. }

  30. /* 定义_sys_exit()以避免使用半主机模式 */
  31. void _sys_exit(int x)
  32. {
  33.     x = x;
  34. }

  35. char *_sys_command_string(char *cmd, int len)
  36. {
  37.     return NULL;
  38. }

  39. /* FILE 在 stdio.h里面定义. */
  40. FILE __stdout;

  41. /* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
  42. int fputc(int ch, FILE *f)
  43. {
  44.     while ((USART1->SR & 0X40) == 0);               /* 等待上一个字符发送完成 */

  45.     USART1->DR = (uint8_t)ch;                       /* 将要发送的字符 ch 写入到DR寄存器 */
  46.     return ch;
  47. }
  48. #endif
  49. /***********************************************END*******************************************/
  50.    
  51. #if USART_EN_RX                                     /* 如果使能了接收 */

  52. /* 接收缓冲, 最大USART_REC_LEN个字节. */
  53. uint8_t g_usart_rx_buf[USART_REC_LEN];

  54. /*  接收状态
  55. *  bit15,      接收完成标志
  56. *  bit14,      接收到0x0d
  57. *  bit13~0,    接收到的有效字节数目
  58. */
  59. uint16_t g_usart_rx_sta = 0;

  60. uint8_t g_Rx_Finish_Flag;

  61. uint8_t g_rx_buffer[RXBUFFERSIZE];                  /* HAL库使用的串口接收缓冲 */

  62. UART_HandleTypeDef g_uart1_handle;                  /* UART句柄 */


  63. /**
  64. * @brief       串口X初始化函数
  65. * [url=home.php?mod=space&uid=271674]@param[/url]       baudrate: 波特率, 根据自己需要设置波特率值
  66. * [url=home.php?mod=space&uid=60778]@note[/url]        注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
  67. *              这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
  68. * @retval      无
  69. */
  70. void Usart_Init(uint32_t baudrate)
  71. {
  72.     g_uart1_handle.Instance = USART1;
  73.         g_uart1_handle.Init.BaudRate = baudrate;
  74.         g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;
  75.         g_uart1_handle.Init.StopBits = UART_STOPBITS_1;
  76.         g_uart1_handle.Init.Parity = UART_PARITY_NONE;
  77.         g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  78.         g_uart1_handle.Init.Mode = UART_MODE_TX_RX;
  79.         HAL_UART_Init(&g_uart1_handle);
  80.        
  81.         HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t*)g_rx_buffer, RXBUFFERSIZE);
  82.         HAL_UART_Transmit_IT(&g_uart1_handle, (uint8_t*)g_usart_rx_buf, 100);
  83. }

  84. /**
  85. * @brief       UART底层初始化函数
  86. * @param       huart: UART句柄类型指针
  87. * @note        此函数会被HAL_UART_Init()调用
  88. *              完成时钟使能,引脚配置,中断配置
  89. * @retval      无
  90. */
  91. void HAL_UART_MspInit(UART_HandleTypeDef *huart)
  92. {
  93.     GPIO_InitTypeDef gpio_init_struct;
  94.     if(huart->Instance == USART1)                               /* 如果是串口1,进行串口1 MSP初始化 */
  95.     {
  96.         __HAL_RCC_USART1_CLK_ENABLE();                          /* USART1 时钟使能 */
  97.         __HAL_RCC_GPIOA_CLK_ENABLE();                           /* 发送接收引脚时钟使能 */

  98.         gpio_init_struct.Pin = GPIO_PIN_9;                                         /* TX引脚 */
  99.         gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */
  100.         gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
  101.         gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
  102.         gpio_init_struct.Alternate = GPIO_AF7_USART1;           /* 复用为USART1 */
  103.         HAL_GPIO_Init(GPIOA, &gpio_init_struct);                                   /* 初始化发送引脚 */

  104.         gpio_init_struct.Pin = GPIO_PIN_10;                         /* RX引脚 */
  105.         gpio_init_struct.Alternate = GPIO_AF7_USART1;          /* 复用为USART1 */
  106.         HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 初始化接收引脚 */

  107. #if USART_EN_RX
  108.         HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */
  109.         HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 抢占优先级3,子优先级3 */
  110. #endif
  111.     }
  112. }

  113. /**
  114. * @brief       Rx传输回调函数
  115. * @param       huart: UART句柄类型指针
  116. * @retval      无
  117. */
  118. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  119. {
  120.     if(huart->Instance == USART_UX)             /* 如果是串口1 */
  121.     {
  122.                 g_usart_rx_buf[g_usart_rx_sta] = g_rx_buffer[0] ;
  123.                        
  124.                 if(g_usart_rx_buf[g_usart_rx_sta] == 0x0a)
  125.                 {
  126.                         g_Rx_Finish_Flag = 1;
  127.                 }
  128.                 else
  129.                 {
  130.                         g_usart_rx_sta++;
  131.                 }

  132.                 HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
  133.     }
  134. }



  135. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
  136. {       
  137.     if(huart->Instance == USART_UX)             /* 如果是串口1 */
  138.     {               
  139.                 printf("发送已完成\r\n");      
  140.                 HAL_UART_Transmit_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);

  141.     }
  142. }


  143. /**
  144. * @brief       串口1中断服务函数
  145. * @param       无
  146. * @retval      无
  147. */
  148. void USART1_IRQHandler(void)
  149. {
  150. #if SYS_SUPPORT_OS                              /* 使用OS */
  151.     OSIntEnter();   
  152. #endif

  153.     HAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */

  154. #if SYS_SUPPORT_OS                              /* 使用OS */
  155.     OSIntExit();
  156. #endif
  157. }

  158. #endif









复制代码
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-10-19 16:11:15 | 显示全部楼层
阿侑kevin 发表于 2023-10-19 15:55
有点意思,关键代码贴出来看看

没有发送任何数据,会一直进入HAL_UART_TxCpltCallback回调函数中
回复

使用道具 举报

11

主题

2130

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4724
金钱
4724
注册时间
2015-1-10
在线时间
590 小时
发表于 2023-10-20 10:06:26 | 显示全部楼层
yangwang1025 发表于 2023-10-19 16:11
没有发送任何数据,会一直进入HAL_UART_TxCpltCallback回调函数中

进中断回调里面有没有执行printf?中断相关的函数不要执行printf这种阻塞的程序
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-10-20 10:30:39 | 显示全部楼层
我知道中断里面尽量不要执行这种printf函数,太耽误时间,我这里只是为了验证一下,这里会一直执行Printf,这就是我疑问的地方,为什么会一直进入发送完成中断回调函数里面。
回复

使用道具 举报

3

主题

805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3830
金钱
3830
注册时间
2017-3-7
在线时间
1670 小时
发表于 2023-10-23 08:26:33 | 显示全部楼层
yangwang1025 发表于 2023-10-20 10:30
我知道中断里面尽量不要执行这种printf函数,太耽误时间,我这里只是为了验证一下,这里会一直执行Printf, ...

这不很容易想明白吗,你在发送中断里printf,printf完又会进中断再次printf,再进中断,不就是一个死循环了吗
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-11-6 11:50:07 | 显示全部楼层
a5820736 发表于 2023-10-23 08:26
这不很容易想明白吗,你在发送中断里printf,printf完又会进中断再次printf,再进中断,不就是一个死循环 ...

这个可以想明白了,但是为什么一开始就会进入发送中断了?初始化之后就进入发送中断了
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-11-6 11:59:05 | 显示全部楼层
a5820736 发表于 2023-10-23 08:26
这不很容易想明白吗,你在发送中断里printf,printf完又会进中断再次printf,再进中断,不就是一个死循环 ...

我测试过了,加不加printf都会进入中断,一直进入,不接收或者发送任何数据都会
回复

使用道具 举报

28

主题

360

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1028
金钱
1028
注册时间
2021-2-4
在线时间
146 小时
发表于 2023-11-6 17:22:32 | 显示全部楼层
yangwang1025 发表于 2023-11-6 11:50
这个可以想明白了,但是为什么一开始就会进入发送中断了?初始化之后就进入发送中断了

初始化完进入发送中断正常.
CubeMX生成的有清除标志位
线上没有数据了就不会再进入了
你开机进中断,中断里单步走,走不出去吗
回复

使用道具 举报

17

主题

175

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1013
金钱
1013
注册时间
2014-4-7
在线时间
98 小时
发表于 2023-11-6 18:42:09 | 显示全部楼层
中断名称叫  发送空中断  只要 空了就有中断  刚初始化完 肯定是空的
在你没有做出成绩之前,这个世界不会在乎你的自尊。
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-11-7 09:38:31 | 显示全部楼层
电子控2021 发表于 2023-11-6 17:22
初始化完进入发送中断正常.
CubeMX生成的有清除标志位
线上没有数据了就不会再进入了

走不出去,一直进入中断,只要开启了HAL_UART_Transmit_IT(&g_uart1_handle, (uint8_t*)g_usart_rx_buf, 100);命令后,就一直在发送完成中断里面出不去了
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-11-7 09:40:38 | 显示全部楼层
亲亻尔嘴 发表于 2023-11-6 18:42
中断名称叫  发送空中断  只要 空了就有中断  刚初始化完 肯定是空的

那意思是必须要接收到数据了不发送出去才不会进入发送中断吗?
回复

使用道具 举报

28

主题

360

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1028
金钱
1028
注册时间
2021-2-4
在线时间
146 小时
发表于 2023-11-7 11:53:29 | 显示全部楼层
yangwang1025 发表于 2023-11-7 09:38
走不出去,一直进入中断,只要开启了HAL_UART_Transmit_IT(&g_uart1_handle, (uint8_t*)g_usart_rx_buf,  ...

在发送完成中断里面把这个发送关闭掉试试
我是没有这么用,我在发送完的地方写了一个RS485进入接收模式
回复

使用道具 举报

13

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
263
金钱
263
注册时间
2023-10-17
在线时间
49 小时
 楼主| 发表于 2023-11-7 15:41:21 | 显示全部楼层
电子控2021 发表于 2023-11-7 11:53
在发送完成中断里面把这个发送关闭掉试试
我是没有这么用,我在发送完的地方写了一个RS485进入接收模式

把发送中断关闭肯定是可以的,中断不开启肯定是不会进入中断的,我现在就是想要知道为什么会一直进入中断!一般是不会这么用的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-24 12:16

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表