历史上的今天
返回首页

历史上的今天

今天是:2025年06月16日(星期一)

正在发生

2021年06月16日 | STM32CubeMX之串口使用(中断方式)

2021-06-16 来源:eefocus

环境:

开发板:STM32F4探索者(正点原子)


一. 在STM32CubeMX 图形化中开启串口中断

在 前一篇 STM32CubeMX之串口的使用 (阻塞模式) 的文章的基础上,打开串口中断,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQaK8Sls-1594052855033)(/image/打开串口中断.png?imageView2/2/w/550)]

然后就可以生成工程了


二. 串口中断相关函数介绍

串口中断函数


如串口1中断函数: USART1_IRQHandler()

发送接收函数


串口中断模式发送: HAL_UART_Transmit_IT()

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)


串口实例的指针

想要发送的数据的指针,如数组的首地址

想要发送数据的个数

串口中断模式接收: HAL_UART_Receive_IT()

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)


串口实例的指针


接收数据缓冲块的首地址,如数组的首地址


想要接收数据的个数


相关回调函数


串口中断模式发送完成回调: HAL_UART_TxCpltCallback

串口中断模式接收完成回调: HAL_UART_RxCpltCallback


三. 串口中断函数使用实例

在 stm32f4xx_it.c 中,先看一下串口中断函数有没有添加上,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqMs01qI-1594052855037)(/image/串口中断函数.png?imageView2/2/w/550)]

现在就可以使用中断相关发送接收函数了


在这里为了方便测试,我添加了一个如下结构体并进行了初始化:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9fgcYndu-1594052855039)(/image/测试串口中断的一个结构体.png?imageView2/2/w/550)]

发送数据

在主函数中,5s 进行一次发送

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PZ0qE45U-1594052855043)(/image/串口中断发送数据.png?imageView2/2/w/550)]

发送成功产生回调,该函数在main.c 中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8l2DCUnN-1594052855045)(/image/串口中断发送成功回调.png?imageView2/2/w/550)]

然后在主程序中查询到发送成功,打印 send done

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m8bURewy-1594052855047)(/image/串口中断发送成功.png?imageView2/2/w/550)]

接收数据


在进入循环的之前,就说明串口要进行10个字节的数据接收

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9WPQTR4-1594052855050)(/image/串口中断接收.png?imageView2/2/w/550)]

接收10个字节成功产生回调,该函数在main.c 中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dClZsbkC-1594052855052)(/image/数据接收成功回调.png?imageView2/2/w/550)]

然后在主函数中,查询是否接收成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1iwq3Dhp-1594052855053)(/image/接收成功.png?imageView2/2/w/550)]

最后运行程序,可以在串口调试助手上显示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j5kjHbQI-1594052855053)(/image/串口中断调试助手显示.png?imageView2/2/w/550)]

注意:


若定长串口中断接收数据,数据溢出,将会产生数据溢出错误,中断不再接收数据,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z9cCh14k-1594052855056)(/image/串口接收中断溢出错误.png?imageView2/2/w/550)]

错误回调函数如下:


//错误回调

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)

{

    if( rxtx_it_usart.huart1 == huart)

    {

       printf("error %drn",huart->ErrorCode); 

    }

}

1

2

3

4

5

6

7

8

以上例子,代码已上传


四. HAL库中的串口相关源码介绍

串口中断函数中的处理函数 HAL_UART_IRQHandler


/**

  * @brief  This function handles UART interrupt request.

  * @param  huart  Pointer to a UART_HandleTypeDef structure that contains

  *                the configuration information for the specified UART module.

  * @retval None

  */

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

  uint32_t isrflags   = READ_REG(huart->Instance->SR);

  uint32_t cr1its     = READ_REG(huart->Instance->CR1);

  uint32_t cr3its     = READ_REG(huart->Instance->CR3);

  uint32_t errorflags = 0x00U;

  uint32_t dmarequest = 0x00U;


  /* If no error occurs */

  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));

  if (errorflags == RESET)

  {

    /* UART in mode Receiver -------------------------------------------------*/

    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

    {

      UART_Receive_IT(huart);

      return;

    }

  }


  /* If some errors occur */

  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))

  {

    /* UART parity error interrupt occurred ----------------------------------*/

    if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_PE;

    }


    /* UART noise error interrupt occurred -----------------------------------*/

    if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_NE;

    }


    /* UART frame error interrupt occurred -----------------------------------*/

    if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_FE;

    }


    /* UART Over-Run interrupt occurred --------------------------------------*/

    if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))

    {

      huart->ErrorCode |= HAL_UART_ERROR_ORE;

    }


    /* Call UART Error Call back function if need be --------------------------*/

    if (huart->ErrorCode != HAL_UART_ERROR_NONE)

    {

      /* UART in mode Receiver -----------------------------------------------*/

      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

      {

        UART_Receive_IT(huart);

        //  printf("rcv agin error %drn",huart->ErrorCode);

      }


      /* If Overrun error occurs, or if any error occurs in DMA mode reception,

         consider error as blocking */

      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);

      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)

      {

        /* Blocking error : transfer is aborted

           Set the UART state ready to be able to start again the process,

           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */

        UART_EndRxTransfer(huart);


        /* Disable the UART DMA Rx request if enabled */

        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))

        {

          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);


          /* Abort the UART DMA Rx stream */

          if (huart->hdmarx != NULL)

          {

            /* Set the UART DMA Abort callback :

               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */

            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;

            if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)

            {

              /* Call Directly XferAbortCallback function in case of error */

              huart->hdmarx->XferAbortCallback(huart->hdmarx);

            }

          }

          else

          {

            /* Call user error callback */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)

            /*Call registered error callback*/

            huart->ErrorCallback(huart);

#else

            /*Call legacy weak error callback*/

            HAL_UART_ErrorCallback(huart);

#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

          }

        }

        else

        {

          /* Call user error callback */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)

          /*Call registered error callback*/

          huart->ErrorCallback(huart);

          

#else

          /*Call legacy weak error callback*/

          HAL_UART_ErrorCallback(huart);

          //printf("dma over error rn");

#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

        }

      }

      else

      {

        /* Non Blocking error : transfer could go on.

           Error is notified to user through user error callback */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)

        /*Call registered error callback*/

        huart->ErrorCallback(huart);

       

#else

        /*Call legacy weak error callback*/

        HAL_UART_ErrorCallback(huart);

        //printf("usart over error rn");

#endif /* USE_HAL_UART_REGISTER_CALLBACKS */


        huart->ErrorCode = HAL_UART_ERROR_NONE;

      }

    }

    return;

  } /* End if some error occurs */


  /* UART in mode Transmitter ------------------------------------------------*/

  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))

  {

    UART_Transmit_IT(huart);

    return;

  }


  /* UART in mode Transmitter end --------------------------------------------*/

  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))

  {

    UART_EndTransmit_IT(huart);

    return;

  }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

主要是分为四个部分:


先读寄存器状态


  uint32_t isrflags   = READ_REG(huart->Instance->SR);

  uint32_t cr1its     = READ_REG(huart->Instance->CR1);

  uint32_t cr3its     = READ_REG(huart->Instance->CR3);

1

2

3

如果没有错误状态产生,且是接收中断,就进行数据接收


  if (errorflags == RESET)

  {

    /* UART in mode Receiver -------------------------------------------------*/

    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

    {

      UART_Receive_IT(huart);

      return;

    }

  }

1

2

3

4

5

6

7

8

9

错误处理


//当有parity error,noise error,frame error,Over-Run 错误产生的时候,通过以下回调来处理

HAL_UART_ErrorCallback(huart);

1

2

注意:


通过查看HAL库,会发现该函数的定义用了关键字__weak (弱符号声明) ,如下:


__weak void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)

推荐阅读

史海拾趣

Condor公司的发展小趣事

关于Condor公司在电子行业的发展,以下是五个相关故事:

  1. Condor的创始与早期发展

Condor公司成立于1893年,起初主要涉及离心机、挤奶机以及泵的生产。随着技术的不断进步和市场需求的变化,公司逐渐转型,开始专注于压力和液位控制组件及系统解决方案的研发与生产。这一转变使得Condor在电子行业中崭露头角,为其后续的发展奠定了坚实的基础。

  1. 专利技术的突破

1935年,Condor取得了世界上的泵压力开关上的第一个专利,这一创新性的技术突破为公司的快速发展注入了新的动力。随着这项专利技术的应用,Condor的产品开始在各种工业领域中得到广泛应用,特别是在需要精确控制压力和液位的场景中,如汽车、冶金、水火核风电等行业。

  1. 国际市场的拓展与合作

随着全球化进程的加速,Condor开始积极拓展国际市场。公司与多个国家的合作伙伴建立了长期稳定的合作关系,共同开发新产品,拓展新的应用领域。这一战略举措不仅提升了Condor在全球电子行业中的影响力,也为其带来了更多的商业机会。

  1. 产品质量的持续提升

Condor一直坚持以最高的质量要求来生产每一款产品。为了确保产品质量,公司在生产过程中严格把控每一个环节,从原材料采购到最终的产品测试,都遵循严格的标准和流程。这种对质量的执着追求,使得Condor的产品在市场上赢得了良好的口碑和客户的信赖。

  1. 技术创新的持续推进

作为家族企业,Condor始终保持着对技术创新的热情和投入。公司不断引进新的技术和设备,优化生产流程,提高产品的性能和可靠性。同时,Condor还积极与科研机构和高校合作,共同研发新的技术和产品,以满足市场不断变化的需求。这种持续的技术创新为Condor在电子行业中保持领先地位提供了有力支持。

以上五个故事展示了Condor公司在电子行业中的发展历程和关键转折点,体现了其对技术、质量和市场的敏锐洞察力和持续创新精神。如需更多信息,建议查阅Condor公司官网或相关新闻报道。

HSMC公司的发展小趣事

HSMC的项目进展迅速,按照规划稳步推进。公司的一期项目设计产能为月产4.5万片晶圆,并计划于2019年底投产。二期项目则采用最新的制程工艺技术,设计月产能同样为4.5万片,预计于2021年第四季度投产。这些项目的顺利推进,不仅提升了HSMC的产能规模,也进一步巩固了其在行业内的地位。

CYAN公司的发展小趣事

随着5G技术的兴起,CYAN敏锐地捕捉到了市场的变化。公司投入大量研发资源,成功开发出一款基于5G技术的高性能网络路由器。这款路由器不仅具有超高的数据传输速度和稳定性,还具备智能管理和安全保护功能,满足了市场对高性能网络设备的需求。

FERYSTER公司的发展小趣事

FERYSTER公司的创始人在一次国际电子展览会上,被一款新型半导体芯片技术深深吸引。他意识到这项技术将引领电子行业的新一轮革命。于是,他果断决定投入大量资金和资源,组建研发团队,对该技术进行深入研究。经过数年的努力,FERYSTER公司成功掌握了这项技术,并推出了基于该技术的全新产品系列。这些产品以其卓越的性能和稳定性,迅速在市场上取得了成功,为公司的快速发展奠定了坚实基础。

Corex Intervest Inc公司的发展小趣事

在技术创新和产品创新的基础上,Corex Intervest Inc公司开始积极拓展市场。公司通过参加国际电子展览、与各大电商平台合作等方式,不断提升品牌知名度和影响力。同时,公司还注重与客户的沟通与合作,根据客户需求定制产品方案,赢得了客户的广泛信任和好评。

Fuji Teminal Industry Co Ltd公司的发展小趣事

在技术创新和产品创新的基础上,Corex Intervest Inc公司开始积极拓展市场。公司通过参加国际电子展览、与各大电商平台合作等方式,不断提升品牌知名度和影响力。同时,公司还注重与客户的沟通与合作,根据客户需求定制产品方案,赢得了客户的广泛信任和好评。

问答坊 | AI 解惑

汽车生产自动化系统的发展趋势

由于中国巨大的汽车市场,各个国际汽车巨头目前纷纷在中国各地投资建厂,汽车制造商为了扩大品牌占有率和汽车销售,会对原有厂房或生产线进行扩建或改造,同时,由于汽车厂商的建厂、改造,必然会带动相关零部件厂商间的竞争,从而零部件厂商也会为 ...…

查看全部问答>

2010年电子报(PDF版本)--1月4日,更新下半年总目录,全部上传完毕

2010年的电子报,PDF版本的,大家来看看啊  第11期在第31楼, 第12期在第38楼, 第十三期在45楼, 第14、15期在51、52楼 第16期在56楼 第17期在58楼 第18期在67楼 第19、20期在88、89楼 第21、22期在91、92楼 第23、24期在94、95 ...…

查看全部问答>

高手进来指导下:关于MC33996和MC33993的开关量输入和开关量输出电路的设计及程序

各位大虾。。小弟刚接手设计一个用MC9S08DZ60与MC33993和MC33996设计一个开关量输入输出的电路,想请你们指导下电路及程序,请设计过这个电路的高手指导下。谢谢哈。····· …

查看全部问答>

单片机 数码管显示

刚学单片机没有多久,遇到了问题,请朋友们帮忙   谢谢 下面是我写的程序,想简单实现 数码管显示01234567 76543210; #include void delay(unsigned int cnt) { while(--cnt); } void main() {        & ...…

查看全部问答>

以太网速度测试工程

以太网速度测试工程…

查看全部问答>

S3C44B0中文技术手册

这是我在网上搜集的有关S3C44B0的技术资料,集中在一起了,还是比较全的,上传与大家分享!…

查看全部问答>

日本地震对全球半导体业的影响

北京时间2011年3月11日下午14时46分左右,日本东北地区宫城县北部发生里氏8.8级特大地震。震中位于日本本州岛仙台港以东130公里处。此地震对日本国宫城县、岩手县、枥木县、福岛县、茨城县、山形县等地造成强烈伤害。由于宫城县、岩手县、枥木县 ...…

查看全部问答>

lpc1769不能烧写程序了

请问lpc1769核心板多少钱…

查看全部问答>