030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集_第1张图片

中断模式和DMA模式进行单通道模拟量采集,这节继续学习独立模式多通道DMA采集,使用到的引脚有之前使用的PC3(电位器),PA4(光敏电阻)、PA6(悬空,可通过杜邦线接3V3或者GND进行测试)。对应引脚通道如下表:

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集_第2张图片

程序仍然在上节的基础上进行修改,先附上关于GPIO宏定义的部分:

//选择ADC1
#define R_ADC                   ADC1
#define R_ADC_CLK               RCC_APB2Periph_ADC1
//电位器 PC3
#define R_ADC_GPIO_PORT1         GPIOC
#define R_ADC_GPIO_PIN1          GPIO_Pin_3
#define R_ADC_GPIO_CLK1          RCC_AHB1Periph_GPIOC
#define R_ADC_CHANNEL_PC3        ADC_Channel_13					//通道13
//光敏电阻 PA4
#define R_ADC_GPIO_PORT2         GPIOA
#define R_ADC_GPIO_PIN2          GPIO_Pin_4
#define R_ADC_GPIO_CLK2          RCC_AHB1Periph_GPIOA
#define R_ADC_CHANNEL_PA4        ADC_Channel_4					//通道4
//悬空 PA6
#define R_ADC_GPIO_PORT3         GPIOA
#define R_ADC_GPIO_PIN3          GPIO_Pin_6
#define R_ADC_GPIO_CLK3          RCC_AHB1Periph_GPIOA
#define R_ADC_CHANNEL_PA6        ADC_Channel_6					//通道6

在使用之前,先来对GPIO进行初始化配置,配置如下:

/** @brief  初始化ADC GPIO引脚
  * @parm   无
  * @retval 无
  */
static void R_ADC_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(R_ADC_GPIO_CLK1 | R_ADC_GPIO_CLK2 | R_ADC_GPIO_CLK3,ENABLE);          //开启ADC外设引脚时钟
    //通用配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;           //配置引脚为模拟输入 
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;        //配置为无上下拉
    //初始化引脚PC3
    GPIO_InitStructure.GPIO_Pin = R_ADC_GPIO_PIN1;           //配置引脚PC3引脚
    GPIO_Init(R_ADC_GPIO_PORT1,&GPIO_InitStructure);         //初始化引脚
    //初始化引脚PA4
    GPIO_InitStructure.GPIO_Pin = R_ADC_GPIO_PIN2;           //配置引脚PC4引脚
    GPIO_Init(R_ADC_GPIO_PORT2,&GPIO_InitStructure);         //初始化引脚c
    //初始化引脚PA6
    GPIO_InitStructure.GPIO_Pin = R_ADC_GPIO_PIN3;           //配置引脚PA6引脚
    GPIO_Init(R_ADC_GPIO_PORT3,&GPIO_InitStructure);         //初始化引脚
}

对于ADC来说,我们使用的是一个ADC,即ADC1,所以关于ADC Common的初始化部分不需要进行修改。这里代码就不网上贴了,不清楚了可以翻看上一节的内容。

下来再看ADC Init初始化结构体,这里有几处需要修改一下:

1、这次因为要对3个通道进行数据采集,因此需要将通道数改为3,为了方便后期更改,这里将通道数进行宏定义:

#define ADC_NOFChannel          3					   //宏定义通道数,位于bsp_adc.h中
ADC_InitStructure.ADC_NbrOfConversion = ADC_NOFChannel;   //转换通道为3,采用宏定义

2、通道数超过1个时,需要开启扫描模式,需要将扫描模式使能:

ADC_InitStructure.ADC_ScanConvMode = ENABLE;               //多通道下用到扫描模式

3、配置多通道的转换顺序,根据我们实际的需求,需要对多个通道的采集先后顺序进行排序,排序如下:

//配置ADC通道转换顺序为1,第一个转换,采集周期为3个周期   
ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PC3,1,ADC_SampleTime_3Cycles);
//配置ADC通道转换顺序为2,第二个转换,采集周期为3个周期   
ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PA4,2,ADC_SampleTime_3Cycles);
//配置ADC通道转换顺序为1,第二个转换,采集周期为3个周期
ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PA6,3,ADC_SampleTime_3Cycles);

4、内存地址需要递增了,这里感谢红茶加巧克力帮忙看出来忘了没改注释。

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;            //存储器地址需要递增了,存储到ADC_Value数组中

关于ADC初始化及DMA初始化的完整程序附在下面:

/** @brief  配置ADC引脚工作模式及DMA
  * @parm   无
  * @retval 无
  */
static void R_ADC_Mode_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    //-----------------DMA Init结构体参数初始化-----------------//
    RCC_AHB1PeriphClockCmd(R_ADC_DMA_CLK,ENABLE);           //开启DMA时钟
    DMA_InitStructure.DMA_PeripheralBaseAddr = R_ADC_DR_ADDR;       //设置ADC外设基地址,为ADC数据寄存器地址
    DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_Value;        //存储器地址,地址为内部SRAM变量
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;         //配置数据传输方向为外设到存储器
    DMA_InitStructure.DMA_BufferSize = ADC_NOFCHANNEL;              //配置缓冲区大小,大小取决于一次传输的量
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //外设寄存器只有一个,不用递增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;            //存储器地址需要递增了,存储到ADC_Value数组中
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据大小为半字(两个字节)
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;     //与外设相同
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                         //循环传输
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                     //传输优先级为高
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  //采用直连,不适用FIFO
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;       //FIFO禁止,下面不用配置
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_Channel = R_ADC_DMA_CHANNEL;              //选择DMA通道
    DMA_Init(R_ADC_DMA_STREAM,&DMA_InitStructure);
    DMA_Cmd(R_ADC_DMA_STREAM,ENABLE);
    RCC_APB2PeriphClockCmd(R_ADC_CLK,ENABLE);               //开启ADC时钟
    //-----------------ADC Common结构体参数初始化--------------//
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;        //设置模式为独立模式
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;     //设置为4分频
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;     //禁止DMA直接访问模式
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles;       //设置采样间隔周期为10个周期
    ADC_CommonInit(&ADC_CommonInitStructure);
    //-----------------ADC Init结构体参数初始化--------------//
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;      //设置ADC采样分辨率为12位
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;               //多通道下用到扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;          //设置为连续转换
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;     //禁用外部边沿触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;      //设置为右对齐
    ADC_InitStructure.ADC_NbrOfConversion = ADC_NOFCHANNEL;                  //转换通道为3,采用宏定义
    ADC_Init(R_ADC,&ADC_InitStructure);
    ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PC3,1,ADC_SampleTime_3Cycles);        //配置ADC通道转换顺序为1,第一个转换,采集周期为3个周期
    ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PA4,2,ADC_SampleTime_3Cycles);        //配置ADC通道转换顺序为2,第二个转换,采集周期为3个周期
    ADC_RegularChannelConfig(R_ADC,R_ADC_CHANNEL_PA6,3,ADC_SampleTime_3Cycles);        //配置ADC通道转换顺序为1,第二个转换,采集周期为3个周期
    //ADC_ITConfig(R_ADC,ADC_IT_EOC,ENABLE);      //ADC转换结束产生中断,在中断服务程序中读取转换数值
    ADC_DMARequestAfterLastTransferCmd(R_ADC, ENABLE);
    ADC_DMACmd(R_ADC,ENABLE);
    ADC_Cmd(R_ADC,ENABLE);                  //使能ADC
    ADC_SoftwareStartConv(R_ADC);           //开始ADC转换,由软件触发
}

这里我们在bsp_adc.c中定义一个数组,用来存放三个通道采集到的数据,再在main函数中用extern调用,再定义用来存放转换后的数组。main中程序如下:

extern __IO uint16_t ADC_Value[ADC_NOFCHANNEL];
float ADC_Vol[ADC_NOFCHANNEL] = {0};

int main(void)
{
    DEBUG_USART1_Config();
    R_ADC_Init();
    SysTick_Init();
    printf("\r\n---------------ADC实验(独立模式多通道DMA模式)----------------\r\n");
    while(1)
    {
        Delay_ms(1000);
        for(int i = 0;i <ADC_NOFCHANNEL;i++)
        {
            if(i == 0)
                printf("-------------------电位器通道-------------------");
            else if(i == 1)
                printf("-------------------光感通道-------------------");
            else
                printf("-------------------悬空通道-------------------");
            printf("\r\n ADC数据(未转换) = 0x%04X \r\n",ADC_Value[i]);
            ADC_Vol[i] =(float)(ADC_Value[i]*3.3/4096); // 读取转换的 AD 值 
            printf("\r\n ADC数据(已转换) = %.2f V \r\n",ADC_Vol[i]);
        }
    }
}

实验效果如下:

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集_第3张图片

1、电位器通道可以通过调整电位器阻值查看采集结果;

2、光感通道可以通过遮挡光敏电阻或者手机闪光灯照射查看采集结果(用手遮了一下光敏模块);

3、悬空通道可以接3.3V或者GND通道来查看采集结果(这里接到GND上的)。

你可能感兴趣的:(stm32,stm32,学习,笔记)