STM32 USART串口DMA 接收和发送的源码详解!

发布者:Ziran520最新更新时间:2019-09-21 来源: eefocus关键字:STM32  USART  串口  DMA  接收和发送 手机看文章 扫描二维码
随时随地手机看文章

硬件平台:STM32F103ZET6; 


开发环境:KEIL 4;


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


串口DMA发送:


发送数据的流程:


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


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


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


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


4.等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循环查询也可以。或者其他方式。


判断数据发送完成:


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


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


2. 关闭串口发送DMA通道


3. 给前台程序设置一个软件标志位,说明数据已经发送完毕


 


串口DMA接收:


接收数据的流程:


串口接收DMA在初始化的时候就处于开启状态,一直等待数据的到来,在软件上无需做任何事情,只要在初始化配置的时候设置好配置就可以了。


 


判断数据数据接收完成:


       这里判断接收完成是通过串口空闲中断的方式实现,即当串口数据流停止后,就会产生IDLE中断。这个中断里面做如下几件事:


1.      关闭串口接收DMA通道,2点原因:1.防止后面又有数据接收到,产生干扰。2.便于DMA的重新配置赋值,下面第4点。


2.      清除DMA 所有标志位


3.      从DMA寄存器中获取接收到的数据字节数


4.      重新设置DMA下次要接收的数据字节数,注意,这里是给DMA寄存器重新设置接收的计数值,这个数量只能大于或者等于可能接收的字节数,否则当DMA接收计数器递减到0的时候,又会重载这个计数值,重新循环递减计数,所以接收缓冲区的数据则会被覆盖丢失。


5.  开启DMA通道,等待下一次的数据接收,注意,对DMA的相关寄存器配置写入,如第4条的写入计数值,必须要在关闭DMA的条件进行,否则操作无效。


说明一下,STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是这样的,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。


 


USART 和 DMA 硬件初始化配置

 

/*--- LumModule Usart Config ---------------------------------------*/

 

#define LUMMOD_UART                      USART3

 

#define LUMMOD_UART_GPIO                 GPIOC

 

#define LUMMOD_UART_CLK                  RCC_APB1Periph_USART3

 

#define LUMMOD_UART_GPIO_CLK        RCC_APB2Periph_GPIOC

 

#define LUMMOD_UART_RxPin               GPIO_Pin_11

 

#define LUMMOD_UART_TxPin               GPIO_Pin_10

 

#define LUMMOD_UART_IRQn                USART3_IRQn

 

#define LUMMOD_UART_DR_Base                  (USART3_BASE + 0x4)  //0x40013804

 

 

#define LUMMOD_UART_Tx_DMA_Channel      DMA1_Channel2

 

#define LUMMOD_UART_Tx_DMA_FLAG         DMA1_FLAG_GL2//DMA1_FLAG_TC2 | DMA1_FLAG_TE2 

 

#define LUMMOD_UART_Tx_DMA_IRQ          DMA1_Channel2_IRQn

 

#define LUMMOD_UART_Rx_DMA_Channel      DMA1_Channel3

 

#define LUMMOD_UART_Rx_DMA_FLAG         DMA1_FLAG_GL3//DMA1_FLAG_TC3 | DMA1_FLAG_TE3 

 

#define LUMMOD_UART_Rx_DMA_IRQ      DMA1_Channel3_IRQn

 

 

void Uart_Init(void)

 

{

 

    NVIC_InitTypeDef NVIC_InitStructure;

 

    GPIO_InitTypeDef GPIO_InitStructure;

 

    USART_InitTypeDef USART_InitStructure;

 

    /* System Clocks Configuration */

 

//= System Clocks Configuration ==============================//

 

 

    /* Enable GPIO clock */

 

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

 

    /* Enable USART Clock */

 

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

 

  

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

 

 

    /* 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====================================================//

 

    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 ------------------------------------------------------*/

 

    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接收

 

}

 

 

void DMA_Uart_Init(void)

 

{

 

    DMA_InitTypeDef DMA_InitStructure;

 

   

 

    /* DMA clock enable */

 

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 开启DMA1时钟

 

//=DMA_Configuration===============================================//

 

/*--- LUMMOD_UART_Tx_DMA_Channel DMA Config ---*/

 

 

 

    DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE);                           // 关DMA通道

 

    DMA_DeInit(LUMMOD_UART_Tx_DMA_Channel);                                 // 恢复缺省值

 

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&LUMMOD_UART->DR);// 设置串口发送数据寄存器

 

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LumMod_Tx_Buf;         // 设置发送缓冲区首地址

 

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                      // 设置外设位目标,内存缓冲区 ->外设寄存器

 

    DMA_InitStructure.DMA_BufferSize = LUMMOD_TX_BSIZE;                     // 需要发送的字节数,这里其实可以设置为0,因为在实际要发送的时候,会重新设置次值

 

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        // 外设地址不做增加调整,调整不调整是DMA自动实现的

 

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 // 内存缓冲区地址增加调整

 

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节

 

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         // 内存数据宽度8位,1个字节

 

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           // 单次传输模式

 

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;                 // 优先级设置

 

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                            // 关闭内存到内存的DMA模式

 

    DMA_Init(LUMMOD_UART_Tx_DMA_Channel, &DMA_InitStructure);               // 写入配置

 

    DMA_ClearFlag(LUMMOD_UART_Tx_DMA_FLAG);                                 // 清除DMA所有标志

 

    DMA_Cmd(LUMMOD_UART_Tx_DMA_Channel, DISABLE); // 关闭DMA

 

    DMA_ITConfig(LUMMOD_UART_Tx_DMA_Channel, DMA_IT_TC, ENABLE);            // 开启发送DMA通道中断

 

/*--- LUMMOD_UART_Rx_DMA_Channel DMA Config ---*/

 

 

 

    DMA_Cmd(LUMMOD_UART_Rx_DMA_Channel, DISABLE);                           // 关DMA通道

 

    DMA_DeInit(LUMMOD_UART_Rx_DMA_Channel);                                 // 恢复缺省值

 

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&LUMMOD_UART->DR);// 设置串口接收数据寄存器

[1] [2]
关键字:STM32  USART  串口  DMA  接收和发送 引用地址: STM32 USART串口DMA 接收和发送的源码详解!

上一篇:stm32上电自启动后运行不正常的故障排查分析
下一篇:STM32中stm32f0xx_flash.icf文件的作用详解!

推荐阅读最新更新时间:2024-11-05 08:09

AVR128单片机最小系统串口,外部中断,跑马灯,uCOS-II移植
实验名称:串口通信实验 功能描述:计算机通过串口向开发板发送数据,开发板将数据原样送回。 实验目的:学习串口通信 实验说明:MCU--M128 内部8M晶振 连接方式:利用串口线将开发板和计算机相连。 单片机源程序如下: /************************************************ 文件:sio.c 用途:结构化串口通信程序 ************************************************/ #include config.h #if USEUART0 siocirqueue RTbuf_UART0; #endif #if USEUART1
[单片机]
基于stm32的GPIO寄存器学习解析
GPIO即通用输入/输出 (General Purpose Input Output) 包括: 两个32位的配置寄存器 GPIOx- CRL,GPIOx- CRH 两个32位的数据寄存器 GPIOx- IDR,GPIOx- ODR 一个32位的 set/reset 寄存器 GPIOx- BSRR 一位16位的 reset 寄存器 GPIOx- BRR 一位32位的锁定寄存器 GPIOx- LCKR 端口的模式包括: 浮空输入(Input floating)—— 即没有上拉电阻和下拉电阻,电压呈不确定性,一般用来做ADC输入用,这样可以减少上下拉电阻对结果的影响 上拉输入(Input pull-up) 下拉输入(Input-pu
[单片机]
基于<font color='red'>stm32</font>的GPIO寄存器学习解析
μC/OS—II的嵌入式串口通信模块设计
在嵌入式应用中,使用RTOS的主要原因是为了提高系统的可靠性,其次是提高开发效率、缩短开发周期。μC/OS-II是一个占先式实时多任务内核,使用对象是嵌入式系统,对源代码适当裁减,很容易移植到8~32位不同框架的微处理器上。但μC/OS-II仅是一个实时内核,它不像其他实时操作系统(如嵌入式Linux)那样提供给用户一些API函数接口。在μC/OS-II实时内核下,对外设的访问接口没有统一完善,有很多工作需要用户自己去完成。串口通信是单片机测控系统的重要组成部分,异步串行口是一个比较简单又很具代表性的中断驱动外设。本文以单片机中的串口为例,介绍μC/OS—II下编写中断服务程序以及外设驅动程序的一般思路。   1 μC/OS-I
[工业控制]
基于单片机通过串口与电脑连接通信
本实验实现串口中断实验,通过中断和计算机进行通信 。 首先接受联机信号,然后接受计算机的相关控制信号。 本实验中,采用发送不同的字符给计算机来模拟接收到的不同的计算机控制命令 。 通过扩展,可以实现不同的功能 * * * * * * ********************************************************************************/
[单片机]
STM32基础入门(三)——Keil的使用
1. Keil概述 Keil MDK,也称MDK-ARM、Realview MDK、I-MDK、uVision4 等。 MDK-ARM软件为基于Cortex-M、Cortex-R4、ARM7、ARM9处理器设备提供了一个完整的开发环境。 MDK-ARM专为微控制器应用而设计,不仅易学易用,而且功能强大,能够满足大多数苛刻的嵌入式应用。 MDK-ARM有四个可用版本,分别是MDK-Lite、MDK-Basic、MDK-Standard、MDK-Professional。所有版本均提供一个完善的C / C++开发环境,其中MDK-Professional还包含大量的中间库。 完美支持Cortex-M、Cortex-R4、A
[单片机]
<font color='red'>STM32</font>基础入门(三)——Keil的使用
VB实现PC与单片机串口通信
VB进行串口的关键在于MScomm控件,下面小厮先就MScomm控件进行介绍。 每个MSComm控件对应于一个串行端口。使用多个串行口时,要使用多个MSComm控件。MSComm控件的主要属性及说明如下。 属性 说明 CommPort 设置并返回通信端口号 Settings 以字符串的形式设置并返回波特率、奇偶校验、数据位、停止位 PortOpen 设置并返回通信端口的状态。也可以打开和关闭端口 Input 从接收缓冲区返回字符 Output 向传输缓冲区写一个字符 工程 部件 ,选中Microsoft Comm c
[单片机]
意法半导体Sensory 开展合作,赋能大众市场嵌入式声控技术应用
意法半导体和Sensory 开展合作,通过STM32Cube 软件生态系统赋能大众市场嵌入式声控技术应用 STM32 MCU搭配 Sensory 的 VoiceHub 技术,简化穿戴设备、物联网和智能家居产品声控用户界面开发 2022 年 6 月 20 日,中国——服务多重电子应用领域、全球排名前列的半导体公司意法半导体(STMicroelectronics,简称ST),与世界排名前列的嵌入式语音识别技术供应商、意法半导体授权合作伙伴 Sensory Inc公司 宣布了一项合作协议,赋能STM32 微控制器 (MCU)用户社区为各种智能嵌入式产品开发直观的语音识别用户界面及产品原型。 该合作项目整合了意法半导体S
[模拟电子]
意法半导体<font color='red'>和</font>Sensory 开展合作,赋能大众市场嵌入式声控技术应用
STM32配置IIC接口通信方式参考源码
最近在读取SHT3x系列sensor的温度和湿度,用到的是IIC接口。 顺便写了一下STM32的IIC接口。 这次配置的是STM32内部的IIC接口。 注意:读的时候,怎么发送Ack, 和 NAck信号,参考stm的设计文档。 #include Dev_SHT3X.h #include globalDef.h #include stdio.h #define I2C1_OWN_ADDRESS7 0x0A #define I2C_Speed 40000 #define SHT3X_ADDRESS 0x44 /* read out command */ #define CMD_READH_SHX
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved