网站建设.国风网络,wordpress答题跳转,wordpress 极简 h5,百度一下你知道一.模数转换原理
ADC模拟-数字转换器可以将引脚上连续变化的模拟电压转换成内存中存储的数字变量#xff0c;建立模拟电路到数字电路的桥梁。另外一种是DAC既是与前面相反#xff0c;如PWM波#xff0c;由于PWM电路简单且没有额外的功率损耗#xff0c;更适用于惯性系统的…一.模数转换原理
ADC模拟-数字转换器可以将引脚上连续变化的模拟电压转换成内存中存储的数字变量建立模拟电路到数字电路的桥梁。另外一种是DAC既是与前面相反如PWM波由于PWM电路简单且没有额外的功率损耗更适用于惯性系统的场景
以下呢是ADC的STM32介绍 12位逐次逼近型ADC1us转换时间信号频率较高时需要注意。输入电压范围0~3.3V转换结果范围0~4095。18个输入通道可测量16个外部GPIO口和2个内部信号源内部温度传感器和内部参考电压。内部温度传感器可以测量芯片温度比如电脑CPU的温度显示。内部参考电压是一个1.2V左右的基准电压不随外部供电电压变化。如果外部供电电压不是3.3V那读取GPIO口的电压就不对此时就可以通过读取这个基准电压来校准。规则组和注入组两个转换单元是stm32的ADC增强功能。模拟看门狗自动监测输入电压范围当AD值高于上阈值或低于下阈值时就会申请中断可减轻软件负担。STM32F103C8T6 ADC资源ADC1、ADC210个外部输入通道。 1.1 ADC电路结构
stm32采用逐次逼近型ADC结构现用ADC0809介绍这种结构 ADC0809是一个独立的8位逐次逼近型ADC单片机内部没有集成ADC时需要外挂ADC芯片ADC0809就是这么一款经典的ADC芯片。现在很多单片机内部已经集成了ADC外设就不需要外挂芯片可以直接测量电压。IN7~IN08路模拟输入。ADDA、ADDB、ADDC、ALE地址锁存选择当前的模拟输入引脚。相当于38译码器。CLOCK时钟线。START开始AD转换。EOC转换结束标志位。内部DAC加权电阻网络用于产生和输入模拟信号进行比较的模拟信号。OE输出使能控制三态门输出。D7~D0输出的8位数字信号。VREF()、V~REF(-)参考电压。 单个ADC框图 ADCx_IN0~ADCx_IN15、温度传感器、VREFINTADC的16个输入通道。注入通道【使用不多】最多一次性选4路通道配合4个16位寄存器就可以一次性转换4路模拟数据。规则通道【常用】最多一次性选16路通道但只有1个16位寄存器存在新来的数据覆盖上一个数据的问题此时要么尽快将数据取走要是使用DMA帮助转运数据进而可以实现一次性转换16路模拟数据。当然一次就选一个通道就是普通的ADC功能。触发转换电路stm32中的ADC触发方式软件触发在程序中手动调一句代码。硬件触发上图所示的触发源。主要来自于定时器TIMx也可以外部中断引脚EXTI。正常思路是定时器每隔1ms产生一次中断 -- 中断函数中开启触发转换信号 -- ADC完成一次转换。缺点是需要频繁进入中断消耗软件资源。但是得益于上图的硬件电路设计stm32可以直接使用定时器主模式触发ADC转换硬件全自动无需申请中断可以极大地减轻CPU负担。VDDA、VSSAADC的供电引脚。VREF、VREF-ADC的参考电压决定了ADC的输入电压的范围。stm32内部已经和VDDA、VSSA连接在一起了。ADCCLK来自ADC的预分频器这个ADC的预分频器则来自于“RCC时钟树”。具体可以查看时钟树的电路默认情况就是对72MHz进行ADC预分频由于ADCCLK最大18MHz所以只能选择6分频/8分频。DMA请求触发DMA进行数据转运。下一章讲。注入通道数据寄存器、规则通道数据寄存器用于存放转换结果。模拟看门狗一旦高于上阈值或低于下阈值就会申请模拟看门狗的中断最终进入NVIC。转换结束EOC规则通道转换完成会在状态寄存器置标志位。注入转换结束JEOC注入通道转换完成会在状态寄存器置标志位。NVIC嵌套向量中断控制器控制是否响应上面这三个中断。 1.2引脚复用关系 其中ADC1和ADC2功用引脚不仅可以单独使用可以组成更加复杂的双ADC模式通过配合可以组成同步模式交叉模式ADC1和ADC2交叉对同一个通道进行采样以提高采样率 1.3规则组的转换模式
stm32的ADC最多同时支持16个通道那么ADC每次扫描1个通道还是多个通道便是选择 非扫描模式/扫描模式而对于单个通道的ADC转换来说触发一次ADC是只转换一次还是自动的进行连续转换便是选择 单次转换/连续转换。上面这两种选择进行组合便产生了 规则组的4种转换模式
1单次转换非扫描模式
触发一次仅转换一次仅序列1有效但可以任意指定需要转换的通道。此时ADC选择一组的方式退化成只能选择一个。读取数据时需要等待EOC标志位置1然后从数据寄存器读取结果。如要再进行转换就需要再次触发转换。 2连续转换非扫描模式 相比于上一个模式仅需要一次触发ADC就会在一次转换完成后立刻进入下一次转换实现不断地自动进行转换。此时就不需要读EOC看转换是否完成直接想读数据的时候就读。
3单次扫描扫描模式
相比于第一种模式可以一次性转换多个通道不过还是触发一次、所有通道只转换一次。 4连续转换扫描模式
不仅可以一次性转换多个通道还可以实现触发一次、自动不间断转换。 1.4触发转换信号 上一小节提到要想ADC进行转换还需要完成 触发 这个操作。触发信号可以是 软件触发、硬件触发。软件触发可以由ADC的库函数完成硬件触发见上图。
1.5数据对齐 因为ADC是12位的而寄存器宽度为16位所有便有了数据对齐方式的选择。 右对齐【常用】读出的值就是实际值。左对齐有时候不需要太大的分辨率便将12位ADC的转换数据左对齐然后只取高8位。 1.6转换时间 低速采样可以忽略转换频率高速采样必须考虑转换时间 的损耗。AD转换的步骤主要为采样保持量化编码。“采样”时间越长越可以消除一些毛刺信号的干扰而“量化、编码”消耗的时间则比“采样、保持”更长。在STM32中ADC的总转换时间 为 T C O N V 采样时间 12.5 个 A D C 周期 T_{CONV} 采样时间 12.5个ADC周期 T CONV 采样时间12.5个ADC周期
采样时间在配置ADC的多路选择开关时可选是ADC采样周期的倍数如1.5倍、7.5倍、13.5倍、……、239.5倍。 ADC周期就是从RCC分频过来的RCCCLK(最高14MHz)总采样时间不会小于1 μ s 1\mu s1μs。
1.7校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间在每个电容器上都会计算出一个误差修正码(数字值)这个码用于消除在随后的转换中每个电容器上产生的误差。 建议在每次上电后执行一次校准。启动校准前 ADC必须处于关电状态超过至少两个ADC时钟周期。校准过程的代码是固定的只需要在ADC初始化之后加几句代码即可。 1.8外围电路设计 在设计ADC的模拟输入源时为确保电路安全可选择以下几种方案电位器产生可调电压注意阻值不要太小(最少为kΩ级)以防烧毁电位器。传感器输出电压如光敏电阻、热敏电阻、红外接收管、麦克风等都可以等效为一个可变电阻。通过与一个固定电阻应于传感器阻值相近进行分压从而输出可调电压此电路图中输出电压与传感器阻值成正比。比如本节就直接用传感器模块的AO引脚。简易电压转换电路经过分压后就可以采集05V、010V的输入电压值但是若电压再高建议使用专用的采集芯片如隔离放大器等做好高低电压的隔离进而保护电路安全。 二.ADC单通道 main.c
#include stm32f10x.h // Device header
#include OLED.h
#include ADC_User.hint main(void){//OLED显示屏初始化OLED_Init();OLED_ShowString(1,1,Voltage-PA0:);OLED_ShowString(2,1,00.00 V); //ADC初始化ADC_User_Init();ADC_User_Start();while(1){OLED_ShowFloat(2,1,(float)ADC_User_Get()*3.3/4095,2,2);};
} - ADC_User.h
#ifndef __ADC_USER_H
#define __ADC_USER_Hvoid ADC_User_Init(void);
void ADC_User_Start(void);
uint16_t ADC_User_Get(void);#endif
- ADC_User.c
#include stm32f10x.h // Device header//ADC初始化-规则组PA0
void ADC_User_Init(void){//1.开启外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//6分频使得ADC时钟为12MHz//2.配置GPIOGPIO_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(GPIOA, GPIO_InitStructure);//3.配置多路开关选择通道进入规则组ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);//4.配置ADC转换器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ContinuousConvMode ENABLE;//连续转换ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right;//数据右对齐ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None;//不使用外部触发软件触发ADC_InitStructure.ADC_Mode ADC_Mode_Independent;//独立模式ADC_InitStructure.ADC_NbrOfChannel 1;//只有1个通道非扫描模式参数不起作用ADC_InitStructure.ADC_ScanConvMode DISABLE;//非扫描模式因为是单通道ADC_Init(ADC1, ADC_InitStructure);//5.配置开关控制ADC_Cmd(ADC1, ENABLE);//6.进行ADC校准ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1)SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1)SET);
}//对ADC进行一次软件触发
void ADC_User_Start(void){ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}//获取ADC转换结果
uint16_t ADC_User_Get(void){//等待转换完成并读取while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) RESET);return ADC_GetConversionValue(ADC1);//硬件会自动清除EOC标志位
} GPIO配置成模拟输入AIN模式。AIN模式下GPIO口无效可以防止GPIO的输入输出对模拟电压造成干扰。AIN模式是ADC的专属模式。实际测试中浮空输入、上拉输入、模拟输入的展示效果几乎没有区别但是硬件原理完全不同。函数提示设置找到扳手图标—-Text Completion栏—-把Show Code Completion List For下面的框全部勾上。读取规则组数据后无需软件清除EOC标志位。参考手册中说明读取ADCC_DR就会自动清除EOC标志位。所以参考手册还是非常重要关于数据抖动。实测发现ADC转换后的结果会抖动若想消除这种现象可以有以下几种方法迟滞比较设置两个阈值低于下阈值执行操作高于上阈值执行操作。滤波如均值滤波LPF。裁剪分辨率去除转换结果的最后抖动的几位。 三。ADC多通道 同时获取电位器、光敏电阻模块、热敏电阻模块、反射红外模块共四组数字量。 main.c
#include stm32f10x.h // Device header
#include OLED.h
#include ADC_User.hint main(void){int i 0;//OLED显示屏初始化OLED_Init();OLED_ShowString(1,1,C0:00.00 V);OLED_ShowString(2,1,C1:00.00 V);OLED_ShowString(3,1,C2:00.00 V);OLED_ShowString(4,1,C3:00.00 V);//ADC初始化ADC_User_InitMuti();while(1){for (i0;i4;i){ADC_User_MutiSel(i);ADC_User_Start();OLED_ShowFloat(i1,4,(float)ADC_User_Get()*3.3/4095,2,2);}};
}
ADC_User.c
//ADC多通道初始化-ADC1的通道0~3-PA0~PA3共四个通道
void ADC_User_InitMuti(void){//1.开启外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//6分频使得ADC时钟为12MHz//2.配置GPIOGPIO_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);//3.配置多路开关选择通道进入规则组ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);//4.配置ADC转换器ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_ContinuousConvMode DISABLE;//单次转换ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right;//数据右对齐ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None;//不使用外部触发软件触发ADC_InitStructure.ADC_Mode ADC_Mode_Independent;//独立模式ADC_InitStructure.ADC_NbrOfChannel 1;//只有1个通道非扫描模式参数不起作用ADC_InitStructure.ADC_ScanConvMode DISABLE;//非扫描模式因为是单通道ADC_Init(ADC1, ADC_InitStructure);//5.配置开关控制ADC_Cmd(ADC1, ENABLE);//6.进行ADC校准ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1)SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1)SET);
}//使用ADC的多路开关选择哪个通道
//通道范围0~3
void ADC_User_MutiSel(uint16_t channelx){switch(channelx){case 0: ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5); break;case 1: ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_1Cycles5); break;case 2: ADC_RegularChannelConfig(ADC1,ADC_Channel_2,1,ADC_SampleTime_1Cycles5); break;case 3: ADC_RegularChannelConfig(ADC1,ADC_Channel_3,1,ADC_SampleTime_1Cycles5); break;default: ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5); break;}
}
//注意别忘了在ADC_User.h头文件中声明up感言 如何实现多通道ADC。若使用扫描模式实现多通道ADC需要考虑数据覆盖的问题。下面是几种实现ADC多通道的思路 扫描模式DMA转运数据DMA是转运多通道数据的最优解但下节才学DMA本节用不了。 扫描模式手动转运数据存在两个问题一个是ADC在最后一个通道转换完成后才会产生EOC标志位此时数据寄存器早就被覆盖成最后一个通道的数据了所以无法确定某个通道的转运时刻ADC转换速度非常快对于手动转运数据的要求非常高。解决思路就是使用间断模式可以使ADC每转换一个通道就暂停一次等待下一次触发才进行下一个通道的转换。于是便可以触发–Delay一段足够长的时间–手动转运完数据–触发……不难发现效率极低。 非扫描模式“时分复用”【本节思路】还是采用“单次转换、非扫描模式”的单路ADC但是可以不断第更换通道–触发ADC–读取数据以软件完成扫描模式进而实现多路ADC“单次转换、扫描模式”的功能。