STM32入门笔记08_ADC模数转换器+案例: ADC单通道&ADC多通道

文章详细介绍了STM32F103C8T6微控制器中的ADC模数转换器的工作原理,包括12位逐次逼近型ADC的特性、转换时间、通道配置、数据对齐以及校准过程。并提供了单通道和多通道ADC转换的C语言配置代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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基本结构

在这里插入图片描述

输入通道

通道ADC1ADC2ADC3
通道0PA0PA0PA0
通道1PA1PA1PA1
通道2PA2PA2PA2
通道3PA3PA3PA3
通道4PA4PA4PF6
通道5PA5PA5PF7
通道6PA6PA6PF8
通道7PA7PA7PF9
通道8PB0PB0PF10
通道9PB1PB1
通道10PC0PC0PC0
通道11PC1PC1PC1
通道12PC2PC2PC2
通道13PC3PC3PC3
通道14PC4PC4
通道15PC5PC5
通道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时钟周期

硬件电路

在这里插入图片描述

案例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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值