STM32F407 ADC多通道采样+DMA

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

我加入工作室参加的第一个比赛是第五届中国高校智能机器人创意大赛,我参加的赛项是开放部件组轮式自主格斗机器人。经历了没日没夜的调试,无数次欣赏凌晨四点半的夜晚,感受着每天就睡两三个小时伴随着疲惫的开心。在我和队友的共同努力之下,我们的成绩也很优异,获得了预期的奖项。虽然原本我还有一个电控队友,但是因为疫情他没能和我一起参与备赛,这是令人可惜的一点。但人生总要向前看,备赛最重要的当然是过程,结果只是水到渠成的必然,宝贵的经历是什么都无法替代的,它使我成长,助我进步。相信我们在以后也会继续向前的。

在先学习DMA之前,我要先了解ADC的原理,然后在ADC程序实现的基础上使用DMA模式,可以加快数据采集和处理,当使用ADC+DMA来做为STM32F4的距离检测基础程序框架,可以实现比赛中距离的实时检测,进而完成比赛。

ADC(模/数转换器)

ACD是指将连续变量的模拟信号转换为离散的数字信号的数字信号(可以表示一定比例电压值);DAC(数/模拟转换器)与之相反。

STM32F407有3个ADC控制器,共24个通道,通道有8个+外部通道16个=24个外部通道

3个ADC控制器中,ADC1和ADC2的IO引脚是一样的。ADC3的IO引脚有一些差异,方便用户使用更多的ADC引脚。

ADC1和ADC2的通道是0~15,PA0~PA7,PB8,PB9,PC0~PC5。

ADC3的通道中4~8对应PF6~10,9对应PF3,14~15对应PF4~5。

DMA模式

直接内存访问(DMA)是用来以提供外设和内存,内存和内存之间的高速数据传输的。数据可以在没有任何CPU干预下通过的DMA进行传输。这使得CPU资源更倾重与其他操作。

DMA控制器基于一个复杂的总线矩阵架构,结合了功能强大的双AHB主总线架构与独立的FIFO,以优化系统宽带。

两个DMA控制器共有16个数据流(stream),每个数据流可以编程与规定的通道中的一个搭配。

DMA的工作模式

单次传输

多次输出(burst):把数据分成多次传输

循环模式:循环模式是可用来处理循环缓冲区和连续的数据流(如ADC扫描模式)。启此功能可以设置DMA_SxCR寄存器的CIRC位启用。(在循环模式,在burst方式下,它必须遵循下面的规则)。

双缓冲模式:双缓冲模式通过设置在DMA_SxCR寄存器的DBM位启用。

双缓冲模式与单缓冲模式的区别在于它有两个地址,当栓缓冲模式被使能,循环模式会被自动使能,每次传输完成,内存地址将会被交换。当一个内存区域被DMA控制器使用时,另一个可供程序使用。

配置程序如下:
u16 number[ADC_NUM];
float averge_1[size][ADC_NUM];

void  Adc1_Init(void)
{    
    GPIO_InitTypeDef  GPIO_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef       ADC_InitStructure;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//PA0-7 通道0-7
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入                                             
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;//PB1 2 通道8 9
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入                                             
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PC1234 通道10-15
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入                                             
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
    
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);          //ADC1复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);    //复位结束     
 
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; //DMA
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
    ADC_CommonInit(&ADC_CommonInitStructure);//初始化
    
     ADC_InitStructure.ADC_Resolution           = ADC_Resolution_12b;//12位模式
    ADC_InitStructure.ADC_ScanConvMode         = ENABLE;//非扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode   = ENABLE;//开启连续转换
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
    ADC_InitStructure.ADC_ExternalTrigConv     = ADC_ExternalTrigConv_T1_CC1;     //定时器触发,此实验用软件触发
    ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;//右对齐
    ADC_InitStructure.ADC_NbrOfConversion      = 14;  //转换规则序列1 
    ADC_Init(ADC1,&ADC_InitStructure);
    
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3 ,1 ,ADC_SampleTime_480Cycles );    //PA3
    ADC_RegularChannelConfig(ADC1,ADC_Channel_6 ,2 ,ADC_SampleTime_480Cycles );    //PA2
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1 ,3 ,ADC_SampleTime_480Cycles );    //PA1
    ADC_RegularChannelConfig(ADC1,ADC_Channel_13,4 ,ADC_SampleTime_480Cycles );    //PC3
    ADC_RegularChannelConfig(ADC1,ADC_Channel_12,5 ,ADC_SampleTime_480Cycles );    //PC2
    ADC_RegularChannelConfig(ADC1,ADC_Channel_4 ,6 ,ADC_SampleTime_480Cycles );    //PA4
    ADC_RegularChannelConfig(ADC1,ADC_Channel_5 ,7 ,ADC_SampleTime_480Cycles );    //PA5
    ADC_RegularChannelConfig(ADC1,ADC_Channel_11,8 ,ADC_SampleTime_480Cycles );    //PC1
    ADC_RegularChannelConfig(ADC1,ADC_Channel_10,9 ,ADC_SampleTime_480Cycles );    //PC0
    ADC_RegularChannelConfig(ADC1,ADC_Channel_7 ,10,ADC_SampleTime_480Cycles );    //PA7
    ADC_RegularChannelConfig(ADC1,ADC_Channel_14,11,ADC_SampleTime_480Cycles );    //PC4
    ADC_RegularChannelConfig(ADC1,ADC_Channel_8 ,12,ADC_SampleTime_480Cycles );    //PB0
    ADC_RegularChannelConfig(ADC1,ADC_Channel_0 ,13,ADC_SampleTime_480Cycles );    //PA0
    ADC_RegularChannelConfig(ADC1,ADC_Channel_15,14,ADC_SampleTime_480Cycles );    //PC5
    
    ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);//开启AD转换器    
}    
//DMAx的各通道配置
//这里的传输形式是固定的
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_Streamx:DMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{ 
    DMA_InitTypeDef  DMA_InitStructure;
    if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能         
    }else 
    {
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能 
    }
    DMA_DeInit(DMA_Streamx);
    while (DMA_GetCmdStatus(DMA_Streamx)!= DISABLE){}//等待DMA可配置 
    
    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel = chx;  //通道选择,DMA_channel DMA_Channel_0~DMA_Channel_7
    DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
    DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
    DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:8位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式 
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//中等优先级
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
    DMA_Init(DMA_Streamx,&DMA_InitStructure);//初始化DMA Stream

    while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}    //确保DMA可以被设置          
    DMA_Cmd(DMA_Streamx,ENABLE);                      //开启DMA传输 
}

将下面两个数据放在adc的配置文件中

#define size 10     //采集次数
#define ADC_NUM 14 //外设数量

处理函数如下

extern u16 number[ADC_NUM];
extern float averge_1[size][ADC_NUM];

void averge(void)
{
    register u16 sum=0;
    u8 count=0,i=0,j=0;
    for(;i<ADC_NUM;i++)
    {
        while(j<size)
        {
            if(averge_1[j][i]<0){}
            else{
                sum+=averge_1[j][i];
                count++;
            }
              j++;
        }
        number[i]=sum/count;
         printf("%f\n",number[i]);//打印数据
        sum=0;count=0;j=0;
    }
}

将一下两行放在主函数中开启传输,main函数中打印数值。

//初始化DMA函数,最后一个参数是定义二位数组的元素
MYDMA_Config(DMA2_Stream0,DMA_Channel_0,(u32)&ADC1->DR,(u32)number,size*ADC_NUM);
ADC_SoftwareStartConv(ADC1);        //使能指定的ADC1的软件转换启动功能

int main()
{
    averge();
}

ADC多指采样+DMA模式使用程序实现,将原始数据进行处理需要自己重新找算法进行优化,原始数据波动很大,需要滤波后的数值才可以稳定。当然我当时也出现过很多离谱的问题,一直无法解决,程序上有问题是一方面,而且还有外部的因素,比如芯片自身的问题等等,具体的问题需要大家自行实践感受。加油,困难一定是可以克服的,问题也是可以解决的,坚持下去,我们都可以的!!!文章来源地址https://www.toymoban.com/news/detail-787402.html

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

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

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

相关文章

  • STM32双路ADC注入通道和规则通道采样

    电机控制使用四路注入通道采集,参考ST官方库,使用定时器10us触发一次,使用ADC1和ADC2各2路注入通道。 需要一路ADC进行规则采样油门信号,使用中断的话会和注入通道中断放在同一个函数里面 ,我不喜欢,所以使用了DMA中断。 PreKnowledge: 规则通道:最多16个规则通道,采样

    2024年04月14日
    浏览(35)
  • STM32 ADC单/多通道采样+DMA搬运

    通过介绍我们可以了解到,ADC是12位的转换器,所以采样值范围是0~4095。18个通道可同时进行转换,也可以单独转换某个通道。 使用ADC的流程应为: 初始化IO口。 我这里使用的是PA1进行采样,也就是ADC1的通道1 初始化ADC。 转换、获取采样值。 多通道的时候我们一般用DMA来搬

    2024年02月14日
    浏览(40)
  • STM32F407ZGT6正点原子F4探索者开发板 -- 跑马灯例程

    LED0 - PF9 LED1 - PF10 PF9 = 0, LED0 亮,PF9 = 1,LED0 灭 PF10 = 0, LED1 亮,PF10 = 1,LED1 灭

    2024年02月15日
    浏览(47)
  • STM32F103采用DMA方式多路ADC采样

    stm32采用DMA方式进行ADC采样可以高效的进行数据采集,不用cpu实时参与,以节省单片机资源,让单片机可以在同一时间里干更多事,STM32F103 ADC为12位ADC的,是一种逐次逼近型模拟数字转换器,它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续

    2024年02月06日
    浏览(40)
  • STM32F3系列 ADC采样单端采样模式(基于LL库)

    芯片型号:STM32f303RBT6 开发软件:MDK5 CubeMX VS Code 目录 STM32F3系列 ADC 单端采样(基于LL库) 目录 引言 1 基础知识 1.1ADC转换基本流程 1.2 时钟树 1.3 关键参数 1.3.1 位数 1.3.2 触发信号 1.3.3 采样时间 1.3.4 转换时间 2 CubeMx 配置步骤 2.1 确定输入通道 2.2 配置ADC 2.3 输出设置 2.4 MD5 设置

    2024年02月08日
    浏览(34)
  • 【STM32】定时器1触发ADC多(规则)通道采样+DMA(CUBEMX配置)

    在用单片机做电源控制时不得不提ADC采集,离散系统是有固定的执行周期的,所以我们采样也是要固定时间去采样。然后就是我希望pwm波(定时器1产出)的频率与采样频率一致。 我下面演示的是G431CBU6,当然其他芯片也大差不差了。 说一下大致流程,TIM1触发ADC采样,然后

    2024年02月01日
    浏览(42)
  • STM32F103:ADC采样——定时器触发+DMA传输

    实现ADC多通道采样,采用DMA传输,采样由定时器触发 初始化代码:

    2024年02月14日
    浏览(35)
  • stm32f030 学习笔记 (1)adc单/双通道采集

     1.实现单通道         如 pa0 pa1 pa2 温度传感器         1.实现单通道步骤                 1):配置RCC   GPIOA,UART1,ADC1使能                         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);                         RCC_APB2PeriphClockCmd(RCC_APB2Periph_A

    2024年02月15日
    浏览(29)
  • STM32基于hal库的adc以DMA的多通道采样以及所遇问题解决

    目录 准备 配置 步骤  总结   正点原子的STM32F103ZET6开发板(精英版) CUBEMX配置软件 KEIL5  右对齐就是正常的数据格式。左对齐除以16后得正常数据。(当输出非常大时考虑是否改了对齐方式,默认都是右对齐)  扫描模式,连续转换模式使能。(多通道下扫描模式自动使能

    2024年02月04日
    浏览(37)
  • 看野火的视频,用正点原子的板子(STM32F4探索者)做ADC读取电压实验

    使用STM32F4的ADC1通道5(PA5)来采样外部电压值(这里采样两个电压值TPAD(3.3v),GND(0v)),最后通过串口打印电压值。 由上图可以看到, ADC1 的通道 5是对应着引脚PA5的。 板子右边是GND,ADC,TPAD引脚,做实验时,把两者相连即可读电压值。 ADC时钟: 这里是用于模拟电路的时

    2024年02月09日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包