;======================================================================
;Title: 简单的ADuC控制台(Simple ADuC Console)
;Description: 使用"Windows超级终端"作为输入设备和显示终端,实现单片机的交互式操作
;Author: Liu Jianying
;Date: 2008-6-1
;
;使用方法:
; 1. 用WSD下载程序至目标单片机
; 2. 打开"Windows超级终端",新建一个连接,命名为"ADuC812"
; 3. 设置每秒位数:9600,数据位:8,奇偶校验:无,停止位:1,数据流控制:无
; 4. 命令:
; aduc812> cls ;清屏
; aduc812> adc n ;n通道AD转换,按<Ctrl+C>结束
; aduc812> dac x ;将十进制数x(0-4095)输出到DAC0
; aduc812> help ;输出帮助信息
; aduc812> stw ;输出锯齿波到DAC0,按<Ctrl+C>结束
;
;======================================================================
;编程中的约定:
; 1. 默认情况下,r7,r6为子程序参数,r2,r3为子程序返回值
; 2. 主程序及其调用子程序使用0组寄存器,低优先级中断服务使用2组寄存器,高优先级中断使用3组寄存器
; 3. 子程序入口标号以大写字母开头(例如Delay1s), 局部标号以下划线_开头和结尾(例如_PutsCLoop_)
; 4. 注释中括弧中的符号为子程序所影响到的寄存器
;
;======================================================================
$mod812
;ASCII控制字符表
NULL equ 0
ETX equ 3 ;结束
ACK equ 6 ;应答
BEL equ 7 ;响铃
BS equ 8 ;退格
HT equ 9 ;垂直制表符
LF equ 10 ;换行
VT equ 11 ;垂直制表符
FS equ 12 ;文字分隔符(清屏)
CR equ 13 ;回车
ESC equ 27 ;ESC
SPACE equ 32 ;空格
DEL equ 127 ;删除
;片内RAM定义
SPBase data 60h ;堆栈基址(60h-7fh)
DispBuf data 28h ;LED数码管显示缓冲(28h-2fh)
IOBuf data 31h ;I/O数据缓冲区(30h-5bh)
IOCount data 30h ;I/O字符计数
IOBufSize equ 2bh ;I/O缓冲区大小
SEQ bit 07h ;相等标志位
BREAKI bit 06h ;强行退出标志位
;
ChCount data 5ch ;全局变量,用于字符计数(2byte)
DACVL data 5ch ;DAC计数变量,为锯齿波准备
DACVH data 5dh ;DAC....
;SBUFF data 5fh ;SBUF备份,为Getc子程序准备
;RII bit 08h ;全局变量,为Getc子程序准备,RII置1表示串口已接收过一帧数据
;片外接口地址定义
DATA8279 xdata 0800h
CTRL8279 xdata 0801h
;=====================================================================
org 0000h
;复位
ljmp Start
org 000bh
;T0溢出中断
reti
org 0013h
;外部中断1
reti
org 001bh
;T1溢出中断
reti
org 0023h
;串行口接收中断
ljmp UART_Service
org 002bh
;T2溢出中断
reti
org 0030h
;主程序入口
Start:
;初始化堆栈指针
mov sp,#SPBase-1
;使用0组寄存器
clr RS0
clr RS1
;初始化
lcall Initialize
;命令行
lcall CommandLine
sjmp $
ret
;命令解析、执行子程序
;(r0,r7)
CommandLine:
push IE
;关中断
clr ES
_Loop7_:
;显示提示符
lcall PutPrompt
;等待用户输入
lcall Gets
;
_Select7_:
_Case71_:
;cls
mov r1,#IOBuf
mov r6,IOCount
mov dptr,#_Cls_
mov r7,#_ClsE_-_Cls_
lcall StrCmp
;不相等则跳到下一个
jnb SEQ,_Case72_
;清屏
mov r7,#FS
lcall Putc
mov r7,#FS
lcall Putc
;;;;;;;;;;;;;;;;;;;;;;;;;;
ljmp _EndSelect7_
_Case72_:
;dac <value>
mov r1,#IOBuf
mov dptr,#_Dac_
mov r7,#_DacE_-_Dac_
mov r6,IOCount
lcall StrCmp
jnb SEQ,_Case73_
;跳过所有空格
_Loop8_:
mov a,@r1
mov r6,a
mov r7,#' '
lcall Cmp
jnz _LoopEnd8_
inc r1
ljmp _Loop8_
_LoopEnd8_:
;参数:r1
lcall ScanNum
;r2高4位清0
mov a,r2
anl a,#0fh
mov r2,a
;DAC0转换
lcall DAConvert
lcall Disp2Byte
;输出"DAC0 output: "
mov dptr,#_DacInfo_
mov r7,#_DacInfoE_-_DacInfo_
lcall PutsC
;输出数值
lcall PrintNum
;回车+换行
mov r7,#CR
lcall Putc
mov r7,#LF
lcall Putc
;
ljmp _EndSelect7_
_Case73_:
;adc <channel>
mov r1,#IOBuf
mov dptr,#_Adc_
mov r7,#_AdcE_-_Adc_
mov r6,IOCount
lcall StrCmp
jnb SEQ,_Case74_
;跳过所有空格
_Loop10_:
mov a,@r1
mov r6,a
mov r7,#' '
lcall Cmp
jnz _LoopEnd10_
inc r1
ljmp _Loop10_
_LoopEnd10_:
;参数:r1
lcall ScanNum
;r3高4位清0
mov a,r3
anl a,#0fh
;通道号存b
mov b,a
;输出"ADC"
mov dptr,#_AdcInfo_
mov r7,#_AdcInfo2_-_AdcInfo_
lcall PutsC
;输出通道号
mov a,b
add a,#'0'
mov r7,a
lcall Putc
;输出" input: "
mov dptr,#_AdcInfo2_
mov r7,#_AdcInfoE_-_AdcInfo2_
lcall PutsC
;
clr BREAKI
push IE
setb ES
_ADCLoop2_:
;ADCn转换
mov r2,b
lcall ADConvert
;输出到DAC0
lcall DAConvert
mov r7,#BS
;5个退格
lcall Putc
lcall Putc
lcall Putc
lcall Putc
lcall Putc
;显示数值
lcall Disp2Byte
;输出数值
lcall PrintNum
;延时
mov r7,#100
lcall Delayms
jnb BREAKI,_ADCLoop2_
pop IE
;
;回车+换行
mov r7,#CR
lcall Putc
mov r7,#LF
lcall Putc
;
ljmp _EndSelect7_
_Case74_:
;stw
mov r1,#IOBuf
mov dptr,#_Stw_
mov r7,#_StwE_-_Stw_
mov r6,IOCount
lcall StrCmp
jnb SEQ,_Case75_
;
;输出锯齿波
mov dptr,#_StwInfo_
mov r7,#_StwInfoE_-_StwInfo_
lcall PutsC
lcall SawToothWave
;回车+换行
mov r7,#CR
lcall Putc
mov r7,#LF
lcall Putc
ljmp _EndSelect7_
_Case75_:
;help
mov r1,#IOBuf
mov dptr,#_Help_
mov r7,#_HelpE_-_Help_
mov r6,IOCount
lcall StrCmp
jnb SEQ,_Case76_
;
lcall PrintHelp
ljmp _EndSelect7_
_Case76_:
_EndSelect7_:
ljmp _Loop7_
_LoopEnd7_:
pop IE
ret
;字符串定义
_Cls_: db 'cls'
_ClsE_:
_Exit_: db 'exit'
_ExitE_:
_Adc_: db 'adc '
_AdcE_:
_Dac_: db 'dac '
_DacE_:
_Help_: db 'help'
_HelpE_:
_Stw_: db 'stw'
_StwE_:
_DacInfo_: db ' DAC0 output: '
_DacInfoE_:
_AdcInfo_: db ' ADC'
_AdcInfo2_: db ' input: '
_AdcInfoE_:
_StwInfo_: db ' Saw-Tooth Wave on DAC0: '
_StwInfoE_:
;打印帮助信息
PrintHelp:
mov dptr,#Help
mov r7,#HelpB-Help
lcall PutsC
mov dptr,#HelpB
mov r7,#HelpC-HelpB
lcall PutsC
mov dptr,#HelpC
mov r7,#HelpD-HelpC
lcall PutsC
ret
;系统初始化
Initialize:
;8279初始化
lcall Init8279
;清显示缓冲区
lcall ClearDispBuf
;UART初始化
lcall InitUART
setb ES
setb EA
;字符计数清0
mov ChCount,#0
mov ChCount+1,#0
mov r2,#0
mov r3,#0
lcall Disp2Byte
;清屏
mov r7,#FS
lcall Putc
lcall Putc
;--------------------------
;显示欢迎字幕
lcall PrintHelp
;--------------------------
ret
;串行口初始化
InitUART:
mov a,TMOD
anl a,#11001111b
orl a,#20h ;T1工作方式2(波特率发生器)
mov TMOD,a
mov TL1,#0fdh ;波特率9600bps
mov TH1,#0fdh
mov SCON,#50h ;串行口工作方式1(8位数据、1结束位、无奇偶校验)
setb REN ;允许接收
setb TR1 ;启动T1
clr RI ;清接收中断标志位
clr TI ;清发送中断标志位
;setb ES ;串行口中断允许
;setb EA ;总中断开
ret
;T0初始化
InitT0:
mov a,TMOD
anl a,#11111100b
orl a,#01h ;T0工作方式1
mov TMOD,a
clr ET0 ;T0关中断(作延时用)
ret
;8279初始化子程序
;(dptr)
Init8279:
mov dptr,#CTRL8279
;设置工作方式
mov a,#00000000b ;左端输入8字符
movx @dptr,a
;设置分频数
mov a,#00110000b ;16分频
movx @dptr,a
ret
;输出一个字符
;r7: 待发送的字符
Putc:
push IE
clr ES
clr TI
mov SBUF,r7
jnb TI,$
clr TI
pop IE
ret
;从终端读取一个字符,不显示
;r2: 结果
Getch:
push IE
clr ES
clr RI
jnb RI,$
mov r2,#SBUF
clr RI
pop IE
ret
;从终端读取一行字符串
;IOBuf: 字符串起始地址
;IOCount: 字符计数
;(r2)
Gets:
;关中断
push IE
clr ES
clr RI
mov IOCount,#0 ;I/O计数清0
mov r0,#IOBuf ;r0指向缓冲区首地址
_GetsLoop_:
jnb RI,$ ;等待输入
clr RI
_If5_:
;如果IOCount==#IOBufSize则退出循环
mov a,#IOBufSize-1
clr c
subb a,IOCount
jz _GetsEndLoop_ ;IOCount==#IOBufSize-1
;jc _GetsEndLoop_ ;IOCount>#IOBufSize-1
;
mov r2,SBUF
mov a,r2
clr c
subb a,#32
jc _Else5_ ;a<32
mov a,#126
clr c
subb a,r2
jc _Else5_ ;a>126
;如果是可视字符
mov a,r2
mov r7,a
;显示该字符
lcall Putc
;存入该字符
mov a,r2
mov @r0,a
;指针、计数+1
inc r0
inc IOCount
;
ljmp _EndIf5_
_Else5_:
;非可视字符/控制字符
_Select5_:
_Case51_:
;退格键
mov a,r2
clr c
subb a,#BS
jnz _Case52_
;
_If6_:
;如果IOCount=0则跳过
mov a,IOCount
jz _EndIf6_
;退格
mov r7,#BS
lcall Putc
;空格
mov r7,#SPACE
lcall Putc
;再退格
mov r7,#BS
lcall Putc
;指针、计数-1
dec r0
dec IOCount
_EndIf6_:
;
ljmp _EndSelect5_
_Case52_:
;回车键
mov a,r2
clr c
subb a,#CR
jnz _Case53_
;
;结束程序
ljmp _GetsEndLoop_
_Case53_:
;其余字符不作处理
_EndSelect5_:
_EndIf5_:
ljmp _GetsLoop_
_GetsEndLoop_:
;*r0=0
mov @r0,#0
;回车+换行
mov r7,#CR
lcall Putc
mov r7,#LF
lcall Putc
;开中断
pop IE
ret
;字节比较程序
;r6,r7: 被比较的两个数
;SEQ: 1相等,0不相等
Cmp:
mov a,r6
clr c
subb a,r7
jnz _Else8_
_If8_:
setb SEQ
ljmp _EndIf8_
_Else8_:
clr SEQ
_EndIf8_:
ret
;输出2字节十进制数
;r2,r3: 数值(r2高,r3低)
PrintNum:
lcall Hex2toBCD
;r2低4
mov a,r2
anl a,#0fh
add a,#'0'
mov r7,a
lcall Putc
;r3高4
mov a,r3
swap a
anl a,#0fh
add a,#'0'
mov r7,a
lcall Putc
;r3低4
mov a,r3
anl a,#0fh
add a,#'0'
mov r7,a
lcall Putc
;r4高4
mov a,r4
swap a
anl a,#0fh
add a,#'0'
mov r7,a
lcall Putc
;r4低4
mov a,r4
anl a,#0fh
add a,#'0'
mov r7,a
lcall Putc
ret
;获取字符串中的十进制数值
;r1: 字符串指针
;r2,r3: 数值(r2高,r3低)
;(r1)
ScanNum:
mov r2,#0
mov r3,#0
_Loop9_:
mov a,@r1
clr c
subb a,#'0'
jc _LoopEnd9_ ;*r1<'0'
mov a,#'9'
clr c
subb a,@r1
jc _LoopEnd9_ ;*r1>'9'
;处理数字
;r2_r3*=10
mov a,r3
mov b,#10
mul ab
mov r3,a
push b
mov a,r2
mov b,#10
mul ab
pop b
add a,b
mov r2,a
;r2_r3+=*r1-'0'
mov a,r3
mov a,@r1
clr c
subb a,#'0'
add a,r3
mov r3,a
mov a,r2
addc a,#0
mov r2,a
;
inc r1
ljmp _Loop9_
_LoopEnd9_:
ret
;字符串比较子程序
;dptr: 字符串1,存于ROM
;r1: 字符串2,存于片内RAM
;r7: 串1长度
;r6: 串2长度
;SEQ: 返回值,1相等,0不相等
;(r1,r7,r6,r5)
;//算法描述:
;bool StrCmp(char * dptr, char * r1, char r7, char r6)
;{
; char i=0;
; while(i!=r7&&i!=r6)
; {
; if(dptr!=*r1)
; return false;
; r1++;
; i++;
; }
; return true;
;}
StrCmp:
mov r5,#0
_Loop6_:
;循环条件
;a==r7
mov a,r5
clr c
subb a,r7
jz _LoopEnd6_
;a==r6
mov a,r5
clr c
subb a,r6
jz _LoopEnd6_
;dptr==*r1
mov a,r5
movc a,@a+dptr
clr c
subb a,@r1
;
inc r1
inc r5
;
jz _Loop6_
;比较不相等
clr SEQ
ret
_LoopEnd6_:
_If7_:
;r5==r7
mov a,r5
clr c
subb a,r7
jnz _Else7_
setb SEQ
ljmp _EndIf7_
_Else7_:
clr SEQ
_EndIf7_:
ret
;输出字符串(程序存储器)
;dptr: 字符串起始地址(Code Memory)
;r7: 字符串长度
;(r6)
PutsC:
push IE
clr ES
mov r6,#0
_PutsCLoop_:
mov a,r6
movc a,@a+dptr
;发送一帧数据
clr TI
mov SBUF,a
jnb TI,$
clr TI
inc r6
;r6==r7?
mov a,r6
clr c
subb a,r7
jnz _PutsCLoop_
pop IE
ret
;输出字符串(片内RAM)
;r0: 字符串基址
;r7: 字符串长度
;(r0,r7)
Puts:
push IE
clr ES
mov a,r7
jz _PutsLoopEnd_
_PutsLoop_:
clr TI
mov SBUF,@r0
jnb TI,$
clr TI
inc r0
djnz r7,_PutsLoop_
_PutsLoopEnd_:
pop IE
ret
;输出提示符 "aduc812> "
;(dptr,r7,r6)
PutPrompt:
mov dptr,#_Prompt_
mov r7,#_PromptE_-_Prompt_
lcall PutsC
ret
_Prompt_: db 'aduc812> '
_PromptE_:
;更新数码管显示
;(r0,r6,dptr)
RefreshDisp:
;写显示RAM
mov dptr,#CTRL8279
mov a,#10010000b
movx @dptr,a
;
mov r0,#DispBuf
mov r6,#8
_RFLoop_:
mov a,@r0
mov dptr,#DATA8279
movx @dptr,a
inc r0
djnz r6,_RFLoop_
ret
;显示2字节子
;高字节存r2,低字节存r3
;(r0,dptr)
Disp2Byte:
mov r0,#DispBuf
mov dptr,#LEDSEG
;r2高半字节
mov a,r2
swap a
anl a,#0fh
movc a,@a+dptr
mov @r0,a
inc r0
;r2低半字节
mov a,r2
anl a,#0fh
movc a,@a+dptr
mov @r0,a
inc r0
;r3高半字节
mov a,r3
swap a
anl a,#0fh
movc a,@a+dptr
mov @r0,a
inc r0
;r3低半字节
mov a,r3
anl a,#0fh
movc a,@a+dptr
mov @r0,a
inc r0
;刷新
lcall RefreshDisp
ret
;显示缓冲区清0
;(r0,r6)
ClearDispBuf:
mov r0,#DispBuf
mov r6,#8
_CDBLoop_:
mov @r0,#0
inc r0
djnz r6,_CDBLoop_
ret
;十六进制->十进制转换子程序
;HEX: 高字节存r2, 低字节存r3
;BCD: 高->低依次r2,r3,r4
;(r2,r3,r4,r7)
Hex2toBCD:
push IOBuf
push IOBuf+1
push IOBuf+2
;三个变量
mov IOBuf,#0
mov IOBuf+1,#0
mov IOBuf+2,#0
;总计移位16次
mov r7,#16
_LoopBCD1_:
;r3左移
mov a,r3
rlc a
mov r3,a
;r2左移
mov a,r2
rlc a
mov r2,a
;r4累加
mov a,IOBuf+2
addc a,IOBuf+2
da a
mov IOBuf+2,a
;r3累加
mov a,IOBuf+1
addc a,IOBuf+1
da a
mov IOBuf+1,a
;r2累加
mov a,IOBuf
addc a,IOBuf
da a
mov IOBuf,a
djnz r7,_LoopBCD1_
;保存变量到r2,r3,r4
mov r2,IOBuf
mov r3,IOBuf+1
mov r4,IOBuf+2
pop IOBuf+2
pop IOBuf+1
pop IOBuf
ret
;AD转换子程序,并显示
;r2存通道数(0-8)
;(r2,r3)
ADConvert:
;ADCCON初始化
;正常工作,转换时间8时钟,8分频
mov ADCCON1,#01111100b
;通道选择
;准备并修正通道号
mov a,r2
anl a,#0fh
mov ADCCON2,a
;启动单次转换
setb SCONV
;延时等待
jnb ADCI,$
;nop
;取结果
mov r2,ADCDATAH
mov r3,ADCDATAL
;此处不显示
;lcall Disp2Byte
nop
ret
;DAC0转换
;r2存高字节, r3存低字节
;()
DAConvert:
;初始化
mov DACCON,#00011111b
;修正高字节
mov a,r2
anl a,#0fh
;存高字节
mov DAC0H,a
;存低字节,同时启动DA转换
mov DAC0L,r3
nop
ret
;输出锯齿波到DAC0
SawToothWave:
;清除空格
mov r7,#BS
lcall Putc
lcall Putc
lcall Putc
lcall Putc
lcall Putc
lcall Putc
lcall Putc
mov r7,#'.'
lcall Putc
lcall Putc
lcall Putc
;初始化
mov DACCON,#00011111b
mov DACVL,#0
mov DACVH,#0
clr BREAKI
push IE
setb ES
_STWLoop_:
;递增
mov a,DACVL
add a,#1
mov DACVL,a
mov a,DACVH
addc a,#0
anl a,#0fh
mov DACVH,a
;转换
mov DAC0H,DACVH
mov DAC0L,DACVL
;
;lcall Delay1ms
;输出数值
;mov r2,DACVH
;mov r3,DACVL
;lcall Disp2Byte
;mov r7,#BS
;lcall Putc
;lcall Putc
;lcall Putc
;lcall Putc
;lcall Putc
;lcall PrintNum
jnb BREAKI,_STWLoop_
pop IE
ret
;延时1ms
Delay1ms:
push PSW
setb RS0 ;使用1组
clr RS1
mov r6,#0ah
_DL2_:
mov r7,#18h
_DL1_:
nop
nop
djnz r7,_DL1_
djnz r6,_DL2_
pop PSW
ret
;延时ms
;r7: 延时长度(ms)
;(r7)
Delayms:
_DL3_:
lcall Delay1ms
djnz r7,_DL3_
ret
;延时1s
Delay1s:
push PSW
setb RS0 ;使用1组
clr RS1
mov r7,#50
_DLS0_:
mov r6,#91
_DLS1_:
mov r5,#100
djnz r5,$
djnz r6,_DLS1_
djnz r7,_DLS0_
pop PSW
ret
;延时ns
;r7: 延时长度(s)
;(r7)
Delays:
_DLS3_:
lcall Delay1s
djnz r7,_DLS3_
ret
;串行口接收中断服务程序
;与Windows超级终端连接
;将主机发送来的字符回传给主机
UART_Service:
push PSW
clr RS0 ;使用2组
setb RS1
push ACC
clr RI
mov r2,SBUF
;------------------
;mov SBUFF,SBUF
;setb RII
;------------------
;判断是否为可视字符
_If4_:
mov a,r2
clr c
subb a,#32
jc _Else4_ ;a<32
mov a,#126
clr c
subb a,r2
jc _Else4_ ;a>126
;
;处理可视字符
ljmp _EndIf4_
_Else4_:
;非可视字符/控制字符
_Select2_:
_Case21_:
_Case25_:
;Ctrl+C
mov a,r2
clr c
subb a,#ETX
jnz _Default2_
;强行结束
setb BREAKI
ljmp _EndSelect2_
_Default2_:
_EndSelect2_:
_EndIf4_:
pop ACC
pop PSW
reti
;字形码表
LEDSEG:
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
db 5fh,03h,6dh,67h,33h,76h,7eh,43h,7fh,77h,7bh,3eh,5ch,2fh,7ch,78h
Help:
db '==== This is the ADuC812 console designed by Liu Jianying. ===='
db CR,LF
HelpB:
db ' aduc812> cls ;Clear screen'
db CR,LF
db ' aduc812> adc n ;Start ADC on channel n, press <Ctrl+C> to EXIT'
db CR,LF
db ' aduc812> dac x ;Execute DAC on channel 0 with value x(0-4095)'
db CR,LF
db ' aduc812> stw ;Output Saw-Tooth Wave to DAC0'
db CR,LF
HelpC:
db ' aduc812> help ;Print infomation for HELP'
db CR,LF,CR,LF
HelpD:
SRT:
db 'Serial port communication testing...'
db CR,LF,CR,LF
SRTE:
end
完整的ASM51源程序请从这里下载: http://download.csdn.net/source/616580
(原创文章,转载时请注明本文网址)