接上篇文章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