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

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

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