📄 rs485.lst
字号:
C51 COMPILER V6.23a RS485 12/22/2005 21:56:39 PAGE 1
C51 COMPILER V6.23a, COMPILATION OF MODULE RS485
OBJECT MODULE PLACED IN RS485.OBJ
COMPILER INVOKED BY: C:\Keil\C51\BIN\C51.EXE RS485.c BROWSE DEBUG OBJECTEXTEND
stmt level source
1 #ifndef __485_C__
2 #define __485_C__
3
4 #include <AT89X51.H>
5 #include <string.h>
6
7 #define uchar unsigned char
8 #define uint unsigned int
9 /* 通信命令 */
10 #define __ACTIVE_ 0x01 // 主机询问从机是否存在
11 #define __GETDATA_ 0x02 // 主机发送读设备请求
12 #define __OK_ 0x03 // 从机应答
13 #define __STATUS_ 0x04 // 从机发送设备状态信息
14
15 #define __MAXSIZE 0x08 // 缓冲区长度
16 #define __ERRLEN 12 // 任何通信帧长度超过12则表示出错
17 uchar dbuf[__MAXSIZE]; // 该缓冲区用于保存设备状态信息
18 uchar dev; // 该字节用于保存本机设备号
19
20 sbit M_DE = P1^0; // 驱动器使能,1有效
21 sbit M_RE = P1^1; // 接收器使能,0有效
22
23 void get_status(); // 调用该函数获得设备状态信息,函数代码未给出
24 void send_data(uchar type, uchar len, uchar *buf); // 发送数据帧
25 bit recv_cmd(uchar *type); // 接收主机命令,主机请求仅包含命令信息
26 void send_byte(uchar da); // 该函数发送一帧数据中的一个字节,由send_data()函数调用
27
28 void main()
29 {
30 1 uchar type;
31 1 uchar len;
32 1
33 1 /* 系统初始化 */
34 1 P1 = 0xff; // 读取本机设备号
35 1 dev = (P1>>2);
36 1 TMOD = 0x20; // 定时器T1使用工作方式2
37 1 TH1 = 250; // 设置初值
38 1 TL1 = 250;
39 1 TR1 = 1; // 开始计时
40 1 PCON = 0x80; // SMOD = 1
41 1 SCON = 0x50; // 工作方式1,波特率9600bps,允许接收
42 1 ES = 0; // 关闭串口中断
43 1 IT0 = 0; // 外部中断0使用电平触发模式
44 1 EX0 = 1; // 开启外部中断0
45 1 EA = 1; // 开启中断
46 1
47 1 /* 主程序流程 */
48 1 while(1) // 主循环
49 1 {
50 2 if(recv_cmd(&type) == 0) // 发生帧错误或帧地址与本机地址不符,丢弃当前帧后返回
51 2 continue;
52 2 switch(type)
53 2 {
54 3 case __ACTIVE_: // 主机询问从机是否存在
55 3 send_data(__OK_, 0, dbuf); // 发送应答信息,这里buf的内容并未用到
C51 COMPILER V6.23a RS485 12/22/2005 21:56:39 PAGE 2
56 3 break;
57 3 case __GETDATA_:
58 3 len = strlen(dbuf);
59 3 send_data(__STATUS_, len, dbuf); // 发送设备状态信息
60 3 break;
61 3 default:
62 3 break; // 命令类型错误,丢弃当前帧后返回
63 3 }
64 2 }
65 1 }
66
67 void READSTATUS() interrupt 0 using 1 // 产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1
68 {
69 1 get_status(); // 获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一字节置0表示数据结束
70 1 }
71
72 /* 该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回
73 * 函数参数type保存接收到的命令字
74 * 当接收到数据帧错误或其地址位不为0时(非主机发送帧),函数返回0,反之返回1
75 */
76 bit recv_cmd(uchar *type)
77 {
78 1 bit db = 0; // 当接收到的上一个字节为0xdb时,该位置位
79 1 bit c0 = 0; // 当接收到的上一个字节为0xc0时,该位置位
80 1 uchar data_buf[__ERRLEN]; // 保存接收到的帧
81 1 uchar tmp;
82 1 uchar ecc = 0;
83 1 uchar i;
84 1
85 1 M_DE = 0; // 置发送禁止,接收允许
86 1 M_RE = 0;
87 1
88 1 /* 接收一帧数据 */
89 1 i = 0;
90 1 while(!c0) // 循环直至帧接收完毕
91 1 {
92 2 RI = 0;
93 2 while(!RI);
94 2 tmp = SBUF;
95 2 RI = 0;
96 2 if(db == 1) // 接收到的上一个字节为0xdb
97 2 {
98 3 switch(tmp)
99 3 {
100 4 case 0xdd:
101 4 data_buf[i] = 0xdb; // 0xdbdd表示0xdb
102 4 ecc = ecc^0xdb;
103 4 db = 0;
104 4 break;
105 4 case 0xdc:
106 4 data_buf[i] = 0xc0; // 0xdbdc表示0xc0
107 4 ecc = ecc^0xc0;
108 4 db = 0;
109 4 break;
110 4 default:
111 4 return 0; // 帧错误,返回
112 4 }
113 3 i++;
114 3 }
115 2 switch(tmp) // 正常情况
116 2 {
117 3 case 0xc0: // 帧结束
C51 COMPILER V6.23a RS485 12/22/2005 21:56:39 PAGE 3
118 3 c0 = 1;
119 3 break;
120 3 case 0xdb: // 检测到转义字符
121 3 db = 1;
122 3 break;
123 3 default: // 普通数据
124 3 data_buf[i] = tmp; // 保存数据
125 3 ecc = ecc^tmp; // 计算校验字节
126 3 i++;
127 3 }
128 2 if(i == __ERRLEN) // 帧超长,错误,返回
129 2 return 0;
130 2 }
131 1 /* 判断帧是否错误 */
132 1 if(i<4) // 帧过短,错误,返回
133 1 return 0;
134 1 if(ecc != 0) // 校验错误,返回
135 1 return 0;
136 1 if(data_buf[0] != dev) // 非访问本机命令,错误,返回
137 1 return 0;
138 1 *type = data_buf[1]; // 获得命令字
139 1 return 1; // 函数成功返回
140 1 }
141
142 /* 该函数发送一帧数据帧,参数type为命令字、len为数据长度、buf为要发送的数据内容 */
143 void send_data(uchar type, uchar len, uchar *buf)
144 {
145 1 uchar i;
146 1 uchar ecc = 0; // 该字节用于保存校验字节
147 1
148 1 M_DE = 1; // 置发送允许,接收禁止
149 1 M_RE = 1;
150 1
151 1 send_byte(dev); // 发送本机地址
152 1 ecc = dev;
153 1 send_byte(type); // 发送命令字
154 1 ecc = ecc^type;
155 1 send_byte(len); // 发送长度
156 1 ecc = ecc^len;
157 1 for(i=0; i<len; i++) // 发送数据
158 1 {
159 2 send_byte(*buf);
160 2 ecc = ecc^(*buf);
161 2 buf++;
162 2 }
163 1 send_byte(ecc); // 发送校验字节
164 1
165 1 TI = 0; // 发送帧结束标志
166 1 SBUF = 0xc0;
167 1 while(!TI);
168 1 TI = 0;
169 1 }
170
171 /* 该函数发送一个数据字节,若该字节为0xdb,则发送0xdbdd,若该字节为0xc0则,发送0xdbdc */
172 void send_byte(uchar da)
173 {
174 1 switch(da)
175 1 {
176 2 case 0xdb: // 字节为0xdb,发送0xdbdd
177 2 TI = 0;
178 2 SBUF = 0xdb;
179 2 while(!TI);
C51 COMPILER V6.23a RS485 12/22/2005 21:56:39 PAGE 4
180 2 TI = 0;
181 2 SBUF = 0xdd;
182 2 while(!TI)
183 2 TI = 0;
184 2 break;
185 2 case 0xc0: // 字节为0xc0,发送0xdbdc
186 2 TI = 0;
187 2 SBUF = 0xdb;
188 2 while(!TI);
189 2 TI = 0;
190 2 SBUF = 0xdc;
191 2 while(!TI)
192 2 TI = 0;
193 2 break;
194 2 default: // 普通数据则直接发送
195 2 TI = 0;
196 2 SBUF = da;
197 2 while(!TI);
198 2 TI = 0;
199 2 }
200 1 }
201
202 #endif
MODULE INFORMATION: STATIC OVERLAYABLE
CODE SIZE = 428 ----
CONSTANT SIZE = ---- ----
XDATA SIZE = ---- ----
PDATA SIZE = ---- ----
DATA SIZE = 9 25
IDATA SIZE = ---- ----
BIT SIZE = ---- 2
END OF MODULE INFORMATION.
C51 COMPILATION COMPLETE. 0 WARNING(S), 0 ERROR(S)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -