📄 fivet140y.c
字号:
/********************************************************************************************************************************
FILE NAME: FIVET38.C
AUTHOR: ZHANG YANG
DATE: 2008.8.18
*********************************************************************************************************************************/
#include<reg52.h>
#include<math.h>
#define LED_SEG P2 //段码控制
#define LED_BIT P0 //位控制
unsigned char code table[16]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0x9e,0x02,0x00,0x6e,0x8e,0x9c};//字形表0~9,E,- ,灭,H,F,C
idata unsigned int time=0;//软件计时
idata unsigned int period=400;//各个通道显示时间计时
idata unsigned char Tns=0;//n秒计时
idata unsigned char Upper[5],Lower[5];//存储上下限
data unsigned char key4_f=0;//记录按下Key4的次数
data unsigned char CHnum=1;//通道号
idata unsigned Upnum=0,Lonum=0;//记录超过限值的通道数
data unsigned char Vcode[7]={0,0,0,0,0,0,0};//待显示的数字存储数组,第一个和第二个是通道号或函数标志,第三个空,后4个是电压量的有效数字
data unsigned char Dis_dat[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};//待显示的数字的字形,初值全灭
bdata bit EA_f;//用以保存EA状态
bdata bit nopt;//空操作位
bdata bit T2ms=1;//2毫秒计时
bdata bit T1m=1;//1秒计时间到标记
bdata bit opAD_flag=1;//是否操作AD7708标志
bdata bit rdAD=0;//是否读取AD转换结果标志
bdata bit v2c_flag=0;//是否需要刷新换显示内容
bdata bit single=0;//单通道显示
bdata bit circle=1;//循环显示模式标志,正常为1
bdata bit Adj_Zero=0;//调0模式标记
bdata bit RomEr=0;//eeprom损坏标志
bdata bit ModeWait=0;//模式确认等待标志
bdata bit low_f=0;//显示下限标志
bdata bit up_f=0;//显示上限标志
bdata bit Modified=0;//上下限是否有修改标志
bdata bit Relay1=0;//继电器1是否接通标志
bdata bit Relay2=0;//继电器2是否接通标志
sbit CS=P1^3;//cs of AD7708
sbit DIN=P1^1;//data in of AD7708
sbit DOUT=P1^2;//data out of AD7708
sbit DRDY=P3^2;//ready of AD7708
sbit SCLOCK=P3^3;//clock of AD7708
sbit EpromW=P3^7;//WP of CAT1161
sbit CATCLK=P3^5;//clock of I2C bus
sbit CATDAT=P3^6;//dat of I2C bus
void dog(void);//喂狗函数
void delay(unsigned int );//延时函数
void wait_delay(void);//等待延时函数
void wait(unsigned int );//等待函数
void writetoreg(unsigned char);//写AD7708寄存器函数
unsigned char readfromreg(void);//读AD7708寄存器
void CTRL_R(float);//继电器控制
float readAD(void);//读AD7708转换结果函数
void initAD(void);//初始化AD7708
void opAD(void);//采集AD7708函数
void disbyte(void);//显示函数
void disperr(void);//eprom不存在或损坏信息显示
void single_disp(void);//单通道显示
void circle_disp(void);//循环显示
float AD2T(float,float *);//AD值转换为浮点数电阻值
void V2CODE(float);//浮点数转换到显示缓存数组
unsigned char ScanKey(void);//扫描键盘函数
void KeyWork(unsigned char);//键盘处理函数
void Key1(void);//K1处理函数
void Key2(void);//K2处理函数
void Key3(void);//K3处理函数
void Key4(void);//K4处理函数
void dislow(void);//显示下限
void disup(void);//显示上限
void sendlim(signed char);//送上(下)限值去显示缓存
void FtoE(float,unsigned char);//存浮点数到EEPROM
float EtoF(unsigned char);//从EEPROM读取浮点数
void mnack(void);//I2C非应答函数
void start(void);//I2C总线开始函数
void stop(void);//I2C总线停止函数
unsigned char erxd(void);//I2C字节接收传送函数
void etxd(unsigned char);//I2C字节写传送函数
unsigned char erd(unsigned char);//I2C字节读函数
void ewr(unsigned char,unsigned char);//I2C字节写函数
void close()//close interrupt
{
EA_f=EA;
EA=0;
}
void open()//open interrupt
{EA=EA_f;}
void clock0_init() reentrant using 0//计时器0初始化函数
{
TCON=0x00;
TR0=0;
TH0=0xFC;
TL0=0x66;//1ms作为基准定时,用模式1,这样1s需要1000个定时过程
TR0=1;
}
void main() //主函数
{
data float ADresult=0.0;
data float Zero[5]={0.0,0.0,0.0,0.0,0.0};//存放0点数值
idata unsigned char Kcode,i;//Kcode存放按键值
TMOD=0x01; //定时器0模式1,
TH0=0xFC; //T0定时1ms初始值
TL0=0x66;
EpromW=0;//允许CAT1161读写
initAD();
ewr(0,0x55);//检查CAT1161的eerom存在否
wait(10000);
i=erd(0);//eeprom的0地址存检查信息
if(i==0x55) //eeprom存在,读取零点值和上下限值
{
/*for(i=0;i<5;i++)
{ ewr(21+i,0); wait(10000); }//写下限为0,调试时候用
for(i=0;i<5;i++)
{ ewr(26+i,100); wait(10000); }//写上限为100 ,调试时候用 */
for(i=0;i<5;i++)
Zero[i]=EtoF(i*4+1);//5个零点值的起始地址分别为1,5,9,13,17 ,各占4个字节
for(i=0;i<5;i++) Lower[i]=erd(21+i); //读取下限值
for(i=0;i<5;i++) Upper[i]=erd(26+i); //读取上限值
for(i=0;i<5;i++)//若上下限不合理,重写EEPROM
{
if(Lower[i]>40||Lower[i]<0)
{ Lower[i]=10;
ewr(21+i,0);
wait(10000);
}
if(Upper[i]>200||Upper[i]<50)
{ Upper[i]=100;
ewr(26+i,100);
wait(10000);
}
}
}
else {disperr();RomEr=1; }//显示eeprom坏,持续5秒
IT0=0;//外部中断0为低电平触发
ET0=1;//打开定时器0中断允许
EA=1;//开总中断
TR0=1;//开定时器0
//EX0=1;//允许外部0中断
while(1)
{
if(!RomEr)
{
while(1)
{
dog();
if(opAD_flag&&(!rdAD)){opAD_flag=0;opAD();EX0=1;dog();}//如果操作AD标志为1则去设置AD并开外部0中断
if(rdAD){
ADresult=readAD(); //读取AD转换结果
rdAD=0;
v2c_flag=1; //刷新显示标志置位
}
if(v2c_flag){
ADresult=AD2T(ADresult,Zero); //转换成温度
close();
V2CODE(ADresult);
open();
CTRL_R(ADresult);
v2c_flag=0;
}
close();
Kcode=ScanKey();//扫描键盘
open();
dog();
//close();
if(Kcode!=0)
KeyWork(Kcode);//根据键值做对应的处理
//open();
if(low_f)
{dog();dislow();} //显示下限
if(up_f)
{dog();disup();} //显示上限
}
}
}
}
/*初始化AD7708*/
void initAD(void)
{
idata int tim;
tim=1000;
/* PRECONFIGURE...*/
DRDY=1;
while(tim--);
SCLOCK=1;
DIN=1;
DOUT=1;
CS=1;
writetoreg(0x03); //write to communication register. The next step is writing to FILTER REGISTER
writetoreg(0x45); //set the FILTER register
writetoreg(0x07); //write to communication register. The next step is writing to IO REGISTER
writetoreg(0x30);//IO1和IO2均为输出,初始状态均为0
}
/*采集AD7708函数*/
void opAD()
{
data unsigned char adcon; //adcon配置AD7708的ADCON寄存器
switch(CHnum) //根据通道号,计算ADCON的值,
{
case 1: adcon=0x82; break;
case 2: adcon=0x92; break;
case 3: adcon=0xa2; break;
case 4: adcon=0xb2; break;
case 5: adcon=0xc2; break;
default: return;
}
//确保1~5通道的adcon分别为0x82,0x92,0xa2,0xb2,0xc2,输入范围为-80mV~+80mV,增益为32
close();
writetoreg(0x02); //write to communication register. The next step is writing to ADC CONTROLO register
open();
close();
writetoreg(adcon); //bipolar,
open();
close();
writetoreg(0x01);//writing to communication register, the next step is write to MODE register
open();
close();
writetoreg(0x13);//chopping,REFIN1,5 fully-differential input,continuous conversion mode
open();
}
/*写AD7708寄存器*/
void writetoreg(unsigned char byteword) //The subroutine write byteword to the corresponding registers of AD7708
{
data unsigned char temp;
idata unsigned char i;
CS=0;
temp=0x80;
for(i=0;i<8;i++)
{
if((temp&byteword)==0)
DIN=0;
else DIN=1;
SCLOCK=0;
SCLOCK=1;
temp=temp>>1;
}
CS=1;
}
/*读AD7708转换结果*/
float readAD()
{
idata unsigned char j;
data float temp=0.0;
close();
writetoreg(0x44);//write to communication register.The next step is reading data from ADC Data register
open();
close();
CS=0;
for(j=0;j<16;j++)
{
SCLOCK=0;
SCLOCK=1;
if(DOUT==1) temp+=pow(2,15-j);
}
CS=1;
open();
return(temp);
}
/*根据转换公式把AD转换结果转换为电阻值并减去对应的0点值*/
float AD2T(float ADresult,float Zero[])
{
data float result=0.0;
close();
result=(ADresult/32768-1)*2.56/32; //电压量
open();
close();
result=(488.7+362*result)/(1.35-result)-270; //电阻值
open();
close();
if(result>=100)//电阻值大于等于100,温度高于或等于0度,用下面算法
{
result=0.0000175926203204-0.0000000232*result;
result=sqrt(result);
result=fabs(result);
result=0.00390802-result;
result=result/0.00000116;
}
else result=0;//否则另温度显示为0(以后加入0度以下的算法)
open();
close();
if(Adj_Zero) //如果是调0模式,记录0值并写入eeprom
{
Zero[CHnum-1]=result;
FtoE(result,(CHnum-1)*4+1);//把0点值写入EEPROM,每个浮点数为32位,CAT1161为8位,
//故要占4个地址,每个0点值的起始地址分别为1,5,9,13,17
}
else
{
if(result>Zero[CHnum-1]) result-=Zero[CHnum-1];//如果转换结果比0点值大,则减去0点值
else result=0.0; //否则,认为结果为0
}
open();
return(result);
}
/*显示*/
void disbyte()
{
data unsigned char i;
for(i=0;i<7;i++)
{
LED_SEG=0x00;//全灭
LED_BIT=0x00;
LED_BIT=(0x40>>i); //P0位选,选通第N个数码管7654321的顺序,P0.6~P0.0
LED_SEG=Dis_dat[i];//从P2口输出字形码
delay(1);
}
LED_SEG=0x00;//全灭
}
/*循环显示控制*/
void circle_disp()
{
CHnum++;
if(CHnum>5)
{ CHnum=1;
if(Adj_Zero) Adj_Zero=0;//如果在调零模式下,CHnum到了5以后,退出调零模式
}
opAD_flag=1;
}
/*单通道显示控制*/
void single_disp()
{
opAD_flag=1; //一秒钟采集一次
}
/*浮点数转换到显示缓存数组*/
void V2CODE(float value)
{
data int Vtemp;
idata unsigned char i;
idata unsigned char DotId,Num=0;//DotId记录小数点位置Num记录无效的0的个数
if(Adj_Zero) //调0模式
{
Vcode[0]=15;//"C"给DS7
Vcode[1]=CHnum;//通道号,给DS6
}
else//测量模式
{
Vcode[0]=CHnum;//通道号,给DS7
Vcode[1]=12;//灭,给DS6
}
if(value<1.0) {DotId=3; value=floor(value*1000);Vtemp=(int)value;}//0.001<=value<1.0,小数点在DS4上,即Vcode[3]
else
{
for(i=1;i<4;i++)
if(value<pow(10,i))
{
//Vtemp=(int)(value*pow(10,4-i));//取整
value=floor(value*pow(10,4-i));
Vtemp=(int)value;
DotId=i+2;
break;
}
}
for(i=0;i<3;i++)//把后面无效的0(最多3个)消去,并移动小数点,对应有几个无效的0,前面就有几个LED灭
{
if((Vtemp%10)==0) { DotId++;Num++;Vtemp=Vtemp/10;Vcode[3+i]=12;}
else break;
}
for(i=6;i>2+Num;i--)//Vcode[6]放数值最低位,Vcode[3]放最高位
{
Vcode[i]=Vtemp%10;
Vtemp=Vtemp/10;
}
for(i=0;i<7;i++)
{
Dis_dat[i]=table[Vcode[i]]; //转换成字形并放入DiCATDAT[]数组
if(i==DotId&&DotId!=6) {Dis_dat[i]|=0x01;}//加小数点,如果DotId==6说明小数点在DS1上,不加
}
}
/*扫描键盘*/
unsigned char ScanKey(void)//P1.7--K4, P1.6--K3, P1.5--K2, P1.4--K1
{
idata int t=8000;
idata unsigned char a,b,c,i,K;
//TR0=0;
//ET0=0;//扫描键盘时候停止T0计数并关闭T0中断
P1=P1|0xf0;//先给P1.7 P1.6 P1.5 P1.4置位
a=P1;//读P1端口
if((a&0xf0)!=0xf0) while(t--);//有键按下,延时,看是否抖动
a=P1;//再读一次P1端口
if((a&0xf0)!=0xf0) //确实有键按下,
{
b=0x80;//从K4(P1.7)开始,向右扫描
c=0xff;
for(i=4;i>0;i--)//从K4到K1扫描
{
c=a&b;
if(c==0) {K=i;break;}//如果扫描到有键按下,记录键值i,停止扫描
b=b>>1;//右移,扫描下一个
}
}
else K=0;
//TR0=1;
//ET0=1;
return(K); //无键按下,返回0
}
/*根据键值做对应的处理*/
void KeyWork(unsigned char Kcode)
{
switch(Kcode)
{
case 1: {Key1();break;}
case 2: {Key2();break;}
case 3: {Key3();break;}
case 4: {Key4();break;}
}
return;
}
/*确认键K1处理函数*/
void Key1()
{
ModeWait=0;
Tns=0;
if(low_f)//如果是在显示下限模式下,则做以下处理
{
if(Modified)//如果下限值有被修改,//将修改过的下限值写入EEPROM
{ close();
ewr(20+CHnum,Lower[CHnum-1]);
//wait(10000);
open();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -