芯片型号:STM32F103RC
软件开发包:标准外设库
一、ADC基本结构
先是输入通道,即 16 个 GPIO 口和 2 个内部通道。
经过选择开关后,进入 AD 转换器,有两个组,即规则组和注入组。规则组最多可以选中 16 个通道,注入组最多可以选中 4 个通道。然后转换的结果存放在 AD 数据寄存器,其中规则组只有一个数据寄存器,而注入组有 4 个。
下面是触发控制,提供了开始转换的 START 信号,有软件触发和硬件触发两种。右边是来自 RCC 的 ADC 时钟,ADC 逐次比较的过程就是有这个时钟驱动的。
然后上面,可以布置一个模拟看门狗用于检测转换结果的范围,如果超出设定的阈值,就通过中断输出控制,向 NVIC 申请中断。另外,规则组和注入组转换完成后会有 EOC 信号,它会置一个标志位,也可以通过中断输出控制,向 NVIC 申请中断。
最后右下角还有一个开关控制,在库函数中就是 ADC_Cmd
函数,用于给 ADC 上电的。
二、ADC 初始化结构体详解
typedef struct
{
uint32_t ADC_Mode; // ADC 工作模式选择
FunctionalState ADC_ScanConvMode; // ADC 扫描(多通道)或者单次(单通道)模式选择
FunctionalState ADC_ContinuousConvMode; // ADC 单次转换或者连续转换选择
uint32_t ADC_ExternalTrigConv; // ADC 转换触发信号选择
uint32_t ADC_DataAlign; // ADC 数据寄存器对齐格式
uint8_t ADC_NbrOfChannel; // ADC 采集通道数
} ADC_InitTypeDef;
- ADC_Mode:选择 ADC 的模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选,一般使用一个 ADC 的独立模式。
- ADC_DataAlign:转换结果数据对齐模式,可选右对齐 ADC_DataAlign_Right 或者左对齐 ADC_DataAlign_Left。一般选择右对齐模式。
- ADC_ContinuousConvMode:可选参数为 ENABLE 和 DISABLE,配置是启动自动连续转换还是单次转换。使用 ENABLE 配置为自动连续转换;使用 DISABLE 配置为单次转换。
- ADC_ExternalTrigConv:外部触发选择,一般使用软件自动触发。
- ADC_ScanConvMode:可选参数为 ENABLE 和 DISABLE,配置是否使用扫描。如果是单通道 AD 转换使用 DISABLE,如果是多通道 AD 转换使用 ENABLE。
- ADC_NbrOfChannel: AD 转换通道数目,该参数仅在扫描模式下才需要用,如果是非扫描的模式,整个列表只有第一个序列有效,无论写多少数目,最终都是只有序列 1 有效。
三、编程要点
-
初始化 ADC 用到的 GPIO,配置为模拟输入;
-
设置 ADC 工作时钟;
使用函数
RCC_ADCCLKConfig
。 -
配置选择开关,连接通道和组,一般使用规则组;
规则组使用函数
ADC_RegularChannelConfig
。 -
初始化 ADC 结构体;
-
使能 ADC;
-
校准。
除此之外:
- 如果需要模拟看门狗,可以使用相关函数配置阈值和检测通道;
- 如果想开启中断,就使用中断控制函数开启对应的中断输出,然后配置 NVIC;
- 如果想用软件触发转换,可以调用函数
ADC_SoftwareStartConvCmd
。
四、举例
4.1 AD 单通道,单次转换,非扫描模式
- 初始化 GPIO
void AD_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 设置为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
- 配置 ADC
void AD_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 配置ADC时钟为PCLK2的6分频(72M/6 = 12MHz)
// 配置ADC1的规则通道11,采样时间为55.5个周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 设置ADC工作在独立模式
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; // 设置转换通道数量为1
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); // 使能ADC1
ADC_ResetCalibration(ADC1); // 复位ADC1的校准寄存器
while (ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准结束
ADC_StartCalibration(ADC1); // 启动ADC1的校准
while (ADC_GetCalibrationStatus(ADC1) == SET); // 等待校准完成
}
- 获取 ADC 的转换结果
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动ADC1的软件转换
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换结束标志位置位
return ADC_GetConversionValue(ADC1); // 获取ADC1的转换值
}
如果使用连续转换,非扫描模式,则需要做出以下变动:
因为连续转换在一次转换结束后不会停止,而是立刻开始下一轮的转换,所以可以将启动软件转换的代码放在配置 ADC 校准后面的,即放在 AD_Config
里。同时在读取 ADC 的转换结果时,也不需要判断标志位了,获取 ADC 的转换结果的函数改变如下,
uint16_t AD_GetValue(void)
{
return ADC_GetConversionValue(ADC1); // 获取ADC1的转换值
}
4.2 AD 多通道,单次转换,非扫描模式
使用单次转换,非扫描模式实现多通道,只需要在每次触发转换之前,手动更改一下列表第一个位置的通道就行了。
以使用两个通道为例,在 AD 单通道的基础上,需要做出如下更改:
- 为了方便,可以使用相邻的 GPIO,如 pc0 和 pc1,这样只需将
AD_GPIO_Config
中的
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
改为
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
这样就完成了 pc0 和 pc1 的初始化。
- pc0 和 pc1 分别对应
ADC_Channel_10
和ADC_Channel_11
,对应通道不同,所以将函数AD_Config
中的
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
提出来放进 AD_GetValue
函数并进行改写
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
// 配置ADC的规则通道,采样时间为55.5个周期
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动ADC1的软件转换
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换结束标志位置位
return ADC_GetConversionValue(ADC1); // 获取ADC1的转换值
}
实现在每次触发转换之前,手动更改一下列表第一个位置的通道。
参考视频源于B站up主: 野火科技、江协科技
参考文档:《STM32库开发实战指南——基于野火MINI开发板》