欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于原子STM32F103RC(STM32Fmini)/STM32F407ZG(STM32F4探索者)的多通道ADC采集,通过MDA传输采集数据。

程序员文章站 2022-04-01 21:50:05
...

在学习STM32的时候,发现无论是STM32F103RC还是STM32F407ZG都只有ADC转换的例程和UART DMA的例程。所以写了一份DMA传输ADC的程序,希望对大家有帮助。
程序:使用了STM32F407ZG(STM32F4探索者)的开发板,通过ADC去采集PA5,PA6,PA7引脚的电平。然后由DMA传输,在串口上显示出采集的值。
PS:程序在STM32F1mini上也通用自己对照着改一下IO口和一些通道配置就好。


首先当然是配置我们的IO口:

void My_DAC_IO_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

      //初始化ADC1通道5.6.7
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;       //PA5 通道5 PA6 通道6 PA7 通道7
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                             //模拟输入模式
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;                         //不带上下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);                                      
}

基于原子STM32F103RC(STM32Fmini)/STM32F407ZG(STM32F4探索者)的多通道ADC采集,通过MDA传输采集数据。基于原子STM32F103RC(STM32Fmini)/STM32F407ZG(STM32F4探索者)的多通道ADC采集,通过MDA传输采集数据。


查阅手册可以看到PA5对应的是ADC的IN5,PA6对应的是ADC的IN6,PA7对应的是ADC的IN7。
这样就配置好了通道。通道也选择的是相近的这方便与DMA传输过程中的地址增加。


接下来配置ADC:

void My_Adc_Init(void)
{
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);


    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;       //禁止DMA直接访问
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;                      //ADC独立模式
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;                   //4分频
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //采样时间间隔
    ADC_CommonInit(&ADC_CommonInitStructure);

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                            //连续转换使能,因为这里是转换三个通道
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                          //ADC的对齐模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None;         //禁止外部触发
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConv_T1_CC1;       //因为禁止了外部这边随便选择什么
    ADC_InitStructure.ADC_NbrOfConversion = 3;                                      //3个通道转换
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                          //12位ADC
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                    //多通道采集开启
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);       //配置ADC通道转换顺序
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 2, ADC_SampleTime_3Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_3Cycles);

  ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);                                 //使能DMA请求
  ADC_DMACmd(ADC1, ENABLE);                                                     //使能ADC-MDA
  ADC_Cmd(ADC1, ENABLE);                                                            //使能ADC
  ADC_SoftwareStartConv(ADC1);                                                      //开启软件转换

}

ADC的配置不会的话可以去看原子提供的ADC视频里面有详细的讲解每个配置功能是干嘛的,这边需要注意的是多了一下两个个函数:
1.

 ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);     //使能DMA请求

这个函数使能了ADC的MDA请求。

2.

ADC_DMACmd(ADC1, ENABLE);   

这个函数使能了ADC的DMA模式。


然后就需要去配置我们的DMA了,

#ifndef __DMA_H
#define __DMA_H
#include "sys.h"
#define RHEOSTAT_NOFCHANEL      3
// ADC DR寄存器的宏定义   ADC转换后的值就存放在这个寄存器里面
#define RHEOSTAT_ADC_DR_ADDR    ((u32)ADC1+0x4c)
extern __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL];


void My_DMA_Init(void);

#endif

这是.h文件,一些定义在.h里面定义

#include "dma.h"

__IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0};

void My_DMA_Init(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 


    DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL;                  //数据大小 = 3
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;                          //DMA通道0
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                 //DMA传输方向从外设到寄存器
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  //不用FIFO用直接模式
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;       //半字 = 两个字节
    DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue;        //寄存器的基地址
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             //FIFO禁用不需要配置
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;     //半字 = 两个字节
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //寄存器地址增加使能。
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                         //DMA循环模式
    DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR;        //外设基地址
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //FIFO禁用不需要配置
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;     //半字 = 两个字节
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外设地址不需要变化
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                             //传输通道为高
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

    DMA_Cmd(DMA2_Stream0, ENABLE);                                                  //使能DMA
}

在这里我们需要注意的一下几点:
1.数据是从ADC传到ADC_ConvertedValue这个数组,也就是从外设(ADC)传输到寄存器(数组存放地址)


2.外设地址:为 ((u32)ADC1+0x4c) 其中ADC1是ADC的基地址,0x4c是ADC_DR寄存器的偏移量,因为ADC_DR寄存器是存放转换结果的,所以我们需要通过DMA传输出去的就是这块寄存的里面的数据。
基于原子STM32F103RC(STM32Fmini)/STM32F407ZG(STM32F4探索者)的多通道ADC采集,通过MDA传输采集数据。


3.寄存器地址:(u32)ADC_ConvertedValue 这个是自己定义的一个数组用来存放我们DMA传输出来的ADC转换后的数据。


4.因为我们采集的三个通道,然后把数据存放在数组中,那么每个通道就对应一个数组的一个元素。所以数组的地址需要递增,也就是寄存器的地址需要增加,但是外设的地址不需要变化,因为每次传输的外设地址都是这个ADC_DR寄存器,这个寄存器的地址是不变的。


备注:如果有DMA通道配置不懂的也可以去看看原子的视频,有详细的讲解。


这样配置完后我们的底层程序就差不多完成。然后在主函数中进行编写应用程序。

float ADC_ConvertedValueLocal[RHEOSTAT_NOFCHANEL]={0}; 


int main(void)
{ 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init(168);        //延时初始化
    uart_init(115200);  //初始化串口波特率 = 115200
    My_DAC_IO_Init();
    My_DMA_Init();
    My_Adc_Init();
    while(1)
    {
        ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*(float)3.3;
        ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*(float)3.3;
        ADC_ConvertedValueLocal[2] =(float) ADC_ConvertedValue[2]/4096*(float)3.3;

        printf("\r\n CH1_C3 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
        printf("\r\n CH2_PA4 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
        printf("\r\n CH3_PA6 value = %f V \r\n",ADC_ConvertedValueLocal[2]);

        printf("\r\n\r\n");
    }
}

这样通过串口工具我们就可以读取到我们的采集结果了。


基于原子STM32F103RC(STM32Fmini)/STM32F407ZG(STM32F4探索者)的多通道ADC采集,通过MDA传输采集数据。

———-附带程序的链接链接:https://pan.baidu.com/s/1TQZzicrVJ5f86FBPI96KYg 密码:du89

相关标签: DMA传输ADC值