STM32 如何使用DMA和获取ADC

目录

背景

‌摇杆的原理

程序

端口配置

ADC 配置

DMA配置


背景

DMA是一种计算机技术,允许某些硬件子系统直接访问系统内存,而不需要中央处理器(CPU)的介入,从而减轻CPU的负担。我们可以通过DMA来从外设(ADC、UART等)读取数据之后,搬运到指定的内存。

ADC是根据用户动作或者环境变化会造成传感器等设备的电压值发生变化,再通过STM32的ADC块实现采样、保持、量化、编码将模拟量转换成数据量。

本篇文章会介绍目前无人机常用的摇杆操作(左右、上下、按下等),变为电压值变化,以及STM32 如何实现DMA定期读取遥感ADC值。

‌摇杆的原理

JS_X:作为X轴方向的模拟信号输入口

JS_Y:作为Y轴方向的模拟信号输入口

JS_D:挥动开关的状态的检测端口

通过原理图可以通过X轴方向滑动可以改变接触点在电阻的位置,从而影响读取到的电压值。Y轴方向亦是同理。因此只需将JS_X和JS_Y的端口设置位模拟量输入端,然后由STM32单片机的ADC块处理。

而按下的操作显然是普通的Port Key, 因此只用将JS_D设置位上拉输入,然后通过读取该端口的状态,来判断是否摇杆被按下。

STM32的DMA通道‌:STM32系列最多有12个独立可配置的通道,包括DMA1(7个通道)和DMA2(5个通道)。每个通道可以分别设置源地址与目的地址,实现独立工作‌

程序

端口配置


#define ADC1_DR_Address    ((uint32_t)0x4001244C) //ADC1这个外设的地址(查参考手册得出)

#define ADCPORT		GPIOA	//定义ADC接口
#define ADC_CH4		GPIO_Pin_4	//定义ADC接口 电压电位器
#define ADC_CH5		GPIO_Pin_5	//定义ADC接口 光敏电阻
#define ADC_CH6		GPIO_Pin_6	//定义ADC接口 摇杆X轴
#define ADC_CH7		GPIO_Pin_7	//定义ADC接口 摇杆Y轴


#define JoyStickPORT	GPIOB	//定义IO接口组
#define JoyStick_KEY	GPIO_Pin_2	//定义IO接口





void ADC_GPIO_Init(void){ //GPIO初始化设置
	GPIO_InitTypeDef  GPIO_InitStructure; 	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);       
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟(用于ADC的数据传送)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//使能ADC1时钟
    GPIO_InitStructure.GPIO_Pin = ADC_CH6 | ADC_CH7; //!!!选择端口                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //选择IO接口工作方式       
	GPIO_Init(ADCPORT, &GPIO_InitStructure);		
}


void JoyStick_Init(void){ //摇杆的挥动开关的接口初始化
	GPIO_InitTypeDef  GPIO_InitStructure; //定义GPIO的初始化枚举结构	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);       
    GPIO_InitStructure.GPIO_Pin = JoyStick_KEY; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻       
	GPIO_Init(JoyStickPORT,&GPIO_InitStructure);			
}

1)GPIOA组、GPIOB组、DMA1的外设时钟使能起来(GPIOC组功能用于其他,我们可以忽略它)

2) X轴和Y轴的输入端要设置为模拟量输入端口

3)Port Key 要设置位上拉电阻输入口,因为在没有被按下时,要能读入高电平!

3)初始化端口

ADC 配置

void ADC_Configuration(void){ //初始化设置
	ADC_InitTypeDef ADC_InitStructure;//定义ADC初始化结构体变量
	ADC_GPIO_Init();//GPIO初始化设置
	ADC_DMA_Init();//DMA初始化设置
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE; //使能扫描
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC转换工作在连续模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//有软件控制转换
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//转换数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 2;//!!!顺序进行规则转换的ADC输入口的数目(根据ADC采集通道数量修改)
	ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
	//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
	//ADC1,ADC通道x,规则采样顺序值为y,采样时间为28周期		 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_28Cycles5);//!!! ADC1选择信道x,采样顺序y,采样时间n个周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_28Cycles5);//!!! ADC1选择信道x,采样顺序y,采样时间n个周期

	ADC_DMACmd(ADC1, ENABLE);// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
	ADC_Cmd(ADC1, ENABLE);//使能ADC1
	ADC_ResetCalibration(ADC1); //重置ADC1校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC1校准重置完成
	ADC_StartCalibration(ADC1);//开始ADC1校准
	while(ADC_GetCalibrationStatus(ADC1));//等待ADC1校准完成
	ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC1软件开始转换
}
12 位分辨率
● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
● 单次和连续转换模式
● 从通道 0 到通道 n 的自动扫描模式
● 自校准
● 带内嵌数据一致性的数据对齐
● 采样间隔可以按通道分别编程
● 规则转换和注入转换均有外部触发选项
● 间断模式
● 双重模式 ( 2 个或以上 ADC 的器件 )
ADC 转换时间:
STM32F103xx 增强型产品:时钟为 56MHz 时为 1 μ s( 时钟为 72MHz 1.17 μ s)
STM32F101xx 基本型产品:时钟为 28MHz 时为 1 μ s( 时钟为 36MHz 1.55 μ s)
STM32F102xxUSB 型产品:时钟为 48MHz 时为 1.2 μ s
STM32F105xx STM32F107xx 产品:时钟为 56MHz 时为 1 μ s( 时钟为 72MHz 1.17 μ s)
ADC 供电要求: 2.4V 3.6V
ADC 输入范围: V REF- V IN V REF+
● 规则通道转换期间有 DMA 请求产生。
STM32F103C8T6由两个ADC。
ADC框图:
ADC1和ADC2独立工作,故配置位独立模式
因为要ADC1扫描有配置的两个通道,因此要使能扫描
因为要连续多次采样,因此要设置位连续模式,而非单次模式
DMA的触发可以通过软件触发(内部触发)和硬件触发(外部触发,硬件触发见截图)。
我们采用内部软件触发

常见的ADC数据对齐方式

右对齐(默认情况):这是大多数STM32 ADC寄存器的默认行为。例如,如果你使用12位分辨率的ADC,那么只有最低的12位将被用来存储转换结果,而最高的4位(在16位寄存器中)将会是0。

左对齐:在某些情况下,你可能需要将数据左对齐,这意味着将最高有效位(MSB)放在寄存器的最高位。这通常通过特定的硬件配置或软件操作来实现,比如在某些STM32系列中,可以通过配置ADC寄存器来实现数据的左对齐。

输入通道数配置,X轴通道和Y轴通道总共两个。

注册规则组

注册包含通道信息、采样顺序、采样时间。ADC通道通过查阅端口定义可知。

STM32F103C8T6


C8:48pin 64K Flash 属于中容量 SRAM 20K.

查看引脚定义可以知道PA6的ADC通道是6,PA7的通道是7.

使能ADC1的DMA请求

使能ADC1

ADC1自校准

软件触发开始ADC1转换

DMA配置


vu16 ADC_DMA_IN[2]; //ADC数值存放的变量

void ADC_DMA_Init(void){ //DMA初始化设置
	DMA_InitTypeDef DMA_InitStructure;//定义DMA初始化结构体
	DMA_DeInit(DMA1_Channel1);//复位DMA通道1
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //定义 DMA通道外设基地址=ADC1_DR_Address
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_DMA_IN; //!!!定义DMA通道ADC数据存储器(其他函数可直接读此变量即是ADC值)
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//指定外设为源地址
	DMA_InitStructure.DMA_BufferSize = 2;//!!!定义DMA缓冲区大小(根据ADC采集通道数量修改)
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//当前外设寄存器地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//!!! 当前存储器地址:Disable不变,Enable递增(用于多通道采集)
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//定义外设数据宽度16位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //定义存储器数据宽度16位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA通道操作模式位环形缓冲模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道优先级高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止DMA通道存储器到存储器传输
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA通道1
	DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA通道1
}

由于是从ADC1外设(ADC1的数据寄存器DR)到内存,因此方向配置如下

DMA设置为循环模式,可以连续多次的从ADC1外设搬运数据到指定内存。

因为ADC1外设(DR)是16位(ADC分辨率是12),所以

DMA1的每个channel用于设置数据源外设和目的地内存地址。因为我们的外设是ADC1。所以我们选择Channel1.

 

ADC1的外设的地址

DMA优先级设置为HIGH

优先级相同情况下,由内部硬件优先级决定!

由于不是内存搬运到内存,故DMA_M2M要设置为Disable

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/971018.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在linux系统中安装Anaconda,并使用conda

系统 : ubuntu20.04 显卡:NVIDIA GTX1650 目录 安装Anaconda第一步:下载合适版本的Anconda1. 查看自己Linux的操作系统及架构命令:uname -a2. 下载合适版本的Anconda 第二步:安装Aanconda1. 为.sh文件设置权限2. 执行.sh文件2.1 .…

【嵌入式Linux应用开发基础】read函数与write函数

目录 一、read 函数 1.1. 函数原型 1.2. 参数说明 1.3. 返回值 1.4. 示例代码 二、write 函数 2.1. 函数原型 2.2. 参数说明 2.3. 返回值 2.4. 示例代码 三、关键注意事项 3.1 部分读写 3.2 错误处理 3.3 阻塞与非阻塞模式 3.4 数据持久化 3.5 线程安全 四、嵌…

计网-数据链路层

3.1数据链路层的概述 概念 链路就是从一个结点到相邻结点的一段物理线路,而中间没有任何其他的交换结点。 数据链路是指把实现通信协议的硬件和软件加到链路上,就构成了数据链路。 数据链路层以帧为单位传输和处理数据。 网络中的主机、路由器等都必须实…

Versal - 基础5(裸机开发 AIE-ML+Vitis2024.2界面aie report介绍)

目录 1. 简介 2. 申请 License 2.1 申请网址 2.2 填写 Host 2.3 导入 License 3. 示例 3.1 vivado_platform 3.1.1 由模板创建 3.1.2 模板参数 3.1.3 修改BD参数 3.1.4 配置CIPS和MC 3.1.5 导出PFM 3.2 vitis_platform 3.2.1 创建组件 3.2.2 导入XSA并配置 3.2…

Python 字典思维导图

在本章中,你将学习能够将相关信息关联起来的Python字典。你将学习如何访问和修改字典中的信息。鉴于字典可存储的信息量几乎不受限制,因此我们会演示如何遍 历字典中的数据。另外,你还将学习存储字典的列表、存储列表的字典和存储字典的字典。…

用pytorch实现一个简单的图片预测类别

前言: 在阅读本文之前,你需要了解Python,Pytorch,神经网络的一些基础知识,比如什么是数据集,什么是张量,什么是神经网络,如何简单使用tensorboard,DataLoader。 本次模型训练使用的是…

计算机视觉:卷积神经网络(CNN)基本概念(一)

第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 一、引言 卷积神经网络&…

PowerBI 矩阵 列标题分组显示(两行列标题)

先看效果 数据表如下: 我们在powerbi里新建一个矩阵,然后如图加入字段: 我们就会得到这样的矩阵: 我们在“可视化”->“列”,上双击,输入空格,就能消除左上角的"类别"两字 同理修…

报名丨Computer useVoice Agent :使用 TEN 搭建你的 Mac Assistant

与 TEN 相聚在「LET’S VISION 2025」大会,欢迎来展位上跟我们交流。这次我们还准备了一场聚焦「computer use」的工作坊,功能新鲜上线,线下首波体验! 📅 TEN 展位:2025年3月1日-2日 TEN workshop&#x…

python opencv基础使用总结

1.安装opencv库:pip install opencv-python 2.基础使用范例 import cv2 #图片的基本操作#1.读取一张图片 参数 1:图片的文件名如果图片放在当前文件夹下,直接写文件名就行,如lena.jpg否则需要给出绝对路径,如D:\Ope…

【STM32】舵机SG90

1.舵机原理 舵机内部有一个电位器,当转轴随电机旋转,电位器的电压会发生改变,电压会带动转一定的角度,舵机中的控制板就会电位器输出的电压所代表的角度,与输入的PWM所代表的角度进行比较,从而得出一个旋转…

OpenEuler学习笔记(三十三):在 OpenEuler 上搭建 OpenGauss 数据库环境

在 OpenEuler 上搭建 OpenGauss 数据库环境需要按照以下步骤进行。OpenGauss 是华为开源的一款高性能关系型数据库,支持高并发、高可用性和分布式部署。 1. 环境准备 确保你的 OpenEuler 系统满足以下要求: 操作系统:OpenEuler 20.03 LTS 或…

智能编程助手功能革新与价值重塑之:GitHub Copilot

引言: GitHub Copilot 的最新更新为开发者带来了显著变化,其中 Agent Mode 功能尤为引人注目。该模式能够自动识别并修复代码错误、自动生成终端命令,并具备多级任务推理能力,这使得开发者在开发复杂功能时,可大幅减少…

【数据结构】(9) 优先级队列(堆)

一、优先级队列 优先级队列不同于队列,队列是先进先出,优先级队列是优先级最高的先出。一般有两种操作:返回最高优先级对象,添加一个新对象。 二、堆 2.1、什么是堆 堆也是一种数据结构,是一棵完全二叉树&#xff0c…

AI大模型的文本流如何持续吐到前端,实时通信的技术 SSE(Server-Sent Events) 认知

写在前面 没接触过 SSE(Server-Sent Events),AI大模型出来之后,一直以为文本流是用 WebSocket 做的偶然看到返回到报文格式是 text/event-stream,所以简单认知,整理笔记博文内容涉及 SSE 认知,以及对应的 D…

计时器任务实现(保存视频和图像)

下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每60秒保存一个视频,图像和视频均以当前时间命名: TimerTask类的实现如下: class TimerTask { public:TimerTask(const std::string& path):…

力扣19题——删除链表的倒数第 N 个结点

#题目 #代码 //定义虚拟头结点ListNode curnew ListNode(0,head); //定义两个指针指向虚拟头结点ListNode lcur;ListNode rcur;for(int i0;i<n;i){rr.next;}while(r!null){rr.next;ll.next;} //l.next就是我们要删除的那个元素if(l.next!null){l.nextl.next.next;}return c…

网络工程师 (42)IP地址

一、定义与功能 IP地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一个逻辑地址&#xff0c;以此来屏蔽物理地址的差异。这种地址分配方式确保了用户在连网的计算机上操作时&#xff0c;能够高效且方便地从众多计算机中选出自己所需…

记忆力训练day19

万能字母组合编码法 所有的文字和字母的背后都有画面 练的不是记单词&#xff0c;练的是注意力给到单词&#xff0c;出什么画面&#xff0c;然后画面与画面之间进行连接 拆的过程就是找熟词的过程 要关注自己的回忆路径是什么&#xff1f;也就是你是怎么回忆起来的&#xff0c…

flutter image_cropper插件安装后 打包apk 报错命名空间问题

本篇文章主要讲解&#xff0c;Flutter安装完新依赖打包apk报错 A problem occurred configuring project ‘:image_cropper’. 命名空间问题的解决办法及原因说明。 日期&#xff1a;2025年2月15日 作者&#xff1a;任聪聪 一、报错现象&#xff1a; 报文信息&#xff1a; FAI…