AD模数转换器
ADC简介
- ADC(Analog-Digtal Converter) 模拟-数字转换器
- ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量, 建立模拟电路到数字电路的桥梁
- 12位逐次逼近型ADC, 1us转换时间
- 输入电压范围: 0~3.3V, 转换结果范围: 0~4095
- 18个输入通道, 可测量16个外部和2个内部信号源
- 规则组和注入组两个转换单元
- 模拟看门狗自动监测输入电压范围
- STM32F103C8T6 ADC资源: ADC1、ADC2, 10个外部输入通道
逐次逼近型ADC
- IN0~IN7是八个输入通道
- 通过配置ADDA~ADDC可以选择一个通道作为信号输入
- 通过比较器, DAC逐渐逼近输入信号, DAC的值最终与输入信号十分接近
ADC框图
ADC基本结构
输入通道
通道 | ADC1 | ADC2 | ADC3 |
---|---|---|---|
通道0 | PA0 | PA0 | PA0 |
通道1 | PA1 | PA1 | PA1 |
通道2 | PA2 | PA2 | PA2 |
通道3 | PA3 | PA3 | PA3 |
通道4 | PA4 | PA4 | PF6 |
通道5 | PA5 | PA5 | PF7 |
通道6 | PA6 | PA6 | PF8 |
通道7 | PA7 | PA7 | PF9 |
通道8 | PB0 | PB0 | PF10 |
通道9 | PB1 | PB1 | |
通道10 | PC0 | PC0 | PC0 |
通道11 | PC1 | PC1 | PC1 |
通道12 | PC2 | PC2 | PC2 |
通道13 | PC3 | PC3 | PC3 |
通道14 | PC4 | PC4 | |
通道15 | PC5 | PC5 | |
通道16 | 温度传感器 | ||
通道17 | 内部参考电压 |
转换模式
- 单次转换, 非扫描模式
- 连续转换, 非扫描模式
- 单次转换, 扫描模式
- 连续转换, 扫描模式
触发控制
数据对齐
- 数据右对齐:
- 数据左对齐:
转换时间
-
AD转换的步骤: 采样, 保持, 量化, 编码
-
STM32 ADC的总转换时间为:
Tconv = 采样时间 + 12.5个ADC周期
-
例如: 当ADCCLK = 14MHz, 采样时间为1.5个ADC周期
Tconv = 1.5 + 12.5 = 14个ADC周期 = 1us
校准
- ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的精准度误差。校准期间, 在每个电容器上都会计算出一个修正码(数字值), 这个码用于消除在随后的转换中每个电容器上产生的误差
- 建议在每次上电后执行一次校准
- 启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
硬件电路
文章来源:https://www.toymoban.com/news/detail-766225.html
案例1: ADC单通道
配置ADC转换
void AD_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz
// 配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 选择规则通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
// 配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换或者连续转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC模式, 单独还是交叉
ADC_InitStructure.ADC_NbrOfChannel = 1; // 扫描的通道数
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式或者非扫描模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发控制
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);
}
RCC_ADCCLKConfig
/**
* @brief Configures the ADC clock (ADCCLK).
* @param RCC_PCLK2: defines the ADC clock divider. This clock is derived from
* the APB2 clock (PCLK2).
* This parameter can be one of the following values:
* @arg RCC_PCLK2_Div2: ADC clock = PCLK2/2
* @arg RCC_PCLK2_Div4: ADC clock = PCLK2/4
* @arg RCC_PCLK2_Div6: ADC clock = PCLK2/6
* @arg RCC_PCLK2_Div8: ADC clock = PCLK2/8
* @retval None
*/
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)
ADC_ContinuousConvMode
*!< Specifies whether the conversion is performed in
Continuous or Single mode.
This parameter can be set to ENABLE or DISABLE. */
ADC_DataAlign
#define ADC_DataAlign_Right ((uint32_t)0x00000000)
#define ADC_DataAlign_Left ((uint32_t)0x00000800)
ADC_Mode
#define ADC_Mode_Independent ((uint32_t)0x00000000)
#define ADC_Mode_RegInjecSimult ((uint32_t)0x00010000)
#define ADC_Mode_RegSimult_AlterTrig ((uint32_t)0x00020000)
#define ADC_Mode_InjecSimult_FastInterl ((uint32_t)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl ((uint32_t)0x00040000)
#define ADC_Mode_InjecSimult ((uint32_t)0x00050000)
#define ADC_Mode_RegSimult ((uint32_t)0x00060000)
#define ADC_Mode_FastInterl ((uint32_t)0x00070000)
#define ADC_Mode_SlowInterl ((uint32_t)0x00080000)
#define ADC_Mode_AlterTrig ((uint32_t)0x00090000)
ADC_NbrOfChannel
/*!< Specifies the number of ADC channels that will be converted
using the sequencer for regular channel group.
This parameter must range from 1 to 16. */
ADC_ScanConvMode
/*!< Specifies whether the conversion is performed in
Scan (multichannels) or Single (one channel) mode.
This parameter can be set to ENABLE or DISABLE */
ADC_ExternalTrigConv
#define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) /*!< For ADC1 and ADC2 */
#define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */
#define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) /*!< For ADC3 only */
#define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) /*!< For ADC3 only */
整体代码:
ADC.c
#include "stm32f10x.h"
/*
初始化ADC
*/
void AD_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz
// 配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 选择规则通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
// 配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换或者连续转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC模式, 单独还是交叉
ADC_InitStructure.ADC_NbrOfChannel = 1; // 扫描的通道数
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式或者非扫描模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发控制
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模块转换的值
*/
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完毕
return ADC_GetConversionValue(ADC1);
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "OLED.h"
#include "ADC.h"
// ADC单通道
// 2023年3月25日19:12:09
uint16_t ADValue;
float volatge;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1, 1, "ADValue:");
OLED_ShowString(2, 1, "Volatge:0.00V");
while(1)
{
ADValue = AD_GetValue();
volatge = (float)ADValue / 4095 * 3.3;
OLED_ShowNum(1, 9, ADValue, 4);
OLED_ShowNum(2, 9, volatge, 1);
OLED_ShowNum(2, 11, (uint16_t)(volatge * 100)% 100, 2);
Delay_ms(100);
}
}
案例2: ADC多通道
整体代码
ADC.c
#include "stm32f10x.h"
/*
初始化ADC
*/
void AD_Init(void)
{
// RCC使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 12MHz
// 配置GPIO口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置ADC转换器
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换或者连续转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC模式, 单独还是交叉
ADC_InitStructure.ADC_NbrOfChannel = 1; // 扫描的通道数
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 扫描模式或者非扫描模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 触发控制
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模块转换的值
*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 软件触发
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完毕
return ADC_GetConversionValue(ADC1);
}
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "OLED.h"
#include "ADC.h"
// ADC多通道
// 2023年3月25日20:42:57
uint16_t AD0, AD1, AD2, AD3;
float volatge;
int main(void)
{
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);
}
}
参考资料
【STM32入门教程-2023持续更新中】 https://www.bilibili.com/video/BV1th411z7sn/?p=22&share_source=copy_web&vd_source=ee06a25b3dfb2900ab707b01fdff6667文章来源地址https://www.toymoban.com/news/detail-766225.html
到了这里,关于STM32入门笔记08_ADC模数转换器+案例: ADC单通道&ADC多通道的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!