1     CURR_NUM    EQU    30H      ;HEX,进行15~1的倒计时
  2     VAR_TIMER    EQU    31H     ;Soft timer,记录溢出的次数
  3     VAR_LED        EQU    32H   ;Led value,#03FH for red led,#0CFH for green led,记录当前是红灯还是绿灯
  4 
  5     DAT_74164    bit    P0.6
  6     CLK_74164    bit    P0.7
  7 
  8     DIG_1        bit    p0.5
  9     DIG_2        bit    p0.4
 10 
 11 ;*******************************************
 12     org    0000H            ;
 13     jmp    MAIN            ;跳到0030H,中间留给中断
 14 
 15     org    000BH            ;预留的写法000BH:8051中断矢量地址,定时器T0中断的矢量地址
 16     jmp    interrupt_T0     ;普通的跳转没有写子程序,预留地址:以防还有其它中断程序冲掉其地址,中断程序没有调用过
 17 /*什么时候执行中断程序?
 18     T0溢出的时候 ~ CPU硬件将主程序自动转到000BH的第一句话:jmp interrupt T0 ~ 执行到RETI
 19   不知道到主程序的哪句话T0会溢出即执行中断程序?程序执行的时机不定
 20 */
 21 ;*******************************************    
 22     org    0030H        ;Start program from 0030H        
 23 MAIN:        ;主程序只显示变量不管怎么改,变量什么时候变?
 24     mov    P0,#0FFH    ;Initialize the port赋初始值
 25     mov    P1,#0FFH    
 26     mov    P2,#0FFH    
 27     mov    P3,#0FFH
 28     
 29     /*Initilize the var*/
 30     mov    CURR_NUM,#15    `;给变量赋#15    
 31     mov    VAR_TIMER,#00H     ;溢出次数赋0
 32     mov    VAR_LED,#03FH     ;红灯:3F #3FH
 33     mov    P1,VAR_LED     ;把3F赋给p1,亮一下红灯
 34 
 35     /*Initialize T0*/     ;给T0定义一下工作模式:16位定时器
 36     mov    TMOD,#01H
 37     mov    TH0,#0B1H    ;20ms,load number,赋20ms
 38     mov    TL0,#0E0H,
 39     setb    TR0        ;Start T0,开始加一
 40     setb    ET0        ;Enable T0 inerrupt,开中断方式一
 41     setb    EA        ;Enable interrupt,程序转到#000B
 42     ;mov    IE,#82H    ;#10000010B ;两种不同的方式开中断
 43 
 44 MAIN_LOOP:
 45     call    DISPLAY_NUM    ;Display number,死循环,displaynumber
 46     jmp    MAIN_LOOP
 47 
 48     ret
 49 ;****************************************************
 50 interrupt_T0:    ;不是调用子程序,在硬件定位的地方直接写中断想做的事,T0溢出的时候执行
 51         /*中断程序执行时间不可太长,太长主程序被堵死*/
 52         /*中断程序中能不用全局变量就不用全局变量:中断程序应做到放在主程序的任何地方都能正确执行*/
 53         /*主程序运行起来,执行过但没有被系统调用过*/
 54     push    acc        ;Pay attention to here,push,pop:备份数据
 55     push    psw        ;类似flag,全局变量,硬件都是默认的全局变量
 56 
 57     ;Reset T0,must be done
 58     ;clr    TF0        ;auto clear the tag of overflow进入中断后程序自动清零
 59     mov    TH0,#0B1H    ;20ms,reload number,清零后重新赋一个初始值
 60     mov    TL0,#0E0H
 61 
 62     inc    VAR_TIMER    ;Add 20ms    ;溢出次数加一
 63     /*If VAR_TIMER=50,then time for 1s */
 64     mov    a,VAR_TIMER
 65     cjne    a,#50,INT_T0_EXIT        ;溢出次数有没有到50,到了清零,没到直接结束
 66                         ;设置为50~20ms为了控制跳变的时间间隔为1s
 67     mov    VAR_TIMER,#00H
 68     call    NUM_SUB                ;一轮结束,15秒显示结束跳到子函数减一显示14
 69 
 70 INT_T0_EXIT:
 71     pop    psw
 72     pop    acc
 73 
 74 reti                ;中断返回通过RETI实现,必须加在中断程序的末尾
 75 ;****************************************************
 76 DISPLAY_NUM:;在执行显示函数的过程中T0在一直往上加,CPU执行显示,
 77         ;定时器是单独的硬件每过一个机器周期加一到溢出~调用000B的程序,同时进行互不干扰
 78         ;显示中:没有写何时调用程序,但中断来何时来显示执行到哪一行算哪一行,随时来随时停~执行中断
 79     ;A<-A/B,
 80     mov    a,CURR_NUM
 81     mov    b,#0Ah
 82     div    ab
 83     mov    r0,a
 84 
 85     ;Display the low value,显示个位
 86     mov    a,b
 87     mov    dptr,#TAB_LED
 88     movc    a,@a+dptr
 89 
 90     call    sendTo74164    ;Display the numbet
 91     clr    DIG_1
 92     setb    DIG_2
 93     call    DELAY_DISP
 94     
 95     ;Display the high value,显示十位
 96     mov    a,r0
 97     mov    dptr,#TAB_LED
 98     movc    a,@a+dptr
 99 
100     call    sendTo74164    ;Display the numbet
101     clr    DIG_2
102     setb    DIG_1
103     call    DELAY_DISP
104 
105     ret
106 ;*******************************************
107 ;Send data of A to chip 74LS164
108 sendTo74164:
109     push    07h
110     push    acc
111 
112     mov    r7,#08        ;send 8 bits      
113 SEND164_LOOP:
114     clr    CLK_74164    ;clear clock-line for reading data
115     rlc    a
116     mov    DAT_74164,c    ;move data-bit to data-line    
117     setb    CLK_74164    ;send data to 74164
118     djnz    r7,SEND164_LOOP
119     clr    CLK_74164    ;clear clock-line for reading data
120         
121     pop    acc
122     pop    07h
123     ret
124 ;****************************************************
125 NUM_SUB:
126     ;Get previos value
127     mov    a,CURR_NUM
128     jz    NUM_SUB_RESET    ;到了1s看看变量是不是0,是赋15(红绿灯换3F变CF),不是-1
129 
130 NUM_SUB_1:
131     ;Simple sub 1
132     dec    CURR_NUM    ;不是0,CURR_NUM-1
133     jmp    NUM_SUB_EXIT
134 
135 NUM_SUB_RESET:
136     
137     mov    CURR_NUM,#15        ;
138     call    CHANGE_LED    ;Red to green or green to red
139     
140 NUM_SUB_EXIT:    
141     
142     ret
143 ;****************************************************
144 CHANGE_LED:
145     push    acc
146 
147     mov    a,VAR_LED
148     cjne    a,#03FH,TO_RED_LED
149     mov    VAR_LED,#0CFH        ;Red to green led
150     jmp    CHANGE_LED_EXIT    
151 
152 TO_RED_LED:
153     mov    VAR_LED,#03FH        ;Green to red led
154 
155 CHANGE_LED_EXIT:
156     mov    P1,VAR_LED
157     pop    acc
158 
159     ret
160 ;****************************************************
161 DELAY_DISP:
162     mov    r7,#15
163 DELAY_DISP_LOOP:
164     mov    r6,#200
165     djnz    r6,$
166     mov    r6,#200
167     djnz    r6,$
168 
169     djnz    r7,DELAY_DISP_LOOP
170     ret
171 ;****************************************************
172 ;****************************************************
173 ;LED code
174 TAB_LED:    
175     DB    0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H
176 ;****************************************************
177     END

 主程序做工作只有显示数码管上的数字,开中断使得数字能够在1s过后跳变为下一个数字和改变后红绿灯