STM32F103采用DMA方式多路ADC采样

这篇具有很好参考价值的文章主要介绍了STM32F103采用DMA方式多路ADC采样。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32F103采用DMA方式多路ADC采样


前言

stm32采用DMA方式进行ADC采样可以高效的进行数据采集,不用cpu实时参与,以节省单片机资源,让单片机可以在同一时间里干更多事,STM32F103 ADC为12位ADC的,是一种逐次逼近型模拟数字转换器,它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。
stm32 ADC供电要求:2.4V到3.6V ,ADC输入电压范围为:VREF- ≤ VIN ≤ VREF+
规则通道转换期间有DMA请求产生。

一、头文件 adc.h

#ifndef __ADC_H
#define __ADC_H	
#include "sys.h"



#define	FIRL_N	16
#define	AD_NUM   8
/*******************************************************************************/
/*          ADC 8路输入                                            */
/*******************************************************************************/
#define ADC_CH0_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH0_GPIO					GPIOA						//PA0	
#define ADC_CH0_PIN					GPIO_Pin_0
#define ADC_CH0_CHNL					ADC_Channel_0

#define ADC_CH1_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH1_GPIO  				GPIOA						//PA1
#define ADC_CH1_PIN					GPIO_Pin_1
#define ADC_CH1_CHNL					ADC_Channel_1

#define ADC_CH2_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH2_GPIO					GPIOA						//PA2
#define ADC_CH2_PIN					GPIO_Pin_2
#define ADC_CH2_CHNL					ADC_Channel_2

#define ADC_CH3_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH3_GPIO					GPIOA						//PA3
#define ADC_CH3_PIN	
#define ADC_CH3_CHNL                  ADC_Channel_3
 
#define ADC_CH4_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH4_GPIO					GPIOA						//PA4
#define ADC_CH4_PIN					GPIO_Pin_4
#define ADC_CH4_CHNL					ADC_Channel_4

#define ADC_CH5_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH5_GPIO					GPIOA						//PA5
#define ADC_CH5_PIN					GPIO_Pin_5
#define ADC_CH5_CHNL					ADC_Channel_5

#define ADC_CH6_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH6_GPIO					GPIOA						//PA6
#define ADC_CH6_PIN					GPIO_Pin_6
#define ADC_CH6_CHNL					ADC_Channel_6

#define ADC_CH7_RCC_APB2Periph_GPIO   RCC_APB2Periph_GPIOA
#define ADC_CH7_GPIO					GPIOA						//PA7
#define ADC_CH7_PIN					GPIO_Pin_7
#define ADC_CH7_CHNL					ADC_Channel_7

二、初始化配置

1.ADC GPIO配置

/*******************************************************************************/
/*           Function 'ADC1_GPIO_Configuration': ADC1_GPIO配置                 */
/*******************************************************************************/
void ADC1_GPIO_Configuration(void)  //ADC1_GPIO配置
{
    //内部温度对应 16通道,无引脚,只需开启adc时钟即可。
    //内部参考电压,对应17 通道。无引脚。只需开启时钟
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA端口时钟
    GPIO_InitStructure.GPIO_Pin = ADC_CH0_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH0_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH1_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH1_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH2_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH2_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH3_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH3_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH4_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH4_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH5_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH5_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH6_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH6_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = ADC_CH7_PIN;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
    GPIO_Init(ADC_CH7_GPIO, &GPIO_InitStructure);
  
}

2.开启ADC和DMA时钟

/*******************************************************************************/
/*           Function 'ADC1_DMA_RCC_Configuration': 外设ADC,DMA时钟开启       */
/*******************************************************************************/
 void ADC1_DMA_RCC_Configuration(void) //
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 
                         | ADC_CH0_RCC_APB2Periph_GPIO 
                         | ADC_CH1_RCC_APB2Periph_GPIO 
                         | ADC_CH2_RCC_APB2Periph_GPIO 
                         | ADC_CH3_RCC_APB2Periph_GPIO 
                         | ADC_CH4_RCC_APB2Periph_GPIO 
                         | ADC_CH5_RCC_APB2Periph_GPIO 
                         | ADC_CH6_RCC_APB2Periph_GPIO 
                         | ADC_CH7_RCC_APB2Periph_GPIO , ENABLE);
}

3.多路ADC DMA采样配置

__IO uint16_t		ADValFilter[AD_NUM];
/*******************************************************************************/
/*           Function 'ADC1_DMA_Init': ADC1  DMA 配置                          */
/*******************************************************************************/
#define ADC1_DR_Address    ((uint32_t)0x4001244C)   //ADC_DR(ADC规则数据寄存器),偏移量=0x4c  ADC1(0x40012400-0x400127ff)
                                                    //so ADC1_DR_Address=0x40012400+0x4c
u16  ADValue[FIRL_N][AD_NUM];

void ADC1_DMA_Init(void)   
{
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    
    DMA_DeInit(DMA1_Channel1);         //选择DMA的通道1
                                       //设定从ADC外设的数据寄存器(ADC1_DR_Address)转移到内存(ADCConcertedValue)
                                       //每次传输大小16位,使用DMA循环传输模式
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADValue;           //数据缓冲区的地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                            //外设为数据源
    DMA_InitStructure.DMA_BufferSize = FIRL_N*AD_NUM;                   //数据缓冲区,大小2半字
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;              // 外设地址固定
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                       //内存地址增加,多组adc时,使能,数据传输时,内存增加
    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_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);    
    DMA_Cmd(DMA1_Channel1, ENABLE);  
     /* ADC1 初始化*/
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                        //ADC独立模式	 相对于双重模式
    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 =AD_NUM;                                   //转换组的通道数目  
    ADC_Init(ADC1, &ADC_InitStructure); 
    RCC_ADCCLKConfig(RCC_PCLK2_Div8);   
     /* ADC1 regular channel11 configuration */ 
    //配置ADC1的通道11为55.5个采样周期
    //默认组,adc1 ,通道11,排序为1,55.5周期
    //ADC1,ch17,序号1,55.5.。。
    ADC_RegularChannelConfig(ADC1, ADC_CH0_CHNL,1, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH1_CHNL,2, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH2_CHNL,3, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH3_CHNL,4, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH4_CHNL,5, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH5_CHNL,6, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH6_CHNL,7, ADC_SampleTime_239Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_CH7_CHNL,8, ADC_SampleTime_239Cycles5);
//    ADC_RegularChannelConfig(ADC1, ADC_Channel_17,10, ADC_SampleTime_239Cycles5);//内部参考电压

//    ADC_TempSensorVrefintCmd(ENABLE);// 使能芯片内部温度传感器,若不需要可以注释掉    
ADC_DMACmd(ADC1, ENABLE);//使能ADC_DMA
    ADC_Cmd(ADC1, ENABLE);    //使能ADC
    ADC_ResetCalibration(ADC1);    //使能ADC1的复位校准寄存器  
    while(ADC_GetResetCalibrationStatus(ADC1));    //等待校准完成
    ADC_StartCalibration(ADC1);    //使能ADC1的开始校准寄存器
    while(ADC_GetCalibrationStatus(ADC1));    //等待完成
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);    //使用软件触发,由于没有采用外部触发

}  

三、软件滤波

采用了16次平均值滤波,除去最小值

void Get_ADConv(u16* value)
{
	u8 i,chnl;
    
    for (i=0;i<AD_NUM;i++)
	{
		ADValFilter[i]=0;
	}	
	
    for(chnl=0; chnl<AD_NUM; chnl++)
    {
        for(i=0;i<FIRL_N;i++)
        {
            ADValFilter[chnl]+=ADValue[i][chnl];
        }
        ADValFilter[chnl]>>=4;
        if(ADValFilter[chnl]<20)ADValFilter[chnl] = 0;
//        ADValFilter[chnl] -= 3;
        *value++ = ADValFilter[chnl];
    }    
}

四、主函数调用

1.初始化函数配置

/*******************************************************************************/
/*           Function 'App_MutiAdcCfg': 对ADC进行初始化配置,并实现DMA方式     */
/*******************************************************************************/
void App_MutiAdcCfg(void)
{
	ADC1_GPIO_Configuration();
	ADC1_DMA_RCC_Configuration();
	ADC1_DMA_Init();
}

2.main函数调用

主程序将采样出来的多路通道ADC采样值 04096转换成010000 ,硬件上对应0~10v输入电压

#define	AD_SCALE	  2.441f

__IO float f_adval[8];


 int main(void)
 { 
    u8 i,ad_chnl = 0;
    u16 ADvolt[AD_NUM];
    uint16_t nCRC = 0;	
    uint16_t SendIndex = 0; 
     
	delay_init();	    	 //延时函数初始化	   
	uart_init(BaudRate);	 	//串口初始化为9600

    App_MutiAdcCfg();		  		//ADC初始化	
    while(1)
	{
		Get_ADConv(ADvolt);
        for (ad_chnl=0; ad_chnl<AD_NUM; ad_chnl++)
        {
            f_adval[ad_chnl] = AD_SCALE * ADvolt[ad_chnl];
            sHoldRegValue[ad_chnl] = (u16)f_adval[ad_chnl];
        }
        nSendBuff[0] = 0x01;
        nSendBuff[1] = 0x03;
        nSendBuff[2] = 0x10;
        for (i=0; i<8; i++)
        {
            nSendBuff[3+i*2] = sHoldRegValue[i]>>8;
            nSendBuff[4+i*2] = sHoldRegValue[i]&0xff;
        }
        SendIndex = 19;
        nCRC = CRC16(nSendBuff,SendIndex);
        nSendBuff[SendIndex++] = (uint8_t)((nCRC>>8)&0x00ff);
        nSendBuff[SendIndex++] = (uint8_t)(nCRC&0x00ff);
        UART_Write(USART1,nSendBuff,19);	
        delay_ms(500);        
	}

总结

项目应用中不建议adc用查询方式进行读取,用DMA结合adc采样,然后用定时器控制采样频率,不建议用延时的方式,由定时器触发ADC采样,这样采样的频率可控,且定时器触发不会占用任何CPU资源。文章来源地址https://www.toymoban.com/news/detail-462590.html

到了这里,关于STM32F103采用DMA方式多路ADC采样的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • STM32F103学习(ADC)

    1、定义 ADC(Analog-to-Digital Converter  模数转换器 )。是指将连续变化的模拟信号转换为离散的数字信号的器件。 2、原理 stm32上的ADC外设采用逐次比较的方式。 逐次比较型ADC工作原理可以类比天平称物体。比如我们假定要称一个21g的物体,我们有16g、8g、4g、2g、1g的砝码。一开

    2024年02月10日
    浏览(34)
  • STM32F407 ADC+DMA+定时器 定时采样模拟量

    项目中需要对多个通道的电压进行一定频率的AD采样,由于采样过程贯穿整个任务,为了使采样过程尽可能不占用CPU资源,采用定时器触发的多通道ADC扫描采样,且采样数据由DMA传到RAM中的缓存。 这样做有以下几个好处:1、由定时器触发ADC采样,这样采样的频率可控,且定时

    2024年02月14日
    浏览(43)
  • STM32f103入门(10)ADC模数转换器

    ADC简介 ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC,1us转换时间 输入电压范围:0~ 3.3V,转换结果范围:0~ 4095 18个输入通道,可测量16个外部和2个内部信号源

    2024年02月10日
    浏览(35)
  • 基于STM32F103C8T6四路AD采集数据显示在oled屏上非DMA传输方式(附百度网盘下载链接)

    本文采用四路AD采集 光照强度、烟雾浓度、一氧化碳、空气质量 等四个物理量,并采用 中位值平均滤波(防脉冲干扰平均滤波法)算法 对偶然出现的脉冲性干扰,消除由其引起的采样值偏差。 STM32F103C8T6有两个ADC,12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,

    2024年02月13日
    浏览(32)
  • [STM32F103C8T6]ADC转换

    什么是ADC转换? ADC转换的全称是: Analog-to-Digital Converter ,指模拟 / 数字转换器 ADC的性能指标: ADC分辨率: SSA与VREF-一起接到地,DDA与VREF+接到3.3v,所以ADC转换的范围是0---3.3v 所以最后的ADC转换值应该是我们的测量值*分辨率    分辨率 = 3.3v/2^12 = (3.3/4096)   12位的转换器所

    2024年02月06日
    浏览(40)
  • STM32F103C6T6之PWM+DMA篇

    最近在学习PWM+DMA配合生成可改变占空比的PWM波形。找了很多很多资料但是感觉对初学者不是很友善,只是提供了很多原理。这边使用的代码是固件库版的,也是学习STM32最基础的固件库代码了吧! 预分频器(TIMx_PSC) 自动重装载寄存器(TIMx_ARR) 捕获/比较寄存器x(TIMx_CCRx) 当P

    2023年04月18日
    浏览(37)
  • 使用STM32F103的SPI+DMA驱动ws2812 LED

    目录 前言 一、WS2812协议 1.1 数据传输编码方式:  1.2 传输的数据结构 二、驱动方式:SPI+DMA 2.1 原理介绍 2.2 SPI+DMA操作  2.3 编写代码 2.4 使用 三 总结 参考文章 主要使用的STM32F103C8T6芯片的SPI+DMA方式实现WS2812的驱动协议,总体可以看作是使用SPI来实现一种通信协议来发送信号。

    2024年02月09日
    浏览(53)
  • stm32f103c8r6 串口2数据DMA的接收

    #define USART_REC_LEN              16      //定义最大接收字节数  16 extern u8 USART2_RX_BUF[USART_REC_LEN]; u8 USART2_RX_BUF[USART_REC_LEN];  void uart2_init(u32 bound) {     //GPIO端口设置     GPIO_InitTypeDef GPIO_InitStructure;     USART_InitTypeDef USART_InitStructure;     //NVIC_InitTypeDef NVIC_InitStructure;   

    2024年01月24日
    浏览(35)
  • STM32F103C8T6 ADC输入电流电压特性

    ADC 输入电压范围:0-VDDA(0-3.3V) 输入电流范围:0-220µA 输入电阻:50kΩ 采样频率:0.6-14MHz   官方STM32C103C8系列数据手册: https://www.st.com/en/microcontrollers-microprocessors/stm32f103c8.html

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

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

    2024年02月12日
    浏览(43)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包