1、 调试步骤:
l 硬件连接:将各芯片插在面包板上并用导线按原理图连接
l 软件开发环境:Keil uVision2 for Windows ,该软件的模拟调试器支持C语言及汇编语言源代码调试,其汇编程序支持宏汇编及模块化编程,使用方便。
l 首先在模拟调试器中调试各子模块,各子模块调试正常后再将各子模块及主模块全部汇编连接成目标文件,最后将目标代码下载到单片机中并连接智能仪表进行统调。
2、 该系统软件部分除报警子模块外已全部开发完成并实际测试通过,测试时用一对长度约1100M的0.5mm2 普通电话线作为单片机装置与两个智能仪表的通讯线,经过一个多星期的连续运行观察,运行可靠稳定,完全满足使用要求。
[注:报警子模块的开发及硬件制版工作正在进行中。]
用单片机+智能仪表构成的温度远程显示系统总造价约人民币7000元(两块智能仪表+温度传感器约3500元,通讯电缆约2000元,单片机装置及施工费用约1500元),与采用其它方案的系统比较造价较低,其硬件及软件的设计、制作都较简单,有一定的电子及单片机知识便可完成。同时对该装置软件稍加修改即可与其他带有RS-485通讯端口的仪器仪表通讯(如变频器、电路传感器等),实现远程测量、监视及控制。
与发达国家相比,我国单片机应用的普及程度较低。通过该实例说明,我们完全可以把我们学到的单片机知识应用到实际工作中,直接创造经济效益。
<<单片机高级语言C51Windows环境编程与应用>> 电子工业出版社
徐爱钧 彭秀华 编著
<<ATMEL89系列Flash单片机原理与应用>> 电子工业出版社
余永权 主编
<<标准集成电路数据手册高速CMOS电路>> 电子工业出版社
<<ATMEL AT89S8252数据手册>> ATMEL公司
<<XJ-08H(S)巡回检测仪使用说明书>> 重庆川仪十八厂
<<工业控制计算机组成原理>> 清华大学出版社
孙廷才 王杰 孙中健 编著
<<电子技术>>2001年11期
;------------1--------rand_main.a51----------------
name rand_main
EXTRN CODE(I_T0,send_order,rec_si,ascii_bcd,key)
extrn data (DISP_buf,disp_wc,time_20ms,wdt)
extrn idata (rec_buf)
public TH0_H,TL0_L,START,ri_f,wdt_time,key_work,key_f
prog SEGMENT CODE ;定义代码段
byte_buff segment data ;定义字节数据段1
byte_buffI segment idata ;定义字节数据段2
bit_buff segment data bitaddressable ;定义位数据段
bit_flag segment bit
stack segment idata ;定义堆栈数据段
rseg stack ;为堆栈保留20个字节
ds 20
CSEG AT 00H ;定义绝对代码段
USING 0 ;选择工作寄存器组第0组
lJMP rand ;复位时程序执行执行点
CSEG AT 03H ;外部中断0
RETI
CSEG AT 0BH ;定时器0中断
lJMP I_T0
CSEG AT 13H ;外部中断1
ljmp key
RETI
CSEG AT 1BH ;定时器1中断
RETI
CSEG AT 23H ;串行中断
ljmp rec_si
RSEG BYTE_BUFF
td_temp: ds 1
TD_n: DS 1 ;通道号
YD_n100: ds 1 ;仪表地址
;----------------------------------
rseg bit_flag
key_work:dbit 1
ri_f: dbit 1 ;串行口正在接收标志
;----主程序
RSEG prog
;------------------------------符号定义
key_f equ p3.3
key_up equ p3.4
key_down equ p3.5
wdt_time equ 100 ;软件看门狗定时器计数值
scon_c equ 01010000b ;串行口设置为10位UART,允许接收
th1_h equ 0fdh ;晶振为11.0592M,波特率为9600时初值
tmod_n equ 21h ;设置定时器(T1作为波特率发生器工作在模式2,T0为模式1)
ie_n equ 82h ;设置串行,定时器0中断
ip_n equ 12h ;设置串行,定时器0中断为高级中断
TH0_H EQU 0FCH
TL0_L EQU 06BH ;设定定时器0为1MS中断初值
;------------------初始化代码
clear_wdt macro ;清硬看门狗宏定义
orl 96h,#2
ENDM
rand: ORL 96H,#0E1H ;启动硬件看门狗
mov p0,#0ffh
mov r0,#20h
mov a,#0
start_300:mov @r0,a
inc r0
cjne r0,#128,start_300
setb key_work ;置巡回/定点标志
mov p3,#0ffh
mov p2,#0ffh
mov disp_wc,#0 ;初始化闪烁控制位
mov ip,#ip_n ;设置串行,定时器0中断为高级中断
mov scon,#scon_c
MOV TMOD,#tmod_n
MOV TH0,#TH0_H ;设定定时器初值
MOV TL0,#TL0_L
mov th1,#th1_h
mov tl1,#th1_h
mov ie,#ie_n
mov pcon,#0
SETB tr1
SETB TR0
;-------显示初始化提示
acall chuhao
CLEAR_WDT
start: clr ea
mov sp,#stack-1
setb ea
clr ri_f ;清接收中标志
clr p3.2 ;置75176为接收状态
jnb key_work,db_work
;-----------------------------------
setb ex1
mov yd_n100,#0ah
mov td_n,#0
s_0: anl disp_wc,#0f0h
mov wdt,#0 ;清看门狗定时器
clear_wdt
mov a,yd_n100
lcall send_order
JNZ s_1
mov disp_buf+5,yd_n100
mov a,td_n
lcall ascii_bcd
jnz s_2
mov disp_buf+4,td_n
acall mov_to_disp
mov wdt,#0
clear_wdt
mov a,#75
add a,time_20ms
cjne a,time_20ms,$
mov wdt,#0
clear_wdt
mov a,#75
, ,
add a,time_20ms
cjne a,time_20ms,$
s_2: inc td_n
mov a,td_n
cjne a,#8,s_0
mov td_n,#0
s_1: inc yd_n100
MOV A,YD_N100
cjne a,#10h,s_0
&nb, sp; mov yd_n100,#0ah
ajmp s_0
;-----------------------------
db_work:setb ex1
orl disp_wc,#01h
d_3: mov wdt,#0 ;清看门狗定时器
clear_wdt
jb key_up,d_4
mov a,#2
add a,time_20ms
cjne a,time_20ms,$
jb key_up,d_4
d_5: mov wdt,#0
clear_wdt
jnb key_up,d_5 ;等待向上键松开
;------------------------------------------------
d_53: mov a,td_n
cjne a,#7,d_50
mov td_n,#0
d_52: inc yd_n100
mov a,yd_n100
cjne a,#10h,d_51
mov yd_n100,#0ah
ajmp d_51
d_50: inc td_n
d_51: mov a,yd_n100
lcall send_order
JNZ d_52
mov disp_buf+5,yd_n100
mov a,td_n
lcall ascii_bcd
jnz d_53
mov disp_buf+4,td_n
acall mov_to_disp
mov a,#100 ;2秒钟定时设定
add a,time_20ms
ajmp d_3
;------------------------------------------------
d_4: jb key_down,d_10
mov a,#2
add a,time_20ms
cjne a,time_20ms,$
jb key_down,d_3
d_6: mov wdt,#0
clear_wdt
jnb key_down,d_6 ;等待向下键松开
;-----------------------------------------------
d_43: mov a,td_n
cjne a,#0,d_40
mov td_n,#7
d_42: dec yd_n100
mov a,yd_n100
cjne a,#9h,d_41
mov yd_n100,#0fh
ajmp d_41
d_40: dec td_n
d_41: mov a,yd_n100
lcall send_order
JNZ d_42
mov disp_buf+5,yd_n100
mov a,td_n
lcall ascii_bcd
jnz d_43
mov disp_buf+4,td_n
acall mov_to_disp
mov a,#100 ;2秒钟定时设定
add a,time_20ms
ajmp d_3
;----------------------------------
d_10: cjne a,time_20ms,d_30
mov a,yd_n100
lcall send_order
jnz d_30
mov a,td_n
lcall ascii_bcd
jnz d_30
acall mov_to_disp
mov a,#100
add a,time_20ms
d_30:ajmp d_3
;----------------------------------
mov_to_disp:mov disp_buf,r1
mov disp_buf+1,r2
mov disp_buf+2,r3
mov disp_buf+3,r4
ret
chuhao: mov r1,#1eh ;初始化等待提示
mov r2,#22h
mov r3,#21h
mov r4,#1fh
mov disp_buf+4,#21h
mov disp_buf+5,#20h
acall mov_to_disp
mov a,#75
add a,time_20ms
cjne a,time_20ms,$
mov wdt,#0
clear_wdt
mov a,#75
add a,time_20ms
cjne a,time_20ms,$
ret
end
;-----------2-------rand_data.a51----------------
name rand_data
extrn idata (rec_buf)
public ascii_bcd
prog SEGMENT CODE ;定义代码段
byte_buff segment data ;定义字节数据段1
byte_buffI segment idata ;定义字节数据段2
bit_buff segment data bitaddressable ;定义位寻址区字节数据段
rseg prog
using 0
;-------------------------------------
ASCII_BCD:mov b,#8 ;计算该通道数据偏移首地址
mul ab
add a,#5
mov r0,#rec_buf
add a,r0
mov b,a
mov r0,a
acall ascii4_bcd3
mov a,b ;还原小数位数
add a,#7
mov r0,a
acall ascii_bin
mov r6,a ;小数位数暂存在R6中
mov a,r5
jz asc_oK
mov a,dpl
cpl a
clr c
inc a
mov dpl,a
mov a,dph
cpl a
addc a,#0
mov dph,a
jnz asc_b
asc_0: mov a,dpl
dec a
jnz asc_b
mov r1,#0fh
mov r2,#0fh
mov r3,#0fh
mov r4,#0fh
mov a,#0fh
ajmp asc_out
asc_b: mov r1,dpl ;为负数处理
mov r2,dph
acall bin_bcd
mov a,b ;还原小数位数
add a,#7
mov r0,a
acall ascii_bin
mov r6,a ;小数位数暂存r6
acall bcd2_bcd1
mov a,r4
dec a
jnz asc_100 ;数据小于-199.9时显示-199.9
mov r4,#23h
ajmp asc_sw
asc_100:mov r4,#23h
mov r3,#9
mov r2,#19h
mov r1,#9
ajmp asc_sw_1
asc_ok: acall bcd2_bcd1 ;正常数据处理程序
asc_sw: mov a,r4 ;清除有效位前面的0
jnz asc_sw_1
mov r4,#1ch
mov a,r3
jnz asc_sw_1
mov r3,#1ch
asc_sw_1:clr a
asc_out:ret
;------------每字节两位BCD码转换为每字节一位BCD码子程序
;入口:r3=个位及十位BCD码,r4=百位及千位BCD码,r6=小数位数
;出口:r1=个位BCD码,r2=十位BCD码,r3=百位BCD码,r4=千位BCD码
bcd2_bcd1:mov a,r3 ;个位及十位BCD数处理
anl a,#0fh
mov r1,a
mov a,r3
anl a,#0f0h
swap a
mov r2,a
mov a,r4 ;百位及千位BCD数处理
anl a,#0fh
mov r3,a
mov a,r4
anl a,#0f0h
swap a
mov r4,a
mov a,r6 ;加入小数点信息
jz bcd2_out
add a,#ar1
mov r0,a
mov a,@r0
add a,#10h
mov @r0,a
bcd2_out:ret
;---------------ASCii4_BCD3转换子程序
;入口:r0=四字节ASCII码首地址
;出口:r5,r4,r3从高至低依次存放BCD码(r3,r4各存2位,r5存1位)
ascii4_bcd3:acall ascii4_bin2
mov dpl,r1
mov dph,r2
acall bin_bcd
ret
;---------------BIN_BCD转换子程序
;入口:r1=BIN低字节,r2=BIN高字节 共2字节
;出口:r3=低2位BCD码,r4=高2位BCD码,r5=可能的最高位BCD码
bin_bcd:PUSH ACC
PUSH PSW
mov r3,#0 ;BCD单元清0
mov r4,#0
mov r5,#0
mov r6,#16 ;设置二进制数位数
clr c
bin_0: mov a,r1
rlc a
mov r1,a
mov a,r2
rlc a
mov r2,a
mov r0,#ar3
mov r7,#3 ;设置BCD字节数
bin_1: mov a,@r0
addc a,@r0
da a
mov @r0,a
inc r0
djnz r7,bin_1
djnz r6,bin_0
POP PSW
POP ACC
ret
;---------------ASCII4_BIN2转换子程序
;入口:R0=ASCII码首地址(共四字节ASCII码)
;出口:r1=BIN码低字节,R2=BIN码高字节
ascii4_bin2:PUSH ACC
acall ascii_bin
anl a,#0fh
swap a
mov r1,a
inc r0
acall ascii_bin
anl a,#0fh
orl ar1,a
inc r0
acall ascii_bin
anl a,#0fh
swap a
mov r2,a
inc r0
acall ascii_bin
anl a,#0fh
orl ar2,a
POP ACC
ret
;---------------ASCII_BIN转换子程序
;入口:R0=ASCII地址
;出口:A=BIN码
ascii_bin:mov a,@r0
clr c
subb a,#3ah
jnc ascii_0
add a,#7
ascii_0:add a,#3
ret
end
;--------3--------rand_disp.a51-------------------------
name rand_disp
extrn number(TH0_H,TL0_L,wdt_time)
PUBLIC I_T0,disp_buf,disp_wc,time_20ms,wdt
prog SEGMENT CODE ;定义代码段
BYTE_BUFF segment data ;定义字节数据段1
byte_buffI segment idata ;定义字节数据段2
bit_buff segment data bitaddressable ;定义位数据段
RSEG BYTE_BUFF
wdt: ds 1
time_s_c: ds 1
time_20ms: ds 1
DISP_C: ds 11 ;显示位
disp_buf data disp_c+1 ;个位缓冲区,此个位并非真正的个位,指最右一位,以下类推
disp_2 data disp_c+2 ;十个位缓冲区
disp_3 data disp_c+3 ;百位缓冲区
disp_4 data disp_c+4 ;千位缓冲区
disp_5 data disp_c+5 ;通道位缓冲区
disp_6 data disp_c+6 ;地址位缓冲区
disp_7 data disp_c+7 ;无
disp_8 data disp_c+8 ;无
disp_s data disp_c+9 ;闪烁计数器
rseg bit_buff
disp_wc: ds 1
disp_c_1 bit disp_wc.0 ;个位闪烁标志位 1-闪烁
disp_c_2 bit disp_wc.1 ;十位闪烁标志位
disp_c_3 bit disp_wc.2 ;百位闪烁标志位
disp_c_4 bit disp_wc.3 ;千位闪烁标志位
disp_s_c bit disp_wc.4 ;闪烁控制位 1-闪烁
RSEG PROG
using 0
dsb equ p3.4
cr_not equ p3.5
cp equ p3.6
I_T0: push acc
push ar0
push dph
push dpl
push psw
mov th0,#th0_h
mov tl0,#tl0_l
mov dptr,#tab
;---------------------------------------------
djnz disp_s,d_20
cpl disp_s_c
;---------------------------------------------
d_20: INC DISP_C
MOV R0,DISP_C
CJNE R0,#1,DISP2 ;r0=1显示个位
mov c,disp_c_1
mov A,disp_buf
mov p1,#0FFH
mov p0,#0feh
ajmp d_10
DISP2: CJNE R0,#2,DISP3 ;显示十位
setb p0.0
mov c,disp_c_2
mov A,disp_2
mov p1,#0FFH
mov p0,#0fdh
ajmp d_10
DISP3: CJNE R0,#3,DISP4 ;显示百位
mov c,disp_c_3
mov A,disp_3
mov p1,#0FFH
mov p0,#0fbh
ajmp d_10
DISP4: CJNE R0,#4,DISP5 ;显示千位
mov c,disp_c_4
mov A,disp_4
mov p1,#0FFH
mov p0,#0f7h
ajmp d_10
DISP5: CJNE R0,#5,DISP6 ;显示通道号
mov A,disp_5
mov p1,#0FFH
mov p0,#0efh
ajmp d_10
DISP6: CJNE R0,#6,DISP7 ;显示仪表地址
mov A,disp_6
mov p1,#0FFH
mov p0,#0dfh
ajmp d_10
DISP7: CJNE R0,#7,DISP8 ;无
mov A,disp_7
mov p1,#0FFH
mov p0,#0bfh
ajmp d_10
DISP8: CJNE R0,#8,d_10 ;无
mov A,disp_8
mov p1,#0FFH
mov p0,#7fh
d_10: acall disp_w
mov r0,disp_c
cjne r0,#10,d_12 ;若disp_c=10则清disp_c
mov disp_c,#0
inc time_s_c ;MS,S计数处理程序
mov a,time_s_c
cjne a,#2,d_12
mov time_s_c,#0
inc time_20ms
inc wdt ;软看门狗处理程序
mov a,wdt
cjne a,#wdt_time,d_12
mov wdt,#0
mov a,#0
push acc
push acc
reti
;-----------------------
d_12: pop psw
pop dpl
pop dph
pop ar0
pop acc
RETI
disp_w: jnc d_0
jnb disp_s_c,d_0
mov p1,#0FFH
ajmp d_1
d_0: movc a,@a+dptr
cpl a
mov p1,a
D_1: ret
;---------------------------------------------------------
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH
; 0 1 2 3 4 5 6 7 8 9
db 77H,7CH,39H,5EH,79H,71H
; A B C D E F
DB 0BFH,86H,0DBH,0CFH,0E6H,0EDH,0FDH,87H,0FFH,0EFH
; 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
db 40H,80H,00H,37h,5ch,1ch,58h,74h,0dch,46h
; - . 空 n o u c h a -1
; 1a 1b 1c 1d 1e 1f 20 21 22 23
END
;----------4--------rand_send.a51----------------
name send_order
extrn idata (rec_buf) ;rec_buff 接收缓冲区
extrn data (time_20ms)
extrn bit (ri_f) ;ri_f 正在接收标志
PUBLIC send_order
prog SEGMENT CODE ;定义代码段
byte_buff segment data ;定义字节数据段1
byte_buffI segment idata ;定义字节数据段2
bit_buff segment data bitaddressable ;定义位数据段
rseg byte_buff
send_n:ds 1
order_buf:ds 10
rseg prog
dd_c equ 4 ;等待回应20m数
cw_n equ 7 ;设置允许错误次数
using 0
;---------------------清命令缓冲区
send_order:
mov dpl,#8
mov r0,#order_buf
send_0: mov @r0,#0
inc r0
djnz dpl,send_0
MOV DPL,#72 ;清接收缓冲区
MOV R0,#REC_BUF
SEND_A: MOV @R0,#0
INC R0
DJNZ DPL,SEND_A
;----------------------发送命令控制程序
mov send_n,#cw_n ;设置允许错误次数
mov b,#10
clr c
subb a,b
mov b,#8
mul ab
mov dptr,#a_order
mov r0,#order_buf-1
mov r1,#10
start_mov:inc r0
push acc
movc a,@a+dptr
mov @r0,a
inc dptr
pop acc
cjne @r0,#0dh,start_mov
;----------------------发送命令子程序
send_start:setb p3.2 ;切换75176至发送状态
mov r0,#order_buf-1
send_10:inc r0
mov sbuf,@r0
jnb ti,$ ;等待一帧数据发完
CLR TI
cjne @r0,#0dh,send_10 ;检测到结束标志退出
;------------------------检测接收标志
mov r0,#30 ;延时60uS等待停止位发送完毕
djnz r0,$
setb es
clr p3.2 ;切换75176至接收状态
mov a,#dd_c ;延时检测仪表有无回应
add a,time_20ms
send_21:jb ri_f,send_20
cjne a,time_20ms,send_21
mov a,#'N'
ajmp send_23
;-------------------------检测接收是否正确
send_20:mov a,#10 ;延时200MS等待接收结束
add a,time_20ms
send_28:jnb ri_f,send_29
cjne a,time_20ms,send_28
clr ri_f ;200MS仍未结束清接收中标志
send_29:mov r0,#rec_buf+4
cjne @r0,#'*',send_22
mov a,#'*'
send_23:djnz send_n,send_start ;达到允许错误次数退出
ajmp send_out
send_22:mov r0,#rec_buf+71
cjne @r0,#0dh,send_23 ;接收缓冲区第72字节不为回车符转出错处理
;------------------------------还原校验码
mov r0,#rec_buf+70
mov a,@r0
clr c
subb a,#3ah
jnc SEND_25
add a,#7
send_25:add a,#3
mov @r0,a
dec r0
mov a,@r0
clr c
subb a,#3ah
jnc SEND_26
add a,#7
send_26:ADD A,#3
swap a
inc r0
xchd a,@r0
dec r0
xch a,@r0
inc r0
mov @r0,#0dh ;检验码后加回车符
;------------------------------检验接收缓冲区数据
mov r0,#rec_buf+1
mov a,@r0
inc r0
send_24:xrl a,@r0
inc r0
cjne @r0,#0dh,send_24
cjne a,#0,send_200 ;接收校验未通过转出错处理
send_out:clr es
ret
send_200:mov a,#1
ajmp send_23
;----------------------------------------------------
a_order: db '@0ARD67',0DH ;读A表全部动态数据命令
b_order: db '@0BRD64',0DH ;读B表全部动态数据命令
c_order: db '@0CRD65',0DH ;读c表全部动态数据命令
d_order: db '@0DRD62',0DH ;读d表全部动态数据命令
e_order: db '@0ERD63',0DH ;读e表全部动态数据命令
f_order: db '@0FRD60',0DH ;读f表全部动态数据命令
END
;-------5----------rand_rec.a51
name rec_si
extrn bit (ri_f)
public rec_si,rec_buf
prog SEGMENT CODE ;定义代码段
byte_buff segment data ;定义字节数据段1
byte_buffI segment idata ;定义字节数据段2
bit_buff segment data bitaddressable ;定义位数据段
rseg byte_buff
rec_buf_z: ds 1 ;接收区指针
rec_err: ds 1 ;接收缓冲区溢出计数器
rseg byte_buffi
rec_buf: ds 75
rseg prog
using 0
rec_si: PUSH PSW
push ar0
push acc
JNB RI,REC_OUT ;为发送中断跳出
clr ri
jb ri_f,rec_0
mov a,sbuf
cjne a,#'@',rec_out ;无效命令过滤处理
setb ri_f ;置接收中标志
mov rec_buf_z,#rec_buf ;接收缓冲区首地址给接收指针
mov rec_err,#73 ;设置最大接收字节数
ajmp rec_1
rec_0: mov a,sbuf
cjne a,#0dh,rec_1
clr ri_f
rec_1: mov r0,rec_buf_z
mov @r0,a
inc rec_buf_z
djnz rec_err,rec_out ;接收溢出清接收标志
clr ri_f
rec_out:pop acc
pop ar0
POP PSW
reti
end
6、巡回/定点转换检测子模块(rand_key.a51)
;-----------6----rand_key.a51
name key
EXTRN CODE(START)
extrn bit(key_work,key_f)
EXTRN DATA(DISP_buf,disp_wc,time_20ms,wdt)
PUBLIC KEY
prog SEGMENT CODE ;定义代码段
RSEG PROG
;-------------------------------------
KEY: mov a,#2
add a,time_20ms
cjne a,time_20ms,$
key_1: mov wdt,#0
orl 96h,#0e1h
jnb key_f,key_1
mov a,#2
add a,time_20ms
cjne a,time_20ms,$
jnb key_f,key_1
clr ea
clr ex1
cpl key_work
;--------------------------------------
key_out:mov dptr,#start
push dpl
push dph
reti
end