STM32 串口 DMA 数据读取(详细代码)

2023-05-16


最近重新开始学32,搞到串口 DMA 的时候, 数据读取卡了很长一段时间,最终,功夫不负有心人终于搞出来了。在此以记录一下,方便以后查询使用。
在调试的过程中也遇到了很多bug,有些简直就是低级问题,但是还是卡了很久,在此写出来给自己加深印象,同时已给后来者一个前车之鉴
1、在32的程序编写中,若使用到了中断部分,特别是中断函数一定要注意,查询清除中断标志位到底是什么。
获取中断标志位 是 USART_GetITStatus 函数,笔者就是没弄清 用成了 USART_ GetFlagStatus 函数,
USART_GetITStatus   检查指定的 USART 中断发生与否
USART_ GetFlagStatus 检查指定的 USART 标志位设置与否
就是这个问题卡了笔者很久,甚至笔者检查了很多次都没注意到

2、中断函数的使用, 这个在使用时若不注意就会用错,比如 中断串口2 ,却使用成了 中断串口1
关于中断函数的查询可以通过kile5 Startup文件夹 下的 startup_stm32f10x_md.s 进行查询

3、代码功能独立
这部分主要就是要将各函数功能进行,独立。方便理清逻辑,可能很多人觉得很麻烦,且很多人没有此习惯,但是在学习和工作中稍微花点时间,将其进行整理还是很有必要的。
笔者在调试这部分时,就出现了逻辑混乱的情况,将 GPIO, 串口,DMA 全部写在一起,导致最后混乱。最终每次只会搬运最后一个字符。具体原因笔者也没搞清楚。若有大佬能够了解,望指点一二。

————————————————————分割线————————————————————

以上废话,下为正文
DMA 串口数据读取主要就是 将串口的数据搬移到内存中
在实际代码中,笔者定义了一个char 数组进行存储。并通过重定义printf 的方式将 char 数组内的内容输出出来(后面看大家需不需要,也可以将DMA 数据发送的代码 分享出来 嘿嘿嘿)。
主要步骤如下
1、选择使用的串口(串口1)
2、查询该串口对应的引脚及DMA通道(A9,A10, DMA1chanel4, DMA1chanel5)Tip:可以通过STM32参考手册查询,后面会放的(感谢正点原子)
3、配置串口1 GPIO
4、配置串口1 USART 及 中断
5、配置串口1 对应 DMA

着重需要注意的是:这里使用的是 串口1 的 空闲中断。空闲中断在设备接收到数据后 一个字节内的时间还是为接收到数据就会产生,在清除之后,当下一次接收到数据之后的1个字节时间内才会再次产生。   说人话就是,正常情况下不会产生,只有在接收数据后,没有数据了,才会再次产生。
此处使用串口 的空闲中断可以实现 接收不定长数据,若使用的是 定长数据 就可以使用DMA 的接收完成中断(接收完成是当前数据接收完成,还需要判断接收次数是否为 0)

笔者设备 STM32F103RCT6 + window10,若其他设备可根据提供的资料进行查询对应的引脚和通道

————————————————————分割线————————————————————

开始放代码
配置引脚

void USART1_GPIO_Init(void){//初始化 串口 1 GPIO
                //GPIO引脚功能初始化结构体
                GPIO_InitTypeDef GPIO_InitStruct;
                //1、使能串口引脚,复用功能
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
               
                //2、初始化引脚功能 输入 悬空(输入高为高, 输入低为低), 输出 复用推挽
                GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//初始化引脚为 A9
                GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//初始化引脚功能为 复用推挽模式
                GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//设置引脚传输速率为 10MHz
                GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A9引脚 (发送)
               
                GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;//初始化引脚为 A10
                GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;//初始化引脚功能为 悬空输入
                GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//设置引脚传输速率为 10MHz
                GPIO_Init(GPIOA, & GPIO_InitStruct);//初始化 A1引脚 (接收)
}

配置串口

void USART1_Init(uint32_t BaudRate){               
                //串口初始化结构体
                USART_InitTypeDef USART_InitStruct;
                //串口优先级结构体
                NVIC_InitTypeDef NVIC_InitStruct;

                //1、使能串口引脚,复用功能
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

                //2、串口初始化
                //2.1 初始化波特率
                USART_InitStruct.USART_BaudRate = BaudRate;//初始化串口波特率(使用形参确定)
                //2.2 初始化数据位
                USART_InitStruct.USART_WordLength = USART_WordLength_8b;//初始化串口数据位为 8 位
                        //2.3 初始化停止位
                USART_InitStruct.USART_StopBits = USART_StopBits_1;//初始化串口数据位为 0 位
                //2.4 初始化奇偶校验位
                USART_InitStruct.USART_Parity = USART_Parity_No;//初始化串口奇偶校验位
                //2.5 初始化流控
                USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//初始化串口控制为无流控
                //2.6 初始化串口工作模式
                USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

                USART_Init(USART1, & USART_InitStruct);               

                //3、设置串口 接收中断 (空闲中断-搬运数据完毕 或 未搬运数据 当开始搬运数据后 一段时间未搬运下一个数据,发出此中断)
                //3.1 配置串口中断优先级通道
                NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
                //3.2 使能命令
                NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
                //3.3 设置抢占优先级
                NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
                //3.4 设置优先级
                NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
                NVIC_Init( & NVIC_InitStruct);
               
                //5、配置串口接收中断
                USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//串口1 空闲中断               
                //5、中断处理
                USART_DMACmd(USART1,USART_DMAReq_Rx, ENABLE);//开启串口1 DMA 接收请求
                //6、使能串口
                USART_Cmd(USART1,ENABLE);//若重载 printf ,就无需使用 DMA 进行数据搬移。(故此处应该无需使用重载)
}

配置 DMA

void USART1_DMA_Init(void){
        //DMA初始化结构体
        DMA_InitTypeDef DMA_InitStruct;

        //1、使能DMA时钟
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
       
        //2、接收数据 DMA通道5初始化
        //2.1 初始化外设地址
        DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)& USART1->DR;//设置串口发送数据寄存器
        //2.2 初始化内存地址
        DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Get_Date;//接收内存地址
        //2.3 初始化 DMA 方向
        DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//外设为源地址
        //2.4 初始化 发送数据大小 ,6.2内存大小
        DMA_InitStruct.DMA_BufferSize = BUFFSIZE;//此处的接收数据大小设置一个固定的,较大的
        //2.5 初始化外设地址增量(向发送端写入数据,无需使用增量)
        DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//无增量
        //2.6 初始化内存地址增量(读取内存地址,写入外设,有增量)
        DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//有增量
        //2.7 初始化外设数据宽度
        DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//无增量的话应该不用设置
        //2.8 初始化内存数据宽度
        DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//增量为全字
        //2.9 初始化DMA工作模式
        DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;//正常循环模式
        //2.10 初始化DMA通道优先级
        DMA_InitStruct.DMA_Priority = DMA_Priority_High;//通道优先级 高
        //2.11 初始化DMA存储器to存储器(内存写入外设,无需使用)
        DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//不使用 内存到内存               

        DMA_Init(DMA1_Channel5, & DMA_InitStruct);//通道5 串口1 读数据

        DMA_Cmd(DMA1_Channel5, ENABLE);//开启通道5 使能位
}

中断和调用函数部分

void Mov_DmaDate_To_Buffer(void){//搬移函数,将DMA寄存器中的数据搬移到另一个寄存器
        DMA_Cmd(DMA1_Channel5, DISABLE);//关闭 DMA 通道 5 (关闭串口1 读)
                       
        DMA1_Channel5->CNDTR = BUFFSIZE;//重新设置 通道 待传输数据大小
               
        DMA_Cmd(DMA1_Channel5, ENABLE);//开启 DMA 通道 5 (开启串口1 读)
       
        printf("%s\n",Get_Date);//输出接收的数据
}


void USART1_IRQHandler(void){//串口1 中断处理函数
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){//若中断标志位为 空闲中断
                //调用搬移函数
                Mov_DmaDate_To_Buffer();//调用空闲中断处理函数

                USART_ReceiveData(USART1);//通过读取数据实现关闭 空闲中断
               
                //清除标志位
                Recevie_State = true;//设置接收数据完毕标志位
        }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 串口 DMA 数据读取(详细代码) 的相关文章

  • 140-基于stm32单片机智能晾衣杆控制系统Proteus仿真+源程序

    资料编号 140 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 ds1302时钟 光敏传感器 蜂鸣器 LED灯 制作一个基于stm32单片机智能晾衣杆控制系统Proteus仿真 2 通过光敏传感器
  • 138-基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真+源程序

    资料编号 138 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 ds1302时钟 LED灯 蜂鸣器 电位器 制作一个基于stm32单片机汽车多功能仪表盘显示系统Proteus仿真 2 通过DHT1
  • rt-thread studio中新建5.02版本报错

    先吐槽一下 rt thread studio出现BUG真多 好多时间都是在找BUG 但里面用好多控件还是挺好用的 真是又爱又恨 所以一般使用功能不多的话还是用keil多一点 创建5 02版本工程之后直接进行编译 直接会报下面这个错误 资源
  • STM32F103

    提示 来源正点原子 参考STM32F103 战舰开发指南V1 3PDF资料 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 开发环境硬件普中科技 接线图在g
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • HAL 锁定和解锁函数如何使用以及为什么?

    我试图理解另一位程序员编写的代码 它使用了I C http en wikipedia org wiki I C2 B2C通信以将数据写入 STM32 微控制器的 EEPROM 一般来说 我理解他的代码是如何工作的 但我不明白他为什么使用HA
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • DMA 与中断驱动的 I/O

    我不太清楚 DMA 和中断 I O 之间的区别 当前正在阅读操作系统概念 第 7 版 具体来说 我不确定在这两种情况下何时会发生中断 以及在这两种情况下 CPU 在什么时候可以自由地执行其他工作 我一直在读但不一定能调和的东西 中断驱动 通
  • CMSIS & STM32,如何开始? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在 STM32 上使用 CMSIS 启动项目 网上一搜 没找到具体的教程 有些使用 SPL 开始项
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧 说起来很简单 就是几行代码的事 但楞是折腾了我大半天时间才搞定 原因后面说 先看代码吧 读操作 读操作很简单 以32位方式读取的时候是这样的 data IO uint32 t 0x0800F000 需要注意的是 当以32位方式读
  • 从没有中断引脚并且在测量准备好之前需要一些时间的传感器读取数据的最佳方法

    我正在尝试将压力传感器 MS5803 14BA 与我的板 NUCLEO STM32L073RZ 连接 根据 第 3 页 压力传感器需要几毫秒才能准备好读取测量值 对于我的项目 我对需要大约 10 毫秒来转换原始数据的最高分辨率感兴趣 不幸的
  • 如何从cdev获取设备

    我正在编写一个内核模块 它将分配一些一致的内存并返回相应的虚拟和物理地址 我正在将模块注册为cdev 分配空间dma alloc coherent 我想使用 mmap 它dma common mmap dma common mmap 需要一
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • STM32F0、ST-link v2、OpenOCD 0.9.0:打开失败

    我在用着发射台 http www ti com ww en launchpad about htmlgcc arm none eabi 4 9 2015q2 为 STM32F0 进行编译 现在我想使用该集合中的 arm none eabi
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • 环形缓冲区和 DMA

    我试图了解从数据包到达网卡到目标应用程序收到数据包之间发生的所有事情 假设 缓冲区足够大 可以容纳整个数据包 我知道情况并非总是如此 但我不想介绍太多技术细节 一种选择是 1 Packet reaches the NIC 2 Interru

随机推荐

  • visual studio 2022 调试时如何1、打开监视窗口;2、监视窗口无法输入问题

    1 如何打开监视窗口 xff1a 注意要先点击调试 xff0c 不然没有这个窗口 2 如果窗口显灰色 xff0c 说明当前调试状态没有中断 xff0c 而只有中断的时候才可以输入或修改 3 点击调试里的 全部中断 后就可以输入了 xff01
  • 单片机学习——定时器/计数器

    单片机必学系列 单片机学习 中断系统 单片机学习 存储器详解 xff08 程序存储器 片内RAM 拓展RAM EEPROM xff09 单片机学习 定时器 计数器 单片机学习 A D转换 更新ing 单片机学习 定时器 计数器 单片机必学系
  • C++的动态多态性理解

    多态 xff1a 指允许不同类的对象对同一消息做出响应 即同一消息可以根据发送对象的不同而采用多种不同的行为方式 xff08 发送消息就是函数调用 xff09 像我们之前学的函数重载和符号重载都是多态现象 例 xff1a 使用运算符 43
  • Hadoop伪分布集群配置(我用的是VMwareWorkstation)

    1 虚拟机环境准备 xff1a 1 0 xff09 首先准备好一台已经安装好了的虚拟机 我这里用的是Centos 2 0 xff09 安装 vim 编辑器 使用 yum y install vim 也可以直接用vi 注意 xff1a 安装好
  • fork函数的用法

    1 头文件 include lt sys types h gt inlcude lt unistd h gt 2 函数原型 pid t fork void 函数参数 xff1a void 3 fork函数功能 fork xff08 xff0
  • gitee配置流水线实现自动打包vue

    1 任务编排 xff1a 第1步 xff1a 创建一个构建任务 xff0c 选择nodejs xff1b 第2步 xff1a 编写构建命令 设置NPM源 xff0c 提升安装速度 npm config set registry https
  • Linux操作系统:Firewalld防火墙

    Linux操作系统 xff1a Firewalld 防火墙 课堂引入 xff1a Linux防火墙是通过netfilter来处理的 xff0c 它是内核级别的框架 iptables被作为netfilter的用户态抽象层 xff0c ipta
  • 全景图拼接

    目录 一 图像拼接基本流程 二 RANSAC 随机一致性采样 2 1 RANSAC基本思想 xff1a 数据中包含正确的点和噪声点 xff0c 合理的模型应该能够在描述正确数据点的同时摒弃噪声点 2 2 RANSAC基本流程 xff1a 2
  • 11. JS操作节点续(2) + DOM 重点核心

    关于dom操作 xff0c 我们主要针对于元素的操作 主要有创建 增 删 改 查 属性操作 事件操作 DOM xff1a 我们获取过来的DOM元素是一个对象 xff08 object xff09 xff0c 所以称为 文档对象模型 创建 d
  • Docker-使用篇

    文章目录 一 Docker镜像和容器 镜像命令镜像下载 xff08 pull xff09 查看镜像 xff08 images xff09 镜像搜索 xff08 search xff09 删除镜像 xff08 rmi xff09 容器命令新建
  • Rviz上发布的点位信息机器人不执行(网络配置原因)已解决

    在调试机器人时发现Rviz上发布的点位信息机器人没有执行 xff0c 经检查是由于网络配置原因 xff0c 本文记录解决方法 使用ssh将笔记本与实物机器人连接 xff0c 机器人中控使用的工控机 xff0c 机器人作为显示器和键盘输入 p
  • gazebo小车自主路径规划导航仿真

    gazebo小车自主路径规划仿真 在之前的文章中完成了对地图的构建 xff0c 接下来使用 Ros navgition完成机器人自主导航 首先是Ros navigation的下载安装 ros功能包 xff1a Navigation ros
  • 关于结构体对齐

    首先我们先了解一下各数据类型所占的字节数 x64系统 xff08 64位 xff09 x86系统 xff08 32位 xff09 在这里有一个很有意思的点 xff0c 我使用VS在x86与x64系统下运行出来的long类型所占据的空间都是4
  • 安装docker报出的错误及解决方案

    1 错误一 xff1a 解决方案 xff1a yum erase podman buildan yum install y docker ce allowerasing 重启服务 systemtl restart docker yum源的安
  • make、makefile的使用解释(Linux项目自动化构建工具)

    本文所使用系统为Linux centos 7 makefile是一个文件 里面包含了 xff1a 1 文件与文件的依赖关系 2 文件与文件的依赖方法 为什么需要包含文件与文件的依赖方法和依赖方法呢 xff1f 一个工程中的源文件不计数 xf
  • elementUI中neditor第一次加载无法正常赋值的解决方法

    1 lt neditor v if 61 34 neditorLoad 34 v model 61 34 formFields content 34 class 61 34 wd editor 34 gt 加上v if 61 34 nedi
  • Gazebo仿真中光源的设置

    目录 写在前面官方文档链接point类型directional类型spot类型 写在前面 最近研究在Gazebo中仿真px4 xff0c 使用Apriltag ros包对Apriltag二维码检测的时候发现光源对检测影响非常大 xff0c
  • 使用Java操作Hbase

    目录 修改hosts文件 导入jar包 配置hbase信息 xff0c 连接hbase数据库 创建表 删除表 获取namespace 获取tables 添加数据 查询表中的数据 查询表中所有数据 关闭流 修改hosts文件 位置 xff1a
  • CAN协议国际标准化协议部分总结(一)

    前言 xff1a 本文主要是对CAN协议中ISO11898做一个简短的总结 ISO11898 ISO11519 ISO15765 CAN协议在OSI模型中包含三层 xff0c 物理层 数据链路层和传输层 各层中CAN定义内容可参考下图 其协
  • STM32 串口 DMA 数据读取(详细代码)

    最近重新开始学32 xff0c 搞到串口 DMA 的时候 xff0c 数据读取卡了很长一段时间 xff0c 最终 xff0c 功夫不负有心人终于搞出来了 在此以记录一下 xff0c 方便以后查询使用 在调试的过程中也遇到了很多bug xff