一、什么是ADC\DAC?
ADC: Analog-to-Digital Converter的缩写,意思是模/数转换器。实现把模拟信号转变为数字量的设备称为模—数(A/D)转换器,简称ADC。
实现把数字量转变为模拟量的设备称为数—模(D/A)转换器,DAC(Digital to Analog Convertor)简称DAC。
二、A/D转换器的结构
STC15系列的A/D转换器结构如图
STC15系列单片机的ADC是逐次比较型ADC。由多路选择器开关,比较器、逐次比较寄存器、10位DAC、转换结果寄存器(ADC_RES和ADC_RESL)以及ADC_CONTR构成。
从图中可以看到P1.0-P1.1口都可以用来进行AD转换功能,只需要在配置相关寄存器后打开对应IO口这个功能就可以了。
三、寄存器配置
为了使用AD功能需要涉及到以下寄存器。
P1模拟功能控制寄存器P1ASF
这个寄存器的功能就是打开对应的IO口,如P1ASF=0X01;就是把P1.0口的AD功能打开了。
ADC控制寄存器ADC_CONTR
使用AD功能最重要的就是配置这个寄存器,下面将介绍每一位的功能。
ADC_POWER:电源控制位
0:关闭电ADC电源。(注:不用AD功能关闭电源可以降低功耗)
1:打开A/D转换器电源。初次打开需要适当的延时。
SPEED1,SPEED0:转换器速度控制位
ADC_FLAG:模数转换器结束标志位,完成后ADC_FLAG=1,要软件清零。
ADC_START:模数转换器转换启动控制位,ADC_START=1开始转换,结束 后自动清零。
CHS2/CHS1/CHS0:模拟输入通道选择。
ADC转换结果调整寄存器——ADRJ
ADRJ:ADC转换结果调整
0:ADC_RES[7:0]存放高8位ADC结果,ADC_RESL[1:0]存放低2位ADC结果
1:ADC_RESL[1:0]存放高2位ADC结果,ADC_RES[7:0]存放低8位ADC结果如果需要取完整10位结果
如果只需要取8位结果
中断允许寄存器IE
EA:总中断开关位
1:CPU接收中断
0:COU屏蔽所有中断
EADC:A/D转换中断允许位
1:允许A/D转换中断
0:禁止A/D转换中断
中断优先级控制寄存器IP
PADC:A/D转换中断优先级控制位
0:设为最低优先级
1:设为最高优先级
举例用lcd1602显示ad采集的电压
main函数:
#include <stc15f2k60s2.h>
#include <15AD.h>
#include <lcd.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
void main()//主函数
{
uint AD_DAT;//AD转换后缓存变量
uchar yi,er;//缓存变量的整数部分、小数部分
adc_init();//打开AD复用功能
LcdInit(); //初始化lcd1602显示屏
while(1)
{
AD_DAT= get_adc();//把转换好的AD数据赋给AD_DAT
AD_DAT=AD_DAT*0.0475;//把AD_DAT转换为十进制数
yi=AD_DAT%100/10;//取AD_DAT的整数部分
er=AD_DAT%10;//取AD_DAT的小数部分
LcdWriteCom(0x80); //0x80是第一行的第一个字符的地址
LcdWriteData('0'+yi);//显示整数部分
LcdWriteData('.');//显示 .
LcdWriteData('0'+er);//显示小数部分
LcdWriteData('V');//显示 V
}
}
15AD.h:
#define __15AD_H
//---重定义关键词---//
#define nop _nop_()
#define ADC_POWER 0x80//开电源
#define ADC_START 0x08
#define ADC_FLAG 0x10
#define ADC_SPEEDH 0x40//转换速度为180个时钟周期
#define ADRJ 0X20 //ADRJ=1
#define AD_P1_0 0X00//P1.0为AD输出
/**********************************
函数声明
**********************************/
void Delay10ms();//10毫秒延时
void adc_init(void);//AD功能初始化
unsigned int get_adc();//获取AD值
#endif
15AD.c:
#include <reg51.h>
#include <intrins.h>
#include <15AD.h>
#define nop _nop_()//延时
#define ADC_POWER 0x80//开电源
#define ADC_START 0x08//AD转换启动控制。
#define ADC_FLAG 0x10//AD转换结束标志
#define ADC_SPEEDH 0x40//转换速度为180个时钟周期
#define ADRJ 0X20 //ADRJ=1
#define AD_P1_0 0X00//P1.0为AD输出
sfr ADC_CONTR = 0Xbc;//命名ADC控制寄存器
sfr ADC_RES = 0Xbd;//命名数据高位
sfr ADC_RESL = 0Xbe;//命名数据低位
sfr P1ASF=0X9D;//命名P1口控制寄存器
sfr PCON2=0X97;//命名时钟分频寄存器
/***************AD初始化函数****************
设置P1.0口为AD输入口;
数据存放方式为高两位低八位;
开启电源;
设置转换速度;
*******************************************/
void adc_init(void)
{
P1ASF=0X01;//P1ASF.0=1;//设置P1为模拟量输入
PCON2=PCON2|ADRJ;//ADRJ=1
ADC_CONTR = ADC_POWER|ADC_SPEEDH|AD_P1_0;
//设置AD电源开启、转换速度设置、AD输入端口
nop;nop;nop;nop;//延时4个机械周期
}
/***************读取AD值函数****************
开始转换AD数据;
等待转换完成;
存放数据;
清零标志位和数据位;
*******************************************/
unsigned int get_adc()//读取AD值
{
unsigned int i,j;
ADC_CONTR=ADC_CONTR|ADC_START;//开始转换
while((ADC_CONTR&ADC_FLAG)!=ADC_FLAG);//等待转换标志位
i=ADC_RES;
j=ADC_RESL;
i=i<<8;
i=i|j;
ADC_CONTR=ADC_CONTR&~ADC_FLAG;//清零转换标志位
ADC_RES=0;//数据清零
ADC_RESL=0;//数据清零
return(i);
}
lcd.h:
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
包含头文件
**********************************/
#include <stc15.h>
#include <intrins.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P4^1;
sbit LCD1602_RW=P4^2;
sbit LCD1602_RS=P4^4;
/**********************************
函数声明
**********************************/
/*在15单片机11.0592MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c); //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/
void LcdWriteData(uchar dat) ;
/*LCD1602初始化子程序*/
void LcdInit();
#endif
lcd.c:
/********************************************************
**文件名:LCD1602驱动
**日 期:2020/11/19
**描 述:
**修改记录:无
********************************************************/
#include"lcd.h"
/*******************************************************************************
* 函 数 名 : Lcd1602_Delay1ms
* 函数功能 : 延时函数,延时1ms
* 输 入 : c
* 输 出 : 无
* 说 名 : 该函数是在11.0592 MHZ晶振下,12分频单片机的延时。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //误差 0us
{
unsigned char i, j;
for (; c>0; c--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
/*******************************************************************************
* 函 数 名 : LcdWriteCom
* 函数功能 : 向LCD写入一个字节的命令
* 输 入 : com
* 输 出 : 无
*******************************************************************************/
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : dat
* 输 出 : 无
*******************************************************************************/
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择写入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //将8位总线转为4位总线
LcdWriteCom(0x28); //在四位线下的初始化
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}