📄 485.lst
字号:
0228 939A ST R25,-Y
0229 93EA ST R30,-Y
022A 93FA ST R31,-Y
022B B62F IN R2,0x3F
022C 922A ST R2,-Y
FILE: D:\avr\+++精华+++\485\485_master\main.c
(0001) /*******************************************************************************
(0002) 485多机通讯
(0003) --------------------------------------------------------------------------------
(0004) 通讯规则:
(0005) 1:时钟7.3728 MHz/波特率9600/9个数据位/奇校验/1个停止位/硬件多机通讯功能/
(0006) 2:通讯连接采用硬件MAX485,双向单工
(0007) 3:每个上行/下行的数据包的字节个数都是一样的(通讯数据量)
(0008) 4:每个上行/下行的数据包都采用CRC8校验
(0009) 5:数据接收采用中断+查询的方式
(0010) 6:总是由主机向从机发送一个数据包,从机收到数据包后向主机回复一个数据包
(0011) 7:不管是主机还是从机,如果收到的数据包有任何错误,都将丢弃该数据包,等效于没有接收
(0012) 8:从机之间不能相互通讯,必须通过主机才能交换数据
(0013) 9:无效地址是0,主机地址是1,从机地址是2.3.4......广播地址是255
(0014) ********************************************************************************/
(0015)
(0016) #include <iom16v.h>
(0017) #include <macros.h>
(0018) #include "delay.h"
(0019) #include "1602.h"
(0020) #include "usart.h"
(0021) #include "crc8.h" //CRC校验函数就在这个文件里面
(0022) #include "key.h"
(0023) #define amount 10 //设定通讯数据量(包括1个地址帧,n个数据帧,1个校验帧)
(0024)
(0025)
(0026) unsigned char send[amount]; //发件箱
(0027) unsigned char inbox[amount]; //收件箱
(0028) unsigned char n=0; //记忆中断次数
(0029) unsigned char flag_me=0;
(0030) unsigned char flag_all=0;
(0031)
(0032)
(0033)
(0034) //-------------------主机接收子程序--------------------------------
(0035) #pragma interrupt_handler RXC_Int: 12
(0036) void RXC_Int(void) //接收中断
(0037) {
(0038) unsigned char ERROR=0;
022D 2700 CLR R16
(0039) if(UCSRA&0x08||UCSRA&0x10 )ERROR=1; //奇偶效验错误(avr自动完成)或者帧错误就记录下来
022E 995B SBIC 0x0B,3
022F C002 RJMP 0x0232
0230 9B5C SBIS 0x0B,4
0231 C001 RJMP 0x0233
0232 E001 LDI R16,1
(0040) inbox[n]=UDR;
0233 E886 LDI R24,0x86
0234 E090 LDI R25,0
0235 91E00060 LDS R30,n
0237 27FF CLR R31
0238 0FE8 ADD R30,R24
0239 1FF9 ADC R31,R25
023A B02C IN R2,0x0C
023B 8220 STD Z+0,R2
(0041) n++; //记忆中断次数
023C 91800060 LDS R24,n
023E 5F8F SUBI R24,0xFF
023F 93800060 STS n,R24
(0042) if(ERROR) inbox[0]=0; //如果通讯有错,收件箱的地址帧就标记成无效地址0
0241 2300 TST R16
0242 F019 BEQ 0x0246
0243 2422 CLR R2
0244 92200086 STS inbox,R2
0246 9029 LD R2,Y+
0247 BE2F OUT 0x3F,R2
0248 91F9 LD R31,Y+
0249 91E9 LD R30,Y+
024A 9199 LD R25,Y+
024B 9189 LD R24,Y+
024C 9109 LD R16,Y+
024D 9029 LD R2,Y+
024E 9518 RETI
(0043) }
(0044)
(0045) void int_485(void)//接收程序,在中断中调用或者扫描调用
(0046) {
(0047) //if(n<3) 如果接收到的数据还不到3个,那么就是通讯线路故障
(0048)
(0049) //如果收件箱已经收到amount个数据,并且crc8校验成功就...
(0050) if(n==amount && inbox[amount-1]==crc8(inbox,amount-1))
_int_485:
024F 91800060 LDS R24,n
0251 308A CPI R24,0xA
0252 F4B1 BNE 0x0269
0253 E029 LDI R18,0x9
0254 E806 LDI R16,0x86
0255 E010 LDI R17,0
0256 DEE8 RCALL _crc8
0257 9020008F LDS R2,0x8F
0259 1620 CP R2,R16
025A F471 BNE 0x0269
(0051) {
(0052) if(inbox[0]==1)flag_me=1;
025B 91800086 LDS R24,inbox
025D 3081 CPI R24,1
025E F419 BNE 0x0262
025F E081 LDI R24,1
0260 93800061 STS flag_me,R24
(0053) //接收完数据后会置标志位
(0054) if(inbox[0]==255) flag_me=1; //请在这里添加收到广播数据的处理程序
0262 91800086 LDS R24,inbox
0264 3F8F CPI R24,0xFF
0265 F419 BNE 0x0269
0266 E081 LDI R24,1
0267 93800061 STS flag_me,R24
(0055)
(0056) }
0269 9508 RET
_out_485:
i --> R20
ptr --> R22
address --> R20
026A 940E0329 CALL push_gset2
026C 01B9 MOVW R22,R18
026D 2F40 MOV R20,R16
(0057)
(0058) }
(0059)
(0060)
(0061)
(0062) void out_485(unsigned char address,unsigned char *ptr)
(0063) {unsigned char i;
(0064) n=0; //中断次数清0
026E 2422 CLR R2
026F 92200060 STS n,R2
(0065) inbox[0]=0; //收件箱地址清0
0271 92200086 STS inbox,R2
(0066) //请更新准备发送的数据
(0067) //send[1]=?
(0068) //......
(0069) //send[n]=?
(0070) send[0]=address; //改变这个地址就可以实现与某个从机对话
0273 93400090 STS send,R20
(0071) for(i=1;i<amount-1;i++)send[i]=*ptr++;//把发送的数据方到发信箱
0275 E041 LDI R20,1
0276 C00B RJMP 0x0282
0277 E980 LDI R24,0x90
0278 E090 LDI R25,0
0279 2FE4 MOV R30,R20
027A 27FF CLR R31
027B 0FE8 ADD R30,R24
027C 1FF9 ADC R31,R25
027D 01DB MOVW R26,R22
027E 902D LD R2,X+
027F 01BD MOVW R22,R26
0280 8220 STD Z+0,R2
0281 9543 INC R20
0282 3049 CPI R20,0x9
0283 F398 BCS 0x0277
(0072)
(0073) send[amount-1]=crc8(send,amount-1); //计算发件箱的crc8校验码
0284 E029 LDI R18,0x9
0285 E900 LDI R16,0x90
0286 E010 LDI R17,0
0287 DEB7 RCALL _crc8
0288 93000099 STS 0x99,R16
(0074)
(0075) usart_out(send,amount); //将发件箱的数据send[]发送出去;
028A E02A LDI R18,0xA
028B E900 LDI R16,0x90
028C E010 LDI R17,0
028D DE90 RCALL _usart_out
(0076)
(0077) //等待,从机接收到数据后会回复数据的,如果是10个字节数据量,不能少于13ms!!!
(0078) //这个时间由人工计算,要考虑从机由于各种中断延长回复时间的可能
(0079)
(0080) delay_nms(15);
028E E00F LDI R16,0xF
028F E010 LDI R17,0
0290 DDE8 RCALL _delay_nms
0291 940E031D CALL pop_gset2
0293 9508 RET
_main:
key --> Y+2
j --> R22
address --> R10
i --> R12
0294 972A SBIW R28,0xA
(0081) }
(0082)
(0083)
(0084)
(0085) void main(void)
(0086) { unsigned char key[8],i,address,j;
(0087) usart_init(); //串口初始化
0295 DE7B RCALL _usart_init
(0088) UCSRA=0x00; //主机关闭地址筛选功能(多机通讯功能)
0296 2422 CLR R2
0297 B82B OUT 0x0B,R2
(0089) LCD_init();//液晶初始化
0298 DDEF RCALL _LCD_init
(0090) SEI(); //打开全局中断,需要macros.h支持
0299 9478 BSET 7
(0091) LCD_write_string(0,0,"out:");
029A E880 LDI R24,0x80
029B E090 LDI R25,0
029C 8399 STD Y+1,R25
029D 8388 STD Y+0,R24
029E 2722 CLR R18
029F 2700 CLR R16
02A0 DE4E RCALL _LCD_write_string
(0092) LCD_write_string(0,1,"int:");
02A1 E78B LDI R24,0x7B
02A2 E090 LDI R25,0
02A3 8399 STD Y+1,R25
02A4 8388 STD Y+0,R24
02A5 E021 LDI R18,1
02A6 2700 CLR R16
02A7 DE47 RCALL _LCD_write_string
02A8 C071 RJMP 0x031A
(0093)
(0094)
(0095) while(1)
(0096) {
(0097) //-------------以下为测试语句------------------------------------
(0098)
(0099) if(flag_me)
02A9 90200061 LDS R2,flag_me
02AB 2022 TST R2
02AC F051 BEQ 0x02B7
(0100) {
(0101) LCD_write_string(7,1,inbox);
02AD E886 LDI R24,0x86
02AE E090 LDI R25,0
02AF 8399 STD Y+1,R25
02B0 8388 STD Y+0,R24
02B1 E021 LDI R18,1
02B2 E007 LDI R16,7
02B3 DE3B RCALL _LCD_write_string
(0102) flag_me=0;
02B4 2422 CLR R2
02B5 92200061 STS flag_me,R2
(0103) }
(0104) i=get_key();
02B7 DF4E RCALL _get_key
02B8 2EC0 MOV R12,R16
(0105) switch (i)
02B9 2D4C MOV R20,R12
02BA 2755 CLR R21
02BB 334D CPI R20,0x3D
02BC E0E0 LDI R30,0
02BD 075E CPC R21,R30
02BE F139 BEQ 0x02E6
02BF E38D LDI R24,0x3D
02C0 E090 LDI R25,0
02C1 1784 CP R24,R20
02C2 0795 CPC R25,R21
02C3 F04C BLT 0x02CD
02C4 324B CPI R20,0x2B
02C5 E0E0 LDI R30,0
02C6 075E CPC R21,R30
02C7 F051 BEQ 0x02D2
02C8 324D CPI R20,0x2D
02C9 E0E0 LDI R30,0
02CA 075E CPC R21,R30
02CB F081 BEQ 0x02DC
02CC C028 RJMP 0x02F5
02CD 3443 CPI R20,0x43
02CE E0E0 LDI R30,0
02CF 075E CPC R21,R30
02D0 F0D9 BEQ 0x02EC
02D1 C023 RJMP 0x02F5
(0106) {
(0107) case '+':{address=2;LCD_write_string(4,0,"2>>");}
02D2 E082 LDI R24,2
02D3 2EA8 MOV R10,R24
02D4 E787 LDI R24,0x77
02D5 E090 LDI R25,0
02D6 8399 STD Y+1,R25
02D7 8388 STD Y+0,R24
02D8 2722 CLR R18
02D9 E004 LDI R16,4
02DA DE14 RCALL _LCD_write_string
(0108) break;
02DB C030 RJMP 0x030C
(0109) case '-':{address=3;LCD_write_string(4,0,"3>>");}
02DC E083 LDI R24,3
02DD 2EA8 MOV R10,R24
02DE E783 LDI R24,0x73
02DF E090 LDI R25,0
02E0 8399 STD Y+1,R25
02E1 8388 STD Y+0,R24
02E2 2722 CLR R18
02E3 E004 LDI R16,4
02E4 DE0A RCALL _LCD_write_string
(0110) break;
02E5 C026 RJMP 0x030C
(0111) case '=':out_485(address,key);
02E6 019E MOVW R18,R28
02E7 5F2E SUBI R18,0xFE
02E8 4F3F SBCI R19,0xFF
02E9 2D0A MOV R16,R10
02EA DF7F RCALL _out_485
(0112) break;
02EB C020 RJMP 0x030C
(0113) case 'C':{j=0;LCD_write_string(7,0," ");}
02EC 2766 CLR R22
02ED E689 LDI R24,0x69
02EE E090 LDI R25,0
02EF 8399 STD Y+1,R25
02F0 8388 STD Y+0,R24
02F1 2722 CLR R18
02F2 E007 LDI R16,7
02F3 DDFB RCALL _LCD_write_string
(0114) break;
02F4 C017 RJMP 0x030C
(0115) default:
(0116) if(j<8&&i<='9'&&i>='0'){key[j++]=i;LCD_write_char(j+6,0,i);}
02F5 3068 CPI R22,0x8
02F6 F4A8 BCC 0x030C
02F7 E389 LDI R24,0x39
02F8 158C CP R24,R12
02F9 F090 BCS 0x030C
02FA 2D8C MOV R24,R12
02FB 3380 CPI R24,0x30
02FC F078 BCS 0x030C
02FD 2E26 MOV R2,R22
02FE 2433 CLR R3
02FF 5F6F SUBI R22,0xFF
0300 01CE MOVW R24,R28
0301 9602 ADIW R24,2
0302 2DE2 MOV R30,R2
0303 27FF CLR R31
0304 0FE8 ADD R30,R24
0305 1FF9 ADC R31,R25
0306 82C0 STD Z+0,R12
0307 82C8 STD Y+0,R12
0308 2722 CLR R18
0309 2F06 MOV R16,R22
030A 5F0A SUBI R16,0xFA
030B DDF9 RCALL _LCD_write_char
(0117)
(0118) }
(0119)
(0120) LCD_write_string(4,1,inbox);
030C E886 LDI R24,0x86
030D E090 LDI R25,0
030E 8399 STD Y+1,R25
030F 8388 STD Y+0,R24
0310 E021 LDI R18,1
0311 E004 LDI R16,4
0312 DDDC RCALL _LCD_write_string
(0121) LCD_write_string(12,1," ");//数组没有结束符,所以要修正液晶后面多余的乱码
FILE: <library>
0313 E683 LDI R24,0x63
0314 E090 LDI R25,0
0315 8399 STD Y+1,R25
0316 8388 STD Y+0,R24
0317 E021 LDI R18,1
0318 E00C LDI R16,0xC
0319 DDD5 RCALL _LCD_write_string
031A CF8E RJMP 0x02A9
031B 962A ADIW R28,0xA
031C 9508 RET
pop_gset2:
031D E0E2 LDI R30,2
031E 940C032F JMP pop
pop_gset3:
0320 E0E4 LDI R30,4
0321 940C032F JMP pop
push_gset5:
0323 92FA ST R15,-Y
0324 92EA ST R14,-Y
push_gset4:
0325 92DA ST R13,-Y
0326 92CA ST R12,-Y
push_gset3:
0327 92BA ST R11,-Y
0328 92AA ST R10,-Y
push_gset2:
0329 937A ST R23,-Y
032A 936A ST R22,-Y
push_gset1:
032B 935A ST R21,-Y
032C 934A ST R20,-Y
032D 9508 RET
pop_gset1:
032E E0E1 LDI R30,1
pop:
032F 9149 LD R20,Y+
0330 9159 LD R21,Y+
0331 FDE0 SBRC R30,0
0332 9508 RET
0333 9169 LD R22,Y+
0334 9179 LD R23,Y+
0335 FDE1 SBRC R30,1
0336 9508 RET
0337 90A9 LD R10,Y+
0338 90B9 LD R11,Y+
0339 FDE2 SBRC R30,2
033A 9508 RET
033B 90C9 LD R12,Y+
033C 90D9 LD R13,Y+
033D FDE3 SBRC R30,3
033E 9508 RET
033F 90E9 LD R14,Y+
0340 90F9 LD R15,Y+
0341 9508 RET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -