找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1605|回复: 7
收起左侧

关于单片机驱动数码管的计数程序(汇编),求解惑

[复制链接]
ID:693473 发表于 2020-3-26 22:39 | 显示全部楼层 |阅读模式
程序目的是用单片机驱动四位一体的数码管动态显示计数从0~2000,计满归零,目前存在问题为仿真动态扫描的时候总是只有一个数码管点亮,计数正常,但是数码管却轮流闪烁,想要的效果是视觉上四个数码管都能正常显示,程序如下,希望有大神为我解惑,万分感激。


NAME HW
PROG        SEGMENT        CODE          ;定义代码段
STACK        SEGMENT        DATA          ;定义数据段
RSEG STACK                                  ;选择stack段                  
        DS    10H             ;16字节堆栈
        CSEG  AT   0              ;声明代码段开始位置
        USING        0             ;使用工作寄存器组0        rs1 rs0 =00
        LJMP  START                  ;跳转至START执行
        RSEG  PROG                  ;选择PROG段
START:  MOV   SP,#STACK-1        ;重新选择堆栈指针位置
              MOV 0x50,#0                ;0x50为全局变量 个位显示
                MOV 0x51,#0                        ;十位显示
                MOV 0x52,#0                ;百位显示
                MOV 0x53,#0                        ;千位显示
                SETB  P1.1
                CLR   P2.0
                CLR   P2.1
                CLR   P2.2
                CLR   P2.3
                SETB  0x10
KEY:        JB   P1.1,NEXT                ;判断键是否按下
                MOV  R4, #10            ;延时去抖动
                CALL DELAY
                JB   P1.0, NEXT
LOOP:        JNB  P1.0, LOOP
        CPL  0x10
NEXT:   JNB  0X10, NEXT1    ;处理数码管
                MOV  LEDVAL,0x50    ;将个位数字送入LEDVAL
                MOV  R4,#10  
                CALL SHOW_NUM
                SETB P2.3                                ;
                CALL DELAY
                CPL  P2.3
                MOV  LEDVAL,0x51    ;将十位数字送入LEDVAL
                CALL SHOW_NUM
                SETB P2.2                        ;               
                CALL DELAY
                CPL  P2.2
                MOV  LEDVAL,0x52    ;将百位数字送入LEDVAL
                CALL SHOW_NUM
                SETB P2.1                        ;               
                CALL DELAY
                CPL  P2.1
                MOV  LEDVAL,0x53    ;将千位数字送入LEDVAL
                CALL SHOW_NUM
                SETB P2.0                        ;               
                CALL DELAY
                CPL  P2.0
                INC  0x50
                MOV  A, #9                    
                CLR  C
                SUBB A, 0x50        ;A=A-(0X50)         判断个位是否大于9
                JNC  NEXT1
                MOV  0X50,#0        ;个位清零
                INC  0x51
                MOV  A, #9                    
                CLR  C
                SUBB A, 0x51        ;A=A-(0X51)         判断十位是否大于9
                JNC  NEXT1
                MOV  0X51,#0        ;十位清零
                INC  0x52
                MOV  A, #9                    
                CLR  C
                SUBB A, 0x52        ;A=A-(0X52)         判断百位是否大于9
                JNC  NEXT1
                MOV  0X52,#0        ;百位清零
                INC  0x53
                MOV  A, #2                    
                CLR  C
                SUBB A, 0x53        ;A=A-(0X53)         判断千位是否大于2
                JNC  NEXT1
                LJMP START          ;归零
NEXT1:        LJMP KEY
SHOW_NUM:  PUSH DPL
           PUSH DPH                    ;为了防止DPTR被篡改
           MOV A,LEDVAL         
           MOV DPTR,#zixing_base
           MOVC A,@A+DPTR
           MOV  P0,A
           POP DPH
           POP DPL
           RET
DELAY:
NEXT2: MOV R5,#255
        MOV R6,#255
NEXT3: DJNZ  R5, NEXT3          ;循环255次
NEXT4: DJNZ  R6, NEXT4          ;循环255次
        DJNZ  R4, NEXT2          
        RET
zixing_base: DB 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90
RSEG  STACK
LEDVAL:  DS  1
END

回复

使用道具 举报

ID:401564 发表于 2020-3-26 23:23 | 显示全部楼层
NAME HW
PROG        SEGMENT        CODE          ;定义代码段
STACK        SEGMENT        DATA          ;定义数据段
RSEG STACK                                  ;选择stack段                  
        DS    10H             ;16字节堆栈
        CSEG  AT   0              ;声明代码段开始位置
        USING        0             ;使用工作寄存器组0        rs1 rs0 =00
        LJMP  START                  ;跳转至START执行
        RSEG  PROG                  ;选择PROG段
START:  MOV   SP,#STACK-1        ;重新选择堆栈指针位置
你能完全理解这一段代码什么意思吗?
我看不明白,我是用汇编的,但我不想明白这一段代码是干嘛的
汇编和硬件是直接关系的,代码放什么位置都是很重要的,一个程序下来,代码多功能却单一,一个简单的功能往往要很多代码去执行
所以,汇编最好是不要用太多伪指令,代码开始用ORG 指定,一个功能最好用CALL子程序,而不是用JMP跳转,这样一来,LOOP循环部分一般都是可以十来条指令就可以了,有问题就比较容易在子程序中查找
回复

使用道具 举报

ID:123289 发表于 2020-3-27 06:47 | 显示全部楼层
如果你能不使用DELAY()就成功了!
写程序先画框图,在框图上直通再写程序,当你在一个管子显示时DELAY了其它三个管子这时会如何呢?是明?是暗?显示了什么?你想过没有?“闪”是什么意思呢?意味着什么呢?
想清楚了,弄明白了,程序就OK了。
回复

使用道具 举报

ID:693473 发表于 2020-3-27 11:16 | 显示全部楼层
yzwzfyz 发表于 2020-3-27 06:47
如果你能不使用DELAY()就成功了!
写程序先画框图,在框图上直通再写程序,当你在一个管子显示时DELAY了 ...

如果不用delay的话应该就看不到显示效果了吧,数码管的动态扫描原理应该是一个个扫描过去的啊,因为我用c51语言编写也是这样但是可以实现,然后我这个汇编程序也是按照c51的思路来写的,但是却无法实现,我也是第一次写汇编可能不太懂,麻烦能不能详细讲讲,万分感谢。
回复

使用道具 举报

ID:693473 发表于 2020-3-27 11:24 | 显示全部楼层
Y_G_G 发表于 2020-3-26 23:23
NAME HW
PROG        SEGMENT        CODE          ;定义代码段
STACK        SEGMENT        DATA      ...

我写这一段的目的就相当于是初始化定义的作用,开辟地址空间可以使用,之所以不用ORG指定是想让系统去自动分配,我也是第一次写汇编程序,可能不太懂,我回去试试直接指定,还有感谢你的经验分享,然后我觉得我的显示有问题是因为显示的那段程序可能有问题,我自己看了很久也不知道怎么改,不知道能否帮忙看看,指导指导。
回复

使用道具 举报

ID:401564 发表于 2020-3-27 15:38 | 显示全部楼层
我看不太懂你的代码
干脆我自己写一个了,以下就是我写的,这个程序仿真不一定行,但实际肯定是可以的,我已经在自己的板子上烧录运行过了,你可以参考一下
每个人写代码的习惯都是不一样的, 我不太习惯由编译器指定地址,有时候要用到连续的地址,我不知道由编译指定的地址是不是连续,所以,就自己指定了,久了就成了一种习惯了


/*0-2000计数程序
;单片机型号:STC8a4k32s2,使用片上24MHZ晶振
如果使用其它型号单片机,延时要调节一下
;COM1,COM2和OUT可以在EQU中修改
;仿真的时候自己做一些修改就可以了,这是一个已经在开发板上验证过的程序*/
;===========================================================================
COM0                        EQU                P2.0
COM1                        EQU                P2.1
COM2                        EQU                P2.2
COM3                        EQU                P2.3        ;数码管的4个位选端口
S1                                BIT                P1.5        ;按键
OUT                                EQU                P0                ;PO用于显示
P2M0                        EQU                096H        ;
P2M1                        EQU                095H        ;控制P2端口输出模式的两个寄存器
;===========================================================================
LED_1                        DATA        030H        ;显示电压用的LED位的个位
LED_10                        DATA        031H        ;显示电压用的LED位的十位
LED_100                        DATA        032H        ;显示电压用的LED位的百位
LED_1000                DATA        033H        ;显示电压用的LED位的千位
DIV_L                        DATA        034H        ;除法高位用的缓存器
DIV_H                        DATA        035H        ;除法低位用的缓存器
DATA_BUF_L                DATA        036H        ;数据暂存器的低位
DATA_BUF_H                DATA        037H        ;数据暂存器的高位
DATA_K_L                DATA        038H        ;数据2000的低位
DATA_K_H                DATA        039H        ;数据2000的高位
;===================================================
                ORG         0000H
                LJMP         MAIN
                ORG         0100H
MAIN:                MOV                DATA_K_L,#00H
                                MOV                DATA_K_H,#00H        ;
                                MOV                P2M1,#000H                ;
                                MOV                P2M0,#0FFH                ;P2端口设定成强推挽输出
;========================================
LOOP_0:         JB                S1,LOOP_1                ;
                                CALL        S1_DISP                        ;调用按键处理子程序
LOOP_1:                        CALL        DISPLAY                        ;
                                JMP                LOOP_0                        ;
;==============================================================================================================
;按键处理子程序
S1_DISP:                CALL        DISPLAY                        ;调用显示一次,就当作是去抖动
                                JNB                S1,S1_DISP                ;这个可以不要,有的话就是当你按下按键不放的时候,显示不会灭灯,
                                                                                ;数字也不会一直的加上去,调试的时候不要这条指令,就可以快速的调到2000循环
                                ;========================
                                CLR                C                                ;
                                MOV                A,DATA_K_L                ;
                                ADD                A,#001H                        ;低位加1
                                MOV                DATA_K_L,A                ;
                                MOV                A,DATA_K_H                ;
                                ADDC        A,#000H                        ;高位带进位加0
                                MOV                DATA_K_H,A                ;
                                ;========================
                                CLR                C
                                MOV                A,#LOW(2000)        ;
                                SUBB        A,DATA_K_L                ;
                                MOV                A,#HIGH(2000)        ;
                                SUBB        A,DATA_K_H                ;
                                JNC                S1_DISP_0                ;C进位标志位为0,就表示还没有加到2000
                                MOV                DATA_K_L,#00H        ;
                                MOV                DATA_K_H,#00H        ;
S1_DISP_0:
RET                                ;返回
;===========================================================================
;显示子程序                                               
DISPLAY:        MOV                B,DATA_K_L
                                MOV                A,DATA_K_H                 ;
                                CALL        DATA_DISP                 ;2000的10进制数据拆分为4个倍数,并存放在四个地址中
                                ;===================================================
                                MOV                A,LED_1
                                CLR                COM0                        ;打开位选
                                CALL        DISP_LED                ;数码管通过查表显示
                                CALL        DELAY1MS                ;延时1mS
                                SETB        COM0                        ;关闭位选
                                ;===================================================
                                MOV                A,LED_10
                                CLR                COM1                        ;打开位选
                                CALL        DISP_LED                ;数码管通过查表显示
                                CALL        DELAY1MS                ;延时1mS
                                SETB        COM1                        ;关闭位选
                                ;===================================================
                                MOV                A,LED_100
                                CLR                COM2                        ;打开位选
                                CALL        DISP_LED                ;数码管通过查表显示
                                CALL        DELAY1MS                ;延时1mS
                                SETB        COM2                        ;关闭位选
                                ;===================================================
                                MOV                A,LED_1000
                                CLR                COM3                        ;打开位选
                                CALL        DISP_LED                ;数码管通过查表显示
                                CALL        DELAY1MS                ;延时1mS
                                SETB        COM3                        ;关闭位选
                                ;===================================================
RET
;=================================================================================================
;数码管查表显示
DISP_LED:                MOV         DPTR,#TABLE
                                MOVC         A,@A+DPTR
                                MOV         OUT,A                         ;
                /*                CALL        DELAY1MS                ;延时1mS,如果延时放在这里扫描显示部分可以少一点,放在显示那是为了方便理解而已*/
RET       
;==================================================================================================
;这个是1mS的延时程序,在STC下载器中可以用软件自动计算
;如果是仿真,可以相应的减少延时的时长                                       
DELAY1MS:                PUSH 30H
                                PUSH 31H
                                MOV 30H,#32
                                MOV 31H,#39
NEXT:                        DJNZ 31H,NEXT
                                DJNZ 30H,NEXT
                                POP 31H
                                POP 30H
RET
;===================================================================================================
;DATA_DISP==============数据拆分,把一个数拆分成四个数,用于显示======================
;把16进制的高低两个字节分别放到A和B,处理之后,个十百千会分别放到4个地址中,使用减法运算来达到除法的效果
;进入之前要先把高位数据存放到A,低位数据存放到B               
DATA_DISP:                MOV                LED_1,#0
                                   MOV                LED_10,#0
                                   MOV                LED_100,#0
                                   MOV                LED_1000,#0                ;先把四个清除
                                   MOV                DATA_BUF_H,A        ;
                                   MOV                DATA_BUF_L,B        ;把数据传送到缓冲器中
                                   MOV                R0,#0E8H                ;
                                   MOV                R1,#03H                        ;1000的16进制为03E8H
                                MOV                R2,#100
                                MOV                R3,#10
                                MOV                R4,#0
SUB_1000:                  CLR                C
                                MOV                A,DATA_BUF_L
                                SUBB        A,R0
                                MOV                DIV_L,A;
                                MOV         A,DATA_BUF_H;
                                SUBB        A,R1
                                MOV                DIV_H,A                       
                                JC                SUB_100                       
                                MOV                DATA_BUF_L,DIV_L
                                MOV         DATA_BUF_H,DIV_H
                                INC                LED_1000
                                JMP                SUB_1000
SUB_100:                CLR                C
                                MOV                A,DATA_BUF_L
                                SUBB        A,R2
                                MOV                DIV_L,A                       
                                MOV         A,DATA_BUF_H;
                                SUBB        A,R4
                                MOV                DIV_H,A                       
                                JC                SUB_10                       
                                MOV                DATA_BUF_L,DIV_L
                                MOV         DATA_BUF_H,DIV_H
                                INC                LED_100
                                JMP                SUB_100
SUB_10:                        MOV                A,DATA_BUF_L
                                MOV         B,R3
                                DIV                AB
                                MOV                LED_10,A
                                MOV                LED_1,B
RET
;===================================================================================
TABLE:                DB                 11111100B,01100000B,11011010B,11110010B,01100110B,10110110B,10111110B,11100000B,11111110B,11110110B        ;表:共阴数码管 0-9
END

回复

使用道具 举报

ID:693473 发表于 2020-3-27 20:45 | 显示全部楼层
Y_G_G 发表于 2020-3-27 15:38
我看不太懂你的代码
干脆我自己写一个了,以下就是我写的,这个程序仿真不一定行,但实际肯定是可以的,我已经 ...

好的,我好好参考一下,十分感谢,还劳烦亲自写一个。
回复

使用道具 举报

ID:87166 发表于 2020-3-27 21:55 | 显示全部楼层
三个亮,一个不良,你排查下问题,动态扫描,就是让你的每一个灯的亮都延时一部分时间。一个不亮,要么你没有点亮它,要么延迟的时间不够,或者你在点亮的同时,干了其他事情把他灭了。不要老是看程序,主要要建立下逻辑思维。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表