STM32F103ZET6【标准库函数开发】------06 ADC实验

本文深入解析STM32的12位逐次逼近型ADC模块,包括其18个通道配置、转换模式、采样时间和转换速率。通过实例演示如何使用ADC1通道1(PA1)进行外部电压采样,涉及时钟配置、初始化、校准和读取转换结果的详细步骤。

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

STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。
STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。
STM32F103ZET 包含有 3 个 ADC,分别为ADC1,ADC2,ADC3。
在这里插入图片描述

对于每个要转换的通道,采样时间建议尽量长一点,以获得较高的准确度,但是这样会降
低 ADC 的转换速率。 ADC 的转换时间可以由以下公式计算:
Tcovn=采样时间+12.5 个周期
其中: Tcovn 为总转换时间,采样时间是根据每个通道的 SMP 位的设置来决定的。例如,当 ADCCLK=14Mhz 的时候,并设置 1.5 个周期的采样时间,则得到: Tcovn=1.5+12.5=14 个周期=14*1/14us=1us。

我们介绍一下我们执行规则通道的单次转换,需要用到的 ADC 寄存器。
1.ADC 控制寄存器(ADC_CR1 和 ADC_CR2)
2. ADC 采样事件寄存器(ADC_SMPR1 和 ADC_SMPR2),这两个寄存器用于设置通道 0~17 的采样时间,每个通道占用 3 个位。
3.ADC 规则序列寄存器(ADC_SQR1~3) ,该寄存器总共有 3 个,这几个寄存器的功能都差不多。
4.ADC 规则数据寄存器(ADC_DR)。规则序列中的 AD 转化结果都将被存在这个寄存器里面,而注入通道的转换结果被保存在 ADC_JDRx 里面。
5.ADC 寄存器为 ADC 状态寄存器(ADC_SR),该寄存器保存了 ADC 转换时的各种状态。

一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一一
本次将利用 STM32F1 的 ADC1通道 1(PA1) 来采样外部电压值,并通过串口调试助手打印出来。

1)开启PA和ADC1时钟+PA1初始化:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );//使能PA和ADC1通道时钟
//PA1 作为模拟通道输入引脚                         
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;		//模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
2)复位ADC1+ 设置分频因子:
ADC_DeInit(ADC1);  //复位ADC1
RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。

3)ADC初始化
ADC_InitTypeDef ADC_InitStructure; 
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
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数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;	//顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 
4)ADC使能并校准
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1	
	ADC_ResetCalibration(ADC1);	//复位校准  	 
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准结束	
	ADC_StartCalibration(ADC1);	 //ADC1校准
	while(ADC_GetCalibrationStatus(ADC1));	 //等待ADC1校准结束 
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	 //使能ADC1的软件转换启动功能
5)读取ADC的值
u16 Get_Adc(u8 ch)   
{
  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );	//ADC1,ADC通道,采样时间为239.5周期	  			     
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		//使能指定的ADC1的软件转换启动功能		 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average(u8 ch,u8 times)  //多次测量求平均值
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
} 	
/*******************************************************************************/
ch是ADC通道,可选择如下
#define IS_ADC_CHANNEL(CHANNEL) (((CHANNEL) == ADC_Channel_0) || ((CHANNEL) == ADC_Channel_1) || \
                                 ((CHANNEL) == ADC_Channel_2) || ((CHANNEL) == ADC_Channel_3) || \
                                 ((CHANNEL) == ADC_Channel_4) || ((CHANNEL) == ADC_Channel_5) || \
                                 ((CHANNEL) == ADC_Channel_6) || ((CHANNEL) == ADC_Channel_7) || \
                                 ((CHANNEL) == ADC_Channel_8) || ((CHANNEL) == ADC_Channel_9) || \
                                 ((CHANNEL) == ADC_Channel_10) || ((CHANNEL) == ADC_Channel_11) || \
                                 ((CHANNEL) == ADC_Channel_12) || ((CHANNEL) == ADC_Channel_13) || \
                                 ((CHANNEL) == ADC_Channel_14) || ((CHANNEL) == ADC_Channel_15) || \
                                 ((CHANNEL) == ADC_Channel_16) || ((CHANNEL) == ADC_Channel_17))
6)主函数
 int main(void)
 {	 
  u16 adcx;
	float temp;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为115200	 	
 	Adc_Init();		  		//ADC初始化

	while(1)
	{
		adcx=Get_Adc_Average(ADC_Channel_1,10);
		temp=(float)adcx*(3.3/4096);
		printf("ADC的值为:%.8f\r\n",temp);//将采集到的ADC的值打印到串口
		delay_ms(250);	
	}
 }
图1
图2
<think>好的,用户想在STM32F103ZE项目中实现电压和电流采集,需要教程和示例代码,特别是ADC配置部分。首先,我需要回忆一下STM32F103系列的ADC相关知识,尤其是关于STM32F103ZE的具体特性。 用户提到的参考引用[1]是关于STM32F103RB的DMA支持,而STM32F103ZE属于同一系列,但可能有更多资源,比如更多的ADC通道或DMA通道。需要确认ZE型号的ADC配置是否与RB类似,通常基本配置是相同的,但引脚和通道可能不同。 首先,电压和电流采集通常需要使用ADC模块。电流采集可能需要使用采样电阻,将电流转换为电压,再通过ADC读取。需要注意信号调理电路,比如运放放大或滤波,以确保ADC测量的准确性。 接下来,用户需要教程和示例代码。我应该分步骤说明ADC的配置过程,包括初始化、通道选择、采样时间设置,可能涉及DMA或中断方式。STM32的标准外设库(Standard Peripheral Library)或HAL库都是常用的,但用户可能更熟悉标准库,因为STM32F1系列常用它。 需要考虑ADC的工作模式,是否单次转换还是连续扫描,是否使用多通道。如果同时采集电压和电流,可能需要配置多个通道,并设置扫描模式。DMA的使用可以减轻CPU负担,特别是在多通道或高速采样时。 另外,STM32F103ZE的ADC分辨率是12位,参考电压通常为3.3V,所以需要计算实际电压值。对于电流,假设使用采样电阻,计算电流时需要知道电阻值和放大倍数。 可能还需要校准ADC,虽然上电后可能有默认校准,但为了精度,可能需要手动执行校准步骤。 示例代码部分需要展示ADC初始化函数、GPIO配置、DMA配置(如果使用),以及读取ADC值的函数。同时,要说明如何将ADC值转换为实际电压或电流值。 用户可能遇到的问题包括ADC引脚配置错误、采样时间不足导致精度不够、DMA传输配置错误等,应该在注意事项中提到这些点。 最后,生成相关问题,帮助用户深入理解,比如多通道采集、DMA使用、软件滤波方法等。</think>### STM32F103ZE电压电流采集方案 #### 一、硬件设计要点 1. **电压采集**:直接通过分压电路接入ADC输入引脚,确保输入电压不超过3.3V[^1] 2. **电流采集**:使用采样电阻+运放电路,将电流转换为电压信号,例如: - 采样电阻$R_{sense}=0.1Ω$ - 运放放大倍数$G=10$,则$V_{out}=I \times R_{sense} \times G$ #### 二、ADC配置步骤 1. **GPIO初始化** ```c // 配置PA1为模拟输入(ADC1通道1) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); ``` 2. **ADC基础配置** ```c ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 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); ``` 3. **校准与使能** ```c ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ``` #### 三、完整示例代码 ```c #include "stm32f10x.h" void ADC1_Init(void) { // 1. 时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); // 2. GPIO配置 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. ADC参数配置 ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 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); // 4. 通道配置 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); // 5. 校准 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } uint16_t Get_ADC_Value(void) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); } // 电压转换公式:V = (ADC_Value * 3.3) / 4095 ``` #### 四、注意事项 1. 参考电压需稳定,建议使用独立基准电压源 2. 采样时间设置需根据信号源阻抗调整,高阻抗源需要更长时间 3. 多通道采集时需启用扫描模式并配置DMA 4. 注意模拟信号走线与数字信号的隔离
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值