在主程序中设置定时器的初值后为什么还要在中断子程序中重新设置初值

在主程序中设置定时器的初值后为什么还要在中断子程序中重新设置初值,第1张

初值在运行过程中计数器的不断加1,直到溢出时产生中断。因为这种定时方式(有的方式可以自动重置的),单片机不能重置初值,所以进入中断后必须人工重置初值,为下一次中断作准备。

主函数里的是初始化的初值。因为有的定时方式,定时器溢出时,单片机没有重装初值的功能。所以定时函数里要重装初值。可以设置不同的值,但定时时间主要是以重装的来计了。

我觉得是这样的,单片机的定时器,它的计数过程是相当于电脑里面一个后台运行的东东一样。在计数时单片机同时在执行其他程序,计数周期就是单片机的一个机器周期。

当我们给定时器初始化后,一但打开(这指内部定时器方式,还有外部脉冲计数方式,都差不多),下个机器周期到来便累加一次。计满时,即定时器十六位为0xffff,再计一次后,相应中断标志置1(TF0、TF1),若之前开启了相应的定时器中断(ET0、ET1)且有相应中断服务函数,单片机会暂停当前正在执行的程序,进入相应中断服务函数里面执行,若定时器还在开启状态,则仍会计数。中断执行完后回到暂停处的主程序里。在一个机器周期一般会做六件事情,其中有项是检查访问内部寄存器,包括中断标志。

11)主程序各行作用如下:

第一行:设置定时器模式

第二行:设置定时器高位寄存器初值

第三行:设置定时器低位寄存器初值

第四行:T0定时器中断使能

第五行:总中断使能

第六行:打开T0定时器

第七行:死循环(主程序停留在此行)

主程序整体实现的功能:初始化定时器T0

12)void Timer0_Int(void)是定时器0中断函数,每行作用如下:

第一行:重新设定定时器高位寄存器初值

第二行:重新设置定时器低位寄存器初值

第三行:如果P1_0 IO口是高电平则改为低电平,如是低电平改为高电平

整体实现的功能:P1_0 IO口高低电平1秒切换一次

妈呀,这么多问题,网上找找,应该有的

会影响的

这个和CPU处理能力有关

所有中断(不论什么等级)时间之和一定要小于系统时间

否则时钟就会变慢(或者低级中断得不到执行)

这取决于你设计的调度机制是抢先式还是时间片式的

如果是抢先式,则可能出现高级中断总能得到执行,低级中断老是轮不到执行

如果是时间片轮转的,则大家轮流坐庄,都能得到执行,但整个系统时钟慢了(在单片机和台式机CPU都能得到验证)

不论什么单片机、DSP还是NP或台式机CPU都不例外

这与保护现场无关(那是必备的次序)

正好我最近一直在搞C51方面的,或许能给些补充,希望有帮助。

#include<reg52h>

sbit ksec=P3^0; //定义端口,秒的调整按键对应p30

sbit kmin=P3^1; //分的调整按键对应p31

sbit khour=P3^2; //时的调整按键对应p32

unsigned char secshi=0,secge=0,minshi=0,minge=0,hourshi=0,hourge=0;

unsigned int num=0,sec=0,min=0,hour=0;

unsigned char code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

//定义数码管显示的0-9的代码

void delay(unsigned int z)

{ //延时程序

unsigned int x,y;

for(x=z;x>0;x--)

for(y=110;y>0;y--);//如果是12MHz晶振,就是110us对应z=1

}

void keyscan();

void display();

void main()

{TMOD=0x01;//T0定时器,模式1定时,13位定时

TH0=(65536-50000)/256; //定时1S的数据设置,定时50000个机器周期后中断一次

TL0=(65536-50000)%256;

EA=1;ET0=1;TR0=1;//开启总中断,允许T0中断,开启T0中断

while(1)

{display();//显示

keyscan();//读取按键

}

}

void time0() interrupt 1

{num++;//T0中断服务程序,定时中断一次后num加一

TH0=(65536-50000)/256;

TL0=(65536-50000)%256;//重装计数值,因为模式1是非自动重装的

}

void display()

{if(num==20)

{num=0; //定时20次后sec加一,那应该是6MHz的晶振,机器周期为2us,500002us20=1s

sec++;

if(sec==60)

{sec=0;

min++;//到60s,min加一,sec清零

if(min==60)

{min=0;

hour++;//到60分,hour加一,分清零

if(hour==24)

{hour=0;

min=0;//到24小时则所有时间清零,新的一天从零时开始计时

sec=0;

}

}

}

}

secge=sec%10;//秒的个位,秒除以10的余数

secshi=sec/10;//十位,秒整除10的商

minge=min%10;

minshi=min/10;

hourge=hour%10;

hourshi=hour/10;

P2=0xfe;//1111 1110,0选通一位数码管,

P0=table[secge];//送秒的各位显示

delay(5);//延时一会儿

P2=0xfd;//选通下一位数码管,1111 1101

P0=table[secshi];//送秒的十位显示

delay(5);

P2=0xfb;//1111 1011,选通再下一位

P0=0x40;//显示分与秒之间的那个点

delay(5);

P2=0xf7;//1111 0111,再下一位

P0=table[minge];//分的个位

delay(5);

P2=0xef;//1110 1111

P0=table[minshi];//分的十位

delay(5);

P2=0xdf;//1101 1111

P0=0x40;//分与时间的点

delay(5);

P2=0xbf;//1011 1111

P0=table[hourge];//小时的个位

delay(5);

P2=0x7f;//0111 1111

P0=table[hourshi];//小时的十位

delay(5);

}

void keyscan()

{if(ksec==0)

{delay(10);//延时防抖动

if(ksec==0)//这里应该按键上接地的,有按键按下就是0

{sec++;//有秒对应的按键按下,则秒加一

if(sec>=60)//秒数到60则清零

sec=0;

}

while(ksec==0)//等待按键释放,

display();}//不做别的 *** 作,就一直显示,等待按键释放,防止一次按键多次 *** 作

if(kmin==0)

{delay(10);//分对应的按键

if(kmin==0)

{min++;

if(min>=60)

min=0;

}

while(kmin==0)

display();

}

if(khour==0)

{delay(10);//小时对应的按键

if(khour==0)

{hour++;

if(hour>=60)

hour=0;

}

while(khour==0)

display();

}

}

这是你们毕业设计的课题吗?我现在大三了,也快面临毕业设计了,比较担心的,不知道怎么做,你们具体怎么 *** 作?就是自己做也该设计吗?

定时器周期太短主程序无法运行解决方法如下:

1、首先在cpu属性中定义0B10为每小时中断一次;

2、然后在OB100中初始化计数变量如mw150为0;

3、创建DB定义变量,打开OB10日期中断编写加周期程序。

主程序:

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。

以上就是关于在主程序中设置定时器的初值后为什么还要在中断子程序中重新设置初值全部的内容,包括:在主程序中设置定时器的初值后为什么还要在中断子程序中重新设置初值、定时器在单片机中程序的运行过程、单片机实验“定时/计数器及中断”的一些问题等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9788902.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存