ashwatermelon

ashwatermelon

【学习笔记】stm32单片机ADC功能的使用及配置方法

今天继续学习笔记。
前面几天学完了 ADC 模块,于是在写完定时器后就接着把 ADC 模块也写了。

(一)ADC 是什么#

在网上稍微查一下我们就知道 ADC 的定义:模数转换,即 Analog-to-Digital Converter,常称 ADC,是指将连续变量的模拟信号转换为离散的数字信号的器件,例如,通过 ADC 把温度传感器产生的电信号转化为数字信号 0101 之类的。
与 ADC 模块对应的就是 DAC 模块,DAC 模块可以把数字信号转化为模拟信号,stm32 有 ADC 模块但没有 DAC 模块。

(二)stm32 上的 ADC 功能#

我们用的芯片 STM32F103C8T6 的 ADC 资源有 ADC1、ADC2,10 个外部输入通道,其中注入组有 4 个通道,其余为规则组。
注入组的四个通道互不干扰,可以同时使用和转换。
规则组则须按列表依次转换,并且只有一个储存位置,后转换的数据将会顶顶掉前一个数据的位置,需要 DMA 的配合才能完成多通道的 ADC 转换。
此外,规则组的配置还有多种模式选择,主要是是否开启连续转换和扫描模式。
连续转换就是在完成一次转换后立刻衔接下一次转换,扫描模式则是接着扫描规则组配置的列表的其他通道,若不开启则只转换一个通道。

(三)AD 单通道配置#

首先我们学习如何配置单通道转换。
先看结构图
image
根据结构图我们知道了如何配置 AD 单通道。
第一步,我们需要开启 ADC 和 GPIO 的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步,我们需要设置 ADC 时钟,调整其预分频,因为 ADC 的最大频率是 14Hz,所以我们只能配置 6 分频往上:
RCC_ADCCLKConfig(RCC_PCLK2_Div6);

第三步,初始化 GPIO 口,配置为 ADC 模式:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

第四步,配置规则组通道(注入组没用过):
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

第五步,ADC 初始化,其中配置了 ADC 独立模式、不连续非扫描模式,无外部触发源(软件触发),只有一个通道,数据右对齐:
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);

第六步,启动 ADC:
ADC_Cmd(ADC1, ENABLE);

第七步,ADC 校验,这个是固定流程:
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);

自此,ADC 配置完成,然后我们可以开启转换:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

转换过程需要时间,我们可以检查标志位判断转换是否完成:
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

最后,我们通过获取数据:
ADC_GetConversionValue(ADC1);

(四)AD 多通道#

AD 多通道就是同时开启多个通道转换,需要用到 DMA。
DMA 结构图如下:

image

那么如何配置 AD 多通道呢?
前三步与 AD 单通道基本一样,不过需要多开启一个 DMA 时钟并且多初始化几个引脚:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

接着我们配置配置规则组通道,也要多配置几个,并且规定好顺序:
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);

接下来初始化 ADC,这次我们要开启连续扫描模式,通道数设置为 4:
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_Init(ADC1, &ADC_InitStructure);

然后我们初始化 DMA,这里。外设和储存器都设置为半个字大小(即 16 位),外设地址为指向寄存器 DR 的指针(前面说的储存数据的位置就是它),外设地址不自增(始终读取 DR 地址),储存器指向储存数据的数组,开启循环:
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

接着我们开启 DMA 并且使 ADC1 触发 DMA1 的信号使能,最后开启 ADC:
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);

还有 ADC 校验也是必不可少:
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);

最后开启转换,我们就能在储存数据的数组里得到想要的数据:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

那么 ADC 的功能就这么多,886。

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.