📄 su232.c
字号:
/*************************************************************
232 Program
For at89s52 MCU
guwenxing
2007-01-01
**************************************************************/
#include "reg52.h"
/****************显示********************/
#define uchar unsigned char
#define uint unsigned int
#define LINE1 0 //显示屏的上行
#define LINE2 1 //显示屏的下行
#define LINE1_HEAD 0x80 //上行的头地址
#define LINE2_HEAD 0xC0 //下行的头地址
#define BUSY 0x80 //忙状态判断位
#define LCD_DATA P0 //LCD的数据线
#define DATA_MODE 0x38 //LCD的模式的控制字
#define OPEN_SCREEN 0x0C //打开显示的控制字
#define DISPLAY_ADDRESS 0x80 //光标返回的控制字
#define CLR 0x01 //清屏的控制字
sbit test=P1^0; //测试,暂时没用
sbit LCD_light=P1^2; //LCD的背灯控制
sbit LCD_MEN=P2^4; //LCD显示的菜单控制键
sbit LED=P2^3; //工作指示灯
sbit LCD_RS=P2^5; //1数据,0命令
sbit LCD_RW=P2^6; //1读,0写
sbit LCD_EN=P2^7; //1到0时(下降沿执行命令)
uchar zf_data[8]={0x0e,0x0a,0x0e,0x00,0x00,0x00,0x00,0x00};//温度单位的字库
void LCD_command(uchar l_cmd,uchar BusyC);//LCD发送命令子函数:l_cmd是命令码,BusyC表示是否读忙状态
void LCD_data(uchar l_data,uchar BusyC); //LCD发送数据子函数:l_data是数据码,BusyC表示是否读忙状态
void LCD_set_xy( uchar x, uchar y ); //LCD定位光标子函数
void LCD_write_char( uchar x,uchar y,uchar dat);//LCD写字符子函数:X,Y是显示的坐标,dat是显示的字符
void LCD_write_string(uchar X,uchar Y,uchar *s);//LCD写字符串子函数:X,Y是显示的坐标,*s是显示的字符串
void LCD_init(void); //LCD初始化子函数
void LCD_ZK(uchar ascii,uchar *z);//LCD的画字符的函数
uchar ReadStatus(void); //读忙子函数
void LCD_MEN1();//按键处理和LCD显示更新
/************************显示*********************************************/
bit s_flag; //关机的命令标志位
bit r_flag; //开机的命令标志位
bit mlflag;//串口命令的标志位
bit frestar; //频率开始位
sbit on_sw=P1^1; //开机控制脚
sbit off_sw=P3^5; //关机控制脚
uint s_time; //关机的时间
uint r_time; //开机的时间
uchar sw_id;//按键值
uchar ionum;//计算串口的数据的字节数
uchar iodat[20];//存放串口的数据
uchar upsstate; //ups的状态位
uint timef; //T2的定时记数变量
void Yuint_char(uint dat,char * cha);//把INT转换成3个字符
void mlcl();//命令处理函数
void delay_5ms(void); //延时子函数
/****************5045********************/
#define WREN 0x06
#define WRDI 0x04
#define RDSR 0x05
#define WRSR 0x01
#define READ0 0x03
#define READ1 0x0b
#define WRITE0 0x02
#define WRITE1 0x0a
sbit WDT_CS=P1^3; /*单片机p1.3为片选 */
sbit WDT_SO=P1^7 ;/*数据输出 */
sbit WDT_SCK=P1^6 ;/* 时钟 */
sbit WDT_SI=P1^5; /* 数据输入*/
uchar WDT_Read8(); //读一个字节的数据
uchar WDT_ReadSR(); //读存储器状态
uchar WDT_WriteSR(uchar cData); //写状态
uchar WDT_Read1B(uchar cAddress,bit bRegion); //读一个字节
void WDT_RstWDT(); //喂狗
void WDT_Write8(uchar cData); //写一个字节的数据
void WDT_Write1B(uchar cData,uchar cAddress,bit bRegion); //写一个字节
uint read5045c(uchar add,uchar add_long);//读5045的参数
void wrio(uchar add,uchar add_long);//发送查询数据;
/****************5045********************/
/****************读取数据********************/
uchar temp;
uchar input;
uchar output;
uchar load;
uchar battery;
uchar infre;
uchar outfre;
bit fre; //输入和输出频率计算的标志位
sbit fail=P3^6;
sbit inv_bypass=P3^7;
void ad_data(); //读取A/D的饿数据
/***TLC0838 A/D转换*****/
sbit AD_CLOCK=P1^6;
sbit AD_IN=P1^5;
sbit AD_OUT=P1^7;
sbit AD_CS=P1^4;
uchar read0838(uchar port);//从TLC0838读取采样值,形参port是采样的通道号
//从TLC0838读取采样值,形参port是采样的通道号
uchar read0838(uchar port)
{
uchar ad;uint i;
ad=0;
AD_CS=1;
AD_CLOCK=0;
AD_CS=0;
AD_IN=1; //Start bit
AD_CLOCK=1;
AD_CLOCK=0;
AD_IN=1;
AD_CLOCK=1;
AD_CLOCK=0;
AD_IN=port&0x01;
AD_CLOCK=1;
AD_CLOCK=0;
AD_IN=port&0x04;
AD_CLOCK=1;
AD_CLOCK=0;
AD_IN=port&0x02;
AD_CLOCK=1;
AD_CLOCK=0;
AD_CLOCK=1;
for(i=0;i<8;i++)
{
AD_CLOCK=0;
ad=ad<<1;//ad=00000000
ad=ad|AD_OUT;
AD_CLOCK=1;
}
AD_CS=1;
return (ad);
}
/****************读取数据********************/
void ad_data()
{
uint j;
uint bat_e;
uint bat_data;
uint bj;//用来防止在+-1跳变
float fbat;
bj=temp;
temp=read0838(0);//温度
temp=(bj+temp)/2;
WDT_RstWDT();
bj=input;
input=read0838(1);//市电电压
if(input<20)infre=0;
input=(bj+input)/2;
WDT_RstWDT();
bj=output;
output=read0838(2);//输出电压
if(output<20)outfre=0;//为了防止在电压突然跳变,没有脉冲后不会进入中断计算,不会返回0;
output=(bj+output)/2;
WDT_RstWDT();
bj=load;
load=read0838(3);//带载
load=(bj+load)/2;
WDT_RstWDT();
bj=battery;
battery=read0838(4);//电池电压
battery=(bj+battery)/2;
WDT_RstWDT();
//根据各状态改变lcd上行的显示内容,
if(~fail)
{
j=10;
while(j--);
if(~fail)upsstate=upsstate&0xef; //延时,防止跳变。
}
else
{
j=10;
while(j--);
if(fail)upsstate=upsstate|0x10; //延时,防止跳变。
}
if(inv_bypass)
{
j=10;
while(j--);
if(inv_bypass)upsstate=upsstate|0x20; //延时,防止跳变。
}
else
{
j=10;
while(j--);
if(~inv_bypass)upsstate=upsstate&0xdf; //延时,防止跳变。
}
//这个ac fail是错误的
bat_data=read5045c(33,4);
fbat=bat_data/255.0;
bat_data=(float)input*fbat;
bat_e=read5045c(193,3);
if(bat_e>bat_data)upsstate=upsstate|0x80;//低压
else upsstate=upsstate&0x7f;//正常
//测电池低压
bat_data=read5045c(65,4);
fbat=bat_data/255.0;
bat_data=(float)battery*fbat;
bat_e=read5045c(209,4);
if(bat_e>bat_data)upsstate=upsstate|0x40;//低压
else upsstate=upsstate&0xbf;//正常
}
/****************5045********************/
//喂狗
void WDT_RstWDT()
{
WDT_CS=0;
WDT_CS=1;
}
//读8个字节数据
uchar WDT_Read8()
{
bit bData;
uchar cLoop;
uchar cData;
WDT_SCK=0;
WDT_CS=0;
for(cLoop=0;cLoop<8;cLoop++) //先接收高位
{
bData=WDT_SO;
WDT_SCK=1;
WDT_SCK=0;
cData<<=1;
if(bData)
{
cData|=0x01;
}
}
return cData;
}
//写8个字节的数据
void WDT_Write8(uchar cData)
{
uchar cLoop;
WDT_SCK=0;
WDT_CS=0;
for(cLoop=0;cLoop<8;cLoop++)
{
if((cData&0x80)==0) //高位开始发送
{
WDT_SI=0;
}
else
{
WDT_SI=1;
}
WDT_SCK=0;
WDT_SCK=1;
cData<<=1;
}
}
//读取5045状态寄存器
uchar WDT_ReadSR()
{
uchar cData;
WDT_SCK=0; //命令开始,先拉高WDT_CS,再拉低WDT_SCK,跟着拉低WDT_CS.
WDT_CS=0;
WDT_Write8(RDSR);
cData=WDT_Read8();
WDT_SCK=0; //命令结束,先拉低WDT_SCK,跟着拉高WDT_CS.
WDT_CS=1;
return cData;
}
//写5045状态寄存器
uchar WDT_WriteSR(uchar cData)
{
uchar cTemp;
WDT_SCK=0;
WDT_CS=0;
cTemp=WDT_ReadSR();
if((cTemp&0x01)==1)return 0; //内部写操作没完成
WDT_Write8(WREN);//**************
WDT_CS=1;
WDT_CS=0;
WDT_Write8(WRSR);
WDT_Write8(cData);
WDT_SCK=0; //命令结束,先拉低WDT_SCK,跟着拉高WDT_CS.
WDT_CS=1;
return 1;
}
//写入一个字节,cData为写入的数,cAddress为写入地址,bRegion为页
void WDT_Write1B(uchar cData,uchar cAddress,bit bRegion)
{
WDT_SCK=0;
WDT_CS=0;
while((WDT_ReadSR()&0x01)==1);
WDT_Write8(WREN);
WDT_CS=1;
WDT_CS=0;
if(bRegion==0)
{
WDT_Write8(WRITE0);
}
else
{
WDT_Write8(WRITE1);
}
WDT_Write8(cAddress);
WDT_Write8(cData);
WDT_SCK=0;
WDT_CS=1;
}
/* 读入一个字节,cAddress为读入地址,bRegion为页 */
uchar WDT_Read1B(uchar cAddress,bit bRegion)
{
uchar cData;
WDT_SCK=0;
WDT_CS=0;
while((WDT_ReadSR()&0x01)==1);
if(bRegion==0)
{
WDT_Write8(READ0);
}
else
{
WDT_Write8(READ1);
}
WDT_Write8(cAddress);
cData=WDT_Read8();
WDT_SCK=0;
WDT_CS=1;
return cData;
}
//发送命令子函数/
void LCD_command(uchar l_cmd,uchar BusyC)
{
if (BusyC) ReadStatus(); //读忙状态
LCD_DATA=l_cmd; //发送命令
LCD_RS=0; //命令
LCD_RW=0; //写
LCD_EN=0; //下降沿
LCD_EN=0; //延时
LCD_EN=1; //返回高电平
}
//发送数据子函数/
void LCD_data(uchar l_data,uchar BusyC)
{
if (BusyC) ReadStatus(); //读忙状态
LCD_DATA=l_data; //发送数据
LCD_RS=1; //发送数据
LCD_RW=0; //写
LCD_EN=0; //下降沿
LCD_EN=0; //延时
LCD_EN=1; //返回高电平
}
//LCD定位光标子函数
void LCD_set_xy( uchar x, uchar y )
{
uchar address;
if (y == LINE1)
address = LINE1_HEAD + x; //1行+80H
else
address = LINE2_HEAD + x; //2行+C0H
LCD_command(address,1); // 移动光标到address,要判断忙信号
}
//LCD写字符子函数:X,Y是显示的坐标,dat是显示的字符
void LCD_write_char( uchar x,uchar y,uchar dat)
{
LCD_set_xy( x, y ); //移动光标到X,Y
LCD_data(dat,1); //输出字符
}
//LCD写字符串子函数:X,Y是显示的坐标,*s是显示的字符串
void LCD_write_string(uchar X,uchar Y,uchar *s)
{
LCD_set_xy( X, Y ); //移动光标到X,Y
while (*s) // 写字符串
{
LCD_DATA=*s;
LCD_data(*s,1); //为什么不是 LCD_data(*s,1);
s++;
}
}
//LCD初始化子函数
void LCD_init(void)
{
delay_5ms();
LCD_command(CLR,0);//清屏
LCD_command(DATA_MODE,1);//LCD的模式
LCD_command(OPEN_SCREEN,1);//打开显示屏
LCD_command(DISPLAY_ADDRESS,1);//返回头地址
LCD_command(CLR,1);//清屏
}
//读忙子函数
uchar ReadStatus(void)
{
LCD_DATA = 0xFF; //I/O口置输入
LCD_RS = 0; //命令
LCD_RW = 1; //读
LCD_EN = 0; //下降沿
LCD_EN = 0; //延时
LCD_EN = 1; //返回高电平
while (LCD_DATA & BUSY); //判断忙信号
return(LCD_DATA); //返回0
}
//===以下是显示自定义字符的程序===1602中还可以自定义8个字符图案 ,图案规格5*8
void LCD_ZK(uchar ascii,uchar *z)
{
uchar address=0,i,temp=0; //ascii为与要定义的图案对应的ascii码值(0x00到0x007间任选)
temp=(ascii&0x07)<<3;
for(i=0;i<8;i++)
{
address = 0x40 +temp+ i;
LCD_command(address,1);
LCD_data(*(z++),1);
}
}
//把uchar的数值转换成字符型
void Yuint_char(uint dat,char * cha)
{
uint dat2;
uint dat1;
char datstr[4];
dat2=dat;
dat1=dat%10;
if(dat1==0)datstr[2]='0';
if(dat1==1)datstr[2]='1';
if(dat1==2)datstr[2]='2';
if(dat1==3)datstr[2]='3';
if(dat1==4)datstr[2]='4';
if(dat1==5)datstr[2]='5';
if(dat1==6)datstr[2]='6';
if(dat1==7)datstr[2]='7';
if(dat1==8)datstr[2]='8';
if(dat1==9)datstr[2]='9';
dat2=dat/10;
dat1=dat2%10;
if(dat1==0)datstr[1]='0';
if(dat1==1)datstr[1]='1';
if(dat1==2)datstr[1]='2';
if(dat1==3)datstr[1]='3';
if(dat1==4)datstr[1]='4';
if(dat1==5)datstr[1]='5';
if(dat1==6)datstr[1]='6';
if(dat1==7)datstr[1]='7';
if(dat1==8)datstr[1]='8';
if(dat1==9)datstr[1]='9';
dat2=dat2/10;
dat1=dat2%10;
if(dat1==0)datstr[0]='0';
if(dat1==1)datstr[0]='1';
if(dat1==2)datstr[0]='2';
if(dat1==3)datstr[0]='3';
if(dat1==4)datstr[0]='4';
if(dat1==5)datstr[0]='5';
if(dat1==6)datstr[0]='6';
if(dat1==7)datstr[0]='7';
if(dat1==8)datstr[0]='8';
if(dat1==9)datstr[0]='9';
cha[0]=datstr[0];
cha[1]=datstr[1];
cha[2]=datstr[2];
}
//延时子函数,调试用***************************
void delay_5ms(void) //5ms
{
uchar i = 5;
uint j;
while(i--){
j=1000;
while(j--);
}
WDT_RstWDT();
}
//读5045的int参数 add地址 add_long长度
uint read5045c(uchar add,uchar add_long)
{
uchar d_add1;
uchar d_add2;
uchar d_dat1;
uint d_dat;
d_dat=0;
d_add1=add;
d_add2=add+add_long;
d_dat1=WDT_Read1B(d_add1,0);
while(d_dat1!=0x0d && d_add1!=d_add2)
{
d_dat1=d_dat1-'0';
d_dat=d_dat*10+d_dat1;
d_add1++;
d_dat1= WDT_Read1B(d_add1,0);
}
return d_dat;
}
void wrio(uchar add,uchar add_long)
{
uchar io_add;
uchar io_add1;
uchar iodat_d;
io_add=add;
io_add1=add+add_long;
iodat_d=WDT_Read1B(io_add,0);
while(iodat_d!=0x0d && io_add!=io_add1)
{
SBUF=iodat_d;
while(TI==0);
TI=0;
io_add++;
iodat_d= WDT_Read1B(io_add,0);
}
}
//键盘处理
void LCD_MEN1()
{
uchar lcd_add=0;
uchar lcd_dat=0;
uchar j=0;
uchar * upsdata; //UPS
uchar upsxs[10]={0,0,0,}; //用来存放现在显示的数据,就是在下行要更新的数据
uchar * upsstatexs;
uint xsdat=0; //存放显示值
float f_xs=0.0;
LED=~LED;
if(upsstate&0x10)upsstatexs="UPS FAIL";
else
{
if(upsstate&0x80)
{upsstatexs="AC FAIL";
if(upsstate&0x40)upsstatexs="AC FAIL LOW DC";
}
else
{
if(upsstate&0x20)
{upsstatexs="BYPASS";
if(upsstate&0x40)upsstatexs="BYPASS LOW DC";
}
else
{upsstatexs="ON LINE";
if(upsstate&0x40)upsstatexs="ON LINE LOW DC";
}
}
}
if( sw_id==0x09) sw_id=0x01;
if(sw_id==0x01) //键盘处理,有8页要显示
{
LCD_command(CLR,0);
LCD_write_string(0,LINE1,upsstatexs);
LCD_write_string(0,LINE2,"MODEL:");
lcd_add=17;j=7;
lcd_dat=WDT_Read1B(lcd_add,0);
while(lcd_dat!=0x0d && lcd_add!=33)
{
LCD_write_char(j,LINE2,lcd_dat);
lcd_add++;j++;
lcd_dat= WDT_Read1B(lcd_add,0);
}
delay_5ms();//这个是UPS型号
}
if(sw_id==0x02)
{
xsdat=read5045c(33,4);
f_xs=xsdat/255.0;
xsdat=(float)input*f_xs;
upsdata=upsxs;
Yuint_char(xsdat,upsxs);
if(upsxs[0]=='0')
{upsxs[0]=' ';
if(upsxs[1]=='0')
{upsxs[1]=' ';
}
}
LCD_command(CLR,0);
LCD_write_string(0,LINE1,upsstatexs);
LCD_write_string(0,LINE2,"INPUT:");
LCD_write_string(7,LINE2,upsdata);//这个是市电输入电压
LCD_write_string(11,LINE2,"V");delay_5ms();
}
if(sw_id==0x03)
{
xsdat=read5045c(49,4);
f_xs=xsdat/255.0;
xsdat=(float)output*f_xs;
upsdata=upsxs;
Yuint_char(xsdat,upsxs);
if(upsxs[0]=='0')
{upsxs[0]=' ';
if(upsxs[1]=='0')
{upsxs[1]=' ';
}
}
LCD_command(CLR,0);
LCD_write_string(0,LINE1,upsstatexs);
LCD_write_string(0,LINE2,"OUTPUT:");
LCD_write_string(8,LINE2,upsdata);//这个是输出电压
LCD_write_string(12,LINE2,"V");delay_5ms();
}
if(sw_id==0x04)
{
xsdat=read5045c(81,4);
f_xs=xsdat/255.0;
xsdat=read5045c(145,3);
f_xs=(f_xs*100)/xsdat;
xsdat=(float)load*f_xs;
upsdata=upsxs;
Yuint_char(xsdat,upsxs);
if(upsxs[0]=='0')
{upsxs[0]=' ';
if(upsxs[1]=='0')
{upsxs[1]=' ';
}
}
LCD_command(CLR,0);
LCD_write_string(0,LINE1,upsstatexs);
LCD_write_string(0,LINE2,"NOW LOAD:");
LCD_write_string(9,LINE2,upsdata);//这个是带载
LCD_write_string(12,LINE2,"%");delay_5ms();
}
if(sw_id==0x05)
{
upsdata=upsxs;
Yuint_char(infre,upsxs);
if(upsxs[0]=='0')
{upsxs[0]=' ';
if(upsxs[1]=='0')
{upsxs[1]=' ';
}
}
LCD_command(CLR,0);
LCD_write_string(0,LINE1,upsstatexs);
LCD_write_string(0,LINE2,"ACIN FRE:");
LCD_write_string(9,LINE2,upsdata);//这个是市电频率
LCD_write_string(13,LINE2,"Hz");delay_5ms();
}
if(sw_id==0x06)
{
upsdata=upsxs;
Yuint_char(outfre,upsxs);
if(upsxs[0]=='0')
{upsxs[0]=' ';
if(upsxs[1]=='0')
{upsxs[1]=' ';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -