📄 snt-c485.asm
字号:
;############################################################
;文件名: IR-485.ASM
;文件说明:本程序为电表采集器
;功能: 1. 遵循电力部DL/T645-1998协议,通过RS485总线,采集并存储
; 电表的数据通过无线(红外)进行数据通讯.
; 2. 设置采集器地址
; 3. 增加、删除电表地址
; 4. 读、写电表地址
; 5. 自动、人工采集数据
; 6. 数据上传功能.
;############################################################
SCMD EQU 0A0H
RCMD EQU 0A1H
WDTC EQU 8FH
;***********************************
;寄存器分配表
;***********************************
CK_ADDR6 EQU 27H ;采集器地址最高字节
CK_ADDR5 EQU 28H
CK_ADDR4 EQU 29H
CK_ADDR3 EQU 2AH
CK_ADDR2 EQU 2BH
CK_ADDR1 EQU 2CH
CK_ADDR0 EQU 2DH ;采集器地址最低字节
ADDR6 EQU 2EH ;接收命令时暂存采集器地址最高字节
ADDR5 EQU 2FH
ADDR4 EQU 30H
ADDR3 EQU 31H
ADDR2 EQU 32H
ADDR1 EQU 33H
ADDR0 EQU 34H ;接收命令时暂存采集器地址最低字节
BADD5 EQU 35H ;接收命令时暂存表地址最高字节
BADD4 EQU 36H
BADD3 EQU 37H
BADD2 EQU 38H
BADD1 EQU 39H
BADD0 EQU 3AH ;接收命令时暂存表地址最低字节
DBADR5 EQU 3BH ;表地址最高字节
DBADR4 EQU 3CH
DBADR3 EQU 3DH
DBADR2 EQU 3EH
DBADR1 EQU 3FH
DBADR0 EQU 40H ;表地址最低字节
;41H--55H 读写缓冲区
;5DH--5FH 延时寄存器
YSRES1 EQU 5DH
YSRES2 EQU 5EH
YSRES3 EQU 5FH
COMMTYPE EQU 60H ;接收命令类型
RECCNT EQU 61H ;接收字节序号
SERNO EQU 62H ;暂存接收命令时采集器的序列号
SER EQU 63H ;采集器的序列号
DBSHU EQU 64H ;采集器所接的电表数
TEMP EQU 65H ;临时寄存器
HOUR EQU 66H ;内部时钟:时
MINUTE EQU 67H ;内部时钟:分
SECOND EQU 68H ;内部时钟:秒
SENDCNT EQU 69H ;发送数据时的表序号
DATA4 EQU 6AH ;电表度数最高字节
DATA3 EQU 6BH
DATA2 EQU 6CH
DATA1 EQU 6DH ;电表度数最低字节
TIMES EQU 6EH ;0.05S定时中断次数
CONS EQU 6FH ;临时寄存器
MINLAY_L EQU 70H ;10S计数器
TEMP1 EQU 71H ;临时寄存器
TEMP2 EQU 72H ;临时寄存器
;****位寄存器标志
TIME_SEND BIT 00H ;定时发送时间到标志
SEC_TIME BIT 01H ;10秒定时到标志
SEND_OK BIT 02H ;发送数据完成标志
CHAOBIAO BIT 03H ;抄表命令标志
DBREAD_F BIT 04H ;读单表数据标志
REC_COMM BIT 05H ;收到新命令标志
ADDR_READ BIT 06H ;读表地址标志位
ADDR_WR BIT 07H ;写表地址标志位
EVEN BIT 08H ;偶校验位
SUCESS BIT 09H ;读单表数据成功标志位
SUCESS1 BIT 0AH ;广播读地址成功标志位
SUCESS2 BIT 0BH ;写电表命令成功标志
MIN_FLAG BIT 0CH ;10秒定时到标志
TINT_F BIT 0DH ;0.05秒定时到标志
ST_YAN BIT 0EH ;允许10秒定时开始标志
SJYS BIT 0FH ;发数据时间到标志
YOUBIAO BIT 11H ;采集器中是否已有表地址标志
ZS_OK BIT 12H ;增删表号成功标志
WRP EQU P1.1
SCL EQU P1.2
SDA EQU P1.3
TR EQU P1.4
WK EQU P1.5
TONG_A EQU P1.6
TONG_B EQU P1.7
;***********************************************
;主程序
;***********************************************
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP TINT0 ;定时器0中断,每200mS中断1次
ORG 0023H
LJMP ESINT ;串口中断
ORG 0030H
MAIN: LCALL DELAY_1S ;上电延时500ms
MOV R0,#08H ;清寄存器08H-FFH
MOV R2,#0F8H
MOV A,#00H
MA1: MOV @R0,A
INC R0
DJNZ R2,MA1
MOV SP,#0B0H ;注意:寄存器的初始化不能放在寄存器清零之前!
CLR WK
MOV TCON,#00H
MOV T2CON,#30H ;T2作波特率发生器
MOV TH2,#0FEH ;波特率为1200
MOV TL2,#0E0H
MOV RCAP2H,#0FEH
MOV RCAP2L,#0E0H
MOV SCON,#50H ;与PC通讯用方式1,1位起始位,8位数据位,1位停止位
MOV TMOD,#01H ;T0设为定时方式1
MOV TL0,#0 ;定时时间0.05S f=11.0592M
MOV TH0,#4CH ;T=11059200*0.05/12=B400H 10000-B400=4C00H
MOV WDTC,#0C7H ;看门狗寄存器
MOV IE,#92H
SETB TR0
SETB TR2
MOV R2,#07H ;读采集器地址
MOV R0,#CK_ADDR6
MOV DPTR,#0
MA2: LCALL READ_1
MOV @R0,A
INC DPL
INC R0
DJNZ R2,MA2
LCALL READ_1 ;读采集器序列号
MOV SER,A
LCALL CBSHU ;查所接电表数
SETB TONG_B ;切换到通道2,无线模块
CLR TONG_A
SETB TIME_SEND ;上电时允许发送
SETB ST_YAN ;上电时允许延时
;****************以下程序为初始化上电时的内部时钟
MOV A,CK_ADDR0
ADD A,CK_ADDR1
MOV B,A
MOV A,CK_ADDR0
ANL A,#0FH
ADD A,B
MOV B,A
MOV A,CK_ADDR0
SWAP A
ANL A,#0FH
ADD A,B
MOV B,A
MOV A,CK_ADDR1
ANL A,#0FH
ADD A,B
MOV B,A
MOV A,CK_ADDR1
SWAP A
ANL A,#0FH
ADD A,B
MOV B,#3CH
DIV AB
MOV A,B
MOV SECOND,A
MOV A,CK_ADDR0
MOV B,A
CLR C
SUBB A,#3CH
JC MA2A
MOV B,A
SUBB A,#3CH
JC MA2A
LJMP MA2B
MA2A: MOV A,B
MA2B: MOV MINUTE,A
MOV A,CK_ADDR0
ANL A,#0FH
MOV HOUR,A
MOV SENDCNT,#00H
SETB TIME_SEND
;*****************初始化时钟结束
MAIN_LOOP:
MOV A,WDTC
ORL A,#40H
MOV WDTC,A ;置CLRW位,看门狗重新计数
JB TIME_SEND,MA3 ;定时发送是否到?
JNB CHAOBIAO,MA6 ;是否抄表?
MA3: SETB ST_YAN ;定时发送到或有抄表命令时允许10S延时
MOV A,SENDCNT ;
CJNE A,DBSHU,MA4 ;是否发送完
SETB SEND_OK ;发送完成,清标志位
CLR TIME_SEND
CLR SJYS
CLR ST_YAN
CLR CHAOBIAO
MOV SENDCNT,#0
LJMP MA6
MA4: JB MIN_FLAG,MA5 ;发送没有完成,10秒定时到吗?
LJMP MA6
MA5: LCALL ADRC ;10秒定时到,采集并发送数据
LCALL READ_DB
LCALL DATASEND
CLR MIN_FLAG
INC SENDCNT ;发送序号增1
MA6: JB REC_COMM,MA7 ;是否收到新的命令
LJMP MA10
MA7: JNB DBREAD_F,MA8 ;是否有读单表数据命令
LCALL PAN_HAO
JB YOUBIAO,MA7A
SJMP MA7B
MA7A: MOV A,R2
MOV SENDCNT,A
LCALL READ_DB ;读数据
LCALL DATASEND ;返回读数据
MA7B: CLR REC_COMM
CLR DBREAD_F
LJMP MA10
MA8: JNB ADDR_READ,MA9 ;是否有读表地址命令
LCALL BROD_AD ;读地址
LCALL RET_ADDR ;返回所读地址
LJMP MA10
MA9: JNB ADDR_WR,MA10 ;是否有写表地址命令
LCALL WRADDR ;写地址
LCALL RET_WR ;返回所写地址
MA10: JB TINT_F,MA11
LJMP MAIN_LOOP
MA11: CLR TINT_F ;0.05S定时中断到标志
INC TIMES
MOV A,TIMES
CJNE A,#20,MA12 ;判断是否到1秒
MA12: JC MAIN_LOOP
MOV TIMES,#0
MOV A,SECOND
ADD A,#1
MOV SECOND,A
MOV B,A
JNB SJYS,MA13 ;判断随机延时是否到,
CJNE A,CONS,MA13 ;
CLR SJYS ;到,置位定时发送标志
MOV SENDCNT,#0 ;
SETB TIME_SEND ;
SETB ST_YAN ;
MA13: MOV A,B ;
CJNE A,#60,MA14
MA14: JC MA21
MOV SECOND,#0
MOV A,MINUTE
ADD A,#1
MOV MINUTE,A
CJNE A,#01H,MA17 ;0点,8点,16点的1分后经随机延时后发送数据
MOV A,HOUR
ANL A,#07H
JNZ MA21
MOV A,TL0 ;随机延时
MOV B,#3CH ;
DIV AB ;
MOV CONS,B ;
SETB SJYS ;
MA17:
MOV A,MINUTE
MA18: CJNE A,#60,MA19
MA19: JC MA21
MOV MINUTE,#0
MOV A,HOUR
ADD A,#1
MOV HOUR,A
CJNE A,#24,MA20
MA20: JC MA21
MOV HOUR,#0
MA21: LJMP MAIN_LOOP
;**********************************************
;根据表序号找表地址子程序
;**********************************************
ADRC: MOV A,SENDCNT
CJNE A,#36,ADRC_1 ;若电表序号大于35,则转EEPROM的第2页
ADRC_1: JC ADRC2
LJMP ADRC4
ADRC2: MOV B,#7
MOV A,SENDCNT
MUL AB
MOV DPL,A ;找到数据块的首址
INC DPL ;增1为地址最高位
MOV DPH,#1
MOV R0,#BADD5
MOV R2,#6
ADRC2A: LCALL READ_1 ;读出数据
MOV @R0,A
INC R0 ;变量增1
INC DPL
DJNZ R2,ADRC2A
RET
ADRC4: MOV A,SENDCNT ;在页面2中查找
CLR C
SUBB A,#36
MOV B,#7
MUL AB
MOV DPL,A ;找到数据块的首址
INC DPL ;增1为地址最高位
MOV DPH,#2
MOV R0,#BADD5
MOV R2,#6
ADRC5: LCALL READ_1 ;读出数据
MOV @R0,A
INC R0
INC DPL
DJNZ R2,ADRC5
RET
;**********************************************
;读电表数据子程序
;读数正确,标志位SUCESS为1,否则为0
;若读数正确,存于DATA4--DATA1中
;**********************************************
READ_DB: CLR TONG_A ;切换到RS485通道
CLR TONG_B
CLR ES ;不允许串口中断
MOV SCON,#0D0H ;串口工作于方式3
;**********************************
;以下程序为查找表地址,找到后存于BADD5--BADD0
MOV A,SENDCNT ;要发送的表序号
CJNE A,#36,READ_DB1 ;判断表地址所在的页面
READ_DB1: JC READ_DB2
LJMP READ_DB4
READ_DB2: MOV B,#7 ;页面1
MUL AB
MOV DPL,A
INC DPL
MOV DPH,#1
MOV R0,#BADD5
MOV R2,#6
READ_DB3: LCALL READ_1
MOV @R0,A
INC R0
INC DPL
DJNZ R2,READ_DB3
LJMP READ_DB6
READ_DB4: MOV A,SENDCNT ;页面2
CLR C
SUBB A,#36
MOV B,#7
MUL AB
MOV DPL,A
INC DPL
MOV DPH,#2
MOV R0,#BADD5
MOV R2,#6
READ_DB5: LCALL READ_1
MOV @R0,A
INC R0
INC DPL
DJNZ R2,READ_DB5
;*******************************
;*******************************
;以下为发送命令程序
READ_DB6: SETB TR ;发送允许
LCALL DBS_COLL ;整理要发送的命令
MOV SBUF,#0FEH ;发送前导符
SETB TB8 ;
READ_DB7: JBC TI,READ_DB8
LJMP READ_DB7
READ_DB8: MOV R2,#14
MOV R0,#41H ;发送的命令存于41H--4EH
READ_DB8A: MOV A,@R0
LCALL EVENJ ;偶校验
JB EVEN,READ_DB9
CLR TB8
LJMP READ_DBA
READ_DB9: SETB TB8
READ_DBA: MOV A,@R0
INC R0
MOV SBUF,A
READ_DBB: JBC TI,READ_DBC
LJMP READ_DBB
READ_DBC: DJNZ R2,READ_DB8A ;是否发送完毕
;命令发送完毕
;*******************************
;*******************************
;以下为接收电表返回数据程序
CLR TR ;开始接收
READ_DBCA: MOV YSRES1,#02H ;500MS延时
READ_DBD: MOV YSRES2,#0E0H
READ_DBE: MOV YSRES3,#0
READ_DBF: JBC RI,READ_DBG
DJNZ YSRES3,READ_DBF
DJNZ YSRES2,READ_DBE
DJNZ YSRES1,READ_DBD
RBFA: LJMP ERR ;若500MS内没有接收到有效数据,出错处理
READ_DBG: MOV A,SBUF
MOV TEMP,A
LCALL EVENJ
JB EVEN,READ_DBH
JB RB8,RBFA ;偶校验错,出错处理
LJMP READ_DBI
READ_DBH: JNB RB8,RBFA ;偶校验错,出错处理
READ_DBI: MOV A,TEMP
CJNE A,#68H,READ_DBCA;判断起始符
MOV R3,#68H
MOV R2,#15
MOV R0,#42H
READ_DBJ: MOV YSRES1,#02H ;500MS延时
READ_DBK: MOV YSRES2,#0E0H
READ_DBL: MOV YSRES3,#0
READ_DBM: JBC RI,READ_DBN
DJNZ YSRES3,READ_DBM
DJNZ YSRES2,READ_DBL
DJNZ YSRES1,READ_DBK
RBFB: LJMP ERR ;若500MS内没有接收到有效数据,出错处理
READ_DBN: MOV A,SBUF
MOV TEMP,A
LCALL EVENJ
JB EVEN,READ_DBO
JB RB8,RBFB ;偶校验错,出错处理
LJMP READ_DBP
READ_DBO: JNB RB8,RBFB ;偶校验错,出错处理
READ_DBP: MOV A,TEMP
MOV @R0,A
INC R0
ADD A,R3
MOV R3,A
DJNZ R2,READ_DBJ
;以下判断校验和
MOV YSRES1,#02H ;500MS延时
READ_DBQ: MOV YSRES2,#0E0H
READ_DBR: MOV YSRES3,#0
READ_DBS: JBC RI,READ_DBT
DJNZ YSRES3,READ_DBS
DJNZ YSRES2,READ_DBR
DJNZ YSRES1,READ_DBQ
RBFC: LJMP ERR ;若500MS内没有接收到有效数据,出错处理
READ_DBT: MOV A,SBUF
MOV TEMP,A
LCALL EVENJ
JB EVEN,READ_DBU
JB RB8,RBFC ;偶校验错,出错处理
LJMP READ_DBV
READ_DBU: JNB RB8,RBFC ;偶校验错,出错处理
READ_DBV: MOV A,R3
CJNE A,TEMP,RBFC
;以下判断结束符
MOV YSRES1,#02H ;500MS延时
READ_DBW: MOV YSRES2,#0E0H
READ_DBX: MOV YSRES3,#0
READ_DBY: JBC RI,READ_DBZ
DJNZ YSRES3,READ_DBY
DJNZ YSRES2,READ_DBX
DJNZ YSRES1,READ_DBW
RBFD: LJMP ERR ;若500MS内没有接收到有效数据,出错处理
READ_DBZ: MOV A,SBUF
MOV TEMP,A
LCALL EVENJ
JB EVEN,READ_D11
JB RB8,RBFD ;偶校验错,出错处理
LJMP READ_D11
READ_D10: JNB RB8,RBFD ;偶校验错,出错处理
READ_D11: MOV A,TEMP
CJNE A,#16H,RBFD
;以下判断数据项的正确性
MOV A,48H
CJNE A,#68H,RBFD
MOV A,49H
CJNE A,#81H,RBFD
MOV A,4BH
CJNE A,#43H,ERR
MOV A,4CH
CJNE A,#0C3H,ERR
;以下比较表地址
MOV R2,#6
MOV R0,#BADD0
MOV R1,#42H
READ_D12: MOV A,@R1
MOV TEMP,A
MOV A,@R0
CJNE A,TEMP,ERR
INC R1
DEC R0
DJNZ R2,READ_D12
;以下整理读数值,存于DATA4--DATA1中
MOV R1,#4DH
MOV R0,#DATA1
MOV R2,#4
READ_D13: MOV A,@R1
CLR C
SUBB A,#33H
MOV @R0,A
INC R1
DEC R0
DJNZ R2,READ_D13
SETB SUCESS
SETB TONG_B
MOV SCON,#50H
SETB ES
RET
ERR: SETB TONG_B
MOV SCON,#50H
CLR SUCESS
SETB ES
RET
;********************************************
;偶校验子程序
;入口:A 出口:C
;********************************************
EVENJ: MOV R7,#8
CLR EVEN
CLR C
EVENJ_1: RLC A
JNC EVENJ_2
CPL EVEN
EVENJ_2: DJNZ R7,EVENJ_1
RET
;********************************************
;发送对电表的读数据请求命令前的整理数据子程序
;整理数据存于:41H--4EH
;********************************************
DBS_COLL: MOV 41H,#68H ;起始符
MOV R3,#68H ;R3:校验和
MOV R0,#BADD0 ;表地址,低位在前,高位在后
MOV R1,#42H
MOV R2,#6
DBS_C1: MOV A,@R0
MOV @R1,A
ADD A,R3
MOV R3,A
DEC R0
INC R1
DJNZ R2,DBS_C1
MOV 48H,#68H
MOV A,R3
ADD A,#68H
MOV R3,A
MOV 49H,#01H ;控制码
MOV A,R3
ADD A,#01H
MOV R3,A
MOV 4AH,#02H ;数据域长度
MOV A,R3
ADD A,#02H
MOV R3,A
MOV 4BH,#43H ;数据标识低字节
MOV A,R3
ADD A,#43H
MOV R3,A
MOV 4CH,#0C3H ;数据标识高字节
MOV A,R3
ADD A,#0C3H
MOV R3,A
MOV 4DH,R3 ;校验和
MOV 4EH,#16H ;结束符
RET
;*********************************************
;向上位机发送数据帧子程序
;*********************************************
DATASEND: MOV SCON,#50H ;通讯用方式1,1位起始位,8位数据位,1位停止位
LCALL DATACOLL
CLR ES
SETB TONG_B
CLR TONG_A
MOV R2,#17H
MOV R1,#41H
DATAS_1: MOV SBUF,@R1
DATAS_2: JBC TI,DATAS_3
LJMP DATAS_2
dATAS_3: INC R1
DJNZ R2,DATAS_1
SETB ES
DATAS_4: RET
;*********************************************
;整理向上位机发送数据帧所需要的数据
;*********************************************
DATACOLL: MOV 41H,#97H ;41H:97 起始符
MOV R3,#97H
MOV 42H,#40H ;42H:40 电表代号
MOV A,R3
ADD A,42H
MOV R3,A
MOV 43H,#0
MOV R2,#6 ;43H-49H:A6-A0 采集器地址
MOV R0,#BADD5
MOV R1,#44H
DATAC_1: MOV A,@R0
MOV @R1,A
ADD A,R3
MOV R3,A
INC R1
INC R0
DJNZ R2,DATAC_1
MOV 4AH,#81H ;4AH:81 控制码
MOV A,R3
ADD A,4AH
MOV R3,A
MOV 4BH,#0AH ;4BH:0A 数据域长度
MOV A,R3
ADD A,4BH
MOV R3,A
MOV 4CH,#90H ;4CH:90 数据标识高字节
MOV A,R3
ADD A,4CH
MOV R3,A
MOV 4DH,#1FH ;4DH:1F 数据标识低字节
MOV A,R3
ADD A,4DH
MOV R3,A
MOV A,SER
MOV 4EH,A ;4EH:SER 本机序列号
ADD A,R3
MOV R3,A
JNB SUCESS,DATAC_3
MOV R2,#4 ;4FH-52H:DATA4-DATA1 电表读数
MOV R0,#DATA4
MOV R1,#4FH
DATAC_2: MOV A,@R0
MOV @R1,A
ADD A,R3
MOV R3,A
INC R0
INC R1
DJNZ R2,DATAC_2
SJMP DATAC_4
DATAC_3: MOV R2,#4
MOV R1,#4FH
DATAC_5: MOV @R1,#0
MOV A,R3
ADD A,@R1
MOV R3,A
INC R1
DJNZ R2,DATAC_5
DATAC_4: MOV @R1,#05 ;53H:05 kWh代号
MOV A,R3
ADD A,#05
MOV R3,A
INC R1
MOV @R1,#00 ;54H:0
INC R1
MOV @R1,#00 ;55H:0
INC R1
MOV A,R3
MOV @R1,A ;56H:R3 校验和
INC R1
MOV @R1,#16H ;57H:16 结束符
RET
;**********************************************
;广播读表地址子程序
;**********************************************
BROD_AD: CLR TONG_A ;切换到RS485通道
CLR TONG_B
CLR ES ;不允许串口中断
SETB TR ;发送允许
MOV SCON,#0D0H ;串口工作于方式3
LCALL BRO_COLL ;整理所要发送的数据存于41H--4EH
MOV SBUF,#0FEH ;发送前导符
SETB TB8 ;
BROD_A1: JBC TI,BROD_A2
LJMP BROD_A1
BROD_A2: MOV R2,#14
MOV R0,#41H ;发送的命令存于41H--4EH
BROD_A2A: MOV A,@R0
LCALL EVENJ ;偶校验
JB EVEN,BROD_A3
CLR TB8
LJMP BROD_A4
BROD_A3: SETB TB8
BROD_A4: MOV A,@R0
INC R0
MOV SBUF,A
BROD_A5: JBC TI,BROD_A6
LJMP BROD_A5
BROD_A6: DJNZ R2,BROD_A2A ;是否发送完毕
;命令发送完毕
;*******************************
;*******************************
;以下为接收电表返回数据程序
CLR TR ;开始接收
BROD_A6A: MOV YSRES1,#02H ;500MS延时
BROD_A7: MOV YSRES2,#0E0H
BROD_A8: MOV YSRES3,#0
BROD_A9: JBC RI,BROD_AA
DJNZ YSRES3,BROD_A9
DJNZ YSRES2,BROD_A8
DJNZ YSRES1,BROD_A7
BRA: LJMP ERR1 ;若500MS内没有接收到有效数据,出错处理
BROD_AA: MOV A,SBUF
MOV TEMP,A
LCALL EVENJ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -