
主程序:
push ds ;保存数据段
mov ax,0000
mov ds,ax ;数据段清零
mov ax,offset irq7 ;取中断程序入口地址
add ax,2000 ;加装时IP=2000地址
mov si,003c ;填8259中断7中断矢量
mov w[si],ax ;填偏移量矢量
mov ax,0000 ;段地址CS=0000H
mov si,003e
mov w[si],ax ;填段地址矢量
pop ds ;d栈
in al,21 ;读8259中断屏蔽字
and al,7f ;开8259中断7
out 21,al
mov al,b4 ;8253的计数器2为方式2,采用二进制计数,先低后高写入计数值 10110100
out 43,al ;写入方式控制字
mov ax,2e9c 0010 1110 1001 1100B 11932D
out 42,al ;写入低字节计数值 1001 1100
mov al,ah
out 42,al ;写入高字节计数值 0010 1110
mov al,81 ;8255的A口为方式0输出,B口为方式0输出,C口下部输入 1000 0001
out 63,al ;写方式控制字
call first ;调用first子程序,赋计数初值
begi:hlt 延时等待
sti ;开中断
mov ah,01
int 16 ;检测是否按了键盘
jz begi
mov ah,00 ;读键值
int 16
cmp al,0d ;是否按了回车
jnz A1
mov si,4000
not [si+04] ;偏移地址为4004的内存单元内容取反
jmp begi
A1:cmp al,1b ;是否按了ESC键
jnz A2
call first ;重新赋初值,相当于清零
A2:jmp begi
中断程序:
irq7:call disp ;调用disp子程序,用来在数码管显示数据
mov si,4000
cmp [si+04],00 ;判断是否按了第2次回车键
je A4
call addn ;调用addn子程序,用来计数
A4:mov al,20
out 20,al
cli ;关中断
iret ;返回
addn程序:
addn:mov si,4000
add [si+03],01 ;百分之一秒加1
cmp [si+03],0a ;判断是否大于10
jz A5
jmp A9
A5:mov [si+03],00
Add [si+02],01 ;十分之一秒加1
cmp [si+02],0a ;判断是否大于10
jz A6
jmp A9
A6:mov [si+02],00
add [si+01],01 ;秒位加1
cmp [si+01],0a ;判断是否大于10
jz A7
jmp A9
A7:mov [si+01],00
add [si],01 ;十秒位加1
cmp [si],06 ;判断是否大于6
jz A8
jmp A9
A8:mov [si],00 ;大于60:00重新开始
A9: ret
赋初值程序:
first:mov si,4000
mov al,00
mov [si],al
mov [si+01],al
mov [si+02],al
mov [si+03],al
mov [si+04],al
ret
显示程序:
disp:push ax ;保存AX
mov si,4000 ;指向数据缓冲区
mov dl,f7 ;1111 0111 指向数码管
mov al,dl ;al=1111 0111
again:out 60,al ;写端口A
mov al,[si]
mov bx,4100 ;指向数码缓冲区 bx=0100 0001 0000 0000
and ax,00ff ; ax=0000 0000 al
add bx,ax ;得到显示代码 bx=0100 0001 al
mov al,[bx]
out 61,al ;写端口B
call dally :调用延时程序dally
inc si
mov al,dl
test al,01
jz out
ror al,1 ;指向下一个数码管
mov dl,al
jmp again
out: pop ax ;d出AX
ret
dally:push cx ;延时程序
push ax
mov cx,0010
t1 :mov ax,0010
t2 dec ax
jnz t2
loop t1
pop ax
pop cx
ret
数码缓冲区:
0000:4000 3f,06,5b4f,66,6d,7d,07,7f,6f
二、 设计思想
电子秒表要实现的功能:用键盘中断来控制整个程序,按一下回车键启动电子秒表,再按一下暂停,按一下ESC键清零,用七段数码管显示时间。整个程序涉及到8255、8253与8259三个芯片。8253的OUT2,CLK2分别连接8259的IRQ7与PCLK,8253的GATE2连接正5伏电压,采用计数器2每隔001秒产生一次中断并且计数,写入以偏移地址4000H开始的4个内存单元,然后利用8255将内存单元的数据输出到七段数码管。由于键盘中断优先于8259的7号中断,所以程序只有在按一下回车键才启动电子秒表,再按一下暂停,按一下ESC键清零,如果超出了60秒,整个程序自动重新开始。
三、 所用芯片工作原理
8255:接口电路在CPU和I/O设备之间起着信号的变换和传输的作用。 任何接口电路与CPU之间的信息传输方式都是并行的,即CPU与接口电路之间以数据字节/字为单位传送信息。接口电路与I/O设备之间的信息传送方式,有并行和串行两种,相应的接口电路称为并行接口和串行接口。
并行接口是在多根数据线上,以数据字节/字与I/O设备交换信息。在输入过程中,输入设备把数据送给接口,并且使状态线“输入准备好”有效。接口把数据存放在“输入缓冲寄存器”中,同时使“输入回答”线有效,作为对外设的响应。外设在收到这个回答信号后,就撤消数据和“输入准备好”信号。数据到达接口中后,接口会在“状态寄存器”中设置输入准备好标志,或者向CPU发一个中断请求。CPU可用查询方式或中断方式从接口中读取数据。接口中的数据被读取后,接口会自动清除状态寄存器中的标志,且撤消对CPU的中断请求。
在输出过程中,每当输出寄存器可以接收数据,接口就会将状态寄存器中“输出准备好”状态置1或向CPU发一个中断请求,CPU可用查询或中断方式向接口输出数据。当CPU输出的数据到达接口后,接口会清除“输出准备好”状态,把数据送往外设,并向外设发一个“数据输出准备好”信号。外设受到驱动后,便接收数据,并向接口电路发一个“输出回答”信号,接口收到该回答信号后,又将状态寄存器中“输出准备好”置位,以便CPU输出下一个数据。
8253:对CLK信号进行“减1计数”。首先CPU把“控制字”,写入“控制寄存器”,把“计数初始值”写入“初值寄存器”,然后, 定时/计数器按控制字要求计数。计数从“计数初始值 开始,每当CLK信号出现一次,计数值减1,当计数值减为0时,从OUT端输出规定的信号(具体形式与工作模式有关)。当CLK信号出现时,计数值是否减1(即是否计数),受到“门控信号”GATE的影响,一般,仅当GATE有效时,才减1门控信号GATE如何影响计数 *** 作,以及输出端OUT在各种情况下输出的信号形式与定时/计数器的工作模式有关。
8259:1 IR线上提出了中断请求的中断源,即出现请求,IRR中断请求寄存器(共有8位D7~D0)对应于连接在IR0~IR7线上的外设的中断请求,哪一根输入线有请求,哪一根输入线就置1。
2 若OCW1(IMR中断屏蔽寄存器)未使该中断请求屏蔽(对应位为0时不屏蔽),该请求被送入PR(优先权分析器)比较。否则,不送入PR比较。
3 PR把新进入的请求与ISR(服务中寄存器)中正在被处理的中断进行比较。如果新进入的请求优先级较低,则8259不向CPU提出请求。如果新进入的请求优先级较高,则8259使INT引脚输出高电平,向CPU提出请求。
4 如果CPU内部的标志寄存器中的IF(中断允许标志)为0,CPU不响应该请求。若IF=1,CPU在执行完当前指令后,从CPU的INTA引脚上向8259发出两个负脉冲。
5第一个 INTA负脉冲到达8259时,8259完成以下三项工作:
a使IRR(中断请求寄存器)的锁存功能失效。这样一来,在IR7~IR0上的请求信号就不会被8259接收。直到第二个INTA负脉冲到达8259时,才又使IRR的锁存功能有效。
b使ISR(服务中寄存器)中的相应位置1。
c使IRR中的相应位清0。
6第二个INTA负脉冲到达8259时,8259完成以下工作:
a将中断类型码(ICW2中的值)送到数据总线上,CPU将其保存在“内部暂存器”中。
b如果ICW4(它设定级中断联方式之特定完全嵌套方式,将在8259的工作方式中详述ICW4)中设置了中断自动结束方式,则将ISR的相应位清0。
AVR128做的,mega16需要更改寄存器名称及中断向量号,自己看手册改吧
#include<iom128vh>
#include<macrosh>
#define uchar unsigned char
#define uint unsigned int
#define rs_L PORTD&=~BIT(6)
#define rs_H PORTD|=BIT(6)
#define E_L PORTD&=~BIT(7)
#define E_H PORTD|=BIT(7)
uint temp=20,temp1;
uchar set;
#pragma data:code
const uchar table[]=" I LOVE MCU !";//定义数组花样
const uchar table1[]="val:";
void delay(uint x)//延时函数
{
uchar i;
while(x--)
for(i=0;i<110;i++);
}
void send_com(uchar com)//地址函数
{
rs_L;
PORTE=com;
delay(10);
E_H;
delay(10);
E_L;
}
void send_date(uchar date)//数据函数
{
rs_H;
PORTE=date;
delay(10);
E_H;
delay(10);
E_L;
delay(10);
}
void dis_num(uint temp)//显示函数
{
send_com(0x80+0x40+8);
send_date(0x30+temp/1000);
send_date(0x30+temp%1000/100);
send_date(0x30+temp%100/10);
send_date(0x30+temp%10);
}
void init()//初始化函数
{
DDRD=0XFF;
PORTD|=BIT(0);
DDRE=0XFF;
DDRC=0X00;
PORTC=0XFF;
E_L;
send_com(0x38);//第一个指令码,设置16X2显示。
delay(10);
send_com(0x0c);//第二个指令码,设置光标。
delay(10);
send_com(0x06);//第三个指令码,设置光标加一。
delay(10);
send_com(0x01);//清屏指令码。
delay(10);
}
void key()
{
if(!(PINC&(BIT(0))))
{
delay(10);
if(!(PINC&(BIT(0))))
{
set++;
if(set==3)
set=0;
}
while(!(PINC&(BIT(0))));
}
if(!(PINC&(BIT(1))))
{
delay(10);
if(!(PINC&(BIT(1))))
{
if(set==1)
{
temp++;
if(temp==9999)
temp=0;
}
if(set==2)
{
temp1++;
if(temp1==9999)
temp1=0;
}
}
while(!(PINC&(BIT(1))));
}
}
void timer1_init(void)
{
// TCCR1B = 0x00; //stop timer
TCNT1H = 0xE3; //设置 TC1 的 计数寄存器 高8位值,基于73728M晶振
TCNT1L = 0xE1; //设置 TC1 的 计数寄存器 低8位值,基于73728M晶振
TCCR1A = 0x00;
TCCR1B = 0x05; //设置TC1 为 CLK/1024分频,启动TC1
MCUCR = 0x00; //设置 MCU 的 控制寄存器
SREG = 0x80; //设置 中断控制寄存器
TIMSK = 0x04; //设置 定时计数器 的 屏蔽寄存器
}
void main()//主函数
{
uchar i;//定义局部变量
init();//调用初始化函数
timer1_init();
send_com(0x80+0x00+3);//调用地址函数
for(i=0;i<14;i++)//显示''字符
{
send_date(table[i]);
delay(10);
}
send_com(0x80+0x40+2);
for(i=0;i<4;i++)
{
send_date(table1[i]);
delay(10);
}
delay(10);
while(1)
{
key();
//dis_num( temp);
if(set==0)
{
TCCR1B = 0x05;
dis_num( temp);
}
if(set==1)
{
TCCR1B = 0x00;
dis_num( temp);
}
if(set==2)
dis_num( temp1);
if(temp==temp1)
PORTD&=~BIT(0);
if(temp==1)
PORTD|=BIT(0);
}
}
/--------------------------------------------------------------------
程序名称:定时器1中断服务程序
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------/
#pragma interrupt_handler timer1_ovf_isr:15
void timer1_ovf_isr(void)//
{
TCNT1H = 0xE3; //reload counter high value
TCNT1L = 0xE1; //reload counter low value
temp--; //每加1S,显示加1
if(temp==0)
temp=1;
}
关键是要采纳,帮人打码很累哦
秒表就是一个计时的工具,为了保证精确度,一般显示秒后面两位,就是10ms位,在单片机定时器中,赋初值1ms,变量不停的累加上去, 累加到10的时候,秒表加1,就是10ms了,
复位就是对秒表的数据进行清零重置,这时就需要一个按键来进行人机交互功能了,这时候就要考虑有几个按键了,一般的秒表设计的时候有两个按键,一个进行启动停止,一个进行清零;
1启动和停止,启动停止的按键,就是按一下让标志位取反一次,
bit flag =0;
if(Key ==0)
{
delay(); //延时10ms;这个程序比较常见,就不写出来了
if(key == 0)
{
flag = !flag; //消抖后检测到按键还是按下状态,就把标志位取反;
while(!Key); //等待松手
}
}
同时在定时器中断里, 根据标志位对 及时变量进行累加
if(flag)
{
t++;
if(t >= 10)
{
t = 0;
ms++;
}
}
就这样 标志位就表示的秒表启动停止的,
2 。 复位,复位顾名思义就是 返回到初始状态,就是0 ; 一般复位是在秒表停止的状态对秒表进行清零;
先在主程序里检测按键
bit clc = 0;
if(key1 == 0)
{
delay(); // 延时10ms
if(Key1 == 0)
{
clc = 1;
while(!Key1); //等待松手
}
}
然后在定时器中断里进行对变量的数值进行清零
if(!flag ) //在停止状态
{
if(clc)
{
ms = 0;
clc = 0;
}
}
到此 秒表的启动停止 和复位就完成了 ,
用单片机的定时器T0定时,计时1秒,实现倒计时的秒表的功能。
程序如下
#include<reg51h>
unsigned char code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//共阳数码管段码表
unsigned char second;//秒倒计时变量
unsigned char t0n;//T0中断次数计数
sbit k1=P3^2;//定义按键
void delay()
{
unsigned int j;
for(j=400;j>0;j--);
}
void display()//显示子程序
{
P2=0x01;
P0=tab[second/10];//显示十位
delay();
P2=0x02;
P0=tab[second%10];//显示个位
delay();
}
void main()
{
TMOD=0x01;//用T0定时,中断方式
TH0 =0x3C;//晶振12M,定时50ms
TL0 =0xB0;
IE =0x82;
while(1)
{
display();//调显示子程序
if(k1==0)//按键按下
{
if(TR0==0)
{
TR0=1;//启动开始计时
second=60;//从60秒开始倒计时
}
else
TR0=0;
while(k1==0);//等待按键释放
}
}
}
//T0中断程序
void T0_int() interrupt 1
{
TH0 =0x3C;
TL0 =0xB0;
t0n++;
if(t0n>=20)//1秒到
{
t0n=0;
second--;//减1秒
if(second==0)TR0=0;
}
}
仿真图如下
以上就是关于汇编语言 秒表程序设计全部的内容,包括:汇编语言 秒表程序设计、求助,AVR单片机做一个可输入时间的倒计时秒表、单片机秒表复位程序如何写等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)