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

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

在这里插入图片描述

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

在这里插入图片描述

程序仍然在上节的基础上进行修改,先附上关于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]);
        }
    }
}

实验效果如下:

在这里插入图片描述

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

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

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

最近更新

  1. TCP协议是安全的吗?

    2023-12-08 04:10:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-08 04:10:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-08 04:10:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-08 04:10:01       20 阅读

热门阅读

  1. ❀My学习Linux命令小记录(15)❀

    2023-12-08 04:10:01       27 阅读
  2. 设计多级菜单的数据结构(C语言实现)

    2023-12-08 04:10:01       37 阅读
  3. 简述本人项目中常用的Typescript的知识

    2023-12-08 04:10:01       35 阅读
  4. 括号匹配的检验(数据结构实训)

    2023-12-08 04:10:01       30 阅读
  5. K8s基础

    K8s基础

    2023-12-08 04:10:01      39 阅读
  6. chatgpt用到哪些算法

    2023-12-08 04:10:01       36 阅读
  7. ElasticSearch之cat nodeattrs API

    2023-12-08 04:10:01       43 阅读
  8. 将linux服务器 设置成 proxy.SOCKS5 服务器

    2023-12-08 04:10:01       35 阅读