[应用相关] STM32 USART 串口 DMA 接收和发送的源码详解!

[复制链接]
1226|32
 楼主| hehhehee 发表于 2021-8-4 21:35 | 显示全部楼层 |阅读模式
一直都没有机会用STM32做什么项目,好在公司产品要平台升级,用到了STM32,所以最近在调试STM32,先说USART,后面再来说I2C 等等

硬件平台:STM32F103ZET6;

开发环境:KEIL 4;

先说说应用通讯模式,串口终端的工作方式和迪文屏差不多,终端被动接受MCU发的指令,终端会偶尔主动发送一些数据给MCU(像迪文屏的触摸信息上传)。


 楼主| hehhehee 发表于 2021-8-4 21:37 | 显示全部楼层
串口DMA发送:

发送数据的流程:

前台程序中有数据要发送,则需要做如下几件事

1.      在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。

2.      将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道)

3.      开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。

4.      等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。
 楼主| hehhehee 发表于 2021-8-4 21:38 | 显示全部楼层
判断数据发送完成:

启动DMA并发送完后,产生DMA发送完成中断,在中断函数中做如下几件事:

1. 清DMA发送完成中断标志位

 楼主| hehhehee 发表于 2021-8-4 21:39 | 显示全部楼层
2. 关闭串口发送DMA通道

 楼主| hehhehee 发表于 2021-8-4 21:40 | 显示全部楼层
3. 给前台程序设置一个软件标志位,说明数据已经发送完毕
 楼主| hehhehee 发表于 2021-8-4 21:41 | 显示全部楼层
串口DMA接收:

接收数据的流程:

串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。
 楼主| hehhehee 发表于 2021-8-4 21:41 | 显示全部楼层
判断数据数据接收完成:

       这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:
 楼主| hehhehee 发表于 2021-8-4 21:45 | 显示全部楼层
1.      关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。
 楼主| hehhehee 发表于 2021-8-4 21:46 | 显示全部楼层
2.      清除DMA 所有标志位
 楼主| hehhehee 发表于 2021-8-4 21:47 | 显示全部楼层
3.      从DMA寄存器中获取接收到的数据字节数
 楼主| hehhehee 发表于 2021-8-4 21:48 | 显示全部楼层
4.      重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。
 楼主| hehhehee 发表于 2021-8-4 21:49 | 显示全部楼层
5.  开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则操作无效。
 楼主| hehhehee 发表于 2021-8-4 21:49 | 显示全部楼层
说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。
 楼主| hehhehee 发表于 2021-8-4 21:50 | 显示全部楼层
USART 和 DMA 硬件初始化配置
 楼主| hehhehee 发表于 2021-8-4 21:52 | 显示全部楼层
  1. /*--- LumModule
  2. Usart Config ---------------------------------------*/



  3. #define LUMMOD_UART
  4.                      USART3

  5. #define
  6. LUMMOD_UART_GPIO                 GPIOC

  7. #define
  8. LUMMOD_UART_CLK                  RCC_APB1Periph_USART3

  9. #define
  10. LUMMOD_UART_GPIO_CLK        RCC_APB2Periph_GPIOC

  11. #define LUMMOD_UART_RxPin
  12.               GPIO_Pin_11

  13. #define
  14. LUMMOD_UART_TxPin               GPIO_Pin_10

  15. #define
  16. LUMMOD_UART_IRQn                USART3_IRQn

  17. #define
  18. LUMMOD_UART_DR_Base                  (USART3_BASE + 0x4)  //0x40013804



  19. #define
  20. LUMMOD_UART_Tx_DMA_Channel      DMA1_Channel2

  21. #define LUMMOD_UART_Tx_DMA_FLAG
  22.         DMA1_FLAG_GL2//DMA1_FLAG_TC2
  23. | DMA1_FLAG_TE2

  24. #define
  25. LUMMOD_UART_Tx_DMA_IRQ          DMA1_Channel2_IRQn



  26. #define
  27. LUMMOD_UART_Rx_DMA_Channel      DMA1_Channel3

  28. #define
  29. LUMMOD_UART_Rx_DMA_FLAG         DMA1_FLAG_GL3//DMA1_FLAG_TC3 | DMA1_FLAG_TE3

  30. #define
  31. LUMMOD_UART_Rx_DMA_IRQ      DMA1_Channel3_IRQn




 楼主| hehhehee 发表于 2021-8-4 21:54 | 显示全部楼层
void
Uart_Init(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

    GPIO_InitTypeDef GPIO_InitStructure;

    USART_InitTypeDef USART_InitStructure;



    /* System Clocks Configuration */

//= System Clocks
Configuration
====================================================================//
 楼主| hehhehee 发表于 2021-8-4 21:55 | 显示全部楼层
   /* Enable GPIO clock */

    RCC_APB2PeriphClockCmd(LUMMOD_UART_GPIO_CLK ,
ENABLE ); // 开启串口所在IO端口的时钟

    /* Enable USART Clock */

    RCC_APB1PeriphClockCmd(LUMMOD_UART_CLK,
ENABLE); // 开始串口时钟

   

   

//=NVIC_Configuration==============================================================================//


 楼主| hehhehee 发表于 2021-8-4 21:59 | 显示全部楼层
/* Configure the NVIC Preemption Priority
Bits */

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);



    /* Enable the DMA Interrupt */

    NVIC_InitStructure.NVIC_IRQChannel =
LUMMOD_UART_Tx_DMA_IRQ;   // 发送DMA通道的中断配置

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority
= 2;     // 优先级设置

    NVIC_InitStructure.NVIC_IRQChannelSubPriority
= 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);



    /* Enable the USART Interrupt */

    NVIC_InitStructure.NVIC_IRQChannel =
LUMMOD_UART_IRQn;     // 串口中断配置

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority
= 2;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority
= 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd =
ENABLE;

    NVIC_Init(&NVIC_InitStructure);

   

//=GPIO_Configuration==============================================================================//
 楼主| hehhehee 发表于 2021-8-4 22:01 | 显示全部楼层


    GPIO_PinRemapConfig(GPIO_PartialRemap_USART3,
ENABLE);  // 我这里没有用默认IO口,所以进行了重新映射,这个可以根据自己的硬件情况配置选择

   

    /* Configure USART3 Rx as input floating */

    GPIO_InitStructure.GPIO_Mode =
GPIO_Mode_IPU;   // 串口接收IO口的设置

    GPIO_InitStructure.GPIO_Pin =
LUMMOD_UART_RxPin;

    GPIO_Init(LUMMOD_UART_GPIO,
&GPIO_InitStructure);



    /* Configure USART3 Tx as alternate function
push-pull */

    GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_50MHz;   // 串口发送IO口的设置

    GPIO_InitStructure.GPIO_Mode =
GPIO_Mode_AF_PP;  // 这里设置成复用形式的推挽输出   

    GPIO_InitStructure.GPIO_Pin =
LUMMOD_UART_TxPin;

    GPIO_Init(LUMMOD_UART_GPIO,
&GPIO_InitStructure);



    DMA_Uart_Init();   // 串口 DMA 配置



    /* USART Format configuration
------------------------------------------------------*/
 楼主| hehhehee 发表于 2021-8-4 22:02 | 显示全部楼层
USART_InitStructure.USART_WordLength =
USART_WordLength_8b;    // 串口格式配置

    USART_InitStructure.USART_StopBits =
USART_StopBits_1;

    USART_InitStructure.USART_Parity =
USART_Parity_No;

    USART_InitStructure.USART_HardwareFlowControl
= USART_HardwareFlowControl_None;

    USART_InitStructure.USART_Mode =
USART_Mode_Rx | USART_Mode_Tx;



    /* Configure USART3 */

    USART_InitStructure.USART_BaudRate = 115200;
//  波特率设置

    USART_Init(LUMMOD_UART,
&USART_InitStructure);



    /* Enable USART3 Receive and Transmit
interrupts */

    USART_ITConfig(LUMMOD_UART, USART_IT_IDLE,
ENABLE);  // 开启 串口空闲IDEL 中断

   

    /* Enable the USART3 */

    USART_Cmd(LUMMOD_UART, ENABLE);  // 开启串口

    /* Enable USARTy DMA TX request */

    USART_DMACmd(LUMMOD_UART, USART_DMAReq_Tx,
ENABLE);  // 开启串口DMA发送

    USART_DMACmd(LUMMOD_UART, USART_DMAReq_Rx,
ENABLE); // 开启串口DMA接收

}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

89

主题

1252

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部