STM32单片机串口接收中断函数的编写

其实学单片机使用的时候,往往大家都觉得简单,很快就过了,但其实有一些东西是值得深思的,我以前在写程序的时候往往都是发送数据,那么调用重写的printf()函数就可以了,但这次的项目中用到了NRF双全工通讯,这就需要串口的收发,这回就发生了写问题,具体的流水账就不说了。简单说就是串口收可比发讲究多了。


 
 
  1. void USART1_IRQHandler(void) //串口1中断服务程序
  2. {
  3. u8 i;
  4. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //如果寄存器中有数据
  5. {
  6. USART_RX_BUF[RxCounter++] = USART_ReceiveData(USART1);
  7. //在这个位置,没有加这条数据帧判断语句,出现了类似于移位的错误,我需要连续发送40次才能得到正确的序列,具体原因不明
  8. //当时我考虑的是报上位机的发送,移到下位机,没想到一下子就可以了
  9. if( (USART_RX_BUF[ 0]== '$') && (USART_RX_BUF[ 1]== 'M') && (USART_RX_BUF[ 2] == '<' )&& (USART_RX_BUF[ 27] == '<' )&& (USART_RX_BUF[ 28] == '<' ) )
  10. {
  11. if(RxCounter== 29)
  12. {
  13. RxCounter = 0;
  14. }
  15. }
  16. }
  17. }
  18. 上述代码段是我地面站的串口中断程序,虽然不难,但是有讲究:
  19. 1.串口每次中段读出的是多少数据,那么打开固件库看,是一个 uint16_t类型,所以说每次串口是读了一个字进来,那我们用 uint16_t的一个变量接受自然没问题,那么用u8接收可以么,因为我马上就要将串口数据无线发出去,无线通讯中一般都是 char型为基本单元,答案是可以,所以应该是发生了隐式类型转换,如果编译器不允许,那么考虑拆分字节传输。
  20. 2.我没加这条协议判断语句的时候USART_RX_BUF里面的内容一致不是我想要的,数据头和尾一直内容不对,后来我发现,我连续上位机传输 40次的时候就出现了正确序列,这说明上位机确实将正确数据发出去了,我在上位机的debug中也验证这一点,那么地面站程序接受的时候不知道发生了什么。
  21. 怀疑:串口地面站接受程序有问题,上位机因为是linux的qt写的,考虑上位机输出有问题。
  22. 解决:上面是一种解决方法,另一种如下:
  23. void USART1_IRQHandler(void) //串口1中断服务程序
  24. {
  25. u8 i;
  26. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //如果寄存器中有数据
  27. {
  28. USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
  29. USART_RX_BUF[RxCounter++] = USART_ReceiveData(USART1);
  30. //在这个位置,没有加这条数据帧判断语句,出现了类似于移位的错误,我需要连续发送40次才能得到正确的序列,具体原因不明
  31. //当时我考虑的是报上位机的发送,移到下位机,没想到一下子就可以了
  32. if(RxCounter== 29)
  33. {
  34. RxCounter = 0;
  35. }
  36. }
  37. }
  38. 上面代码段的这种方案很好理解,信道优良,短距离,没什么干扰,比较理想的情况。
  39. 第一种的话我还不能完全表述出来,就是在不清除标志位的情况下,这种就不分析了,比较复杂,还是用第二种方法比较好,中断一次,都一个字,依次读完。
  40. 最后贴出一篇文章,几种串口手法程序的优缺点,供以后查看和大家参考:
  41. 实例一:
  42. void USART1_IRQHandler(u8 GetData)
  43. {
  44. u8 BackData;
  45. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生
  46. {
  47. USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志.
  48. GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR;
  49. USART1_SendByte(GetData); //发送数据
  50. GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED闪烁,接收成功发送完成
  51. delay( 1000);
  52. GPIO_ResetBits(GPIOE, GPIO_Pin_8 );
  53. }
  54. }
  55. 这是最基本的,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main函数里无其他要处理的。
  56. 优点:简单,适合很少量数据传输。
  57. 缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失 。
  58. 实例二:
  59. void USART2_IRQHandler()
  60. {
  61. if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
  62. {
  63. USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
  64. Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2);
  65. Uart2_Rx_Num++;
  66. }
  67. if((Uart2_Buffer[ 0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num -1] == 0xA5)) //判断最后接收的数据是否为设定值,确定数据正确性
  68. Uart2_Sta= 1;
  69. if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
  70. {
  71. USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR
  72. USART_ReceiveData(USART2); //读DR
  73. }
  74. }
  75. if( Uart2_Sta )
  76. {
  77. for(Uart2_Tx_Num= 0;Uart2_Tx_Num < Uart2_Rx_Num;Uart2_Tx_Num++)
  78. USART2_SendByte(Uart2_Buffer[Uart2_Tx_Num]); //发送数据
  79. Uart2_Rx_Num = 0; //初始化
  80. Uart2_Tx_Num = 0;
  81. Uart2_Sta = 0;
  82. }
  83. 这是加了数据头和数据尾的接收方式,数据头和尾的个数可增加,此处只用于调试之用。中断函数用于接收数据以及判断数据的头尾,第二个函数在main函数里按照查询方式执行。
  84. 优点:较简单,采用缓存区接收,对提高数据的正确行有一定的改善 。
  85. 缺点:要是第一次数据接收错误,回不到初始化状态,必须复位操作 。
  86. 实例三:
  87. vvoid USART2_IRQHandler()
  88. {
  89. if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
  90. {
  91. USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志.
  92. Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
  93. Uart2_Rx++;
  94. Uart2_Rx &= 0x3F; //判断是否计数到最大
  95. }
  96. if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
  97. {
  98. USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR
  99. USART_ReceiveData(USART2); //读DR
  100. }
  101. }
  102. if( Uart2_Tx != Uart2_Rx )
  103. {
  104. USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据
  105. Uart2_Tx++;
  106. Uart2_Tx &= 0x3F; //判断是否计数到最大
  107. }
  108. 采用FIFO方式接收数据,由 0x3F可知此处最大接收量为 64个,可变,中断函数只负责收,另一函数在main函数里执行,FIFO方式发送。
  109. 优点:发送和接收都很自由,中断占用时间少,有利于MCU处理其它。
  110. 缺点:对数据的正确性没有判断,一概全部接收。
  111. 实例四:
  112. void USART2_IRQHandler()
  113. {
  114. if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
  115. {
  116. USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
  117. Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
  118. Uart2_Rx++;
  119. Uart2_Rx &= 0xFF;
  120. }
  121. if(Uart2_Buffer[Uart2_Rx -1] == 0x5A) //头
  122. Uart2_Tx = Uart2_Rx -1;
  123. if((Uart2_Buffer[Uart2_Tx] == 0x5A)&&(Uart2_Buffer[Uart2_Rx -1] == 0xA5)) //检测到头的情况下检测到尾
  124. {
  125. Uart2_Len = Uart2_Rx -1- Uart2_Tx; //长度
  126. Uart2_Sta= 1; //标志位
  127. }
  128. if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
  129. {
  130. USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR
  131. USART_ReceiveData(USART2); //读DR
  132. }
  133. }
  134. if( Uart2_Sta )
  135. {
  136. for(tx2= 0;tx2 <= Uart2_Len;tx2++,Uart2_Tx++)
  137. USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据
  138. Uart2_Rx = 0; //初始化
  139. Uart2_Tx = 0;
  140. Uart2_Sta = 0;
  141. }
  142. 数据采用数据包的形式接收,接收后存放于缓存区,通过判断数据头和数据尾(可变)来判断数据的“包”及有效性,中断函数用于接收数据和判断头尾以及数据包长度,另一函数在main函数里执行,负责发送该段数据。
  143. 优点:适合打包传输,稳定性和可靠性很有保证,可随意发送,自动挑选有效数据。
  144. 缺点:缓存区数据长度要根据“包裹”长度设定, 要是多次接收后无头无尾,到有头有尾的那一段数据恰好跨越缓存区最前和最后位置时,可能导致本次数据丢失,不过这种情况几乎没有可能。


  •                     <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#csdnc-thumbsup"></use>
                        </svg><span class="name">点赞</span>
                        <span class="count"></span>
                        </a></li>
                        <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-Collection-G"></use>
                        </svg><span class="name">收藏</span></a></li>
                        <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true">
                            <use xlink:href="#icon-csdnc-fenxiang"></use>
                        </svg>分享</a></li>
                        <!--打赏开始-->
                                                <!--打赏结束-->
                                                <li class="tool-item tool-more">
                            <a>
                            <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
                            </a>
                            <ul class="more-box">
                                <li class="item"><a class="article-report">文章举报</a></li>
                            </ul>
                        </li>
                                            </ul>
                </div>
                            </div>
            <div class="person-messagebox">
                <div class="left-message"><a href="https://blog.csdn.net/kelixier">
                    <img src="https://profile.csdnimg.cn/B/1/9/3_kelixier" class="avatar_pic" username="kelixier">
                                            <img src="https://g.csdnimg.cn/static/user-reg-year/1x/4.png" class="user-years">
                                    </a></div>
                <div class="middle-message">
                                        <div class="title"><span class="tit"><a href="https://blog.csdn.net/kelixier" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">休闲娱乐家</a></span>
                                            </div>
                    <div class="text"><span>发布了22 篇原创文章</span> · <span>获赞 11</span> · <span>访问量 6万+</span></div>
                </div>
                                <div class="right-message">
                                            <a href="https://im.csdn.net/im/main.html?userName=kelixier" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信
                        </a>
                                                            <a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a>
                                    </div>
                            </div>
                    </div>
    
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要下载STM32串口中断接收数据程序,需要按照以下步骤进行操作: 1. 首先需要准备好开发环境,包括ST-Link下载调试器、编程软件(如Keil、IAR等)、USB转串口模块等。 2. 确保硬件连接正确。将STM32单片机与ST-Link下载调试器通过JTAG/SWD接口相连,将USB转串口模块的TX和RX引脚分别与STM32单片机的相应串口引脚相连。 3. 在编程软件中创建一个新的工程,并添加相应的库文件。打开文件->新建->MDK-ARM Project,然后选择对应的芯片型号。 4. 在工程中添加对应的串口库文件,例如“stm32f10x_usart.h”和“stm32f10x_usart.c”。 5. 配置串口的中断接收。在main函数中,通过设置USART_InitTypeDef结构体参数,配置相应串口的波特率、数据位、停止位等参数。然后通过NVIC_Configuration函数开启串口的中断。 6. 实现串口接收中断函数。在stm32f10x_it.c文件中,找到USARTx_IRQHandler函数。在该函数编写串口接收数据的处理代码。例如,可以通过判断USART_GetITStatus(USARTx, USART_IT_RXNE)的返回值来判断是否收到数据,并通过USART_ReceiveData(USARTx)读取接收到的数据。 7. 编译并下载程序。在编程软件中点击“Build”,编译源代码并生成bin或hex文件。然后使用ST-Link下载调试器将生成的bin或hex文件下载到STM32单片机中。 8. 在STM32单片机上运行程序。将USB转串口模块连接电脑,并通过串口调试软件(如Tera Term)打开串口进行数据接收。 通过以上步骤,即可成功下载STM32串口中断接收数据程序,并实现数据的接收和处理。不过要注意,在编写代码过程中,需要根据具体的芯片型号和组件进行相应的配置和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值