打印

求救!哪位前辈帮我指点一下这个程序

[复制链接]
1598|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
许世霞|  楼主 | 2007-10-12 14:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
;这是频率计的例子程序,包含:外部中断设置,中断服务程序,定时程序,定时服务程序
;以及数据处理,显示,包括 两位十进制数转化为三位BCD码,
;这里是一个高精度频率计的设计程序
;现象:数码管led1不断闪烁,同时,数码管显示当前计数的频率值!
;只要我们把p1.0(假想的信号源)和p3.2(外部中断0)直接相连,就可以在数码管看到频率值

        beep   bit  p3.7


        segdata equ p0      ;数据 输出
        sege    equ p2.7    ;显示 选中
        segb    equ p2.6    ;位 选
        segd    equ p2.5    ;段 选
    
        timer_h   equ   46h    ;定时器高位字节单元
        timer_l   equ   47h    ;定时器低位字节单元
        timcount  equ   48h    ;时间中断数
        count_h   equ   49h    ;计数值高位
        count_l   equ   4ah    ;计数值低位

        int_h     equ   45h    ;中断计数缓冲单元高地址
        int_l     equ   44h    ;中断计数缓冲单元低地址
        int_data  equ   43h    ;用来刷新LED指示的数据单元
         
        t_h       equ   60h    ;数据显示的高位
        t_s       equ   61h    ;数据显示中位
        t_m       equ   62h    ;数据显示低位
        disstart  equ   70h    ;显示单元首地址
        flag      equ   71h    ;显示结果

    org 00h                    ;代码开始地址
    jmp main                   ;主程序开始 
    
    org 03h                    ;外部中断EX0入口地址
    jmp ex_int0                ;中断服务程序 

    org 1bh
    jmp timer_int              ;定时器T1中断服务程序
    
    org 030h

   main:mov sp,#30h             ; 设置sp指针
        lcall pro_set           ; 初始化
        lcall pro_int0          ; 外部中断0工作初始化
        lcall tim_t1            ; 定时器T1工作方式设定

    mlp:lcall ex_pro            ; 外部中断数据转换
        lcall ex_display        ; 外部中断数据显示
        cpl p1.0                ; 取反 p1.0 获得外部脉冲
                                ; 我们利用它来进行中断计数操作
        jmp mlp

pro_set:mov a,#00h               ;初始化程序
        mov b,#00h
        mov p1,0ffh              ;p1 = 255 (十进制,写成十六进制 0FFH )   
        mov int_h,#00h
        mov int_l,#00h
        mov t_s,#00h
        mov t_h,#00h
        mov t_m,#00h
        mov timcount,#20
        mov timer_h,#3ch           ;定时 50 ms
        mov timer_l,#0c1h    
        mov count_l,#0
        mov count_h,#0      ;

        clr beep
     ret
;  **************  定时器设置   ************************
tim_t1: mov tmod,#10h           ;设置定时器,定时1s
        setb et1                ;允许定时中断
        mov th1,timer_h         ;设置定时初值高位
        mov tl1 ,timer_l        ;设置定时初值低位
        setb tr1                ;定时器开始工作
        ret
;  ***********  定时器中断服务程序  *******************
   
timer_int:  
             clr tr1            ;定时器中断服务,关闭定时器
             mov tl1,timer_l    ;重新赋初值
             mov th1,timer_h
             mov r0,timcount                
             djnz r0,t_end
             mov timcount,#20   ;到1s
             mov int_l,count_l  ;刷新显示部分
             mov int_h,count_h 
             mov count_l,#0
             mov count_h,#0            ;
       t_end:mov timcount,r0 
             setb tr1           ;重新开始定时操作
         reti
;  *****************  外部中断服务程序  ****************
ex_int0:
        inc  count_l            ;将中断缓冲区低地址加1
        mov a,count_l           ;判断是否有进位
        jnz int_end             ;没有则返回
        inc count_h             ;否则,将高地址加1
     int_end:  reti             ;中断返回
;***********************************
;*******   设置中断  ****************
pro_int0:
        clr c                   ;清进位标志
        setb  it0               ;设置中断触发方式:脉冲触发
        setb ea                 ;总的中断允许
        setb ex0                ;允许外部中断EX0中断
        clr ex1                 ;禁止外部中断EX1中断
       ret                      ;返回
; **********************************
ex_display:
           mov r0,#disstart     ;获得显示单元首地址
           mov r1,#01h          ;从第一个数码管开始
           mov r2,#06h          ;共显示6位数码管
           clr sege
     dislp:mov segdata,@r0     ;读取显示单元数据
           setb segd
           nop
           clr segd  
           inc r0               ;取下一个单元地址
           mov segdata,r1       ;开始显示当前位
           setb segb
           nop
           clr segb
           mov a,r1             ;准备显示下一位
           rl a                          ;
           mov r1,a             ;下一位
           lcall delay5ms       ;延时 5 ms
           djnz r2,dislp        ; 重复显示下一个
           
           mov segdata,#0       ;不显示
           setb segb
           nop
           clr segb
           
           
         ret                    ;显示完成,返回

;ex_pro   数据处理,主要为 bcd码转换,查表
ex_pro:   clr ea
          setb psw.3            ;准备 寄存器 
          clr psw.4                     ;
          mov r6,int_h          ;得到高位数据
          mov r7,int_l          ;得到低位数据
         
          mov r0,#disstart      ;开始填充显示单元    
                
          mov a,r7              ;获得低3位数据
          mov b,#10             ;变换的原理是如果a=0xff(十六进制)
          div ab                ;那么就相当于255(十进制),每次除以10取余数就可以分开成三个2,5,5 
          mov r5,b              ;保存第一位(个位)
          mov b,#10
          div ab
          mov r4,b              ;十位
          mov r3,a              ;百位
          
          mov a,r5
          mov @r0,a
          
          inc r0          
          mov a,r4
          mov @r0,a
          
          inc r0          
          mov a,r3
          mov @r0,a 
          inc r0
          ;////////////////////////////////////////// 
          mov a,r6              ;获得高3位数据
          mov b,#10
          div ab
          mov r5,b              ;保存第一位(个位)
          mov b,#10
          div ab
          mov r4,b              ;十位
          mov r3,a              ;百位
          
          mov a,r5
          mov @r0,a
          
          inc r0          
          mov a,r4
          mov @r0,a
          
          inc r0          
          mov a,r3
          mov @r0,a           
          
          mov r0,#disstart      ;开始填充显示单元
          mov r2,#06h           ;共计填充 6 位
     prlp:mov a,@r0             ;获得当前位地址
          mov dptr,#tab_nu      ;获得表头
          movc a,@a+dptr        ;获得编码数据
          mov @r0,a             ;保存编码数据
          inc r0                ;指向下一个带转换数据
          djnz r2,prlp          ;继续转换,直到完成
          setb ea
       ret                      ;转换完成,返回
       
       

;************  250 ms 延时(粗略) ******************8

delay:push psw                  ; 保存原来的寄存器单元
      clr psw.3                 ; 设置新的寄存器
      setb psw.4                ; 
      mov r0,#2                 ; 延时参数1 
      mov r1,#250               ; 延时参数2
      mov r2,#2                 ; 延时参数3
  dl1:djnz r0,dl1               ; 延时循环1
      mov r0,#250               ; 重新设置循环数据
  dl2:djnz r1,dl1               ; 开始第二道循环 
      mov r0,#240               ;
      mov r1,#248               ; 
  dl3:djnz r2,dl1               ; 第三道循环
      nop                       ;  修正定时精度
      pop psw                   ;  恢复原来的寄存器组
    ret                         ;  返回 
;  ***********************************************

;**************  定时 5ms ************
delay5ms:                       ;参见上面说明
      push psw
      clr  psw.3
      setb  psw.4
      mov r0,#250
      mov r1,#3
  d20:djnz r0,d20
      mov r0,#250
      djnz r1,d20
      pop psw
    ret

; ****************************************
;这是数字显示表格,其中 带小数点的数字比不带小数点的数字大16
; 比如 0 的显示代码为 0;那么 0.的显示代码为 16;如此类推

tab_nu: db 0c0h,0f9h, 0a4h, 0b0h, 99h , 92h , 82h, 0f8h ; number 0 to 7 no dp..
        db 80h , 90h, 88h , 83h , 0c6h, 0a1h, 86h, 8eh  ; number 8 to f no dp..
        db 40h , 79h, 24h , 30h , 19h , 12h , 02h, 78h  ; number 0 to 7 with dp..
        db 00h , 10h, 08h , 03h , 46h , 21h , 06h, 0eh  ; number 8 to f with dp..

      end             ;告诉编译器本程序到此结束,一定需要加上,否则编译通不过。

   序我有点不明白。这个程序里涉及到两个中断。两个中断由于优先级的不同肯定不能同时工作了。但我就是不明白外部中断和定时器是怎样配合工作的?可以在一秒的时间内测出外部中断了多少次,从而得出频率是多少呀?前段时间问了一个人说是存在精度和滞后性的问题。这又怎么理解呀?还请前辈们能给我指点迷经。

相关帖子

沙发
zhaohe2001| | 2007-10-12 15:32 | 只看该作者

re

ex_int0:
        inc  count_l            ;将中断缓冲区低地址加1
        mov a,count_l           ;判断是否有进位
        jnz int_end             ;没有则返回
        inc count_h             ;否则,将高地址加1
int_end:  reti                  ;中断返回
定时器只管定时一秒
外部中断服务程序中用count进行计数,每次中断加一,一秒时间里的值就是其频率

使用特权

评论回复
板凳
5880527| | 2007-10-12 18:21 | 只看该作者

这有什么精度可言

从没做过频率计什么的,但我想至少也该取长一点的时间,或是多几次来个平均,不过上面的程序基本原理好象还是有的

使用特权

评论回复
地板
许世霞|  楼主 | 2007-10-13 16:30 | 只看该作者

谢谢了

我似乎明白了。应该可以肯定地是这两个中断肯定不能同时工作。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

439

主题

3781

帖子

4

粉丝