📄 485.lst
字号:
(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 <iom64v.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: 31
(0036) void RXC_Int(void) //接收中断
(0037) {
(0038) unsigned char ERROR=0;
0256 2700 CLR R16
(0039)
(0040) if(UCSR1A&0x08||UCSR1A&0x10 )ERROR=1; //奇偶效验错误(avr自动完成)或者帧错误就记录下来
0257 9020009B LDS R2,0x9B
0259 FC23 SBRC R2,3
025A C004 RJMP 0x025F
025B 9020009B LDS R2,0x9B
025D FE24 SBRS R2,4
025E C001 RJMP 0x0260
025F E001 LDI R16,1
(0041) inbox[n]=UDR1;
0260 E286 LDI R24,0x26
0261 E091 LDI R25,1
0262 91E00100 LDS R30,n
0264 27FF CLR R31
0265 0FE8 ADD R30,R24
0266 1FF9 ADC R31,R25
0267 9020009C LDS R2,0x9C
0269 8220 STD Z+0,R2
(0042) n++; //记忆中断次数
026A 91800100 LDS R24,n
026C 5F8F SUBI R24,0xFF
026D 93800100 STS n,R24
(0043) if(ERROR) inbox[0]=0; //如果通讯有错,收件箱的地址帧就标记成无效地址0
026F 2300 TST R16
0270 F019 BEQ 0x0274
0271 2422 CLR R2
0272 92200126 STS inbox,R2
0274 9029 LD R2,Y+
0275 BE2F OUT 0x3F,R2
0276 91F9 LD R31,Y+
0277 91E9 LD R30,Y+
0278 9199 LD R25,Y+
0279 9189 LD R24,Y+
027A 9109 LD R16,Y+
027B 9029 LD R2,Y+
027C 9518 RETI
(0044)
(0045) }
(0046)
(0047)
(0048) //-----------------------主机接收函数-------------------------------------------
(0049) void int_485(void) //接收程序,在中断中调用或者扫描调用
(0050) {
(0051) //if(n<3) 如果接收到的数据还不到3个,那么就是通讯线路故障
(0052)
(0053) //如果收件箱已经收到amount个数据,并且crc8校验成功就...
(0054) if(n==amount && inbox[amount-1]==crc8(inbox,amount-1))
_int_485:
027D 91800100 LDS R24,n
027F 308A CPI R24,0xA
0280 F4B1 BNE 0x0297
0281 E029 LDI R18,0x9
0282 E206 LDI R16,0x26
0283 E011 LDI R17,1
0284 DEE3 RCALL _crc8
0285 9020012F LDS R2,0x12F
0287 1620 CP R2,R16
0288 F471 BNE 0x0297
(0055) {
(0056) if(inbox[0]==1)flag_me=1; //主机地址
0289 91800126 LDS R24,inbox
028B 3081 CPI R24,1
028C F419 BNE 0x0290
028D E081 LDI R24,1
028E 93800101 STS flag_me,R24
(0057) //接收完数据后会置标志位,在读取数据后要把标志位置零
(0058) if(inbox[0]==255) flag_all=1; //广播地址,接收后不要回复
0290 91800126 LDS R24,inbox
0292 3F8F CPI R24,0xFF
0293 F419 BNE 0x0297
0294 E081 LDI R24,1
0295 93800102 STS flag_all,R24
(0059) //接收完数据后会置标志位,在读取数据后要把标志位置零
(0060)
(0061) }
0297 9508 RET
_out_485:
i --> R20
ptr --> R22
address --> R20
0298 940E035D CALL push_gset2
029A 01B9 MOVW R22,R18
029B 2F40 MOV R20,R16
(0062)
(0063) }
(0064)
(0065)
(0066) //-------------------主机发送函数-----------------------------------------------
(0067) void out_485(unsigned char address,unsigned char *ptr)
(0068) {unsigned char i;
(0069) n=0; //中断次数清0
029C 2422 CLR R2
029D 92200100 STS n,R2
(0070) inbox[0]=0; //收件箱地址清0
029F 92200126 STS inbox,R2
(0071) //请更新准备发送的数据
(0072) //send[1]=?
(0073) //......
(0074) //send[n]=?
(0075) send[0]=address; //改变这个地址就可以实现与某个从机对话
02A1 93400130 STS send,R20
(0076) for(i=1;i<amount-1;i++)send[i]=*ptr++;//把发送的数据方到发信箱
02A3 E041 LDI R20,1
02A4 C00B RJMP 0x02B0
02A5 E380 LDI R24,0x30
02A6 E091 LDI R25,1
02A7 2FE4 MOV R30,R20
02A8 27FF CLR R31
02A9 0FE8 ADD R30,R24
02AA 1FF9 ADC R31,R25
02AB 01DB MOVW R26,R22
02AC 902D LD R2,X+
02AD 01BD MOVW R22,R26
02AE 8220 STD Z+0,R2
02AF 9543 INC R20
02B0 3049 CPI R20,0x9
02B1 F398 BCS 0x02A5
(0077)
(0078) send[amount-1]=crc8(send,amount-1); //计算发件箱的crc8校验码
02B2 E029 LDI R18,0x9
02B3 E300 LDI R16,0x30
02B4 E011 LDI R17,1
02B5 DEB2 RCALL _crc8
02B6 93000139 STS 0x139,R16
(0079)
(0080) usart_out(send,amount); //将发件箱的数据send[]发送出去;
02B8 E02A LDI R18,0xA
02B9 E300 LDI R16,0x30
02BA E011 LDI R17,1
02BB DE83 RCALL _usart_out
(0081)
(0082) //等待,从机接收到数据后会回复数据的,如果是10个字节数据量,不能少于13ms!!!
(0083) //这个时间由人工计算,要考虑从机由于各种中断延长回复时间的可能
(0084)
(0085) delay_nms(15);
02BC E00F LDI R16,0xF
02BD E010 LDI R17,0
02BE DDD6 RCALL _delay_nms
02BF 940E0351 CALL pop_gset2
02C1 9508 RET
_main:
key --> Y+2
address --> R10
j --> R20
i --> R12
02C2 972A SBIW R28,0xA
(0086) }
(0087)
(0088)
(0089)
(0090) void main(void)
(0091) { unsigned char key[8],i,address,j=0;
02C3 2744 CLR R20
(0092) usart_init(); //串口初始化
02C4 DE68 RCALL _usart_init
(0093) UCSR1A=0x00; //主机关闭地址筛选功能(多机通讯功能)
02C5 2422 CLR R2
02C6 9220009B STS 0x9B,R2
(0094) LCD_init(); //液晶初始化
02C8 DDDB RCALL _LCD_init
(0095) SEI(); //打开全局中断,需要macros.h支持
02C9 9478 BSET 7
(0096) LCD_write_string(0,0,"out:");
02CA E280 LDI R24,0x20
02CB E091 LDI R25,1
02CC 8399 STD Y+1,R25
02CD 8388 STD Y+0,R24
02CE 2722 CLR R18
02CF 2700 CLR R16
02D0 DE3A RCALL _LCD_write_string
(0097) LCD_write_string(0,1,"int:");
02D1 E18B LDI R24,0x1B
02D2 E091 LDI R25,1
02D3 8399 STD Y+1,R25
02D4 8388 STD Y+0,R24
02D5 E021 LDI R18,1
02D6 2700 CLR R16
02D7 DE33 RCALL _LCD_write_string
02D8 C075 RJMP 0x034E
(0098) while(1)
(0099) {
(0100) int_485();
02D9 DFA3 RCALL _int_485
(0101)
(0102)
(0103)
(0104) if(flag_me)
02DA 90200101 LDS R2,flag_me
02DC 2022 TST R2
02DD F0A9 BEQ 0x02F3
(0105) {
(0106) //-------------以下为测试语句------------------------------------
(0107) LCD_write_string(4,1,inbox);
02DE E286 LDI R24,0x26
02DF E091 LDI R25,1
02E0 8399 STD Y+1,R25
02E1 8388 STD Y+0,R24
02E2 E021 LDI R18,1
02E3 E004 LDI R16,4
02E4 DE26 RCALL _LCD_write_string
(0108) LCD_write_string(12,1," ");//数组没有结束符,所以要修正液晶后面多余的乱码
02E5 E185 LDI R24,0x15
02E6 E091 LDI R25,1
02E7 8399 STD Y+1,R25
02E8 8388 STD Y+0,R24
02E9 E021 LDI R18,1
02EA E00C LDI R16,0xC
02EB DE1F RCALL _LCD_write_string
(0109) n=0; //中断次数清0
02EC 2422 CLR R2
02ED 92200100 STS n,R2
(0110) inbox[0]=0; //收件箱地址清0
02EF 92200126 STS inbox,R2
(0111) flag_me=0;//清收信箱满标志位
02F1 92200101 STS flag_me,R2
(0112) //---------------------------------------------------------------
(0113) }
(0114) //-------------以下为测试语句------------------------------------
(0115) i=get_key();
02F3 DF3B RCALL _get_key
02F4 2EC0 MOV R12,R16
(0116) switch (i)
02F5 2D6C MOV R22,R12
02F6 2777 CLR R23
02F7 3461 CPI R22,0x41
02F8 E0E0 LDI R30,0
02F9 077E CPC R23,R30
02FA F069 BEQ 0x0308
02FB 3462 CPI R22,0x42
02FC E0E0 LDI R30,0
02FD 077E CPC R23,R30
02FE F099 BEQ 0x0312
02FF 3463 CPI R22,0x43
0300 E0E0 LDI R30,0
0301 077E CPC R23,R30
0302 F169 BEQ 0x0330
0303 3464 CPI R22,0x44
0304 E0E0 LDI R30,0
0305 077E CPC R23,R30
0306 F0A9 BEQ 0x031C
0307 C031 RJMP 0x0339
(0117) {
(0118) case 'A':{address=2;LCD_write_string(4,0,"2>>");}
0308 E082 LDI R24,2
0309 2EA8 MOV R10,R24
030A E181 LDI R24,0x11
030B E091 LDI R25,1
030C 8399 STD Y+1,R25
030D 8388 STD Y+0,R24
030E 2722 CLR R18
030F E004 LDI R16,4
0310 DDFA RCALL _LCD_write_string
(0119) break;
0311 C03C RJMP 0x034E
(0120) case 'B':{address=3;LCD_write_string(4,0,"3>>");}
0312 E083 LDI R24,3
0313 2EA8 MOV R10,R24
0314 E08D LDI R24,0xD
0315 E091 LDI R25,1
0316 8399 STD Y+1,R25
0317 8388 STD Y+0,R24
0318 2722 CLR R18
0319 E004 LDI R16,4
031A DDF0 RCALL _LCD_write_string
(0121) break;
031B C032 RJMP 0x034E
(0122) case 'D':
(0123) {out_485(address,key);
031C 019E MOVW R18,R28
031D 5F2E SUBI R18,0xFE
031E 4F3F SBCI R19,0xFF
031F 2D0A MOV R16,R10
0320 DF77 RCALL _out_485
(0124) LCD_write_string(4,0,send);
0321 E380 LDI R24,0x30
0322 E091 LDI R25,1
0323 8399 STD Y+1,R25
0324 8388 STD Y+0,R24
0325 2722 CLR R18
0326 E004 LDI R16,4
0327 DDE3 RCALL _LCD_write_string
(0125) LCD_write_string(12,1," ");//数组没有结束符,所以要修正液晶后面多余的乱码
0328 E185 LDI R24,0x15
0329 E091 LDI R25,1
032A 8399 STD Y+1,R25
032B 8388 STD Y+0,R24
032C E021 LDI R18,1
032D E00C LDI R16,0xC
032E DDDC RCALL _LCD_write_string
(0126) }
(0127) break;
032F C01E RJMP 0x034E
(0128) case 'C':{j=0;LCD_write_string(7,0," ");}
0330 2744 CLR R20
0331 E083 LDI R24,3
0332 E091 LDI R25,1
0333 8399 STD Y+1,R25
0334 8388 STD Y+0,R24
0335 2722 CLR R18
0336 E007 LDI R16,7
0337 DDD3 RCALL _LCD_write_string
(0129) break;
0338 C015 RJMP 0x034E
(0130) default:
(0131) if(j<8&&i<='9'&&i>='0'){key[j]=i;LCD_write_char(j+7,0,i);j++;}
FILE: <library>
0339 3048 CPI R20,0x8
033A F498 BCC 0x034E
033B E389 LDI R24,0x39
033C 158C CP R24,R12
033D F080 BCS 0x034E
033E 2D8C MOV R24,R12
033F 3380 CPI R24,0x30
0340 F068 BCS 0x034E
0341 01CE MOVW R24,R28
0342 9602 ADIW R24,2
0343 2FE4 MOV R30,R20
0344 27FF CLR R31
0345 0FE8 ADD R30,R24
0346 1FF9 ADC R31,R25
0347 82C0 STD Z+0,R12
0348 82C8 STD Y+0,R12
0349 2722 CLR R18
034A 2F04 MOV R16,R20
034B 5F09 SUBI R16,0xF9
034C DDD4 RCALL _LCD_write_char
034D 9543 INC R20
034E CF8A RJMP 0x02D9
034F 962A ADIW R28,0xA
0350 9508 RET
pop_gset2:
0351 E0E2 LDI R30,2
0352 940C0363 JMP pop
pop_gset3:
0354 E0E4 LDI R30,4
0355 940C0363 JMP pop
push_gset5:
0357 92FA ST R15,-Y
0358 92EA ST R14,-Y
push_gset4:
0359 92DA ST R13,-Y
035A 92CA ST R12,-Y
push_gset3:
035B 92BA ST R11,-Y
035C 92AA ST R10,-Y
push_gset2:
035D 937A ST R23,-Y
035E 936A ST R22,-Y
push_gset1:
035F 935A ST R21,-Y
0360 934A ST R20,-Y
0361 9508 RET
pop_gset1:
0362 E0E1 LDI R30,1
pop:
0363 9149 LD R20,Y+
0364 9159 LD R21,Y+
0365 FDE0 SBRC R30,0
0366 9508 RET
0367 9169 LD R22,Y+
0368 9179 LD R23,Y+
0369 FDE1 SBRC R30,1
036A 9508 RET
036B 90A9 LD R10,Y+
036C 90B9 LD R11,Y+
036D FDE2 SBRC R30,2
036E 9508 RET
036F 90C9 LD R12,Y+
0370 90D9 LD R13,Y+
0371 FDE3 SBRC R30,3
0372 9508 RET
0373 90E9 LD R14,Y+
0374 90F9 LD R15,Y+
0375 9508 RET
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -