文章目录
- 小码农电压使者怎么敢说不会采集
- 模拟量与单片机的数字量之间的关系
- 模拟量转换成数字的方式
- 逐次比较器ADC的概念
- 一个超级好的例子分享给你们
- STC内部ADC模块的寄存器
- 这里我们需要采集电池电压(我们用P1.0采集)
- ==P1M1 |= 0x01;P1M0 &= ~0x01;//P1.0脚ADC0==
- ==P1ASF |= 0x01;==
- ==CLK_DIV |= 0x20;==
- ==ADC_RES = 0;ADC_RESL = 0;==
- ADC初始化
- ==ADC_CONTR = 0x88;==
- ADC读数据底层驱动
- 演示视频
- 采集电压
- ADC代码
- ADC_Drive.c(还有一个我自己写的滤波函数,使得数据稳定)基本这个水平可以拿省二了
- ADC_Drive.h
小码农电压使者怎么敢说不会采集
模拟量—>数字量(ADC模块)
模拟量与单片机的数字量之间的关系
5V 单片机 CPU 电路是二进制的,运算过程中,电压只有2种:高电平 5V 和低电平 0V 。对于电压或者电流连续变化的信号,就需要通过模数转换电路,变成单片机可以识别的数字电平信号。 MP3 就是用 ADC 采样保存的失真文件。
模拟量转换成数字的方式
模拟量变成数字量,通常都是用比较器来负责转换。目前来说,常见的有两种方式,一种是并行比较,一种是逐次比较。
**并行比较器:**速度比较快,但是采用的元件非常非常多。成本会非常高。所以,实用性不是很广泛
**逐次比较器:**通过反馈控制,多次运算后,转换出结果。具有成本低、元件简单等优势,而且容易做出高精度的转换器,所以被广泛使用。
逐次比较器ADC的概念
一个超级好的例子分享给你们
先来玩个游戏 :狗蛋拿了些花生米,跟你说,想吃就要先猜对有多少个。告诉你最多是 255 颗,你猜的时候,可以告诉你多了或者少了。那么,怎么猜才能最快猜出花生米的数量?
猜的时候,为了方便计算, 我们多加 0.5 颗花生米。
==第一步:==猜 255 ÷ 2 +0.5=128. 狗蛋告诉你,多了 (0) 。
第二步:猜 128 ÷ 2=64. 狗蛋告诉你,少了 (1)。
第三步:猜 (128 + 64) ÷ 2=96. 狗蛋 告诉 你,多了 (0) 。
第四步:猜 (96 + 64) ÷ 2=80. 狗蛋 告诉 你,少了 (1) 。
第五步:猜 (96 + 80) ÷ 2=88. 狗蛋 告诉 你,少了(1)。
第六步:猜 (96 + 88) ÷ 2=92. 狗蛋 告诉 你,多了(0)。
第七步:猜 (92+ 88) ÷ 2=90. 狗蛋 告诉 你,多了(0) 。
第八步:猜 (90+ 88) ÷ 2=89. 狗蛋 告诉 你,猜对 (?) 。
得出结果: 如果不加 0.5 ,实际计算公式得结果是 88.65234375 。实际上88.65比89小所以是 1
四舍五入, 89>88.65, 取 ?= 1 ;得出结果就是 0 1 0 1 1 0 0 1 =89=0x59;
STC内部ADC模块的寄存器
1.ADC口配置成ADC输入模式或者高阻模式
2.ADC控制寄存器:ADC_CONTR.控制电源,转换速度,标志位,启动位,通道选择[2:0]
3.ADC采样结果输出寄存器ADC_RES,ADC_RESL。可以是[1:0]+[7:0],也可以是[7:0]+[1:0].
4.ADC转换,跟中断有关的寄存器IE
5.辅助寄存器AUXR1,主要是控制结果寄存器的存储格式
这里我们需要采集电池电压(我们用P1.0采集)
我是准备用ADC0来检测电池电压的,具体看老师需求,然后把示数显示到数码管上面,因为之前我出过数码管博客,大家可能还有点印象,不知道的看真正的数码管
P1M1 |= 0x01;P1M0 &= ~0x01;//P1.0脚ADC0
P1ASF |= 0x01;
CLK_DIV |= 0x20;
ADC_RES = 0;ADC_RESL = 0;
ADC初始化
//ADC初始化
void ADC_Init()
{
P1M1 |= 0x0f;
P1M0 &= ~0x0f;//P1.0脚ADC0
P1ASF |= 0x0f;
// P1M1 |= 0x02;
// P1M0 &= ~0x02;//P1.1脚ADC1
// P1ASF |= 0x02;
CLK_DIV |= 0x20;
ADC_RES = 0;
ADC_RESL = 0;
}
ADC_CONTR = 0x88;
ADC读数据底层驱动
//ADC读数据底层驱动
void ADC_Read_Data_Drive()
{
//转换之前先把转换结果寄存器清零
ADC_RES = 0;
ADC_RESL = 0;
//启动转换
ADC_CONTR = 0x88;//转换速度我用最慢的
//等到ADC_FLAG为1
while(!(ADC_CONTR&0x10));
//然后把数据传到缓存变量里面去
ADC_Read_Data = ADC_RES<<8;
ADC_Read_Data = ADC_Read_Data+ADC_RESL;
}
演示视频
采集电压
采集电压
ADC代码
ADC_Drive.c(还有一个我自己写的滤波函数,使得数据稳定)基本这个水平可以拿省二了
#include "all.h"
//有数据那我们就得存
u16 xdata ADC_Read_Data = 0;
u16 xdata ADC_Filter_Data = 0;
//ADC初始化
void ADC_Init()
{
P1M1 |= 0x0f;
P1M0 &= ~0x0f;//P1.0脚ADC0
P1ASF |= 0x0f;
// P1M1 |= 0x02;
// P1M0 &= ~0x02;//P1.1脚ADC1
// P1ASF |= 0x02;
CLK_DIV |= 0x20;
ADC_RES = 0;
ADC_RESL = 0;
}
//ADC读数据底层驱动
void ADC_Read_Data_Drive()
{
//转换之前先把转换结果寄存器清零
ADC_RES = 0;
ADC_RESL = 0;
//启动转换
ADC_CONTR = 0x88;//转换速度我用最慢的
//等到ADC_FLAG为1
while(!(ADC_CONTR&0x10));
//然后把数据传到缓存变量里面去
ADC_Read_Data = ADC_RES<<8;
ADC_Read_Data = ADC_Read_Data+ADC_RESL;
}
//全局的ADC滤波数据结构体指针
ADC_Data* adc_filter;
//ADC滤波数据底层驱动
void ADC_Filter_Data_Drive()
{
/*u16 ADC_Min = 0;
u16 ADC_Max = 0;
u16 ADC_Tmp = 0;
u16 ADC_Result = 0;*/
//设置两个循环变量
u8 i = 0;
u8 j = 0;
ADC_Filter_Data = 0;
ADC_Read_Data_Drive();
for(i = 0;i<4;i++)//外层8次循环
{
adc_filter->ADC_Result = 0;
adc_filter->ADC_Min =
adc_filter->ADC_Max =
ADC_Read_Data;
for(j = 0;j<4;i++)//内层8次循环
{
adc_filter->ADC_Tmp = ADC_Read_Data;
if (adc_filter->ADC_Tmp < adc_filter->ADC_Min)
{
adc_filter->ADC_Result += adc_filter->ADC_Tmp;
adc_filter->ADC_Min = adc_filter->ADC_Tmp;
}
else if (adc_filter->ADC_Tmp > adc_filter->ADC_Max)
{
adc_filter->ADC_Result += adc_filter->ADC_Tmp;
adc_filter->ADC_Max = adc_filter->ADC_Tmp;
}
else
{
adc_filter->ADC_Result += adc_filter->ADC_Tmp;
}
}
adc_filter->ADC_Result /= 4;
ADC_Filter_Data += adc_filter->ADC_Result;
}
ADC_Filter_Data /= 4;
}
ADC_Drive.h
#ifndef ADC_Drive
#define ADC_Drive
typedef struct ADC_Filter_Data
{
u16 ADC_Min; //ADC最小值
u16 ADC_Max; //ADC最大值
u16 ADC_Tmp; //ADC临时值
u16 ADC_Result; //ADC结果
} ADC_Data;
//外部声明
extern void ADC_Init();
extern void ADC_Read_Data_Drive();
extern void ADC_Filter_Data_Drive();
extern u16 xdata ADC_Read_Data;
extern u16 xdata ADC_Filter_Data;
#endif