⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 su232.c

📁 89C52 UPS后备电源 R232通信源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*************************************************************
 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 + -