📄 mcu.asm
字号:
;触发外部中断0。
call ENABLEINT0 ;开启外部中断0。
mov a,MENUINDEX ;取得功能序号。
mov dptr,#FUNCTABLE ;
rl a ;
rl a ;
jmp @a+dptr ;按功能序号转移至相应功能处。
FUNCTABLE: ljmp FUNCTION0 ;一定要强制使用ljmp指令,以保证每个
;小段都是4个字节。
nop ;
ljmp FUNCTION1 ;
nop ;
ljmp FUNCTION2 ;
nop ;
ljmp FUNCTION3 ;
nop ;
ljmp FUNCTION4 ;
nop ;
ljmp FUNCTION5 ;
nop ;
ljmp FUNCTION6 ;
nop ;
ljmp FUNCTION7 ;
nop ;
ljmp FUNCTION8 ;
nop ;
ljmp FUNCTION9 ;
nop ;
ljmp FUNCTION10 ;
nop ;
ljmp FUNCTION11 ;
nop ;
ljmp FUNCTION12 ;
nop ;
ljmp FUNCTION13 ;
nop ;
;;;;;;;;;;;;;;;;功能选择子程序结束;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;欢迎子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;>>>>>>>>>>>>>>>资源占用报告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>临时占用a,dptr
;>>>>>>>>>>>>>>>报告完毕>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
FUNCTION0: mov dptr,#8000h ;
mov a,#81h ;
movx @dptr,a ;命令自建元器件进入欢迎状态。
;再啰嗦几句,如果您要使用自建
;元器件,那么必须自己改写动态
;库,作者提供一个简单的动态库
;开源项目。
mov a,#80h ;
movx @dptr,a ;命令自建元器件进入待机状态。
mov a,#LCD_CLS ;
call WRCMD ;清屏。
mov dptr,#WELCOME_1 ;
call WRSTR ;初始化LCD屏幕,显示第一行。
mov a,#LCD_SETDDADDR+64 ;换行。
call WRCMD ;
inc dptr ;
call WRSTR ;
FUNCTION0_1: mov a,RETURNFLAG ;检查返回标志,决定是否返回。
jz FUNCTION0_CON ;如果为零,继续执行。CON=CONTINUE。
jmp main ;
FUNCTION0_CON: jmp FUNCTION0_1 ;
;;;;;;;;;;;;;;;;欢迎子程序结束;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;测量电压功能子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;>>>>>>>>>>>>>>>资源占用报告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>临时占用a,b,c,dptr,bank0区r0~r7
;>>>>>>>>>>>>>>>报告完毕>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
FUNCTION1: call DISABLEINT1 ;屏蔽外部中断1。
;作者没有使用中断的方法处理ADC0804的
;$INTR$引脚变化,所以必须屏蔽外部中
;断1。
mov a,STATUS ;取得外部电设备状态字。
orl a,#01h ;进入测量电压状态。
anl a,#0FDh ;
mov STATUS,a ;保存外部电设备状态字。
mov dptr,#8100h ;
movx @dptr,a ;
nop ;稍微停顿一下。
nop ;
FUNCTION1_1: mov a,RETURNFLAG ;检查返回标志,决定是否返回。
jz FUNCTION1_CON ;如果为零,继续执行。
jmp main ;
FUNCTION1_CON: call ADCIO ;调用ADC0804读写操作子程序。
;读取的数值放在a和地址ADCOUTCUR中。
cjne a,ADCOUTBAK,FUNCTION1_2 ;比较当前和上一次ADC0804输出,如果
;相同,那么表明外部电压没有发生改
;变,也就没有必要刷新显示,这样视觉
;效果比较舒服。
jmp FUNCTION1 ;
FUNCTION1_2: mov r3,a ;ADC0804的数值乘以5,除以255就是对应
;的模拟电压值。现在将这个模拟电压值
;的单位换算为mV,也就是扩大1000倍,
;然后取得4位计算结果。当然了,最后
;那一位没有意义,因为ADC0804只有8
;bit精度,您可以算算它对应的最小电
;压分辨率是多少。
mov r2,#00h ;
mov r7,#88h ;
mov r6,#13h ;十六进制1388等于十进制5000。
call MULD2 ;调用双字节无符号乘法子程序。
mov r0,#DIVD4ADDRESS0 ;以下准备调用4字节无符号除法子程序,
;将刚才的乘法结果除以255。下面是一些
;赋初始值的准备工作。
mov r1,#DIVD4ADDRESS4 ;
mov a,r2 ;
movx @r1,a ;
inc r1 ;
mov a,r3 ;
mov @r1,a ;
inc r1 ;
mov a,r4 ;
mov @r1,a ;
inc r1 ;
mov a,r5 ;
mov @r1,a ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#0FFh ;准备除以的255。
call DIVD4 ;调用4字节无符号除法子程序。
;除法结束之后就应该显示结果了,对吧!
;可是您别着急,在内存中的数值是二进制
;的,一个字节对应2个十六进制数字,所
;以必须先做一些转换工作。有两种方法。
;第一种:将运算结果连续的进行除以10的操
;作,依次取得个位、十位、百位等等,就
;像下面的程序那样,这么做比较浪费处理
;器的时间,因为您做的是除法。第二种方
;法:对结果进行BCD调整。这个方法应该简
;单,留给您自己思考了,我没有编写。
mov r1,#DIVD4ADDRESS8 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#0Ah ;准备除以10。
mov dptr,#LCD0 ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;DIVD4ADDRESS3单元存放的是除法后的最低位
;余数,由于是除以10的余数,只能是0123456
;789之一。
movc a,@a+dptr ;要是直接显示这个数字的话,恐怕您什么都
;看不到。LCD1602不认识啊,它只认识ASCII
;码,所以还得取得这个数字对应的ASCII码才
;行。作者已经在前面列出了必要的ASCII码表。
;也许作者这个处理方法复杂了,要是您有好的
;方法,不吝赐教哦!作者QQ66410070。
mov RESULT5,a ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT4,a ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT3,a ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT1,a ;
mov a,#0Dh ;小数点。
movc a,@a+dptr ;
mov RESULT2,a ;
mov a,#0Ch ;
movc a,@a+dptr ;
mov RESULT6,a ;单位V。
mov a,#00h ;
mov RESULT7,a ;空终止。后面的程序类似,不再解释。
mov a,#LCD_CLS ;清屏。
call WRCMD ;
call WRRESULT ;调用写结果字符串子程序。
jmp FUNCTION1_1 ;
;;;;;;;;;;;;;;;;测量电压功能子程序结束;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;ADC读写子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;>>>>>>>>>>>>>>>资源占用报告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>临时占用a,dptr,c,r7
;>>>>>>>>>>>>>>>报告完毕>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ADCIO: mov a,ADCOUTCUR ;
mov ADCOUTBAK,a ;前一次结果保存在ADCOUTBAK中。
mov dptr,#8200h ;选择ADC0804,一定要保证P2.7处于高
;电平,禁止ADC的输出。作者把启动
;ADC0804转换的操作映射为外部内存的
;空写操作(随便;写任何数值)。但是
;作者没有将ADC0804的的读取映射为外
;部内存的读操作。作者曾经试图这么
;做,但是失败了!也许是Proteus软件
;在时序方面的问题,也许是ADC0804器
;件的问题,当然也可能是作者水平有
;限,没能找到解决方案。如果您有好的
;设计,千万告知作者,谢谢!
movx @dptr,a ;空写ADC0804,启动转换。
setb c ;
mov p3.3,c ;读取数据必须先写1。
ADCIO_1: mov c,P3.3 ;等待ADC0804转换完成。
jc ADCIO_1 ;
mov p0,#0FFh ;读取数据必须先写1。
clr c ;
mov p2.7,c ;开启ADC0804的输出允许。
nop ;不要马上读取。
nop ;ADC0804转换结束与输出需要间隔几个
;时钟周期。
nop ;具体需要几个时钟周期请参考手册,自
nop ;行调整。
nop ;
nop ;
nop ;
nop ;
mov a,p0 ;读端口,取得转换的数字值。
mov ADCOUTCUR,a ;写入ADCOUTCUR。
setb c ;
mov p2.7,c ;关闭ADC0804的输出允许,以免影响后
;续对其它器件的操作。一定要关闭啊!
ret ;
;;;;;;;;;;;;;;;;ADC读写子程序结束;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;测量电阻功能子程序;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;>>>>>>>>>>>>>>>资源占用报告>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>>>>>>>>>>>>>>>临时占用a,b,c,dptr,bank0区r0~r7
;>>>>>>>>>>>>>>>>>报告完毕>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
FUNCTION2: call DISABLEINT1 ;屏蔽外部中断1。
mov a,STATUS ;取得外部电设备状态字。
orl a,#03h ;进入测量电阻状态。
mov STATUS,a ;保存外部电设备状态字。
mov dptr,#8100h ;
movx @dptr,a ;
nop ;稍微停顿一下。
nop
FUNCTION2_1: mov a,RETURNFLAG ;检查返回标志,决定是否返回。
jz FUNCTION2_CON ;
jmp main ;
FUNCTION2_CON: call ADCIO ;调用ADC0804读写操作子程序。
;读取的数值放在a和地址ADCOUTCUR中。
cjne a,ADCOUTBAK,FUNCTION2_2 ;比较当前和上一次ADC0804输出,如果
;相同,那么表明外部电压没有发生改
;变,也就没有必要刷新显示,这样视
;觉效果比较舒服。
jmp FUNCTION2 ;
FUNCTION2_2: mov r3,a ;ADC0804的数值乘以23500,除以3060,
;再减去910,就是待测电阻值。参考电
;路图,您可以自己思考为什么是这个算
;式?以下的程序与测电压大同小异,不
;再多解释。
mov r2,#00h ;
mov r7,#0CCh ;
mov r6,#5Bh ;十六进制5BCC等于十进制23500。
call MULD2 ;调用双字节无符号乘法子程序。
mov r0,#DIVD4ADDRESS0 ;
mov r1,#DIVD4ADDRESS4 ;
mov a,r2 ;
movx @r1,a ;
inc r1 ;
mov a,r3 ;
mov @r1,a ;
inc r1 ;
mov a,r4 ;
mov @r1,a ;
inc r1 ;
mov a,r5 ;
mov @r1,a ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#0Bh ;
inc r1 ;
mov @r1,#0F4h ;十六进制0BF4等于十进制3060。
call DIVD4 ;
clr c ;清除c。
mov r1,#DIVD4ADDRESS7 ;以下减去910,四个字节减法。
mov a,@r1 ;
subb a,#8Eh ;
mov @r1,a ;
dec r1 ;
mov a,@r1 ;
subb a,#03h ;
mov @r1,a ;
dec r1 ;
mov a,@r1 ;
subb a,#00h ;
mov @r1,a ;
dec r1 ;
mov a,@r1 ;
subb a,#00h ;
mov @r1,a ;
mov r1,#DIVD4ADDRESS8 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#00h ;
inc r1 ;
mov @r1,#0Ah ;
mov dptr,#LCD0 ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT3,a ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT2,a ;
call DIVD4 ;
mov a,DIVD4ADDRESS3 ;
movc a,@a+dptr ;
mov RESULT1,a ;
mov a,#0Bh ;R的字符。
movc a,@a+dptr ;
mov RESULT4,a ;
mov a,#00h ;
mov RESULT5,a ;
mov a,RESULT1 ;灭零处理。比如待测的电阻是20R,
;希望显示结果20R,而不是020R,灭
;掉前导零。
cjne a,#30h,FUNCTION2_3 ;先取得最高位字符,如果是零(ASCII
;码30h),那么灭掉,其后的字符依次
;前移一位。否则不灭零,直接显示。
mov a,RESULT2 ;
mov RESULT1,a ;
mov a,RESULT3 ;
mov RESULT2,a ;
mov a,RESULT4 ;
mov RESULT3,a ;
mov a,RESULT5 ;
mov RESULT4,a ;
mov a,RESULT1 ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -