第一次写博客呀多多关照~
采用ADC0809和AT89C51单片机及显示电路完成0~5V、0~15V两个量程的直流电压的检测,并通过LCD1602液晶屏实时显示。通过开关SW1和SW2选择5V或15V,当所测电压超过量程时,报警电路的小灯闪烁、蜂鸣器发出警报,同时液晶屏显示QAQ(哈哈哈闲着没事干就加了),当两个开关同时按下也会触发报警电路。
至于两个档位的区别,为了模拟实际的电压表,所以设计的数字电压表显示的精度不一样,15V量程的精度为0.1V,5V量程的精度为0.001V。
(想说一下,我这里ADC0809的out输出接了上拉电阻,要不然显示屏显示不正常,但是参考别人的不接上拉电阻也可以正常工作QAQ)
使用keil编写的c语言代码.
#include
#define uchar unsigned char //宏定义无符号字符型
#define uint unsigned int //宏定义无符号整型
sbit START=P2^7; //AD启动转换信号
sbit OE=P2^5; //数据输出允许信号
sbit EOC=P2^6; //AD转换结束信号
sbit CLK=P2^4; //时钟脉冲
sbit RS=P2^0; //LCD1602数据/命令选择端(H/L)
sbit RW=P2^1; //LCD1602数/写选择端(H/L)
sbit E=P2^2; //LCD1602使能信号
sbit led=P3^0;
sbit buzzer=P3^1;
sbit SW1=P3^2; //5V量程选择开关
sbit SW2=P3^3; //15V量程选择开关
sbit addr_a=P3^5;
sbit addr_b=P3^6;
sbit addr_c=P3^7;
//函数声明
uint ADC(); /* AD转换函数 */
void delayMS(uint xms); /* 延时函数 */
bit lcd_busy_check(); /* 忙检测函数 */
void lcd_write_com(uchar com); /* LCD1602写入8位命令子函数 */
void lcd_write_data(uchar date); /* LCD1602写入8位数据子函数 */
void init_lcd(); /* LCD1602初始化子程序 */
void lcd_show_string1(uchar a[]); /* 第一行从头开始显示字符串 */
void lcd_show_string2(uchar a[]); /* 第二行从头开始显示字符串 */
void lcd_show_string(uchar add,uchar a[]); /* 指定位置显示字符串 */
void display(); /* 显示函数 */
void alarm(); /* 报警函数 */
void range(); /* 量程选择函数 */
//定义全局变量
unsigned int volt;
unsigned long vo;
unsigned char code table[]="0123456789";
/**************************函数功能:AD转换子程序***************************/
uint ADC()
{
START=0; //确保进入正常AD转换状态
OE=0; //转化初始化
START=1;
START=0; //AD开始转换
while(EOC==0); //外部中断等待AD转换结束
OE=1; //读取转换的AD值
volt=P1;
OE=0; //输出转换结束
return volt;
}
/**********************函数功能:液晶屏LCD1602显示子程序****************/
/*延时函数:DelayMS()*/
void delayMS(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
/*忙检测函数:lcd_busy_check()*/
bit lcd_busy_check()
{
bit result;
RS=0;
RW=1;
E=1;
delayMS(10);
result=(bit)(P0&0x80);
E=0;
return result;
}
/*写命令函数:lcd_write_com()*/
void lcd_write_com(uchar com)
{
RS=0;
E=0;
RW=0;
P0=com;
delayMS(5);
E=1;
delayMS(5);
E=0;
}
/*写数据函数:lcd_write_data()*/
void lcd_write_data(uchar date)
{
RS=1;
E=0;
RW=0;
P0=date;
delayMS(5);
E=1;
delayMS(5);
E=0;
}
/* LCD1602初始化函数:init_lcd()*/
void init_lcd()
{
E=0; //默认开始状态为关使能端
lcd_write_com(0x38); //显示模式设置
lcd_write_com(0x01); //显示清屏,将上次的内容清除
lcd_write_com(0x0c); //开显示,不显光标,光标不闪
lcd_write_com(0x06); //读一个字符光标加1
}
/* 指定位置显示字符串函数:lcd_show_string() */
/* 参数 add 地址 第一行 0~27 */
/* 第二行 40~67 */
/* a[] 字符串 "abc" */
void lcd_show_string(uchar add,uchar a[])
{
uchar i;
lcd_write_com(0x80+add);
for(i=0;a[i]!='\0';i++)
{
lcd_write_data(a[i]);
}
}
/* 第一行显示字符串 */
void lcd_show_string1(uchar a[])
{
uchar i;
lcd_write_com(0x80);
for(i=0;a[i]!='\0';i++)
{
lcd_write_data(a[i]);
}
}
/* 第二行显示字符串 */
void lcd_show_string2(uchar a[])
{
uchar i;
lcd_write_com(0x80+0X40);
for(i=0;a[i]!='\0';i++)
{
lcd_write_data(a[i]);
}
}
/* LCD1602显示函数:display()*/
void display1() //5V的显示
{
uint v_1v,v_100mv,v_10mv,v_1mv; //定义变量用于显示
vo = volt*19.6; //转换值处理 (满量程为5V,转换分辩率为8位即最大值是255,5/255=19.6mV,即1代表19.6mV)
v_1v = vo/1000; //1伏显示位
v_100mv = vo/100%10; //100毫伏显示位
v_10mv = vo/10%10; //10毫伏显示位
v_1mv = vo/1%10; //1毫伏显示位
lcd_write_com(0x80+0x40+0x05); //选中第二行第5个位置
lcd_write_data(table[v_1v]);
lcd_write_data('.');
lcd_write_data(table[v_100mv]);
lcd_write_data(table[v_10mv]);
lcd_write_data(table[v_1mv]);
lcd_write_data('V'); //显示电压的单位V
lcd_write_data(' ');
lcd_write_data(' ');
lcd_write_data(' ');
}
void display2() //15V的显示
{
uint v_10v,v_1v,v_100mv;
vo = volt*19.6;
v_10v = vo/10000; //10伏显示位
v_1v = vo/1000%10; //1伏显示位
v_100mv = vo/100%10; //100毫伏显示位
lcd_write_com(0x80+0x40+0x05);
lcd_write_data(table[v_10v]);
lcd_write_data(table[v_1v]);
lcd_write_data('.');
lcd_write_data(table[v_100mv]);
lcd_write_data('V');
lcd_write_data(' ');
lcd_write_data(' ');
lcd_write_data(' ');
lcd_write_data(' ');
lcd_write_data(' ');
}
void display3() //报警时的显示
{
lcd_write_com(0x01);
lcd_show_string1(" QAQ ");
delayMS(50);
lcd_show_string2(" Ooooooops ");
delayMS(50);
}
/***************************函数功能:报警********************************/
void alarm()
{
int i;
display3(); //调用报警时的显示
for(i=0;i<100;i++)
{
led=1; //控制发光二极管D2闪烁,发出光报警信号
buzzer=~buzzer; //控制蜂鸣器发声,发出声音报警信号
delayMS(1);
led=0;
buzzer=~buzzer;
delayMS(1);
}
}
/********************函数功能:选择量程 15V or 5V 并测量电压************************/
void range()
{
if((SW1==0)&&(SW2!=0)) //按下SW1
{
lcd_show_string(0x06,"0~5V "); //LCD1602显示->量程5V
lcd_show_string1("Range:"); //LCD1602显示->第一行为Range:
lcd_show_string2("Volt:"); //LCD1602显示->第二行为Volt:
addr_a=0;
addr_b=0;
addr_c=0;
ADC(); //调用模数转换程序
if(volt>=0xFF) //当大于5v时,使用LED和蜂鸣器报警
{ alarm(); }
else //否则取消报警
{
led=0; //控制发光二极管D2灭
buzzer=0; //控制蜂鸣器不发声
display1(); //调用显示程序1
}
}
else if((SW1!=0)&&(SW2==0)) //按下SW2
{
lcd_show_string(0x06,"0~15V "); //LCD1602显示->量程15V
lcd_show_string1("Range:"); //LCD1602显示->第一行
lcd_show_string2("Volt:"); //LCD1602显示->第二行
addr_a=1;
addr_b=0;
addr_c=0;
ADC();
volt=3*volt; //转换的值*3,变为15v范围
if(volt>=0x2FD) //当大于15v时,使用LED和蜂鸣器报警
{
alarm();
}
else //否则取消报警
{
led=0; //控制发光二极管D2灭
buzzer=0; //控制蜂鸣器不发声
display2(); //调用显示程序2
}
}
else if((SW1==0)&&(SW2==0)) //同时按下SW1、SW2的误操作,报警
{
alarm();
}
else
{ //SW1、SW2均未按下,提示选择量程
lcd_show_string1(" Choose range ");
delayMS(1);
lcd_show_string2(" 5V or 15V ");
delayMS(1);
}
}
/***************************函数功能:主程序********************************/
void main(void)
{
TMOD=0x01; //设定定时计数工作方式
TH0=0XFF; //为定时器初赋值
TL0=0XB4;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //开启定时器0
led=0;
buzzer=0;
init_lcd(); //LCD1602初始化函数
while(1)
{
range();
}
}
/**************************函数功能:定时器0时钟信号*************************/
void timer() interrupt 1
{
TH0=0XFF; //初值重置
TL0=0XF0;
CLK=~CLK; //取反 产生时钟信号
}