HD8001 ADC外设
一、datasheet介绍
主要特点:
① 12bit,代表该芯片ADC模块采样最大可以有12位2进制的值(4096)。
② 参考电压可以是VDD、外部参考电压、内部参考电压。
③ 转化完成时可以产生中断。
配置过程(即初始化)
1. 端口配置
这里配置是做什么?
就两点,使用的IO口是输入还是输出,是模拟还是数字型号。
Example:
TRISA=0B00000000; //输入输出设置,0-输出,1-输入
ANSELA= 0B00100000;//控制IO的数模输入,1:对应的IO为模拟管脚,0:对应的IO为数字IO,设置AN5为模拟管脚
2.通道选择
通道选择是用来做什么?
选择哪一个通道作为ADC转换的通道。
Example:
ADCON0=0B01010000;//通道5
3.触发方式选择
这里是有这么个功能,能软件置位后自己触发,也可以给寄存器赋值之后由硬件触发。(默认是软件触发,程序里并未使用硬件触发的功能)
也是ADCON0寄存器来控制的
4.触发源选择
结合三来进行使用的,选择的是外部触发源。
虽然没有用到,但这里的逻辑应该是,我选用PWM作为外部触发源,更改PWM周期和占空比,我来控制ADC转化多久停多久。
5.触发类型选择
和上一个结合使用,是PWM控制还是别的什么控制。
6.触发延时配置
这个也没有用到,也是外部触发进行的延时,但是这个应该是特殊情况下很有用,比如延时等待稳定,可能有些采样的开始会失真。
7.ADC 参考电压
核心部分:
内部参考电压可以与0.5v,2v,3v 或者悬空。
所谓参考电压,也就是选择之后,采样的最大值就代表参考电压。
即采样到的值/4096 * 参考电压 = 采样得到的电压值。
Example:
ADCON2=0B01000000; //ADC内部参考电压2V
采样得到的结果是619,实际采样得到的电压应该为:0.3v(实际中是计算电流点,超过多少报警,超过多少停止电机,由于电阻的原因和采样算法,存在部分误差,需要我用负载机检测实际的报警电流和急停电流,然后微调程序)
8. 转换时钟
作用其实就是AD转化的时间,时间越长采样的样本就越多,得到的平均值也就越准确。
通过ADCON1 寄存器的 ADCS 位用软件选择,
ADCON1=0B11100100; //ADC转换结果右对齐,即装入转换结果时,ADRESH的高4位被设置为0,ADC转换时钟设置为Fosc/64
9. 中断
转化完成后进中断,程序没使用中断,不过也可以在中断中完成取平均值的过程吧。可能弊端是中断进入了,没法实时进行电流监测,可能会造成过载还没停的情况。
10.转换结果的格式
这里就无非是左对齐还是右对齐,也是在ADCON1里面设置的。
简单带过。
11. 阈值比较
这样做的应该是每采样到一次结果,就比较一下,比较的更快,但比起采样后做平均,肯定是采样后平均更准确。
工作原理(工作的启动配置等)
1. 启动转化
这里其实就是 ADON = 1。
若 ADEX=0 时,将 ADCON0 寄存器的 GO/DONE 位置 1 将启动 AD 转换。GO/DONE位 == 1,就是正在进行转换。(由软件置位)
2. 转化完成
当转化完成时,会自动清除GO/DONE标志位。
会把ADIF标志位置1。
其实主要也就是使用这两点。
3. 终止转化
转化完成前需要终止的话,就把GO/DONE位清零就行,就不会再更新这次转化。
程序举例
//ADC 初始化
void ADC_INIT(void)
{
ANSELA=0B00100000; //控制IO的数模输入,1:对应的IO为模拟管脚,0:对应的IO为数字IO,设置AN5为模拟管脚
PCKEN|=0B00000001;
ADCON0=0B01010000; //选择模拟通道AN0,当软件设定GO/DONE位时启动AD转换(即不用外部触发源)
ADCON1=0B11010100; //ADC转换结果右对齐,即装入转换结果时,ADRESH的高4位被设置为0,ADC转换时钟设置为Fosc/64,负参考电压-GND,正参考电压-内部参考电压
ADCON2=0B01000000; //ADC内部参考电压2V
ADCON3=0B00000000;
ADON=1; //使能ADC
}
//转化ADC过程
uint16_t GET_ADC_DATA(uint8_t adcChannel)
{
ADCON0&=0B00001111;
ADCON0|=adcChannel<<4;
Delay_us(40); //等待时间稳定
GO=1;
NOP();
NOP();
while(GO);
return (uint16_t)(ADRESH<<8|ADRESL);
}
//对转化的数据进行处理
void READ_ADC(void)
{
MotorADCValueTemp + = GET_ADC_DATA(5);
ADC_VOL_Array[ADC_VOL_Array_Index] = MotorADCValueTemp;
// ADC_VOL_Cnt = 0;
MotorADCValueTemp = 0;
ADC_VOL_Array_Index++;
if (ADC_VOL_Array_Index >>3)
{
uint16_t max = ADC_VOL_Array[0];
uint16_t min = ADC_VOL_Array[0];
uint32_t sum = 0;
uint16_t average;
uint8_t i;
for (i = 0;i < ADC_VOL_Array_Index;i++)
{
if (ADC_VOL_Array[i] > max)
{
max =ADC_VOL_Array[i];
}
if (ADC_VOL_Array[i] < min)
{
min = ADC_VOL_Array[i];
}
sum += ADC_VOL_Array[i];
}
average = (sum-max-min)/(ADC_VOL_Array_Index-2);
MotorADCValue= average;
ADC_VOL_Array_Index = 0;
MotorADCGetFlag = 1;
}
}