• ADC模数转换(二)——独立模式多通道电压采集实验


     

    接上篇文章ADC模数转换(一)——独立模式单通道电压采集实验,这篇讲了ADC的基础以及独立模式单通道采集实验。现在将介绍独立模式的多通道采集实验,还会有一篇文章介绍双重ADC模式的采集实验。

    这个实验和上篇文章相比,只是通道多了,使用了DMA代替中断读取的方式,所以在上个实验的基础上,稍加修改即可。

    现在我们需要先确定ADC和DMA的配置关系。

    查阅参考手册DMA篇章可得,ADC1对应DMA1的通道1,ADC3对应DMA2的通道5,而ADC2则没有DMA功能。如图22-1,图22-2。所以,这里我们选择ADC1,其对应了DMA1的通道1。

    图22-1

    图22-2

    接下来确定使用ADC1的哪些通道。查阅数据手册(Table 5. High-density STM32F103xx pin definitions)可知,PC0~PC3对应ADC1/2/3_IN10~ADC1/2/3_IN13,我们就选这4个引脚。然后可以开始配置了。

    ADC的GPIO配置

    PC0~PC3四个引脚都需要配置,引脚模式都是模拟输入。

    /**
      * @brief  ADC的GPIO配置
      * @param  无
      * @retval 无
      */
    static void ADC1_GPIO_Config(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;               // 模拟输入
        GPIO_Init(GPIOC, &GPIO_InitStructure);	
    }
    

    ADC配置

    包括DMA和ADC1的配置说明,比较简单,有关DMA也在之前的文章有介绍,所以直接在下面的程序里通过注释简单说明了。

    __IO uint16_t ADC_ConvertedValue[4] = {0, 0, 0, 0};
    
    /**
      * @brief  ADC配置
      * @param  无
      * @retval 无
      */
    static void ADC1_Mode_Config(void)
    {
        /*------------------- DMA配置 -------------------*/
        DMA_InitTypeDef DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        DMA_DeInit(DMA1_Channel1);                                           // 复位DMA
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));  // 外设基地址为ADC1_DR寄存器地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; // 内存存储地址,即ADC_ConvertedValue数组的首地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                   // 数据来源于外设
        DMA_InitStructure.DMA_BufferSize = 4;                                // 缓冲区大小,这里为ADC_ConvertedValue数组的长度
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;     // 只有ADC1一个外设,所以地址不递增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;              // 内存存储地址递增
        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通道优先级为高,当使用一个DMA通道时,优先级设置不受影响
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                         // 外设到内存模式
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        DMA_Cmd(DMA1_Channel1, ENABLE);
    
        /*------------------- ADC配置 -------------------*/
        ADC_InitTypeDef ADC_InitStruct;	
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);          
        ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;                      // 独立模式,只使用一个ADC           
        ADC_InitStruct.ADC_ScanConvMode = ENABLE;                            // 扫描模式
        ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;	                 // 连续转换
        ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;     // 不使用外部触发,用软件触发
        ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;                  // 转换结果右对齐
        ADC_InitStruct.ADC_NbrOfChannel = 4;	                         // 转换通道数量
        ADC_Init(ADC1, &ADC_InitStruct);
    
        RCC_ADCCLKConfig(RCC_PCLK2_Div8);                                    // 8分频,9MHz
    
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);      // ADC转换通道10,转换顺序1,采样周期55.5
        ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);      // ADC转换通道11,转换顺序2,采样周期55.5
        ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);      // ADC转换通道12,转换顺序3,采样周期55.5
        ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);      // ADC转换通道13,转换顺序4,采样周期55.5
    
        ADC_DMACmd(ADC1, ENABLE);                                            // 使能ADC的DMA请求
    
        ADC_Cmd(ADC1, ENABLE);	
    
        ADC_ResetCalibration(ADC1);                                          // 初始化ADC校准寄存器
        while(ADC_GetResetCalibrationStatus(ADC1));                          // 等待校准寄存器初始化完成
        ADC_StartCalibration(ADC1);                                          // ADC开始校准
        while(ADC_GetCalibrationStatus(ADC1));                               // 等待校准完成
    
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                              // 软件触发ADC转换
    }
    

    配置程序就只是完成ADC和DMA的配置,配置项多了点,其实并不复杂。

    由于采用了DMA的方式代替了中断读取的方式,所以直接main()函数里将读取到的值转换成可读的模拟电压值。

    extern __IO uint16_t ADC_ConvertedValue[4];
    
    float ADC_ConvertedValueLocal[4];
    
    ADC_ConvertedValueLocal[0] = (float)ADC_ConvertedValue[0] / 4096 * 3.3;
    ADC_ConvertedValueLocal[1] = (float)ADC_ConvertedValue[1] / 4096 * 3.3;
    ADC_ConvertedValueLocal[2] = (float)ADC_ConvertedValue[2] / 4096 * 3.3;
    ADC_ConvertedValueLocal[3] = (float)ADC_ConvertedValue[3] / 4096 * 3.3;
    
    printf("
     CH10 value = %f V 
    ", ADC_ConvertedValueLocal[0]);
    printf("
     CH11 value = %f V 
    ", ADC_ConvertedValueLocal[1]);
    printf("
     CH12 value = %f V 
    ", ADC_ConvertedValueLocal[2]);
    printf("
     CH13 value = %f V 
    ", ADC_ConvertedValueLocal[3]);
    

    关于转换公式,可参考ADC模数转换(一)——独立模式单通道电压采集实验

    有一点需要注意,每个转换的ADC通道引脚都需要为其提供电源输入,以作为待测电压进行转换。可以用杜邦线连接开发板上的3V3电源输入。

  • 相关阅读:
    微服务通过feign.RequestInterceptor传递参数
    fastdfs的storage的IP地址映射docker宿主地址
    Sentinel对Feign的支持
    SpringBoot设置MultipartFile文件大小限制
    SpringBoot+JWT@注解实现token验证
    springBoot 使用 mybatis-plus 实现分页
    MyBatis-Plus 使用xml文件
    MAC inode提示:正在查询SSLVPN网关参数... 查询SSLVPN 网关参数失败,请检查网络配置或联系
    MacOS launchctl 启动进程控制
    可执行Jar格式-1
  • 原文地址:https://www.cnblogs.com/fire909090/p/8882777.html
Copyright © 2020-2023  润新知