学习STM32第十天

ADC模数转换器

一、存储器映像

当身边没有STlink时,可以使用串口对STM32进行下载程序。但是要开发板要支持串口下载程序,需要将BOOT0跳线到 高电平,此时MCU是系统存储器启动,同时按一下复位键。MCU只有在刚复位时才会读取BOOT引脚并进入BootLoader程序(自举程序),然后不断接收USART1的数据并刷新到主闪存,下载完程序需要将BOOT0恢复低电平同时按一下复位键,程序才会执行。
存储器映像
由上图可知BootLoader不断将程序刷新到起始地址为0x0800 0000的Flash中。可以设计一键下载电路免去跳冒步骤。其中选项字节可以设置读保护(在取消读保护时会清空芯片程序)、硬件参数用户参数写保护等,这些字节可存储不随程序变化而变化的参数,可以用上位机修改并用串口下载。

二、ADC

ADC可将引脚上连续变化的模拟电压转换为数字变量,建立模拟电路到数字电路的桥梁。ADC步骤:采样、保持、量化、编码,总转换时间 T C O N V = 采样时间 + 12.5 个 A D C 周期 T_{CONV}=采样时间+12.5个ADC周期 TCONV=采样时间+12.5ADC周期,12位需要比较12次,多的0.5周期是其他时间。如果要达到最快采样,则需要设置采样时间为1.5个周期,最短转换时间 T C O N V m i n = 14 个 A D C 周期 T_{CONV_{min}} = 14个ADC周期 TCONVmin=14ADC周期,而ADC采样频率最大是14MHz,最短转换时间 T C O N V m i n = 1 u s T_{CONV_{min}} = 1us TCONVmin=1us采样时间越长,采样结果越稳定。F407VET6有三组12位ADC,1us转换时间(转换频率为1MHz),每组最多有16个外部通道。模拟看门狗自动检测输入电压范围,通过阈值判断。
逐次逼近型ADC
ADC外设采用逐次逼近型,上图是一个8位逐次逼近型ADC芯片。从8个输入通道中任选一个输入待测信号,由地址锁存和译码进行通道的选择,然后通过比较器将模拟信号进行对应位数的数字编码,一般采用二分法进行比较,12位的ADC就需要进行12次比较,最后由8位三态锁存缓冲器输出。 V R E F ( + ) V_{REF(+)} VREF(+) V R E F ( − ) V_{REF(-)} VREF()是DAC参考电压,决定了ADC的输入范围,也是ADC的参考电压。
ADC框图
通过16个GPIO口、一个内部温度传感器、一个内部参考电压和一个外置电池电压共19路输入。通过模拟多路开关选择所需输入,在模数转换器中进行逐次比较并将结果存储在数据寄存器中。进入模数转换器有两组通道。

  • 规则通道
    一般使用的就是这个通道,最多可选中16个通道,但是规则通道只能存一个通道的比较结果,最好配合DMA实现,即完成比较后立即将数据转移到其他位置。
  • 注入通道
    能插队的通道,在规则通道转换的时候强行插入要转换的一种通道。 如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程,只有在规则通道存在时才会出现注入通道。最多可选中4个通道,注入通道有4个数据寄存器,可同时处理4个通道的信号。
    ADC基本结构
    三组ADC有共用的GPIO口,需要进行引脚复用配置,还存在双ADC模式,即两个ADC可配置为同步模式、交叉模式等等。
    规则组有四种转换模式
  • 单次转换,非扫描模式
    为所需信号选择合适的通道进行转换即可,只有第一个序列1的位置有效,转换完成后输出EOC标志,通过新的触发才能开始下一轮的转换
  • 连续转换,非扫描模式
    只有第一个序列1的位置有效,但是在一次转换结束后不会停止而是立即开始下一轮的转换然后一直持续下去只需最开始触发一次
  • 单次转换,扫描模式
    通过设置通道数目,依次对所选通道进行转换,为避免转换数据被覆盖,需要DMA及时将数据挪走,待所选通道转换完毕后产生EOC信号,转换结束,然后再触发下一轮转换。
  • 连续转换,扫描模式
    设置通道数目,依次对所选通道进行转换,在一次转换完成后立即进行下一轮转换
    单次转换
    连续转换
    单次转换扫描模式
    连续转换扫描
    ADC触发控制
    对于规则通道,有以下外部触发。
    ADC用于规则通道的外部触发
    ADC数据对齐
    由于寄存器都是16位,而ADC转换结果是12位,因此需要进行数据对齐,分为左对齐和右对齐。注意二进制数据左移一位等效于把这个数据乘2
    ADC数据对齐
    ADC有一个内置自校准模式,校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间在每个电容器上都会计算出一个误差修正码用于消除在随后的转换中每个电容器上产生的误差,建议在每次上电后执行一次校准,启动校准前ADC必须处于关电状态超过至少两个ADC时钟周期
    关于ADC外围电路,有条件使用专业的ADC模块,不要直接与MCU相联

三、案例实验

  1. 使用ADC单通道采集电位器电压
    这里给出配置代码
void ADC_MYInit()
{
	//开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//配置GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//浮空
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//通用ADC配置
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//不使用DMA
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立ADC模式
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div6;//6分频,72MHz/6 = 12MHz
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//采样延时
	ADC_CommonInit(&ADC_CommonInitStructure);
	//配置ADC1,使用非扫描模式
	ADC_InitTypeDef ADC_InitStructure;
	ADC_StructInit(&ADC_InitStructure);
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//不使用连续转换
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
	ADC_InitStructure.ADC_NbrOfConversion = 1;//所用到的通道数量,仅在扫描模式下使用
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//采用12位分辨率
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_56Cycles);//规则通道0,次序1,采样时间为56个采样周期
	//F4系列不需要校准,内部自动校准
}

//获取采样结果
uint16_t ADC_GetValue()
{
	ADC_SoftwareStartConv(ADC1);//软件触发
	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//直到接收到转换结束标志退出循环
	return ADC_GetConversionValue(ADC1);//返回转换结果
}

  1. 使用ADC多通道
    这里采用单次转换、非扫描模式,在每次触发转换之前,手动更改列表第一个位置的通道
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
		
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	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;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}

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函数代码如下

uint16_t AD0, AD1, AD2, AD3;

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);
	}
}
  • 40
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值