第十四章 ADC(下篇)
目录
1 例程设计
1.1 ADC_Double例程
这是一个基于 W55MH32 的 ADC(模拟 - 数字转换器)双模式测试例程。它的主要功能是配置串口、ADC 和 DMA,并且通过 ADC1 和 ADC2 同时对模拟信号进行采样,最后把采样结果通过串口打印出来。下面是对这个例程的设计分析:
1.系统初始化
- 配置系统时钟、延时函数、串口、ADC 和 DMA。
- 打印系统时钟频率信息。
2. ADC 双模式采样
- ADC1 和 ADC2 工作于规则同步模式,同时对通道 0 和通道 1 进行采样。
- 转换结果通过 DMA 传输到内存缓冲区。
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
ADC_DeInit(ADC1);
ADC_DeInit(ADC2);
// 配置为规则同步模式
ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure);
/* channel configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
/* module enablement */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
/* adc calibration */
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
ADC_ResetCalibration(ADC2);
while (ADC_GetResetCalibrationStatus(ADC2));
ADC_StartCalibration(ADC2);
while (ADC_GetCalibrationStatus(ADC2));
DMA_Configuration();
}
3.数据处理与输出
- DMA 传输完成后触发中断,将 ADC 数字值转换为电压值并通过串口打印。
void DMA1_Channel1_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC1);
DMA_ClearFlag(DMA1_FLAG_TC1);
// 数据处理与输出
printf("ADC1 Code Value = %d ,voltage value = %2.4f\n", DAM_ADC_Value[0] & 0xFFFF,
(float)VREF * (DAM_ADC_Value[0] & 0xFFFF) / 4095 / 1000);
printf("ADC2 Code Value = %d ,voltage value = %2.4f\n", (DAM_ADC_Value[0] >> 16) & 0xFFFF,
(float)VREF * ((DAM_ADC_Value[0] >> 16) & 0xFFFF) / 4095 / 1000);
}
}
1.2 ADC_Single例程
该例程是一个基于 W55MH32 微控制器的 ADC 单通道采样程序,主要功能是周期性采集模拟输入信号并通过串口输出 ADC 值及其对应的电压。以下是详细的工作流程总结:
1.时钟配置
- 获取系统各时钟频率(SYSCLK/HCLK/PCLK/ADCCLK),并通过串口打印。
2.UART 配置
- 初始化 USART1 为 115200 波特率,用于串口输出数据。
3.ADC 配置
- 使能 ADC1 时钟,配置 PA6 为模拟输入模式。
- ADC 工作在独立模式,禁用连续转换,启用扫描模式(单通道时仅触发一次转换)。
- 执行 ADC 校准以确保精度。
void ADC_Configuration(void)
{
uint32_t i;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 使能 ADC1 和 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// 配置 PA6 为模拟输入模式
GPIO_InitStructure.GPIO_Pin = ADC_TEST_CHANNEL_PIN; // PA6
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// ADC 时钟配置(PCLK2 的 1/8)
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
ADC_DeInit(ADC1); // 复位 ADC1
// ADC 初始化配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 启用扫描模式(单通道时仅转换一次)
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 禁用连续转换,需软件触发
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐
ADC_InitStructure.ADC_NbrOfChannel = CONV_CHANNEL_NUM; // 通道数(1)
ADC_Init(ADC1, &ADC_InitStructure);
// 配置 ADC 通道(通道 6,采样时间 239.5 周期)
for (i = 0; i < CONV_CHANNEL_NUM; i++)
{
ADC_RegularChannelConfig(ADC1, ADC_CovChannel[i], i + 1, ADC_SampleTIME[i]);
}
// 启动 ADC 转换并使能 ADC
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
// ADC 校准
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
// 配置 DMA 传输
DMA_Configuration();
}
4.DMA 配置
- 设置 DMA1 通道 1 为循环模式,将 ADC 数据寄存器(ADC1->DR)的数据传输到内存数组DAM_ADC_Value。
- 使能 DMA 传输完成中断(TC 中断),触发数据处理。
1.3 ADC_VrefintTemper例程
该例程是一个基于 W55MH32 的 ADC 多通道采样程序,主要用于同时采集内部温度传感器和 VREFINT(内部参考电压)的模拟信号,并通过串口输出测量结果。以下是其主要工作流程如下:
1.系统初始化
a.UART 配置:初始化 USART1 为 115200 波特率,用于串口输出。
b.ADC 配置:使能 ADC1 时钟,配置为独立模式,启用扫描模式(多通道依次转换)。
- 配置通道 16(温度传感器)和通道 17(VREFINT),采样时间 239.5 周期。
- 校准 ADC 并使能内部温度传感器和 VREFINT。
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 启用扫描模式,多通道依次转换
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 禁用连续转换,需软件触发
ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器和VREFINT
c.DMA 配置:设置 DMA1 通道 1 为循环模式,将 ADC 数据寄存器(ADC1->DR)的数据传输到内存数组DAM_ADC_Value。
- 使能 DMA 传输完成中断(TC 中断)。
2.主循环逻辑
a.每秒调用ADC_SoftwareStartConvCmd(ADC1, ENABLE)触发 ADC 转换。
b.延时 1 秒后重复触发,实现周期性采样。
3.数据处理与输出
void DMA1_Channel1_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC1) != RESET) // 检查传输完成中断
{
DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除中断标志
DMA_ClearFlag(DMA1_FLAG_TC1);
// 计算温度传感器和VREFINT的电压值(VREF=3.3V,ADC精度12位)
float tempVoltage = (float)VREF * DAM_ADC_Value[0] / 4095 / 1000; // 温度传感器电压
float vrefintVoltage = (float)VREF * DAM_ADC_Value[1] / 4095 / 1000; // VREFINT电压
// 串口输出结果
printf("Temperature Sensor AD Value: %d, Voltage: %.4f V\t", DAM_ADC_Value[0], tempVoltage);
printf("VREFINT AD Value: %d, Voltage: %.4f V\n", DAM_ADC_Value[1], vrefintVoltage);
}
}
a.DMA 中断处理:当 DMA 传输完成时,触发DMA1_Channel1_IRQHandler。
b.电压计算:根据公式 电压 = VREF × ADC值 / 4095 / 1000 计算实际电压值(VREF=3.3V)。
c.串口打印:输出温度传感器和 VREFINT 的 ADC 值及电压值。
2 下载验证
2.1 ADC_Double例程
程序运行时,ADC1和ADC2以规则同步模式周期性采样两个模拟通道(PA0和PA1),转换结果通过DMA传输至内存。每次DMA传输完成后触发中断,在中断中计算并通过串口打印ADC1和ADC2的原始数值(12位)及对应的电压值(单位:V),显示间隔由主循环中的1秒延时控制。系统启动时会输出各时钟频率参数,随后每秒更新一次ADC数据。
2.2 ADC_Single例程
程序运行时,系统首先输出各时钟频率参数,随后每秒触发一次ADC1通道6(PA6)的模拟信号采样。ADC转换结果通过DMA自动传输至内存,每次DMA传输完成后触发中断,在中断服务函数中计算并通过串口打印ADC原始值(12位)及对应的电压值(单位:V)。系统以1秒为间隔循环触发采样,实现周期性数据更新,最终在串口终端每秒显示一次ADC数据。
2.3 ADC_VrefintTemper例程
程序运行时,系统首先输出各时钟频率参数,随后每秒触发一次ADC1通道16(内部温度传感器)和通道17(VREFINT)的模拟信号采样。ADC转换结果通过DMA自动传输至内存,每次DMA传输完成后触发中断,在中断服务函数中计算并通过串口打印两个通道的ADC原始值(12位)及对应的电压值(单位:V)。系统以1秒为间隔循环触发采样,实现周期性数据更新,最终在串口终端每秒显示一次内部温度传感器和VREFINT的测量结果。