输入模拟量,转化为数字量
逐次逼近型ADC:
DAC(数模转换器)的工作原理:
给定DAC一个数据,DAC能够输出数据相对应的电压。
当外部传来一定大小,编码未知的电压时,DAC输出电压通过比较器和未知电压进行比较,DAC输出的电压较小就增大,较大就减小。通过逼近的方法来实现这个过程。
规则组和注入组:
注入组,转化的通道数据多,但会丢失。
规则组,转化的通道数据少,但是都不会丢失。
触发转换的信号:(产生信号使得转换开始)
软件触发
硬件触发
判断转换是否结束
开关控制:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
float Voltage;
int main(void)
{
OLED_Init();
AC_Init();
OLED_ShowString(1,1,"ADValue:");
OLED_ShowString(1,1,"Voltage:0.00v");
while (1)
{
ADValue = AD_GetValue();
Voltage= (float)ADValue /4095 * 3.3;//ADVlaue是整数,做完运算之后会丢失小数导致错误,进行强制转换。
OLED_ShowNum(1,9,ADValue,4);
//显示浮点数
OLED_ShowNum(2,9,Voltage,1);//Voltage的值为0-3.3,只显示一位会将小数舍弃。
OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);//显示浮点数
//先扩大一百倍,后对100取余。注意类型。显示两位,
Delay_ms(100);
}
}
#include "stm32f10x.h" // Device header
void AC_Init(void)
{//开始ADC和GPIO的时钟,也包括ADCLK的分频器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//配置GPIO,配置成为模拟输入的模式
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(GPIOA,&GPIO_Initstructure);
//配置多路开关,将左边的通道接入到规则组列表里
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//第二个参数是ADC引脚的复用
//配置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。供电
ADC_Cmd(ADC1,ENABLE);
//校准,减小误差
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1)==SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)==SET);
}
//获得输出的结果
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
return ADC_GetConversionValue(ADC1);
}
//开始ADC和GPIO的时钟,也包括ADCLK的分频器
//配置GPIO,配置成为模拟输入的模式
//配置多路开关,将左边的通道接入到规则组列表里
//配置ADC转换器
//开启ADC。供电
//校准,减小误差
用于给ADC上电
ADC能够将引脚上连续变化的模拟电压变为内存中储存的数字变量。
单次转换、连续转换;
区别:单词转换完成后停止,再次进行转换需要手动设置;连续转换再结束一次转换后会自动进行下一次转换。
扫描模式、非扫描模式;
区别:是否用到“菜单列表”,非扫描模式只会读取第一个“菜”;扫描模式会顺着菜单往下。
DMA及时将数据挪走;
通道转换完之后产生EOC标识符,通过读取标识符来判断转换是否结束。
扫描模式中还有间断模式,即扫描几个通道之后暂停,需要再次触发。
触发控制。
数据对齐:ADC是12位的,寄存器是16位的。有左右对齐之分。一般为右边对齐,左对齐会降低精度,用于对数据要求不是那么高的情况。
转换时间:AD转化的步骤。采样、保持(编码进行时电压会变化,需要将电压采集,以便分析)、量化、编码(ADC逐次比较的过程完成对输入模拟信号的拟合)
转化的时间:采样保持+12.5ADC周期
校准的实现方式:在ADC初始化之后加几行代码
下图为电压转换的电路:VIN电压为5v但是最大电压只有3.3,通过分压进行转换
数据的抖动处理
1、通过判断值来开关灯。
数据的波动会出现来回开关灯的现象。
迟滞比较:设置1两个阈值,高于上阈值的时候开灯;低于下阈值的时候关灯;GPIO施密特触发器。
数据跳动太厉害
希望值变化平滑
均值滤波:取多个数据的平均值作为AD的值;
裁剪分辨率,将数据的位数去掉。
多通道转换的功能
手动转运数据
单次非扫描的模式,在转换之前先手动改变通道。