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

【MCU实战经验】STM32F407的串口编程经验

[复制链接]
wdzfd-25908 发布时间:2014-4-8 22:02
HAL驱动的串口编程陷阱

STM32远程升级(基于串口本地升级与WiFi通信远程升级)



串口是嵌入式开发中最常前的外设设备,既可以用作不同单片机之间的通信,也可以用作在STM32 MCUPC机之间的通信,STM32F407的串口功能非常强大,可以接红外,可以接流控,也可以接SIM卡接口,但我这里只介绍我们最常用的UART通信的一点调试经验,以STM32F407为例,对其它STM32芯片也适用,希望对大家有所帮助,如有错误不当之处欢迎大家联系指正。

一、串口的三种工作方式
操作串口一般有两种方式:查询和中断;STM32还支持第三种DMA方式。
1)查询:串口程序不断地循环查询标志,看看当前有没有数据要它传送或接收。如果有的话进行相应的写操作和读操作进行传送或接收数据。
2中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着有数据需要接收(接收中断)或数据已经发送完成(发送中断)。
3DMA方式,设置好DMA工作方式,由DMA来自动接收或发送数据。
一般来说,查询方式的效率是比较低的,并且由于STM32UART硬件上没有FIFO,如果程序功能比较多,查询不及时的话很容易出现数据丢失的现象, 故实际项目中这种方式用的并不多。
中断方式的话我们可以分别设置接收中断和发送中断,当串口有数据需要接收时才进入中断程序进行读读操,这种方式占用CPU资源比较少,实际项目中比较常用,但需要注意中断程序不要太复杂使执行时间太长,如果执行时间超过一个字符的时间的话也会出现数据丢失的现象,这个波特率比较高的串口编程中比较容易出现,可以考虑用循环BUF方法,在中断程序中只负责实时地接收实数数和发送时的填数(写发送寄存器),其它操作放在中断外处理。
STM32还提供了第三种DMA方式用来支持高速地串口传输。这种方式只要设置好接收和发送缓冲位置,可以由DMA来自动接收和发送数据,这可以最小化占用CPU时间。

二、串口的使用步骤
1)中断方式
基本步骤是初试化时钟,脚位、波特率设置、安装中断服务程序、开中断等,参考代码如下:

  1. void uart_init(void)
  2. {
  3.    USART_InitTypeDef USART_InitStructure;
  4.   NVIC_InitTypeDef NVIC_InitStructure;
  5.   GPIO_InitTypeDef  GPIO_InitStructure;
  6.    
  7.   /* Enable GPIO clock  */
  8.    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  9.   
  10.    /* Enable USART clock */
  11.    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  12.   
  13.    /* Connect USART pins to AF7 */
  14.    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
  15.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource11,  GPIO_AF_USART3);
  16.    
  17.   /* Configure USART Tx and Rx as  alternate function push-pull */
  18.    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  19.   GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_100MHz;
  20.    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  21.   GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;
  22.    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  23.   GPIO_Init(GPIOC,  &GPIO_InitStructure);
  24.    
  25.   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11;
  26.   GPIO_Init(GPIOC,  &GPIO_InitStructure);
  27.   /*  USARTx configuration  ----------------------------------------------------*/
  28.   /* USARTx configured as follow:
  29.         - BaudRate = 3750000 baud
  30.   - Maximum BaudRate that can be achieved when  using the Oversampling by 8
  31.      is: (USART APB Clock / 8)
  32. Example:
  33.    - (USART3 APB1  Clock / 8) = (30 MHz / 8) = 3750000 baud
  34.    - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000  baud
  35.   - Maximum BaudRate that can  be achieved when using the Oversampling by 16
  36.     is: (USART APB Clock / 16)
  37. Example: (USART3 APB1 Clock / 16) = (30 MHz / 16)  = 1875000 baud
  38. Example: (USART1  APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud
  39.         - Word Length = 8 Bits
  40.         - one Stop Bit
  41.         - No parity
  42.         - Hardware flow control disabled (RTS and  CTS signals)
  43.         - Receive and  transmit enabled
  44.    */
  45.    USART_InitStructure.USART_BaudRate = 115200;
  46.   USART_InitStructure.USART_WordLength =  USART_WordLength_8b;
  47.    USART_InitStructure.USART_StopBits = USART_StopBits_1;
  48.   USART_InitStructure.USART_Parity =  USART_Parity_No;
  49.    USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
  50.    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  51.   USART_Init(USART3,  &USART_InitStructure);
  52.    
  53.   /* NVIC configuration  */
  54.   /* Configure the Priority  Group to 2 bits */
  55.    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  56.   
  57.    /* Enable the USARTx Interrupt */
  58.   NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  59.    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  60.   NVIC_InitStructure.NVIC_IRQChannelSubPriority =  0;
  61.    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  62.    NVIC_Init(&NVIC_InitStructure);
  63.   
  64.   /* Enable USART  */
  65.   USART_Cmd(USART3,  ENABLE);
  66.   USART_ITConfig(USART3,  USART_IT_RXNE, ENABLE);
  67. }
复制代码

中断服务程序如下:
  1. void USART3_IRQHandler(void)
  2. {
  3. unsigned char ch;  
  4. if(USART_GetITStatus(USART3,  USART_IT_RXNE) != RESET)
  5.    {
  6.     /* Read one byte from the  receive data register */
  7.     ch =  (USART_ReceiveData(USART3));

  8.      printf("in[%c].\r\n",ch);
  9.   }   
  10. }
复制代码


直接把接收到的字符打印出来。

2DMA方式
基本步骤同中断方式,额外需要DMA的初始化配置,参考代码如下:
  1. void  uart_init(void)
  2. {
  3.   USART_InitTypeDef  USART_InitStructure;
  4.    NVIC_InitTypeDef NVIC_InitStructure;
  5.   GPIO_InitTypeDef GPIO_InitStructure;
  6.   DMA_InitTypeDef DMA_InitStruct;
  7.   
  8.    /* Enable GPIO clock */
  9.    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  10.   
  11.    /* Enable USART clock */
  12.    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  13.   
  14.    /* Connect USART pins to AF7 */
  15.    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
  16.   GPIO_PinAFConfig(GPIOC, GPIO_PinSource11,  GPIO_AF_USART3);
  17.    
  18.   /* Configure USART Tx and Rx as  alternate function push-pull */
  19.    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  20.   GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_100MHz;
  21.    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  22.   GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_UP;
  23.    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  24.   GPIO_Init(GPIOC,  &GPIO_InitStructure);
  25.    
  26.   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11;
  27.   GPIO_Init(GPIOC,  &GPIO_InitStructure);
  28.   /*  USARTx configuration  ----------------------------------------------------*/
  29.   /* USARTx configured as follow:
  30.         - BaudRate = 3750000 baud
  31.   - Maximum BaudRate that can be achieved when  using the Oversampling by 8
  32.      is: (USART APB Clock / 8)
  33. Example:
  34.    - (USART3 APB1  Clock / 8) = (30 MHz / 8) = 3750000 baud
  35.    - (USART1 APB2 Clock / 8) = (60 MHz / 8) = 7500000  baud
  36.   - Maximum BaudRate that can  be achieved when using the Oversampling by 16
  37.     is: (USART APB Clock / 16)
  38. Example: (USART3 APB1 Clock / 16) = (30 MHz / 16)  = 1875000 baud
  39. Example: (USART1  APB2 Clock / 16) = (60 MHz / 16) = 3750000 baud
  40.         - Word Length = 8 Bits
  41.         - one Stop Bit
  42.         - No parity
  43.         - Hardware flow control disabled (RTS and  CTS signals)
  44.         - Receive and  transmit enabled
  45.    */
  46.    USART_InitStructure.USART_BaudRate = 115200;
  47.   USART_InitStructure.USART_WordLength =  USART_WordLength_8b;
  48.    USART_InitStructure.USART_StopBits = USART_StopBits_1;
  49.   USART_InitStructure.USART_Parity =  USART_Parity_No;
  50.    USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
  51.    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  52.   USART_Init(USART3,  &USART_InitStructure);

  53. /*  DMA_Configuration */
  54.    DMA_DeInit(DMA1_Stream1);
  55.    
  56.   DMA_InitStruct.DMA_Channel =  DMA_Channel_4;   
  57.    DMA_InitStruct.DMA_PeripheralBaseAddr =  (u32)&USART3->DR; //source  buf
  58.    DMA_InitStruct.DMA_Memory0BaseAddr = (u8)pdata; //target buf

  59.   DMA_InitStruct.DMA_DIR =  DMA_DIR_PeripheralToMemory;
  60.    DMA_InitStruct.DMA_BufferSize = lenght;  //BuffSize;
  61.   DMA_InitStruct.DMA_PeripheralInc =  DMA_PeripheralInc_Disable;
  62.    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  63.   DMA_InitStruct.DMA_PeripheralDataSize =   DMA_PeripheralDataSize_Word;
  64.    DMA_InitStruct.DMA_MemoryDataSize =  DMA_MemoryDataSize_Byte;
  65.   DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;  //DMA_Mode_Normal;
  66.    DMA_InitStruct.DMA_Priority = DMA_Priority_High;
  67.   DMA_InitStruct.DMA_FIFOMode =  DMA_FIFOMode_Disable;
  68.    DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  69.   DMA_InitStruct.DMA_MemoryBurst =  DMA_MemoryBurst_Single;
  70.    DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  71.   DMA_Init(DMA1_Stream1,  &DMA_InitStruct);

  72.   /* NVIC configuration  */
  73.   /* Configure the Priority  Group to 2 bits */
  74.    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  75.   
  76.    /* Enable the USARTx Interrupt */
  77.   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn;  
  78.    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  79.   NVIC_InitStructure.NVIC_IRQChannelSubPriority =  0;
  80.    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  81.   NVIC_Init(&NVIC_InitStructure);  

  82.   /* Open DMA  interrupt*/
  83.    DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE);
  84.   DMA_Cmd(DMA1_Stream1, ENABLE);
  85.   USART_Cmd(USART3, ENABLE);
  86.    USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);
  87. }
复制代码


DMA中断服务程序如下:
  1. void DMA1_Stream1_IRQHandler(void) //UART3_RX
  2. {
  3.      static short i;

  4.     //When a  Transfer Complete
  5. if(SET ==  DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1))
  6. {
  7. DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1);
  8. i++;
  9. }
  10. }
复制代码


上面程序只配了DMA接收,发送类似。


三、实现DMX512协议
DMX512 协议是美国剧场技术协会( United States Institute for Theater Technology,  USITT) 制定的数字多路复用协议, 其制定的初衷是为了使舞台、剧场等地所使用的众多的调光器和控制器能相互兼容。虽然它不是一个行业或国家标准, 但是由于它的简单性和实用性, 自从出台以来, 得到了世界各地生产商和使用者普遍承认,这个协议在LED控制方面应用很广泛,利用STM32 USART可以高速传输的特性,我们很容易用STM32来实现DMX512协议。
1)数据的格式及传输
DMX512  协议规定数据以数据包的形式通过异步通讯的方式进行传输。每个数据包由若干数据帧组成, 每帧数据包括1 位低电平起始位、8 位数据位和2 位高电平停止位。DMX 协议要求数据传输的波特率为250kb/s, 亦即每位的传输时间为4us, 每帧数据的传输时间为44us, 它支持多达512 帧数据传输, 每帧数据与相应的控制支路相对应。数据包的传送要符合一定的格式和时序要求。为了使接收器能够分辨出第一帧数据, 每一个数据包以一个不短于88us 的低电平信号为起始信号, 即所谓的“Break”信号, 接收器接收到“Break”信号就准备接受随后而来的数据帧; 紧接着“Break”信号之后是不短于8us 的高电平信号M. a. b ( Mark after  Break) ; 之后就是数据帧。在DMX512 协议中, M. a. b 之后的第一帧数据被称
为“Star-t code, 在协议中规定其为零, 但在实际应用中可以由生产厂家自己确定其具体的值,  以传递特殊消息。“Star-t  code”标明其后面的数据是8  位控制信号数据帧。数据帧之间可以有时间间隔, 也可以没有;  同样, 数据包之间可以有时间间隔, 也可以没有。DMX512 协议规定“Break”信号、M. a. b 信号的最短时间, 并规定“Break”信号、M. a. b 信号、
数据帧之间及数据包之间的时间间隔的最大值不得超过1s, 否则做出错处理, 但是DMX512 协议并未对出错处理做任何规定。为了严格实现DMX512  数据的时序要求,“Break”和M.  a. b信号我们可以用定时器来实现。
具体的UART配置如下:
  
  1. USART_InitStructure.USART_BaudRate =  250000;
  2.    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  3.   USART_InitStructure.USART_StopBits =  USART_StopBits_2;
  4.    USART_InitStructure.USART_Parity = USART_Parity_No;
  5.   USART_InitStructure.USART_HardwareFlowControl =  USART_HardwareFlowControl_None;
  6.    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  7.   USART_Init(USART1,  &USART_InitStructure);
复制代码



发送DMX512信号过程如下,先把UARTTX脚配置为普通的GPIO并输出低电平,然后启动定时器计时88us,  时器到后把TX脚置为高电平并计时8us, 时器到了后在配为UART模式用DMA方式把数据发出。
DMX512信号的接收是个难点,一般直接配为UART接收就行,不需要在UART模式和GPIO模式间切换,但需要在接收过程中检查接收到“Break”信号时的状态是有帧错误出现,并且接收数据全为零,这样的话可以确认已经收到“Break”信号,随后数据正常DMA接收就行了。

1 收藏 4 评论3 发布时间:2014-4-8 22:02

举报

3个回答
lyzd 回答时间:2018-6-29 09:43:46
很全哦。。。
radio2radio 回答时间:2018-6-29 10:40:13
串口编程,我的经验是:
1. 使用已经调试好的例程,特别是参考官方例程包。
2. 使用KEIL的RTE配置串口,很好用。
3. 使用CubeMX配置串口,也很好用。
SZHYK 回答时间:2019-7-27 16:10:25
谢谢分享!!

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

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