ADC模数转换器(相当于电压表)
2026/5/13 22:26:10 网站建设 项目流程

1.ADC简介

1.简述(根据第二点):

原本只有高、低电平之分,现在通过ADC可以得到具体的电压值(数字电路只有高低电平)

2.转换频率:1MHz(根据第三点的1us转换时间)

3.模拟看门狗:

可以监测指定的某个通道(达到某个条件就会申请中断,在中断中执行某些操作)

4.另外:

DAC是数字-模拟转换器,PWM也是数字到模拟的桥梁,通过调整占空比来模拟信号

2.ADC内部结构

1.普通ADC内部结构

总结:通过比较器,DAC采用二分法输出已知编码的电压与输入电路中未知编码的电压比较,逐次逼近未知编码,最后输出正确的电压值(VREF是参考电压,结果取决于其电压值)

2.STM32的ADC内部结构

注意:注入通道由4个数据寄存器,可以同时存4个数据;而规则通道只有一个数据寄存器,同时传入16个数据时只能通过1个,其他的会被挤掉,所以最好配合DMA(数据转运帮手)使用。

触发ADC开始转换的信号:软件触发,程序中手写代码;硬件触发,利用定时器的更新事件触发,也可以选择外部中断引脚(即EXTI)来触发转换

VDDA和VSSA是内部模拟部分的电源

ADCCLK是用于驱动内部逐次比较的时钟,在RCC中通过ADC分频器后得到(最大14MHz),所以ADC分频器只能选择6分频(12MHz)和8分频(9MHz)

EOC:规则组的完成信号(标志位)

JEOC:注入组的完成信号(标志位)

3.ADC基本结构

部分解释:触发控制就是选择软件触发还是硬件触发,开关控制就是ADC_Cmd函数给ADC上电

4.细节

1.输入通道(对应的GPIO口)

注意:STM32只有ADC1和ADC2

2.规则组的4种转换模式

1.单次转换,非扫描模式

解释:在非扫描模式下,16个序列就只有序列1有效,在此选择通道后,ADC对这个通道进行模数转换,完成后在EOC置1即可。(每次都会结束)

2.连续转换,非扫描模式

解释:一直进行非扫描模式的转换。(像读AD值的时候直接读数据寄存器)

3.单次转换,扫描模式

解释:通道数目需要直接手动写入参数,在扫描模式下,16个序列可以自由使用,但是每次转换都会有多个结果放在数据寄存器里,这就意味着需要用DMA及时将数据挪走。

4.连续转换,扫描模式

上面已经解释过两个模式的具体区别,在此不再解释。

3.触发控制(规则组的触发源)

倒数第二个触发源的类型究竟是引脚还是定时器需要用AFIO重映射来确定

4.数据对齐

原因:ADC是12位的,转换结果是一个12位的数据,但是数据寄存器是16位的(一般用右对齐)

5.转换时间

这就是稳定情况下最快1us的来源

6.校准(了解)

5.实战代码

1.部分函数的功能

//ADCCLK的配置函数(配置ADCCLK分频器) void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); //配置ADC转换器 void ADC_DeInit(ADC_TypeDef* ADCx); void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct); void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//开启DMA输出信号 void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);//中断输出控制 void ADC_ResetCalibration(ADC_TypeDef* ADCx);//复位校准 FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);//获取复位校准状态 void ADC_StartCalibration(ADC_TypeDef* ADCx);//开始校准 FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);//获取开始校准状态 void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//用于软件触发 FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx); //ADC获取软件开始转换状态(不能判断是否结束) FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//获取标志位状态(看EOC) //配置间断模式 void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);//每隔几个通道间断一次 void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//是否启动间断模式 void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); //ADC规则组通道配置(在序列中选择通道) void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //ADC外部触发转换控制(是否允许外部触发转换) uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx); //ADC获取转值(读取AD转换的数据寄存器,即读取转换结果) uint32_t ADC_GetDualModeConversionValue(void); //ADC获取双模式转换值 //注入组 void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv); void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx); void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length); void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset); uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel); //模拟看门狗 void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog); //是否启动看门狗 void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold); //配置高低阈值 void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel); //配置看门通道 //ADC温度传感器内部参考电压控制 void ADC_TempSensorVrefintCmd(FunctionalState NewState); FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//获取标志位状态 void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);//清除标志位 ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);//获取中断状态 void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);//清除中断挂起位

2.配置思路

1.RCC开启时钟(把GPIO和ADC的时钟打开,包括ADCCLK的分频器也要配置)

2.配置GPIO(配置成模拟输入模式)

3.配置开关,将左边的通道接入右边的规则组里(就是选择通道)

4.配置ADC转换器(转换模式、通道数、触发源、数据对齐等)

5.开启ADC

3.基本配置格式(AD单通道、非扫描模式)

//ADC都是APB2上的设备 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC1的时钟 //需要用到PA0口将可调的电压输出 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //配置ADCCLK RCC_ADCCLKConfig(RCC_PCLK2_Div6); //配置GPIO时钟 GPIO_InitTypeDef GPIO_InitStructure;//结构体定义 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //模拟输入(GPIO无效,即为ADC专属模式) GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//IO口 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); //选择规则组的输入通道(在序列1写入通道0) ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); //初始化ADC ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//ADC模式(独立还是双模式) 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 //校准 ADC_ResetCalibration(ADC1);//复位校准 while(ADC_GetResetCalibrationStatus(ADC1)==SET);//获取复位校准状态 ADC_StartCalibration(ADC1);//开始校准 while(ADC_GetCalibrationStatus(ADC1)==SET);//获取开始校准状态

4.程序编写的细节

1.避免AD的输出抖动,采用迟滞比较,即设置高低阈值,高于上阈值或低于下阈值才进行操作。

2.AD值跳变程度太高,可以采用滤波的方法或裁剪分辨率(即将数据尾部去掉)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询