STM32F103C8T6的ADC:ADC1、ADC2
实际通道:共10个,ADC1与ADC2共引脚,PA0~PA7,PB0~PB1
F1系列最多输入通道:共18个通道,16个外部,2个内部(温度传感器、内部参考电压)
不同引脚所对应的ADC通道不同!!!
只改变引脚而不改变通道的话,会导致ADC转换无效。
也就是ADC12_INx的x就是不同引脚对应的通道。(24.10.11晚)
ADC工作模式:
①独立模式(常用):单个ADC进行工作。
②多重模式:多个ADC进行工作,就是近似能同时读取不同通道的值,能够提高转换效率,。
(不甚了解多重模式,目前已知是一个ADC作为主ADC,其他ADC作为从ADC,从ADC在主ADC工作一段时间后(大约是一个采样周期后)才会启动)
ADC工作步骤:
采样——>保持——>量化——>编码
采样:接收传感器传输的数据
保持:保存数据。定格数据,不再接收新的数据,避免一直采样导致数据一直波动,无法正常量化的情况。
量化:将连续的模拟信号值近似为有限多个离散值。量化精度与分辨率有关。
编码:将量化后的数字值转换为二进制数字的过程。
分辨率:ADC的分辨率是指其能够分辨量化的最小信号的能力,一个12位的ADC,其分辨率就是12位。
对于3.3v供电且参考电压(VREF–、VREF+)与电源(VDDA 和、VSSA )相接的板子而言,也就是可以把电源电压3.3v用0~4095范围内的值来量化。
ADC工作原理:逐次逼近。
逐逼与二分法类似,实现方式是从最高位起开始判断置1或0后,硬件的值与输入值的大小关系。
若置1大则0,若置1小则1,然后下一位,直至最低位也操作完成。
(样例供参考:5位二进制数,值18)
在ADC的逐次逼近型寄存器,就会从高位开始置位,并根据置位不同产生的不同电压来匹配外部输入的电压(0v~3.3v),要是接近的话,那么此时的置位结果从二进制转化为十进制数就是ADC的转换结果(会自动放在对应组别的数据寄存器里)。多少位的ADC,就要判断多少次
ADC通道分组:
规则组(Regular Group):
最多有16个通道。
但由于只有1个规则组数据寄存器,对于多次转化或扫描转换,需要配合DMA使用,否则新数据会覆盖旧数据,最终只能读取到最新的数据。
注入组(Injected Group):
最多有4个通道。
犹豫刚好有4个注入组数据寄存器,因此可以保证不同通道同时转换,而数据不被覆盖。
区别:注入组可以中断规则组的转换,优先转自己的。
通道的操作:既可以同时开启多个注入组通道,然后同时读取;也可以逐个开关规则组通道,实现读一个关一个,开另一个,然后再开始读。两种方式都可以实现对不同通道数据的转换。
ADC转运模式:
扫描模式:在扫描模式下,ADC可以设置多个输入通道进行连续转换,按照通道号的顺序对这些通道进行转换,并将结果按顺序保存在对应的数据寄存器中。
连续模式:在连续模式下,ADC在完成一次转换后会自动开始下一次转换,无需外部触发。
①单次非扫描:对一个通道转一次停一次置一次EOC,不更改通道。结束后需要等待下一次触发
②单次扫描:转完所有通道后才停止置位EOC。需要用DMA,否则前面通道的数据会被后面通道的覆盖。结束后需要等待下一次触发
③连续非扫描:一直对一个通道进行转换,不停。
④连续扫描:一直对好几个通道进行扫描,不停。
⑤间断模式:扫几次就停,需要触发。
相关标志位:
EOC是转换完成标志位,完成1,未完0。中断使能标志位是EOCIE
AWD是模拟看门狗中断标志位。中断使能标志位是AWDIE
JEOC是注入组转换结束标志位。中断使能标志位是JEOCIE
START是开启转换标志位,置1表示开始转换。
如果开启了对应的NVIC的中断通道,那么产生中断标志的时候就会触发中断
左右对齐:
ADC是12位的,但是数据寄存器是16位的,也就是有4位空余,这导致了需要考虑左对齐还是右对齐。
左对齐:直接读取会导致精度下降。(相当于读取值=原值 x 16)
右对齐:直接读取就是目标值。(常用)
触发源:软件触发源--调用函数。
硬件触发源-- 定时器、 外部中断
时钟:AHB——>APB2时钟(72MHZ)——>ADC预分频器(2、4、6、8分频)——>DACCLK
由于ADC的时钟频率上限是14MHZ,而RCC的时钟是72MHZ,所以需要选择6、8分频,否则越界容易导致转换的结果会有误(超频 )。
转换周期:采样时间+12.5个ADC周期(12bit算一个ADC周期,余下0.5算硬件操作时间)
采样时间:看ADCCLK,如当ADC_CLK=14MHZ时,采样时间位1.5ADC周期,此时转换一次的时间时1us
校准:使用库配置好的代码,使ADC的采样防止电容变化导致的精度不准。需要ADC断电一段时间后才能校准,但在初始化后校准一下就可以了。
模拟看门狗:模拟看门狗检测某个输入通道的值,一旦高于或低于中断标志位AWD就是置位,就会申请中断。
配置要点:
①是否连续转换:转一次数据就结束一次,还是转多次数据才结束
⑥是否扫描模式:完成一个通道之后,是否接着转其他通道
②数据左右对齐:左对齐(降低精度,共12位,取高8,舍低4)
右对齐(实际值,直接读取即可)
③ADC的触发方式(硬件、软件):一般软件触发
④单多ADC运行:一般单ADC运行
⑤ADC通道选择:就是GPIO口,看GPIO口的配置中将哪个口配置成了AIN模式
数据位数称呼及对应大小
STM32F103C8T6是一款基于ARM Cortex-M3内核的32位微控制器,其数据位数和其他数据大小称呼如下:
字(Word) :STM32F103C8T6的数据总线宽度为32位,因此一个字(Word)是32位(4字节)。
半字(Half Word) :半字通常指的是16位,即2字节。
字节(Byte) :字节是8位,即1字节。
主要代码(参考自江协)
ADC与GPIO口的初始化函数
void AD_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*设置ADC时钟*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入
/*规则组通道配置*/
为所选ADC(ADC1)配置其对应的常规通道(ADC_Channel_0)、排序(1)、采样时间(ADC_SampleTime_55Cycles5)。
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,配置为通道0
/*ADC初始化*/
ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置
ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1
/*ADC使能*/
ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行
/*ADC校准*/
ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
获取ADC转换值的函数
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位,即等待AD转换结束
return ADC_GetConversionValue(ADC1); //读数据寄存器,得到AD转换的结果
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/QL_SD/article/details/142791325
|