STM32F103 ADC采样

ADC采样

ADC采样有一下几种方式:

  • 积分型
  • 逐次比较型
  • 并行比较型
  • 电容阵列逐次比较型
  • 压频变换型

stm32的adc采样

我们stm32的adc采样使用的是逐次比较型的方式进行采样的
配置过程也很容易实现,思路很简单:

  1. 配置初始化
  2. 配置软件/硬件采样方式
  3. 设置对齐方式
逐次逼近法

通过地址锁存和译码器选择ADC转换的输入通道。

然后进行比较,比较时使用一个DAC输入的电压作为参考,如果DAC电压比输入的电压大,就调小DAC的电压,DAC在改变的时候通过12位的比较逐次比较,直到DAC的电压达到分辨率的最大值,此时与外部输入的电压近似相等,把此时的DAC编码值作为外部输入电压的编码值。
在这里插入图片描述

所以过程可以分为:采样与保持量化与编码

在stm32f103里,转换时间 = 采样时间 + 12.5个ADC时钟周期
比如在ADCCLK为14Mhz的情况下 采样时间 = 1.5个ADC时钟周期(前提是采样时间寄存器相关控制位配置为000),转换时间为14个ADC时钟周期,总时间为1us。

stm32的ADC采样框图如下。
在这里插入图片描述

它有两种转换方式,一种规则转换,最大16个ADC通道同时转换,但是规则通道数据寄存器只有16位,所以只能存下最新的数据,故在读取数据时要注意时序,不过也可以一组规则转换里只转换一个通道;另一种是注入转换,它每次最多可以转换4个通道的数据,并且存放时也是保留了全部的数据。如果需要使用规则组的多通道转换一般需要搭配DMA来完成任务。

转换的开始信号可以由软件触发(即调用代码出发转换),也可以由触发源触发也就是图上EXTI_15和EXTI_11那里的触发源(一个是注入组的转换,一个是规则组的转换)
在这里插入图片描述

右边的ADCCLK是用来驱动ADC逐次比较的时钟,它的时钟来源于ADC预分频器,它又来自于RCC时钟的APB2,但是ADCCLK的最大频率是14MHz,而APB2的时钟频率是72MHz,所以在设置分频系数的时候取值是有限制的,要么取6获得12Mhz的ADCCLK,要么取8获得9MHz的ADCCLK。
在stm32的库函数里是这样定义分频系数的取值的:

#define RCC_PCLK2_Div2                   ((uint32_t)0x00000000)
#define RCC_PCLK2_Div4                   ((uint32_t)0x00004000)
#define RCC_PCLK2_Div6                   ((uint32_t)0x00008000)
#define RCC_PCLK2_Div8                   ((uint32_t)0x0000C000)

当ADC转换完成之后,会对转换完成标志位置位,如果是规则组转换完成,那么EOC标志位置位,如果是注入组转换完成,那么JEOC标志位置位(在图的最上面有说明),如果配置了转换完成的中断,那么结束后还可以触发相关的NVIC中断。

ADC通道的相关引脚如下:
在这里插入图片描述

ADC转换的顺序是可以配置的,比如我希望先转换通道3里的数据,然后再转换通道0里的数据,这些顺序是可以由使用者自行决定的,以下对转换顺序里的每个内容的位次称作序列,比如希望最先转换通道3里的数据,那么序列1所对应的内容就是通道3,希望第2位转换的数据来自通道0,那么序列2所对应的内容就是通道0。然后下面开始讨论ADC转换的4种转换模式。

ADC转换的4种转换模式
  • 单次转换,非扫描模式
    由触发信号触发转换,并且只转换序列0里的数据,然后停止,想要再次转换需要再次给入触发转换的信号。如果希望换一个通道转换数据,那么需要在开始转换前把序列0里的内容更改为其它通道。

  • 连续转换,非扫描模式
    和上一种模式的转换方式差不多,只是在给入转换触发信号后,不需要在转换结束后再次给入触发信号,ADC转换会持续进行。

  • 单次转换,扫描模式
    你需要告诉单片机需要转换的序列数量,然后单片机会依次转换序列里内容所指向的通道,并且只转换一次,当转换结束后EOC置位,如果需要再次转换,就需要再次给入触发转换的信号。

  • 连续转换,扫描模式
    和上一种转换的方式差不多,但是不需要在转换结束后再次给入触发信号,ADC转换会持续进行。

对齐模式

在采集数据之前,需要配置数据的左右对齐模式,由于数据寄存器是16位的,而stm32的采集分辨率是12位的,会有4位的数据空出来,左对齐就是把数据从高位到低位放在数据寄存器的高12位上,右对齐就是把数据从高位到低位放在数据寄存器的低12位上,一般用右对齐就好了。

校准

在stm32f103进行ADC采样之前需要进行校准步骤,并且启动校准前ADC需要处于关电状态超过2个ADC时钟周期,这个校准过程虽然复杂,但是在代码里却是固定的,只需要把相关代码写上去就行了。

寄存器

所涉及寄存器:
ADC状态寄存器(主要关注转换结束标志位)
ADC控制寄存器1(配置ADC的各种模式、是否允许中断等)
ADC控制寄存器2(主要是配置ADC转换的触发方式、数据对齐等)
ADC采样时间寄存器1(配置ADC的采样时间)
ADC规则组序列寄存器1/2/3(配置转换几个规则组序列,转换规则组的通道顺序)
ADC注入组序列寄存器(同上)
ADC注入数据寄存器x(存放注入组x的转换结果)
ADC规则数据寄存器(存放规则组的转换结果)

函数

主要用到的库函数:

ADC_RegularChannelConfig( ADCx, ADC_Channel_x , Rank_x , ADC_SampleTime);

上面的函数主要用于配置规则组转换的序列和采样时间,填入所使用的ADC,然后指定某个通道,再告诉函数你希望把这个通道配置的序列值是多少,最后指定该通道的采样时间。

ADC_SoftwareStartConvCmd(ADCx,ENABLE);

调用这个函数就可以通过软件来触发ADC采样。

然后等待采样完成即可读取采样结果

while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0);//等待采样结束

采样完毕之后调用函数获取采样结果

val = ADC_GetConversionValue(ADCx);

示例代码

代码
// 使用PC0作为采样引脚
void ADC_Init_PC0(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);    // 使能时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);   
		
  RCC_ADCCLKConfig(RCC_PCLK2_Div6);                      // ADCCLK的选择分频系数
    
  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(GPIOC,&GPIO_InitStructure);
    
  ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_239Cycles5);
    
  ADC_InitTypeDef ADC_InitStructure;
  ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;         					// Ö¸¶¨ADC¹¤×÷ÔÚ¶ÀÁ¢Ä£Ê½
  ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;     					// Ö¸¶¨ADCת»»½á¹ûÊý¾ÝΪÓÒ¶ÔÆëģʽ
  ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;        					// Á¬Ðøת»»ÉèÖùرգ¬¼´µ¥´Îת»»Ä£Ê½
  ADC_InitStructure.ADC_ScanConvMode=DISABLE;												// ·ÇÁ¬ÐøɨÃè
  ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; // ²»Ê¹ÓÃÍⲿ´¥·¢Ô´£¬Ê¹ÓÃÈí¼þ´¥·¢         
  ADC_InitStructure.ADC_NbrOfChannel=1;                         		// Ö¸¶¨×ª»»µÄÐòÁÐÊýÄ¿£¬±¾½ÚÀïֻʹÓÃÁËÒ»¸öIO¿Ú£¬ËùÒÔÖ»Òª1¸ö¾Í¹»ÁË              
  ADC_Init(ADC1,&ADC_InitStructure);
    
  ADC_Cmd(ADC1,ENABLE);															// ¿ªÆôADCµçÔ´
    
	/*У׼*/	
  ADC_ResetCalibration(ADC1);             				                
  while(SET==ADC_GetResetCalibrationStatus(ADC1));        
  ADC_StartCalibration(ADC1);                             
  while(SET==ADC_GetCalibrationStatus(ADC1));            
}

u16 get_adc_val(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE); 						// ¸øADC1Ò»¸ö´¥·¢×ª»»µÄÐźÅ
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0); // µÈ´ýת»»Íê³É
	
	return ADC_GetConversionValue(ADC1);
}



// 主函数
u16 ad_val = 0;
int main(void)
{
	OLED_Init();
	OLED_Clear();
	OLED_ShowString(1, 1, "ADC");
	OLED_ShowString(2, 1, "Initializing...");
	OLED_ShowString(3, 1, "val:----");
	ADC_Init_PC0();
	OLED_ShowString(2, 1, "Initialized    ");
	OLED_ShowString(3, 1, "val:    ");
	while (1)
	{
		ad_val = get_adc_val();
		OLED_ShowNum(3,5,ad_val,4);
	}
}
效果

【STM32】ADC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值