20.AD单通道&AD多通道应用程序示例
摘要:本文介绍了STM32单片机ADC模块的单通道和多通道配置方法。单通道配置包括初始化ADC时钟、GPIO设置、ADC参数配置及校准流程,并通过软件触发读取转换值。多通道配置采用非扫描模式,通过循环切换通道实现多路采样,同样使用软件触发方式。代码示例展示了如何初始化ADC、读取转换值及电压计算,其中单通道使用PA0引脚,多通道扩展至PA0-PA3引脚。两种模式均采用12MHz时钟和55.5周期采
·
一、单通道

》单通道很简单
1.配置ADC的初始化
(1)初始化通道引脚的时钟和ADC的时钟,并且注意ADC是特殊的最大14Hz所以需要分频
(2)GPIO配置
(3)配置ADC
注意开关什么的都是最后配置
首先对ADC的常规规则通道进行配置,
之后初始化ADC,
之后可以配置ADC相关的中断或者模拟看门狗,
最后开启ADC的总开关,触发输入的开关(硬件开关/软件开关),
(4)开启校准
2.封装取DR下的值函数
3.main函数不断调用这个函数
mian.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t AD_Value;
float Voltage;
int main()
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "AD_Value:");
OLED_ShowString(2, 1, "Voltage:0.00V");
while(1)
{
AD_Value = AD_GetValue();
Voltage = (float)AD_Value / 4095 * 3.3; // 整数除以小数会舍弃小数部分
OLED_ShowNum(1, 10, AD_Value, 4);
OLED_ShowNum(2, 9, Voltage, 1); // 显示整数部分
OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); // 显示小数部分
Delay_ms(100);
}
}
adc.c
#include "stm32f10x.h" // Device header
/**
* @brief ADC初始化函数(软件触发,且这里不使用模拟看门狗和中断)
* @param 无
* @retval 无
*/
void AD_Init(void)
{
// 1. RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADCCLK = 72MHz / 6 = 12MHz
// 2. 配置GPIO
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);
// 3. 将指定的GPIO端口接入规则组列表中
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 把通道0填入序列1中,通道的采样周期是55.5个ADCCLK的周期
// 4. 配置ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // ADC模式(独立模式或双ADC模式):独立模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // ADC数据对齐:右对齐
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // ADC外部触发源选择:不使用外部源触发(这里使用软件触发)
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; // ADC连续转换模式:单次转换
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // ADC扫描模式:非扫描
ADC_InitStruct.ADC_NbrOfChannel = 1; // 扫描模式下通道的数量
ADC_Init(ADC1, &ADC_InitStruct);
/* 中断和模拟看门狗在此配置 */
// 5. 开关控制
ADC_Cmd(ADC1, ENABLE);
// 6. 对ADC进行校准
ADC_ResetCalibration(ADC1); // 复位校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成
ADC_StartCalibration(ADC1); // 开始校准
while (ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成
}
/**
* @brief ADC结果读取函数(软件触发)
* @param 无
* @retval 转换之后的结果
*/
uint16_t AD_GetValue(void)
{
// 1. 软件触发开启转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
// 3. 读取ADC数据寄存器并返回
return ADC_GetConversionValue(ADC1); // 读取之后会自动清除EOC标志位
}
二、多通道
因为多通道单次常规转换会导致值的覆盖,所以后续使用DMA
这里未使用DMA,所以只读取就行,不管覆盖
所以这里,多初始化了几个引脚,然后主函数轮流实现getValue()
这里的getValue()做了特殊处理,即在每次转换前,根据函数形参灵活更改规则组的通道1
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t AD0, AD1, AD2, AD3;
int main()
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "AD0:");
OLED_ShowString(2, 1, "AD1:");
OLED_ShowString(3, 1, "AD2:");
OLED_ShowString(4, 1, "AD3:");
while(1)
{
AD0 = AD_GetValue(ADC_Channel_0);
AD1 = AD_GetValue(ADC_Channel_1);
AD2 = AD_GetValue(ADC_Channel_2);
AD3 = AD_GetValue(ADC_Channel_3);
OLED_ShowNum(1, 5, AD0, 4);
OLED_ShowNum(2, 5, AD1, 4);
OLED_ShowNum(3, 5, AD2, 4);
OLED_ShowNum(4, 5, AD3, 4);
Delay_ms(100);
}
}
adc.c
#include "stm32f10x.h" // Device header
/**
* @brief ADC初始化函数(单次转换非扫描实现多通道转换,软件触发,且这里不使用模拟看门狗和中断)
* @param 无
* @retval 无
*/
void AD_Init(void)
{
// 1. RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADCCLK = 72MHz / 6 = 12MHz
// 2. 配置GPIO
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);
// 3. 将指定的GPIO端口接入规则组列表中
/* 这里要在每一次转换前都更改转换列表中要转换的GPIO端口 */
// 4. 配置ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // ADC模式(独立模式或双ADC模式):独立模式
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // ADC数据对齐:右对齐
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // ADC外部触发源选择:不使用外部源触发(这里使用软件触发)
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; // ADC连续转换模式:单次转换
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // ADC扫描模式:非扫描
ADC_InitStruct.ADC_NbrOfChannel = 1; // 扫描模式下通道的数量
ADC_Init(ADC1, &ADC_InitStruct);
/* 中断和模拟看门狗在此配置 */
// 5. 开关控制
ADC_Cmd(ADC1, ENABLE);
// 6. 对ADC进行校准
ADC_ResetCalibration(ADC1); // 复位校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成
ADC_StartCalibration(ADC1); // 开始校准
while (ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成
}
/**
* @brief ADC结果读取函数(单次转换非扫描实现多通道转换,软件触发)
* @param 无
* @retval 转换之后的结果
*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); // 把通道作为参数填入序列1中,通道的采样周期是55.5个ADCCLK的周期
// 1. 软件触发开启转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
// 3. 读取ADC数据寄存器并返回
return ADC_GetConversionValue(ADC1); // 读取之后会自动清除EOC标志位
}
更多推荐



所有评论(0)