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

STM32心得:串口通信相关知识及配置方法

[复制链接]
STMCU小助手 发布时间:2022-11-20 18:08
主要内容:
1) 串行通信接口背景知识;
2) STM32F1串口框图讲解;
3) STM32串口部分常用寄存器和库函数;
4) 串口配置一般方法;
5) ALIENTEK提供的公用代码usart.c和usart.h解读。

1. 处理器与外部设备通信的两种方式
1.1 并行通信,传输原理:数据各个位同时传输。优点:速度快。缺点:占用引脚资源多。
1.2 串行通信,传输原理:数据按位顺序传输。优点:占用引脚资源少。缺点:速度相对较慢。
2. 串行通信(按照数据传送方向可分为)
2.1 单工:数据传输只支持数据在一个方向上传输(图a);
2.2 半双工:允许数据在两个方向上传输,但在某一时刻,只允许数据在一个方向上传输,实际上是一种切换方向的单工通信(图b);
2.3 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力(图c)。

20200406091726697.jpg

3. 串行通信的通信方式
3.1 同步通信:带时钟同步信号传输,包括SPI,IIC通信接口;
3.2 异步通信:不带时钟同步信号,包括UART(通用异步收发器,双方需事先约定好波特率),单总线。

4. 常见的串行通讯接口

2020040609190067.png
5. STM32的串口通信接口
5.1 UART:通用异步收发器;
5.2 USART:通用同步异步收发器。
备注:大容量STM32F10x系列芯片,包含3个USART和2个UART。

6. UART异步通信方式引脚连接方法
6.1 RXD:数据输入引脚。数据接受;
6.2 TXD:数据发送引脚。数据发送。

20200406092107514.jpg

6.3 开发版上的串口引脚如下表所示:

20200406092152980.png

7. UART异步通信方式特点
7.1 全双工异步通信;
7.2 分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s;
7.3 可编程的数据字长度(8位或者9位);
7.4 可配置的停止位(支持1或者2位停止位);
7.5 可配置的使用DMA多缓冲器通信;
7.6 单独的发送器和接收器使能位;
7.7 检测标志:① 接受缓冲器 ②发送缓冲器空 ③传输结束标志;
7.8 多个带标志的中断源。触发中断;
7.9 其他:校验控制,四个错误检测标志。

8. 串口通信过程

20200406092341382.png

9. STM32串口异步通信需要定义的参数

9.1 起始位;
9.2 数据位(8位或者9位);
9.3 奇偶校验位(第9位);
9.4 停止位(1,15,2位);
9.5 波特率设置。

20200406092501380.png

10. STM32串口框图
10.1 对于大容量的STM32F10x芯片,有5个串口,串口1时钟来源PCLK2,串口2~4时钟来源PCLK1。

20200406092600669.png

11. 常用的串口相关寄存器
11.1 USART_SR状态寄存器(串口通信的状态位);
11.2 USART_DR数据寄存器(读写都通过该寄存器);
11.3 USART_BRR波特率寄存器。

12. 串口操作相关库函数

  1. void USART_Init();                      //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能//
  2. void USART_Cmd();                       //使能串口//
  3. void USART_ITConfig();                  //使能相关中断//
  4. void USART_SendData();                  //发送数据到串口,针对DR寄存器//
  5. uint16_t USART_ReceiveData();           //接受数据,从DR读取接受到的数据,针对DR寄存器//
  6. FlagStatus USART_GetFlagStatus();       //获取状态标志位,针对SR寄存器//
  7. void USART_ClearFlag();                 //清除状态标志位,针对SR寄存器//
  8. ITStatus USART_GetITStatus();           //获取中断状态标志位,针对SR寄存器//
  9. void USART_ClearITPendingBit();         //清除中断状态标志位,针对SR寄存器//
复制代码

13. 串口常用寄存器解读
13.1 状态寄存器(USART_SR)

  1. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
复制代码

20200407143351654.png

13.2 数据寄存器(USART_DR)

  1. void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
  2. uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
复制代码

20200407143449289.png

13.3 波特比率寄存器(USART_BRR)

  1. void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
复制代码

14. 波特率计算方法


202004071436317.jpg

15. 串口配置一般步骤

15.1 串口时钟使能,GPIO时钟使能;

  1. RCC_APB2PeriphClockCmd();     //USART1位于RCC_APB2PeriphClockCmd中//
复制代码

15.2 串口复位;

  1. USART_DeInit();               //这一步不是必须的//
复制代码

15.3 GPIO端口模式设置;

  1. GPIO_Init();                  //TX模式设置为GPIO_Mode_AF_PP,RX模式设置为GPIO_Mode_IN_FLOATING //
复制代码

15.4 串口参数初始化;

  1. USART_Init();
复制代码

15.5 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤);

  1. NVIC_Init();
  2. USART_ITConfig();
复制代码

15.6 使能串口;

  1. USART_Cmd();
复制代码

15.7 编写中断处理函数;

  1. USARTx_IRQHandler();
复制代码

15.8 串口数据收发;

  1. void USART_SendData();                      //发送数据到串口,DR//
  2. uint16_t USART_ReceiveData();               //接受数据,从DR读取接受到的数据//
复制代码

15.9 串口传输状态获取;

  1. FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
复制代码

20200407144125217.png

  1. void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
复制代码

20200407144213278.png

16. 串口配置案例

  1. //案例说明:设置PA9和PA10位USART1的TX和RX,开启USART_IT_RXNE接收中断,中断服务函数目的为,当USART_IT_RXNE发生,USART1接收数据并发送回去,需配合串口调试助手进行实验//
  2. #include "stm32f10x.h"
  3. //编写我的初始化函数//
  4. void My_USART1_Init(void)
  5. {
  6. GPIO_InitTypeDef GPIO_InitStruct;
  7. USART_InitTypeDef  USART_InitStruct;
  8. NVIC_InitTypeDef NVIC_InitStruct;
  9. //第一步,使能相关时钟//
  10. //使能GPIOA时钟,RCC_APB2PeriphClockCmd()位于stm32f10x.rcc.c文件中//
  11. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  12. //使能USART1时钟//
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);                     
  14. //第二步,串口复位//
  15. //将外设 USARTx 寄存器重设为缺省值,复位USART1,USART_DeInit()位于stm32f10x.usart.c文件中//
  16. USART_DeInit(USART1);                                                            
  17. //第三步,GPIO端口模式设置,PA9对应RXD,PA10对应TXD//
  18. //先对PA9进行设置,模式为复用推挽输出,引脚9,速度随意//
  19. GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;         //复用推挽输出//
  20. GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;               //引脚9//
  21. GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;       //随意设置//
  22. //根据上述GPIO_InitStruct中指定的参数初始化外设GPIOA寄存器,,GPIO_Init()位于stm32f10x.gpio.c文件中//
  23. GPIO_Init(GPIOA,&GPIO_InitStruct);                                          
  24. //再对PA10进行设置,模式为浮空输入或带上拉输入,引脚10,速度随意//
  25. GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //浮空输入//
  26. GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;              //引脚9//
  27. GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;       //随意设置//
  28. //根据GPIO_InitStruct中指定的参数初始化外设GPIOA寄存器,GPIO_Init()位于stm32f10x.gpio.c文件中//
  29. GPIO_Init(GPIOA,&GPIO_InitStruct);                                          
  30. //第四步,串口参数初始化,在电脑上进行串口通信时,串口调试软件也需按下述参数设置//
  31. USART_InitStruct.USART_BaudRate=115200;                                    //波特率为115200//
  32. USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用硬件流控制//
  33. USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;                 //收发都使能,可用或运算//
  34. USART_InitStruct.USART_Parity=USART_Parity_No;                             //不用奇偶校验位//                           
  35. USART_InitStruct.USART_StopBits=USART_StopBits_1;                          //设置1个停止位//
  36. USART_InitStruct.USART_WordLength=USART_WordLength_8b;                     //设字长为8,因为不用奇偶校验//
  37. //根据上述USART_InitStruct中指定的参数初始化外设USART1寄存器,USART_Init()位于stm32f10x.usart.c文件中//
  38. USART_Init(USART1,&USART_InitStruct);
  39. //第五步,开启指定中断,并初始化NVIC//   
  40. //NVIC初始化//
  41. NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;            //选择位于stm32f10x.h文件中STM32F10X_HD中的USART1_IRQn//
  42. NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;              //使能上述中断通道//
  43. NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;    //因为没有别的中断,根据中断分组2,参数可设0~3之间//
  44. NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;           //因为没有别的中断,根据中断分组2,参数可设0~3之间//
  45. //根据上述NVIC_InitStruct中指定的参数初始化外设NVIC寄存器,NVIC_Init()位于misc.c文件中//
  46. NVIC_Init(&NVIC_InitStruct);            
  47. //使能USART1的USART_IT_RXNE中断,RXNE是状态寄存器USART_SR的第5位,意思是接收中断//
  48. USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  49. //第六步,使能串口//  
  50. //使能USART1外设,USART_Cmd()位于stm32f10x.usart.c文件中//
  51. USART_Cmd(USART1,ENABLE);   
  52. }
  53. //第七步,编写中断服务函数//
  54. //函数名称USART1_IRQHandler是由位于启动文件startup_stm32f10x_hs.s文件里定义的//
  55. void USART1_IRQHandler(void)                                                   
  56. {
  57. u8 data;
  58. //第八步,串口状态获取//
  59. //检查USART1的接受中断USART_IT_RXNE发生与否,USART_GetITStatus()函数位于stm32f10x_usart.c文件中//
  60. if(USART_GetITStatus(USART1,USART_IT_RXNE))                                 
  61. {
  62. //第九步,串口数据收发,较为常用//
  63. //返回USART1最近接收到的数据,USART_ReceiveData()函数位于stm32f10x_usart.c文件中//
  64. data=USART_ReceiveData(USART1);
  65. //通过外设USART1发送单个数据,USART_SendData()函数位于stm32f10x_usart.c文件中//  
  66. USART_SendData(USART1,data);                                               
  67. }
  68. }
  69. //编写主函数//
  70. int main(void)
  71. {
  72.   //设置优先级分组:先占优先级和从优先级//
  73.   //设置分组2,即2位抢占优先级,2位响应优先级,NVIC_PriorityGroupConfig()位于misc.c文件中//
  74.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                             
  75.   My_USART1_Init();
  76.   while(1)
  77.   {
  78.   }
  79. }
复制代码

17. usart.h代码讲解

  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stdio.h"   
  4. #include "sys.h"
  5. #define USART_REC_LEN    200            //定义最大接收字节数 200//
  6. #define EN_USART1_RX     1              //使能(1)/禁止(0)串口1接收//
  7. extern u8 USART_RX_BUF[USART_REC_LEN];  //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符//
  8. extern u16  USART_RX_STA;               //接收状态标记//      
  9. //如果想串口中断接收,请不要注释以下宏定义//
  10. void uart_init(u32 bound);              //设置波特率//
  11. #endif
复制代码

18. usart.c里中断服务函数USART1_IRQHandler函数代码讲解

  1. void USART1_IRQHandler(void)      //串口1中断服务程序//
  2. {
  3.    u8 Res;                          //定义一个变量Res,用来接收数据//
  4.    #if SYSTEM_SUPPORT_OS                //如果SYSTEM_SUPPORT_OS为真,则需要支持OS//
  5.        OSIntEnter();   
  6.    #endif
  7.    //*判断接收中断USART_IT_RXNE是否发生,发生则为1,不发生为*0//
  8.    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //RESET=0//
  9.       {
  10.       //*若接收中断USART_IT_RXNE发生,Res读取接收到的数据*//
  11.         Res =USART_ReceiveData(USART1);         
  12.       //判断变量U16 USART_RX_STA的位15是否为0,当USART_RX_STA的位15为0时,则与运算后值为0,if返回1(真),反之if返回0(假)*//
  13.         if((USART_RX_STA&0x8000)==0)                  
  14.            {
  15.            //*若USART_RX_STA的位15为0时,判断USART_RX_STA的位14是否为0*//
  16.               if(USART_RX_STA&0x4000)                  
  17.                  {
  18.                  //*若USART_RX_STA的位14为1时,则判断Res接收的数据是否为0x0A,0x0A为换行标志*//
  19.                     if(Res!=0x0A)   
  20.                        //*若Res接收的数据不是换行标志,则接收错误,重新开始*//            
  21.                        USART_RX_STA=0;   
  22.                     //*若Res接收的数据是换行标志,则USART_RX_STA的位15至1* //      
  23.                     else USART_RX_STA|=0x8000;      
  24.                   }
  25.                //*若USART_RX_STA的位14为0时,执行else *//
  26.                else                                
  27.                   {     
  28.                     //*判断Res是否等于(接收到)0x0D,0x0D为回车标志*//
  29.                     if(Res==0x0d)
  30.                        //*若Res接收到回车标志,if为1(真),则USART_RX_STA位14至1 //                     
  31.                        USART_RX_STA|=0x4000;
  32.                     //*若Res未接收到回车标志,if为0(假),执行else//
  33.                     else                              
  34.                          {
  35.                           USART_RX_BUF[USART_RX_STA&0X3FFF]=Res;
  36.                           USART_RX_STA++;
  37.                               //*若USART_RX_STA值大于所设最大接收字节数,则接收数据错误,重新开始接收*//   
  38.                               if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;                              
  39.                           }
  40.                    }
  41.            }                  
  42.      }
复制代码

上述代码中,变量U16 USART_RX_STA用法如下图所示:

2020040722410483.png

19. main.c文件里主函数代码讲解


  1. int main(void)
  2. {            
  3.   u16 t;  
  4.   u16 len;   
  5.   u16 times=0;
  6.   delay_init();                    //*延时函数初始化*//
  7.   //设置NVIC中断分组2:2位抢占优先级,2位响应优先级//
  8.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  9.   uart_init(115200);            //串口初始化为115200//
  10.   LED_Init();                       //LED端口初始化//
  11.   KEY_Init();               //初始化与按键连接的硬件接口//
  12.   while(1)
  13.        {
  14.          //*判断USART_RX_STA的位15是否为1*//
  15.          if(USART_RX_STA&0x8000)
  16.            {     
  17.             //*若USART_RX_STA的位15为1*//                          
  18.             len=USART_RX_STA&0x3fff;        //得到此次接收到的数据长度//
  19.             printf("\r\n您发送的消息为:\r\n\r\n");
  20.             for(t=0;t<len;t++)
  21.                {
  22.                   USART_SendData(USART1, USART_RX_BUF[t]);   //向串口1发送第t个数据//
  23.                   //*等待发送结束,USART_FLAG_TC意思是Transmission Complete flag*//
  24.                   while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
  25.                 }
  26.              printf("\r\n\r\n");                                      //插入换行//
  27.                      USART_RX_STA=0;
  28.            }else
  29.                 {
  30.                 times++;
  31.                 if(times%5000==0)                                     //*times为5000的整数倍时*//
  32.                   {
  33.                     printf("\r\n战舰STM32开发板 串口实验\r\n");
  34.                     printf("正点原子@ALIENTEK\r\n\r\n");
  35.                    }
  36.                  if(times%200==0)printf("请输入数据,以回车键结束\n");   //*times为200的整数倍时*//
  37.                      //*times为30的整数倍时,闪烁LED,提示系统正在运行*//
  38.                      if(times%30==0)LED0=!LED0;         
  39.                      delay_ms(10);   
  40.                  }
  41.            }     
  42.   }
复制代码

20. usart.c里中断服务函数printf()函数代码讲解

  1. #if 1
  2. #pragma import(__use_no_semihosting)            
  3. //标准库需要的支持函数//                 
  4. struct __FILE
  5. {
  6.        int handle;
  7. };
  8. FILE __stdout;      
  9. //定义_sys_exit()以避免使用半主机模式//   
  10. _sys_exit(int x)
  11. {
  12.     x = x;
  13. }
  14. //重定义fputc函数//
  15. int fputc(int ch, FILE *f)
  16. {      
  17.     while((USART1->SR&0X40)==0);//循环发送,直到发送完毕//  
  18.     USART1->DR = (u8) ch;      
  19.     return ch;
  20. }
  21. #endif
  22. //若要对其他串口进行操作,只需将上述代码中的USART1改成USARTx即可。这段代码方便开发过程中查看代码执行情况以及一些变量值,该代码不需要修改,引入到 usart.h 即可//
复制代码

————————————————
版权声明:天亮继续睡


202004071435316.png
收藏 评论0 发布时间:2022-11-20 18:08

举报

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