电压表代码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include"reg52.h"
#define uchar unsigned char
#define uint unsigned int
void Write_Data(uchar dat);
void Set_Cursor(uchar x, uchar y);
void fraction_to_str(float a,uchar* pStr);
void float_to_str(float a,uchar* pStr);
void display(uchar x,uchar y,uchar* str);
void delay(uint i);
uchar unit[4];
uchar f_str[15];
//lcd显示定义
#define LCD_DATA P1 /*数据口*/
sbit RS = P2^0; /*并行的指令/数据选择信号, H数据, L命令*/
sbit RW = P2^1; /*并行读写选择信号, H读, L写*/
sbit E = P2^2; /*并行使能端, H有效, L无效*/
//sbit PSB = P0^4; /*串并行选择端,H选择并行,L选择串行*/ //sbit RST = P0^3;
//bit busy = 0; /*忙碌标志*/
//sbit A1 = P2^2; //模拟开关1(CD4051)的地址输入端,以及使能端
//sbit B1 = P1^1;
//sbit INH1 = P1^2;
//sbit A2 = P2^1; //模拟开关2(CD4051)的地址输入端,以及使能端
//sbit B2 = P2^0;
//sbit INH2 = P1^5;
sbit sh=P2^4;
sbit a=P2^5;
sbit b=P2^6;
sbit range=P2^6;
bit flag = 0; //退出定时器20ms中断0标志
bit temp = 0; //退出外部中断即反向积分完毕标志
uchar index = 1; //待测电压放大倍数选择标志位
//bit zero = 0; //校零标志
uint pp;
//此处变量的定义有以下两种模式,分别对应于不同的display()函数。
uint Time1 = 10000;
uint Time2 = 0; //反向积分时间
float V1 = 0, V2 = 0; //正常电压输入模式,校零模式的测得的电压值
float Vi = 0; //输入电压值
float Vref = 1.5; //参考电压为2V
//*****************************lcd显示程序*********************************//
void display(uchar x,uchar y,uchar *str)
{
uchar i=0;
Set_Cursor(x,y); //设置显示的起始地址
while(str[i]!='\0')
{
Write_Data(str[i]); //写入需要显示字符的显示码
i++;
}
}
void delay1(uint k)
{
uint i;
uchar j;
for(i=0;i<k;i++)
{
for(j=0;j<10;j++);
}
}
/*bit CheckBusy() //读BF标志位,检查LCD是否就绪
{
RS=0;
delay(1);
RW=1;
delay(1);
E=1;
delay(1);
if(LCD_DATA&0x80)
return 1;
else
return 0;
}
void Wait() //等待LCD就绪
{
while(CheckBusy()==1)
busy=0;
//busy=1;
}*/
uchar Read_Data() //读数据
{
delay1(1);
RS=1;
RW=1;
E=1;
delay1(5);
return LCD_DATA;
}
void Write_Data(uchar dat) //写一个字节数据{
delay1(1);
RS=1;
RW=0;
E=1;
delay(1);
LCD_DATA=dat;
E=0;
delay(1);
}
void Write_Command(uchar dat) //写命令{
delay1(1);
RS=0;
RW=0;
E=1;
delay(1);
LCD_DATA=dat;
E=0;
delay(1);
}
void Set_Cursor(unsigned char x, unsigned char y)
{
unsigned char i;
switch(x)//确定行号
{
case 0x00: i=0x80; break;//第一行
case 0x01: i=0x90; break;//第二行
case 0x02: i=0x88; break;//第三行
case 0x03: i=0x98; break;//第四行
default : break;
}
i = y+i;//确定列号
Write_Command(i);//写地址
}
void LCD_Init() /*LCD初始化*/
{
delay(45); //延时45ms
//PSB=1; //8位并行口
//复位操作
//RST=1;delay(1);
//RST=0;delay(1);
//RST=1;delay(1);
Write_Command(0x30); //设置为8位并行口,基本指令集
delay(10);
Write_Command(0x30); //再次设置为8位并行口,基本指令集
delay(5);
Write_Command(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据delay(5);
Write_Command(0x08);
delay(5);
Write_Command(0x01);//清显示
delay(5);
Write_Command(0x06);//整屏不移动,光标自动右移
delay(5);
Write_Command(0x0c);//开显示不显示光标
delay(5);
//Write_Command(0x80);
//Write_Data (str1);
//Write_Command(0xc0);
//Write_Data (str2);
}
void delay(uint i) //延时函数
{
uchar j;
for( ;i > 0;i --)
for(j = 110;j > 0;j --);
}
void input_Vi() //Vi电压信号输入{
// INH2 = 0;
a = 0;
b= 1;
}
void input_Vref() //基准电压输入
{
// INH2 = 0;
a= 1;
b = 1;
}
void close_Vref() //断开基准电压
{
// INH2=0;
a=0;
b=0;
}
/*void revise() //系统零输入校正{
// INH1=0;
A2=1;
B2=1;
}*/
void roomin_1() //电压放大1倍{
// INH1 = 0;
range=0;
}
void roomin_10() //电压放大10倍
{
// INH1 = 0;
range=1;
}
/*void roomin_100() //电压放大100倍
{
INH1 = 0;
A1 = 0;
B1 = 1;
} */
void cap_discharge()//电容放电
{
// INH2 = 0;
a= 0;
b= 0;
}
void T0_init() //定时20MS,对Time1正向积分计时
{
TH0=(65536-20000)/256;//装初值11.0592M晶振定时20ms数为18349
TL0=(65536-20000)%256;
ET0=1; //允许定时器0中断
TR0 = 0; //关闭定时器0
}
void T1_init() //对Time2反向积分计时
{
TH1 = 0; //最大定时
TL1 = 0;
ET1 = 1; //允许定时器1中断
TR1 = 0; //关闭定时器1
}
void exter0_init() //外部中断0,用于检测积分过零点
{
IT0 = 0;
/*
外部中断为低电平触发,此处如果改为IT0 = 1;的话,会出现显示结果不断跳变的现象
IT0 = 1;表示下降沿触发
*/
EX0 = 1; //关闭外部中断1
}
/************************字符串换算***********************/ void float_to_str(float a,uchar* pStr)
{
int temp;
if(a>=1000)
{
a /=1000.0;
unit[0] = 'V';
unit[1] = ' ';
unit[2] = ' ';
unit[3] = '\0';
}
else
{
unit[0] = 'm';
unit[1] = 'V';
unit[2] = ' ';
unit[3] = '\0';
}
temp = (int)a;
pStr[0] = temp/1000 + 0x30;
pStr[1] = (temp/100)%10 + 0x30;
pStr[2] = (temp/10)%10 + 0x30;
pStr[3] = temp%10 + 0x30;
pStr[4] = '.';
fraction_to_str((a - temp), &pStr[5]);
pStr[10] = '\0';
}
void fraction_to_str(float a,uchar* pStr)
{
long int temp;
temp = (long int)(a*100000);
pStr[0] = temp/10000 + 0x30;
pStr[1] = (temp/1000)%10 + 0x30;
pStr[2] = (temp/100)%10 + 0x30;
pStr[3] = (temp/10)%10 + 0x30;
pStr[4] = temp%10 + 0x30;
}
void main()
{
EA = 1;
TMOD = 0X99;
T0_init();
T1_init();
exter0_init();
LCD_Init();
// A1=0;
while(1)
{
cap_discharge();
delay(500); //确保电容要放电完毕
if(pp>=200)
index=1;
else
index=2;
switch(index)
{
case 1: roomin_1(); break; //放大1倍
case 2: roomin_10(); break; //放大10倍
// case 3: roomin_100(); break; //放大100倍
}
/*if(zero == 0)
{*/
input_Vi(); //待测试电压输入,此时电容开始充电
/*}
else
{
revise(); //校零模式
}*/
TR0 = 1; //定时器T0开始定时,在此定时20ms while(temp == 1) //直到反向积分完毕
{temp = 0;} //仍将temp置0,为下一次测试做准备
/*if(zero == 1)
{*/
V1 = Time2*Vref/Time1; //正常输入电压,测得的电压值
/*}
else
{
V2 = Time2*Vref/Time1; //0输入电压,测得的电压值
}*/
/*
此处表达式右端如果有float型数据的话,并且Vi本身也是float型,计算过后这Vi会
自动转换为float型数据,而不需要强制转换,如果仅仅Vi是float型,而其他变量不
是float型,计算结果是错误的。
*/
Vi =V1;
pp=Vi*1000;
float_to_str(pp, f_str);
display(1,0,"电压值: ");
display(2,0,f_str);
display(2,6,unit);
delay(10);
//lcd_display();
// display();
}
}
void timer0() interrupt 1 //10ms定时器中断0
{
TR0 = 0; //关闭定时器0,即每一次的测试只要求电容充电10ms
TH0=(65536-20000)/256;//装初值11.0592M晶振定时20ms数为18349
TL0=(65536-20000)%256;
EX0 = 1;
input_Vref(); //输入参考电压,开始反向积分
TR1 = 1; //定时器T1开始定时计数
//打开外部中断1,开始检测反向积分过零信号
}
void exter0() interrupt 0 //反向积分过零信号下降沿触发单片机
{
TR1 = 0; //停止T1的定时计数
EX0 = 0; //关闭外部中断,防止干扰
close_Vref();
delay(500); //当检测到外部中断的时候就断开基准电压
Time2 = TH1*256 + TL1; //将T1定时计数器的值付给Time2
/*
Time2 = TH1<<8 + TL1; 这条语句是错误的,因为TH1为8位的寄存器,左移8位后会变为0;
解决的办法是将TH1与TL1赋值给整形变量x与y。
或者将该句写成Time2 = TH1 * 256 + TL1;
*/
TH1 = 0; //将定时计数值清零,为下一次测量做准备
TL1 = 0;
temp = 1;
//zero = ~zero;
}。