基于STM32F103C8T6的高速DMA传输多通道ADC数据

这篇具有很好参考价值的文章主要介绍了基于STM32F103C8T6的高速DMA传输多通道ADC数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

ADC在STM32系列单片机的使用中占用着很大的比例,常见的案例是通过ADC单次转换电压值,这种方式的缺陷在于转换效率不高。一般的单片机带有ADC1和ADC2两个ADC转换,单次转换需要执行一定的程序,想得到结果需要耗费一些时间在赋值,调用中断上面。在此基础上,为了提高转换的效率,借用单片机内部自带的DMA传输单元,可以直接越过CPU指令,将数据传送到我们所定义的寄存单元内部,这样我们需要查看检测的电压数据时,只需要直接访问存储数组即可。


一、软件设计思路

整体的软件设计思路分为两个大的环节:初始化ADC和开启高速DMA数据传输。在本次实验中,选用ADC1作为转换单元,这是比较基础的只用到一个ADC的转换方式,在ADC的使用之中,可以以ADC1和ADC2相互配合的方式进行交替采样,其优点在于两次采样中间只需要间隔极短的时间,比单次采样要快很多,在后续会进行更新,此处只用到一个ADC单元。

ADC初始化需要设置好转换的时间,转换的IO口以及转换的触发方式。而高速DMA也需要设置对应的触发方式,这里是通过ADC进行触发。在DMA传输的过程中,需要设定好DMA传输的方式以及地址,下面就针对具体的代码进行设计。

二、代码

代码如下:开头用define定义了ADC1_DR_Address,这是ADC存放检测数据的地址,DMA单元可以通过此地址访问数据,并将数据存储到我们定义的数组内部。那么后面定义了全局变量ADC_ConvertedValue,我们检测到的所有数据要存放到这个数组内部,可以看到,目前设置的ADC存放数据总共有四个,对应四个检测通道,可以根据自己的实际需求,去进行设计。具体数组的存放大小计算公式是:设置的检测通道*每个通道想要求平均的个数。比如四个通道,十个想要求平均的数据,则数组大小就设置为40,那么通过软件设置,数组[0]对应的就是第一个通道第一个数据,数组[1]对应的是第二个通道第一个数据,数组[4]对应的就是第一个通道第二个数据,依此类推。

在实际的ADC初始化中,调用ADC,DMA,GPIO三个InitTypeDef,这些都是实现定义好的,但是记得在FWlib库中调用dma和adc的官方例程库。前面初始化了DMA时钟,ADC1时钟,以及我们所定义的采样引脚,在这里定义的ADC采样引脚为PA1-PA4,可以自行修改。那么在GPIO口初始化了以后,就开始对DMA进行配置。

DMA配置过程中需要对几个参数进行注意,在这里重点说明一下:

DMA_PeripheralBaseAddr:可以理解为获取数据的地址,我们需要获取ADC的数据,则将ADC存放数据的地址放到此处。
DMA_MemoryBaseAddr:存放数据的地址,这里的地址单元由我们定义的数组决定,只需要将定义数组赋值过去即可。
DMA_BufferSize:缓冲区长度,取决于你的数组长度,有多少个数据就填多少
DMA_PeripheralDataSize:与下方内存的DataSize类似,都设置为了half word,那么half word其实等同于16位,2个byte,根据自己需求决定

其它的就正常配置就行,DMA配置完毕以后,就要对ADC进行设置。ADC设置的话是要与DMA相互配合,故初始化ADC的工作模式为独立工作,之前提到了ADC可以互相配合也可以单独工作。在只使用一个ADC的情况下,只需要设置为独立工作模式即可。需要注意的是,如果需要连续不断地采集ADC数据,就要设置ADC工作在扫描和连续转换模式中。用于转换的通道也可以进行设置,具体看通道的个数,用到了多少通道就设置参数为多少。通道配置中根据芯片本身的资源,可以从channel0-channel15(以STM32F103ZET6)为例,1,2,3,4等数代表的是转换的次序,主要是方便查看你的数据位置,避免出错。转换精度此处我们设置为239.5,这个得根据你自己的需求来,设置的精度越高转换时间越长,精度自然越好,反之亦然,这里折中设置。最后再对ADC进行一些使能即可。

adc.c

#include "adc.h"
#define ADC1_DR_Address   ((u32)0x40012400+0x4c)
__IO uint16_t ADC_ConvertedValue[4];//ADC存放数据地址
void Init_adc(void)
{	
	ADC_InitTypeDef ADC_InitStructure;	
	DMA_InitTypeDef DMA_InitStructure; 	
	GPIO_InitTypeDef GPIO_InitStructure; 	   
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//启动DMA时钟 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//启动ADC1时钟 	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//采样脚设置		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
	GPIO_Init(GPIOA, &GPIO_InitStructure); 	
	//DMA配置
	DMA_DeInit(DMA1_Channel1);//DMA1通道1配置		
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;//外设地址			
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;//内存地址	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//dma传输方向单向			
	DMA_InitStructure.DMA_BufferSize = 4;//设置DMA在传输时缓冲区的长度		
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设置DMA的外设递增模式,一个外设			
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//设置DMA的内存递增模式		
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据字长	
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	//内存数据字长	
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	//设置DMA的传输模式:连续不断的循环模式	
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设置DMA的优先级别			
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//设置DMA的2个memory中的变量互相访问	
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);			
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能通道1 	
	//ADC配置	
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立工作模式			
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描方式	
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换		
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//外部触发禁止		
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐			
	ADC_InitStructure.ADC_NbrOfChannel = 4;//用于转换的通道数	
	ADC_Init(ADC1, &ADC_InitStructure);		
	//规则模式通道配置	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1 , 1, ADC_SampleTime_239Cycles5);	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2 , 2, ADC_SampleTime_239Cycles5);		
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3 , 3, ADC_SampleTime_239Cycles5);	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4 , 4, ADC_SampleTime_239Cycles5);			
	ADC_DMACmd(ADC1, ENABLE);//使能ADC1的DMA			
	ADC_Cmd(ADC1, ENABLE);//使能ADC1		 	
	ADC_ResetCalibration(ADC1);//使能ADC1复位校准寄存器		
	while(ADC_GetResetCalibrationStatus(ADC1));//检查校准寄存器是否复位完毕		
	ADC_StartCalibration(ADC1);//开始校准			
	while(ADC_GetCalibrationStatus(ADC1));//检测是否校准完毕	 		
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启ADC1的软件转换
} 

adc.h

#ifndef __ADC_H
#define	__ADC_H


#include "stm32f10x.h"

void Init_adc(void);

#endif /* __ADC_H */


需要调用参数只需要在定时器里面进行计数求平均即可,当初始化ADC以后,我们所定义的数组里面就会源源不断的出现数据,如前文提到的,第一个数据对应的就是第一个转换通道的,那么根据这个关系,就可以对采集到的数据进行平均化处理。

总结

此代码还有很多可以优化的地方,比如利用到交替采样。如果用到了F4的单片机,还可以利用F4的DSP库进行一些函数的计算,比如均方根算法,进行交流电压交流电流的采样。文章来源地址https://www.toymoban.com/news/detail-665252.html

到了这里,关于基于STM32F103C8T6的高速DMA传输多通道ADC数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32项目设计:基于stm32f103c8t6智能电梯系统

    资料链接:待更新~ 哔哩哔哩视频链接:https://www.bilibili.com/video/BV17D4y1V7HG/?vd_source=e5082ef80535e952b2a4301746491be0(bilibili:化作尘my) 资料链接:https://pan.baidu.com/s/1qObK7KBl50RmFrAtoX12kw 提取码:iih4 实物链接:https://m.tb.cn/h.5h5mDXI?tk=MdxLWYHgKnz CZ0001 1、OLED显示当前楼层、目标楼层等信息

    2024年02月03日
    浏览(26)
  • 基于stm32f103c8t6的fft频率计

    之前项目中需要用到正弦信号的频率测量,也参考了几个大佬的博客(链接如下),但可能是由于stm32的型号不匹配,虽然也在网上查了一些需要修改的地方,但结果一直不太对,后来经过自己摸索结果终于对了,在这里给大家分享下,具体原理不在赘述。 参考的部分大佬博

    2024年02月14日
    浏览(17)
  • 基于STM32F103C8T6的HC-06蓝牙通信

    如果朋友们 遇到了如下问题 ,可以仔细借鉴本文章和另一篇专门讲解 蓝牙通信问题 的文章,一定能够解决你在蓝牙通信时遇到的诸多困难 1.在调试蓝牙模块AT指令时无返回值 2.身边 无USB转TTL模块 可以直接调试蓝牙模块(本人就是由于无模块花了了整整一天才调试成功)

    2024年02月03日
    浏览(30)
  • 基于STM32F103C8T6ADC检测交流电压

    上篇文章写了硬件部分的实现思路,通过采样电阻的到小电压后经过二级放大电路得到单片机可处理的交流电压,此文介绍了如何采用单片机采集交流电压以及stm32ADC外设的使用。首先是硬件电路部分。  电路没有采用核心板,而是直接将芯片焊接到主板上,采用type-c接口供

    2024年02月12日
    浏览(24)
  • STM32f103c8t6模板的搭建-基于正点例程

           笔者认为正点编写的官方例程结构较为整洁,可以便于后期的例程开发,如果开发者对于项目开发中芯片要求较高的话,有很多人会选择正点的开发板,但是通常大多数是stm32初学者会选择用价格更为便宜的c8t6来进行学习,而正点选用的教程开发板大多都是些RC、ZE、

    2024年02月06日
    浏览(38)
  • 基于STM32F103C8T6的超声波测距应用

    #一、超声波HC_SR04简介 #二、超声波工作原理 #三、超声波测距步骤 #四、硬件接线 #五、项目代码 一、超声波HC_SR04简介 超声波传感器模块上面通常有两个超声波元器件,一个用于发射,一个用于接收。电路板上有四个引脚:VCC、GND、Trig(触发)、Echo(回应) 工作电压与电流

    2024年02月03日
    浏览(18)
  • STM32 DMA1和DMA2通道一览表、STM32F103C8T6定时器通道对应的引脚

    TIM1_BRK_IRQn               = 24,      TIM1_UP_IRQn                = 25,      TIM1_TRG_COM_IRQn           = 26,     TIM1_CC_IRQn                = 27,     TIM2_IRQn                   = 28,     TIM3_IRQn                   = 29,    这个函数TIM_SetCompare1,这个函数有四个,分别是TIM_SetC

    2024年02月05日
    浏览(22)
  • HX711压力传感器(基于STM32F103C8T6)

    HX711模块是我们目前比较常见的压力传感器模块,主要的作用是用来做压力检测,重量监测等等。博主的这篇博文主要实现功能为,在对重量或者压力进行监测的同时,可以累加或者清零数值,在此基础上就可以对比如饮水量进行统计等等。 HX711模块是市面上比较常见的模块

    2024年02月11日
    浏览(22)
  • 基于stm32f103c8t6的定时器详解(持续更新)

    先声明:stm32f103c8t6中没有基本定时器、只有TIM1-TIM4:分别是高级定时器和通用定时器(对照下图请自行阅读stm32f103x的datasheet) 1、定时器功能:定时、输出比较、输入捕获、互补输出,其中基本定时器只有定时功能、通用定时器只没有互补输出功能、高级定时器具有所有功能

    2023年04月24日
    浏览(22)
  • [STM32F103C8T6]基于stm32的循迹,跟随,避障智能小车

    目录 1.小车驱动主要是通过L9110S模块来驱动电机 motor.c 2.我们可以加入串口控制电机驱动(重写串口接收回调函数,和重定向printf) Uart.c main.c  3.点动功能 uart.c main.c 为什么使用的是HAL_Delay()要设置滴答定时器的中断优先级呢? 4.小车PWM调速,  6.跟随功能 7.避障功能 超声波测距

    2024年02月13日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包