📄 485main.c
字号:
/********************************************************************************
Serial.C
此程序是RS-485 通讯,包含3 部分:接收帧程序、发送帧程序及执行命令程序。
从机通讯地址储存在E2PROM 的0x00~0x05 中,密码在0x06~0x09。
内部振荡源
*********************************************************************************/
#include <Reg935.h>
#include<intrins.h>
#include<485e.h>
#define uchar unsigned char
/********************************************************************
延时函数
原型:void Delay_T(uchar);
功能:延时1ms*i
入口参数: i 是设定延时时间
出口参数:无
********************************************************************/
void Delay_T(uchar i)
{
uint j;
for(;i>0;i--)
for(j=0;j<700;j++);/*1ms*/
}
/********************************************************************
CPU 各个部件的初始化函数
原型:void Ini_CPU();
功能:初始化CPU 各个部件
入口参数:无
出口参数:无
********************************************************************/
void Ini_CPU()
{
P1M1&=0x7e; /*设置P1.0,P1.7 为推挽输出,P1.1 为输入状态*/
P1M2|=0x81;
P1M1|=0x02;
P1M2&=0xfd;
Delay_T(100); /*延时100ms,以稳定CPU*/
CTRL485=1; /*485通讯为接收状态*/
/*串口初始化*/
PCON&=0x3f; /*UART 设置工作方式3,11 位数据*/
SCON=0xd0;
SSTAT=0x00;
BRGCON=0x00; /*装入波特率常数,1200bps*/
BRGR1=BRGR1_DATA;
BRGR0=BRGR0_DATA;
BRGCON=0x03;
ESR=1; /*启动接收状态*/
}
/********************************************************************
接收一个字节通讯函数
原型:uchar Receive_Data();
功能:接收一个字节通讯
入口参数:无
出口参数:返回接收值
********************************************************************/
uchar Receive_Data()
{
RI=0;
while(!RI);
RI=0;
ACC=SBUF;
if(P!=RB8) /*偶校验正确吗?*/
{
SP--;SP--;CY=0;return CY; /*错误返回*/
}
return (ACC); /*接收一个字节,并进行偶校验*/
}
/********************************************************************
接收一帧通讯函数
原型:void Receive_One(uchar *);
功能:接收一帧通讯
入口参数:接收存取地址指针
出口参数:接收正确标志,1 为接收正确
********************************************************************/
bit Receive_One(uchar *s)
{
uchar CS=0x00,Serial_data;
char i,j;
RI=0;
Serial_data=SBUF; /*接收第一字节*/
while(Serial_data!=0xfe)
return 0; /*不是前导字节*/
do
Serial_data=Receive_Data(); /*是前导字节,继续查询*/
while(Serial_data==0xfe); /*是前导字节吗?*/
if(Serial_data!=0x68) /*是帧头吗?*/
return 0;
CS+=0x68;
for(i=0;i<=5;i++) /*接收电表通讯地址*/
{
*(s+i)=Receive_Data();
CS+=*(s+i);
}
if(Receive_Data()!=0x68) /*是数据帧头吗?*/
return 0;
CS+=0x68;
CS+=(*(s+6)=Receive_Data()); /*接收通讯命令*/
j=*(s+7)=Receive_Data(); /*接收通讯数据长度*/
CS+=j;
for(i=0;i<=(j-1);i++) /*接收N 个数据*/
{
CS+=(*(s+i+8)=Receive_Data());
*(s+i+8)-=0x33;
}
if(CS!=Receive_Data()) /*校验正确吗?*/
return 0;
if(Receive_Data()!=0x16) /*是帧尾吗?*/
return 0;
ESR=0;
return 1; /*一帧接收成功,关闭接收通讯,处理一帧完后再打开*/
}
/********************************************************************
串口接收中断服务程序
功能:接收数据
********************************************************************/
void RXD_Int(void) interrupt 4
{
CY=Receive_One(Serial_buf);
if(CY)
Command_status1|=0x04; /*一帧接收成功,通知主程序进行通讯处理*/
}
/********************************************************************
串口发送一个字节
功能:发送一个字节数据
入口参数:发送数据
出口参数:无
********************************************************************/
void Send_Data(uchar Serial_data)
{
ACC=Serial_data;
TB8=P;TI=0;
SBUF=Serial_data;
while(!TI);
TI=0; /*发送一个字节,并进行偶校验*/
}
/********************************************************************
发送一帧数据函数
原型:void TXD_Int(uchar *);
功能:发送一帧数据
入口参数:发送数据帧地址指针
出口参数:无
********************************************************************/
void TXD_Int(uchar *s)
{
uchar CS=0x68;
char i,j;
CTRL485=0; /*RS-485 通讯,切换为发送状态*/
Delay_T(1);
TI=0;
Send_Data(0xfe); /*发送2 个前到字节*/
Send_Data(0xfe);
Send_Data(0x68); /*发送帧头*/
for(i=0;i<=5;i++) /*发送电表通讯地址*/
{CS+=*(s+i);Send_Data(*(s+i));}
CS+=0x68;Send_Data(0x68); /*发送数据帧头*/
CS+=*(s+6);Send_Data(*(s+6)); /*发送帧命令*/
CS+=*(s+7);j=*(s+7);Send_Data(j); /*发送数据长度*/
for(i=0;i<=j-1;i++) /*发送数据*/
{
(*(s+i+8))+=0x33;
Send_Data(*(s+i+8));
CS+=(*(s+i+8));
}
Send_Data(CS); /*发送校验字节*/
Send_Data(0x16); /*发送帧尾*/
RI=0;TI=0;
Delay_T(1);
CTRL485=1; /*一帧发送完毕,恢复信道切换功能*/
}
/********************************************************************
通讯地址判断函数
原型:uchar Serial_Address(uchar *);
功能:通讯地址判断,通讯地址存储E2PROM 0 区0x00~0x05 中
全局变量:
入口参数:s1 指向从通讯地址
出口参数:0x00 错误,0x01 正确,0x02 广播地址
********************************************************************/
uchar Serial_Address(uchar *s1)
{
uchar i,a[6];
IRcvStr(CAT24W08,0x00,a,6); /*读取电表通讯地址*/
for(i=0;i<=5;i++)
{
if((*(s1+i))!=0x99)
break; /*不是广播地址*/
if(i==5)
return(0x02); /*是广播地址*/
}
for(i=0;i<=5;i++)
{
if((*(s1+i))!=a[i])
return(0x00); /*地址不相同*/
}
return(0x01); /*地址相同*/
}
/********************************************************************
通讯密码判断函数
原型:bit Serial_Password(uchar *);
功能:通讯密码判断,密码存储E2PROM 0 区0x06~0x09 中
全局变量:
入口参数:s1 指向从通讯密码地址
出口参数:0 错误,1 正确
********************************************************************/
bit Serial_Password(uchar *s1)
{
uchar i,a[4];
IRcvStr(CAT24W08,0x06,a,4);
for(i=0;i<=3;i++)
{
if((*(s1+i))!=a[i])
return 0; /*密码不对*/
}
return 1; /*密码正确*/
}
/********************************************************************
通讯执行函数
原型:bit Serial_Command_Run(uchar *);
功能:执行通讯命令
入口参数:帧地址
出口参数:是否正确及是否完毕,0 为错误和通讯没有完成,1 为正确和通讯完成
********************************************************************/
bit Serial_Command_Run(uchar *s)
{
switch(Serial_Address(s)) /*判断地址是否正确*/
{
case 0x02: /*广播地址999999999999H*/
break;
case 0x01: /*正常地址*/
switch(*(s+6))
{
case 0x0f: /*进行密码修改*/
if(~Serial_Password(s+8)) /*密码是否正确*/
return 0; /*错误,返回*/
ISendStr(CAT24W08,0x06,s+12,4);/*存取新密码*/
Delay_T(5);
/*构造返回数据帧*/
IRcvStr(CAT24W08,0x00,s,6); /*读取电表通讯地址*/
IRcvStr(CAT24W08,0x06,s+8,4); /*读取存取的密码*/
(*(s+6))|=0x80;(*(s+7))=0x04; /*存入命令码及长度字节*/
TXD_Int(s); /*发送一帧数据*/
break;
case 0x01: /*读数据*/
break;
case 0x04: /*写数据*/
break;
default: /*其他命令*/
break;
}
break;
case 0x00: /*地址错误*/
return 0;
break;
}
return 1; /*帧执行正确,返回*/
}
/********************************************************************
通讯主函数
原型:void Serial_Command();
功能:执行通讯命令
入口参数:无
出口参数:无
********************************************************************/
void Serial_Command()
{
if(Command_status1&0x04) /*通讯事件发送*/
{
if(~Serial_Command_Run(Serial_buf)) /*帧执行*/
{ESR=1;Command_status1&=0xfb;return;} /*帧错误,恢复信道功能*/
ESR=1; /*恢复信道功能*/
Command_status1&=0xfb; /*j 清除通讯处理事件*/
}
}
/********************************************************************
电表程序主函数
原型:void main();
功能:完成通讯主流程
入口参数:无
出口参数:无
********************************************************************/
void main()
{
Ini_CPU(); /*对CPU 各个部件初始化*/
EA=1; /*打开中断开关*/
while(1)
{
Serial_Command();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -