;这是频率计的例子程序,包含:外部中断设置,中断服务程序,定时程序,定时服务程序 ;以及数据处理,显示,包括 两位十进制数转化为三位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 ;告诉编译器本程序到此结束,一定需要加上,否则编译通不过。 序我有点不明白。这个程序里涉及到两个中断。两个中断由于优先级的不同肯定不能同时工作了。但我就是不明白外部中断和定时器是怎样配合工作的?可以在一秒的时间内测出外部中断了多少次,从而得出频率是多少呀?前段时间问了一个人说是存在精度和滞后性的问题。这又怎么理解呀?还请前辈们能给我指点迷经。 |