精华内容
下载资源
问答
  • 51单片机程序注释特齐全
  • 单片机定时器Timer.asm

    2020-04-04 19:47:33
    单片机定时器汇编程序,含注释单片机定时器程序汇编含注释,单片机实现定时器含注释,汇编语言有注释单片机定时器汇编程序
  • 描述单片机定时器中断是我们经常都需要用的,下面将以51单片机为例子来说明单片机定时器中断原理。80C51的定时/计数器的结构定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成。TMOD是定时/计数器...

    描述

    单片机定时器中断是我们经常都需要用的,下面将以51单片机为例子来说明单片机定时器中断原理。

    80C51的定时/计数器的结构

    定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。

    92b0414119ae0172c2969ca79c62f11f.png

    中断系统介绍

    中断系统是一套硬件电路,它可以在每个机器周期对所有的外设的标志位作查询。相比于前面的软件查询(if(xx==1)),中断系统也可以叫做硬件查询。51的中断系统可查询以下6个标志位。

    IE0(TCON.1),外部中断0中断请求标志位。

    IT1(TCON.2),外部中断1触发方式控制位。

    IE1(TCON.3),外部中断1中断请求标志位。

    TF0(TCON.5),定时/计数器T0溢出中断请求标志位。

    TF1(TCON.7),定时/计数器T1溢出中断请求标志位。

    RI(SCON.0)或TI(SCON.1),串行口中断请求标志。当串行口接收完一帧串行数据时置位RI或当串行口发送完一帧串行数据时置位TI,向CPU申请中断。

    当中断系统查询到外设的标志位变为1时,中断系统可暂停当前的主循环,并且将程序跳转到用户预先指定的函数中执行。要启动中断系统,必须先进行中断初始化,其流程如下:

    a、是否要查询外设标志(EA=0或EA=1,EA 也叫 CPU中断允许(总允许)位)

    b、查询到标志1,是否要跳程序

    c、跳转的目标函数,即中断服务子函数

    所以在使用定时器中断时,我们只需要首先初始化中断系统,开启总中断(相当于总开关),开启定时器对应的控制位(相当于支路开关),再初始化定时器即可。中断系统作为单片机的外设,只有在某个中断产生时才会打断主循环,并由相应的中断号引入到相应的中断服务子函数。下图是6个中断标志位的信息。

    0e9887d6f09e7b3ce3352811f9394b4d.png

    80C51单片机定时器中断原理

    这里将涉及到单片机中断的应用,在cpu的一步步按照指令运行的过程中(主程序),可能会有其它的更紧急的需要做的事情(中断服务程序),需要cpu暂时停止当前的程序(主程序),做完了(中断服务程序)之后,又可以继续去运行先前的程序(主程序)。就像你正在吃饭,一边又在给水桶里放水,吃着吃着,水满了,你就得赶快去把水龙头关掉或者换一个空的水桶,再回来吃饭。

    单片机的定时器就像是一个水桶,你让它启动了,也就是水龙头打开了;开始装水了;定时在每个机器周期不断自动加1,最后溢出了;水桶的水不断增加,最也就满出来了;定时器溢出时,你就要去做处理了;水桶的水满了,你也应该处理一下了;处理完后,单片机又可以回到刚刚开停止的地方继续运行;水桶处理了,先前你在做什么也可以继续去做什么了。

    单片机的主程序是从0x0000开始运行的,单片机服务程序从哪里开始运行呢?在51里,有多个中断服务程序入口,0号入口是外中断0,地址在0x0003;1号入口是定时器0,在 0x000B;2号入口是外中断1;地址在0x0013,3号入口是定时器2;地址在0x001B,等等。当中断发生时,程序就记下当前运行的位置,跳到对应的中断入口去运行中断服务程序,运行完之后,又跳回到原来的位置继续运行。

    在C51中,你不用理会中断服务程序放在哪里,会怎么跳转。你只要把某个函数标识为几号中断服务函数就可以了。在发生了对应的中断时,就会自动的运行这个函数。

    定时/计数器的工作原理

    加1计数器输入的计数脉冲有两个来源,一个是由系统的时钟振荡器输出脉冲经12分频后送来;一个是T0或T1引脚输入的外部脉冲源。每来一个脉冲计数器加1,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使TCON中TF0或TF1置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。

    可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。

    设置为定时器模式时,加1计数器是对内部机器周期计数(1个机器周期等于12个振荡周期,即计数频率为晶振频率的1/12)。计数值N乘以机器周期Tcy就是定时时间t 。

    设置为计数器模式时,外部事件计数脉冲由T0或T1引脚输入到计数器。在每个机器周期的S5P2期间采样T0、T1引脚电平。当某周期采样到一高电平输入,而下一周期又采样到一低电平时,则计数器加1,更新的计数值在下一个机器周期的S3P1期间装入计数器。由于检测一个从1到0的下降沿需要2个机器周期,因此要求被采样的电平至少要维持一个机器周期。当晶振频率为12MHz时,最高计数频率不超过1/2MHz,即计数脉冲的周期要大于2  Us。

    4a8d7569c5d36f95c1040d39069cba2e.png

    39e7dbf3fd2abbcefd333c80f0ecffaa.png

    b3ee55ff43ecdb7beabe7b6f17b29f8e.png

    单片机定时器利用中断实现延时原理解析

    e40eea169cff3ee64c57142552beb203.png

    #define _1231_C_

    #include “reg51.h”

    //sbit OE=P2^3;

    unsigned int SystemTime;

    void timer0(void) interrupt 1 using 3 //中断部分代码,见下文的释疑

    {

    TH0 = 0xdb;

    TL0 = 0xff;

    // TF0 = 0;

    SystemTime++;

    }

    void main()

    {

    TMOD &= 0xF0;

    TMOD |= 0x01; //TMOD的值表示定时器工作方式选择

    TH0 = 0xdb; //写入初始值,初始值可以决定定时多久

    TL0 = 0xff;

    //根据上文的木桶比喻的话,如果TH0 = 0x00;TL0 = 0x00;则表示从桶底开始装水。

    //TH0 = 0xdb;TL0 = 0xff;可以这样子理解相当于木桶里已经有部分液铅在里面,

    //TH0和TL0这个两个值表示木桶里液铅的高度,即此时桶里只能从液铅的高度以上开始装水,

    //TH0 = 0xff;TL0 = 0xff;即表示桶的最高位置。

    TF0 = 0; //计数到时TF0为1,即当TH0 = 0xff;TL0 = 0xff;再运行一步TF0 = 1;

    TR0 = 1; //开始计数,从这时起,每运行一步TH0和TL0都会增加,直到TH0 = 0xff;TL0 = 0xff;

    //相当于开水龙头,如TR0=0则TH0和TL0不变

    ET0 = 1; //允许定时器0中断

    EA=1; //开总中断

    //下面是个死循环,程序里每运行一步TH0和TL0都会增加,当增加到TH0 = 0xff;TL0 = 0xff;

    //单片机会从死循环里退出,去执行中断部分的代码,即开始运行void timer0(void) interrupt 1 using 3{}

    //运行完中断部分的代码后,接着继续执行死循环里的代码。

    //注意:当TH0 = 0xff;TL0 = 0xff;再运行,TF0并没有从0变为1,个人猜测TF0=1;时触发了中断,并重新被置零。

    //如把ET0 = 1;和EA=1;注释掉,当TH0 = 0xff;TL0 = 0xff;再运行,TF0会变为1,此时不会再执行中断部分代码。

    while(1)

    {

    if ((SystemTime%100)《50) //SystemTime除以100,余数小于50为真

    {

    …………;

    }

    else

    {

    …………;

    }

    };

    }

    释疑:void Timer0() interrupt 1 using 1

    Timer0 是函数名,随便取的

    interrupt xx using y

    跟在interrupt 后面的xx 值得是中断号,就是说这个函数对应第几个中断端口,一般在51中

    0 外部中断0

    1 定时器0

    2 外部中断1

    3 定时器1

    4 串行中断

    实际上编译的时候就是把你这个函数的入口地址方到这个对应中断的跳转地址

    using y 这个y是说这个中断函数使用的那个寄存器组,51里面一般有4组 r0 -- r7寄存器,一共有32个,如果你的终端函数和别的程序用的不是同一个寄存器组则进入中断的时候就不会将寄存器组压入堆栈返回时也不会谈出来节省代码和时间

    初始值算法:定时器是当总数达到FFFFH后产生中断吧!那你要让它计数10000,是不是用FFFF(16进制)减去10000(十进制)的数当计数初值 啊?TH0=-(10000/256); TL0=-(10000%256)跟FFFF(16进制)减去10000(十进制)的数是一样的。从TH0=-(10000/256); TL0=-(10000%256)开始计数,计数到10000刚好满。跟用FFFF(16进制)减去10000(十进制)的数一样!!!写起来更简单,不 用算!!!

    看看原码、补码就知道。正数的补码是对应的二进制数,符号位为零,负数的补码是它的绝对值对应的二进制数按位取反再加一,符号位为一。无符号数不考虑符号,那么这个结果就跟用FFFF减去它的绝对值一样。

    打开APP阅读更多精彩内容

    点击阅读全文

    展开全文
  • 51单片机定时器0产生200mS方波keil工程文件C源文件,包含keil的工程文件,C语言源码,头文件等。程序注释非常详细,用keil5可以直接打开。
  • 单片机定时器延时程序单片机的延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR...

    单片机定时器延时程序

    单片机的延时程序(包括asm和C程序,都是我在学单片机的过程中用到的),在单片机延时程序中应考虑所使用的晶振的频率,在51系列的单片机中我们常用的是11.0592MHz和12.0000MHz的晶振,而在AVR单片机上常用的有8.000MHz和4.000MH的晶振所以在网上查找程序时如果涉及到精确延时则应该注意晶振的频率是多大。

    软件延时:(asm)

    晶振12MHZ,延时1秒

    程序如下:

    DELAY:MOV 72H,#100

    LOOP3:MOV 71H,#100

    LOOP1:MOV 70H,#47

    LOOP0JNZ 70H,LOOP0

    NOP

    DJNZ 71H,LOOP1

    MOV 70H,#46

    LOOP2JNZ 70H,LOOP2

    NOP

    DJNZ 72H,LOOP3

    MOV 70H,#48

    LOOP4JNZ 70H,LOOP4

    定时器延时:

    晶振12MHZ,延时1s,定时器0工作方式为方式1

    DELAY1:MOV R7,#0AH ;; 晶振12MHZ,延时0.5秒

    AJMP DELAY

    DELAY2:MOV R7,#14H ;; 晶振12MHZ,延时1秒

    DELAY:CLR EX0

    MOV TMOD,#01H ;设置定时器的工作方式为方式1

    MOV TL0,#0B0H ;给定时器设置计数初始值

    MOV TH0,#3CH

    SETB TR0 ;开启定时器

    HERE:JBC TF0,NEXT1

    SJMP HERE

    NEXT1:MOV TL0,#0B0H

    MOV TH0,#3CH

    DJNZ R7,HERE

    CLR TR0 ;定时器要软件清零

    SETB EX0

    RET

    C语言延时程序:

    void delay_18B20(unsigned int i)

    {

    while(i--);

    }

    void Delay10us( ) //12mhz

    {

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    }

    /*****************11us延时函数*************************/

    //

    void delay(uint t)

    {

    for (;t>0;t--);

    }

    1ms延时子程序(12MHZ)

    void delay1ms(uint p)//12mhz

    { uchar i,j;

    for(i=0;i

    {

    for(j=0;j<124;j++)

    {;}

    }

    }

    函数功能:延时20ms的子程序

    **************************************************************/

    void delay20ms(void) //3*i*j+2*i=3*100*60+2*100=20000μs=20ms;

    { //(3*60+2)*100

    unsigned char i,j;

    for(i=0;i<100;i++)

    for(j=0;j<60;j++)

    ;

    }

    10ms延时子程序(12MHZ)

    void delay10ms(void)

    {

    unsigned char i,j,k;

    for(i=5;i>0;i--)

    for(j=4;j>0;j--)

    for(k=248;k>0;k--);

    }

    ((248*2+3)*4+3)*5+5=10ms

    1s延时子程序(12MHZ)

    void delay1s(void)

    {

    unsigned char h,i,j,k;

    for(h=5;h>0;h--)

    for(i=4;i>0;i--)

    for(j=116;j>0;j--)

    for(k=214;k>0;k--);

    }

    200ms延时子程序(12MHZ) www.dgzj.com

    void delay200ms(void)

    {

    unsigned char i,j,k;

    for(i=5;i>0;i--)

    for(j=132;j>0;j--)

    for(k=150;k>0;k--);

    }

    500ms延时子程序程序: (12MHZ)

    void delay500ms(void)

    {

    unsigned char i,j,k;

    for(i=15;i>0;i--)

    for(j=202;j>0;j--)

    for(k=81;k>0;k--);

    }

    下面是用了8.0000MHZ的晶振的几个延时程序(用定时0的工作模式1):

    (1)延时0.9MS

    void delay_0_9ms(void)

    {

    TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/

    TH0=0xfd;

    TL0=0xa8;

    TR0=1; /*启动定时器*/

    while(TF0==0);

    TR0=0;

    }

    (2)延时1MS

    void delay_1ms(void)

    {

    TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/

    TH0=0xfd;

    TL0=0x65;

    TR0=1; /*启动定时器*/

    while(TF0==0);

    TR0=0;

    }

    (3)延时4.5ms

    void delay_4_5ms(void)

    {

    TMOD=0x01; /*定时器0工作在模式1下(16位计数器)*/

    TH0=0xf4;

    TL0=0x48;

    TR0=1; /*启动定时器*/

    while(TF0==0);

    TR0=0;

    }

    在用定时器做延时程序时如果懒得计算定时器计数的初始值可以在网上找一个专门用来做延时的小软件,我在用着感觉很实用,如果找不到的话可以留言,留下自己的邮箱我给发过去;如果上面的延时中有错误敬请指正。

    Keil C51程序设计中几种精确延时方法

    2009年07月28日 星期二 下午 11:15

    延时通常有两种方法:一种是硬件延时,要用到定时器/计数器,这种方法可以提高CPU的工作效率,也能做到精确延时;另一种是软件延时,这种方法主要采用循环体进行。

    1 使用定时器/计数器实现精确延时

    单片机系统一般常选用11.059 2 MHz、12 MHz或6 MHz晶振。第一种更容易产生各种标准的波特率,后两种的一个机器周期分别为1 μs和2 μs,便于精确延时。本程序中假设使用频率为12 MHz的晶振。最长的延时时间可达216=65 536 μs。若定时器工作在方式2,则可实现极短时间的精确延时;如使用其他定时方式,则要考虑重装定时初值的时间(重装定时器初值占用2个机器周期)。

    在实际应用中,定时常采用中断方式,如进行适当的循环可实现几秒甚至更长时间的延时。使用定时器/计数器延时从程序的执行效率和稳定性两方面考虑都是最佳的方案。但应该注意,C51编写的中断服务程序编译后会自动加上PUSH ACC、PUSH PSW、POP PSW和POP ACC语句,执行时占用了4个机器周期;如程序中还有计数值加1语句,则又会占用1个机器周期。这些语句所消耗的时间在计算定时初值时要考虑进去,从初值中减去以达到最小误差的目的。

    2 软件延时与时间计算

    在很多情况下,定时器/计数器经常被用作其他用途,这时候就只能用软件方法延时。下面介绍几种软件延时的方法。

    2.1 短暂延时

    可以在C文件中通过使用带_NOP_( )语句的函数实现,定义一系列不同的延时函数,如Delay10us( )、Delay25us( )、Delay40us( )等存放在一个自定义的C文件中,需要时在主程序中直接调用。如延时10 μs的延时函数可编写如下:

    void Delay10us( ) {

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    _NOP_( );

    }

    Delay10us( )函数中共用了6个_NOP_( )语句,每个语句执行时间为1 μs。主函数调用Delay10us( )时,先执行一个LCALL指令(2 μs),然后执行6个_NOP_( )语句(6 μs),最后执行了一个RET指令(2 μs),所以执行上述函数时共需要10 μs。 可以把这一函数当作基本延时函数,在其他函数中调用,即嵌套调用[4],以实现较长时间的延时;但需要注意,如在Delay40us( )中直接调用4次Delay10us( )函数,得到的延时时间将是42 μs,而不是40 μs。这是因为执行Delay40us( )时,先执行了一次LCALL指令(2 μs),然后开始执行第一个Delay10us( ),执行完最后一个Delay10us( )时,直接返回到主程序。依此类推,如果是两层嵌套调用,如在Delay80us( )中两次调用Delay40us( ),则也要先执行一次LCALL指令(2 μs),然后执行两次Delay40us( )函数(84 μs),所以,实际延时时间为86 μs。简言之,只有最内层的函数执行RET指令。该指令直接返回到上级函数或主函数。如在Delay80μs( )中直接调用8次Delay10us( ),此时的延时时间为82 μs。通过修改基本延时函数和适当的组合调用,上述方法可以实现不同时间的延时。

    2.2 在C51中嵌套汇编程序段实现延时

    在C51中通过预处理指令#pragma asm和#pragma endasm可以嵌套汇编语言语句。用户编写的汇编语言紧跟在#pragma asm之后,在#pragma endasm之前结束。

    如:#pragma asm

    汇编语言程序段

    #pragma endasm

    延时函数可设置入口参数,可将参数定义为unsigned char、int或long型。根据参数与返回值的传递规则,这时参数和函数返回值位于R7、R7R6、R7R6R5中。在应用时应注意以下几点:

    ◆ #pragma asm、#pragma endasm不允许嵌套使用;

    ◆ 在程序的开头应加上预处理指令#pragma asm,在该指令之前只能有注释或其他预处理指令;

    ◆ 当使用asm语句时,编译系统并不输出目标模块,而只输出汇编源文件;

    ◆ asm只能用小写字母,如果把asm写成大写,编译系统就把它作为普通变量;

    ◆ #pragma asm、#pragma endasm和 asm只能在函数内使用。

    将汇编语言与C51结合起来,充分发挥各自的优势,无疑是单片机开发人员的最佳选择。

    2.3 使用示波器确定延时时间

    利用示波器来测定延时程序执行时间。方法如下:编写一个实现延时的函数,在该函数的开始置某个I/O口线如P1.0为高电平,在函数的最后清P1.0为低电平。在主程序中循环调用该延时函数,通过示波器测量P1.0引脚上的高电平时间即可确定延时函数的执行时间。方法如下:

    sbit T_point = P1^0;

    void Dly1ms(void) {

    unsigned int i,j;

    while (1) {

    T_point = 1;

    for(i=0;i<2;i++){

    for(j=0;j<124;j++){;}

    }

    T_point = 0;

    for(i=0;i<1;i++){

    for(j=0;j<124;j++){;}

    }

    }

    }

    void main (void) {

    Dly1ms();

    }

    把P1.0接入示波器,运行上面的程序,可以看到P1.0输出的波形为周期是3 ms的方波。其中,高电平为2 ms,低电平为1 ms,即for循环结构“for(j=0;j<124;j++) {;}”的执行时间为1 ms。通过改变循环次数,可得到不同时间的延时。当然,也可以不用for循环而用别的语句实现延时。这里讨论的只是确定延时的方法。

    2.4 使用反汇编工具计算延时时间

    用Keil C51中的反汇编工具计算延时时间,在反汇编窗口中可用源程序和汇编程序的混合代码或汇编代码显示目标应用程序。为了说明这种方法,还使用“for (i=0;i

    C:0x000FE4CLRA//1T

    C:0x0010FEMOVR6,A//1T

    C:0x0011EEMOVA,R6//1T

    C:0x0012C3CLRC//1T

    C:0x00139FSUBBA,DlyT //1T

    C:0x00145003JNCC:0019//2T

    C:0x00160E INCR6//1T

    C:0x001780F8SJMPC:0011//2T

    可以看出,0x000F~0x0017一共8条语句,分析语句可以发现并不是每条语句都执行DlyT次。核心循环只有0x0011~0x0017共6条语句,总共8个机器周期,第1次循环先执行“CLR A”和“MOV R6,A”两条语句,需要2个机器周期,每循环1次需要8个机器周期,但最后1次循环需要5个机器周期。DlyT次核心循环语句消耗(2+DlyT×8+5)个机器周期,当系统采用12 MHz时,精度为7 μs。

    当采用while (DlyT--)循环体时,DlyT的值存放在R7中。相对应的汇编代码如下:

    C:0x000FAE07MOVR6, R7//1T

    C:0x00111F DECR7//1T

    C:0x0012EE MOVA,R6//1T

    C:0x001370FAJNZC:000F//2T

    循环语句执行的时间为(DlyT+1)×5个机器周期,即这种循环结构的延时精度为5 μs。

    通过实验发现,如将while (DlyT--)改为while (--DlyT),经过反汇编后得到如下代码:

    C:0x0014DFFE DJNZR7,C:0014//2T

    可以看出,这时代码只有1句,共占用2个机器周期,精度达到2 μs,循环体耗时DlyT×2个机器周期;但这时应该注意,DlyT初始值不能为0。

    注意:计算时间时还应加上函数调用和函数返回各2个机器周期时间。

    展开全文
  • 单片机定时器中断原理 #define _1231_C_ #include "reg51.h" //sbit OE=P2^3; unsigned int SystemTime; void timer0(void) interrupt 1 using 3 //中断部分代码,见下文的释疑 { TH0 = 0xdb; ...

    单片机定时器中断原理

     

    #define _1231_C_

    #include "reg51.h"

     

    //sbit OE=P2^3;

    unsigned int SystemTime;

    void timer0(void) interrupt 1 using 3 //中断部分代码,见下文的释疑

    {

        TH0 = 0xdb;

        TL0 = 0xff;

    //    TF0 = 0;

        SystemTime++;

    }

    void main()

    {

        TMOD &= 0xF0;

        TMOD |= 0x01; //TMOD的值表示定时器工作方式选择

        TH0 = 0xdb; //写入初始值,初始值可以决定定时多久

        TL0 = 0xff;

    //根据下文的木桶比喻的话,如果TH0 = 0x00;TL0 = 0x00;则表示从桶底开始装水。

    //TH0 = 0xdb;TL0 = 0xff;可以这样子理解相当于木桶里已经有部分液铅在里面,

    //TH0和TL0这个两个值表示木桶里液铅的高度,即此时桶里只能从液铅的高度以上开始装水,

    //TH0 = 0xff;TL0 = 0xff;即表示桶的最高位置.

        TF0 = 0; //计数到时TF0为1,即当TH0 = 0xff;TL0 = 0xff;再运行一步TF0 = 1;

        TR0 = 1; //开始计数,从这时起,每运行一步TH0和TL0都会增加,直到TH0 = 0xff;TL0 = 0xff;

                     //相当于开水龙头,如TR0=0则TH0和TL0不变

        ET0 = 1; //允许定时器0中断

        EA=1;   //开总中断

    //下面是个死循环,程序里每运行一步TH0和TL0都会增加,当增加到TH0 = 0xff;TL0 = 0xff;

    //单片机会从死循环里退出,去执行中断部分的代码,即开始运行void timer0(void) interrupt 1 using 3{}

    //运行完中断部分的代码后,接着继续执行死循环里的代码。

    //注意:当TH0 = 0xff;TL0 = 0xff;再运行,TF0并没有从0变为1,个人猜测TF0=1;时触发了中断,并重新被置零。

    //如把ET0 = 1;和EA=1;注释掉,当TH0 = 0xff;TL0 = 0xff;再运行,TF0会变为1,此时不会再执行中断部分代码。

        while(1)

        {

            if ((SystemTime%100)<50)       //SystemTime除以100,余数小于50为真

            {

              …………;

            }

            else

            {

                 …………;

            }

        };

    }

    释疑:void Timer0() interrupt 1 using 1

    Timer0   是函数名,随便取的

    interrupt   xx   using   y

    跟在interrupt   后面的xx   值得是中断号,就是说这个函数对应第几个中断端口,一般在51中

    0   外部中断0   

    1   定时器0

    2   外部中断1

    3   定时器1

    4   串行中断

    实际上编译的时候就是把你这个函数的入口地址方到这个对应中断的跳转地址

    using   y   这个y是说这个中断函数使用的那个寄存器组,51里面一般有4组   r0   --   r7寄存器,一共有32个,如果你的终端函数和别的程序用的不是同一个寄存器组则进入中断的时候就不会将寄存器组压入堆栈返回时也不会谈出来节省代码和时间

    初始值算法:定时器是当总数达到FFFFH后产生中断吧!那你要让它计数10000,是不是用FFFF(16进制)减去10000(十进制)的数当计数初值 啊?TH0=-(10000/256); TL0=-(10000%256)跟FFFF(16进制)减去10000(十进制)的数是一样的。从TH0=-(10000/256); TL0=-(10000%256)开始计数,计数到10000刚好满。跟用FFFF(16进制)减去10000(十进制)的数一样!!!写起来更简单,不 用算!!!

    看看原码、补码就知道。正数的补码是对应的二进制数,符号位为零,负数的补码是它的绝对值对应的二进制数按位取反再加一,符号位为一。无符号数不考虑符号,那么这个结果就跟用FFFF减去它的绝对值一样

    我们学习了用指令延时闪灯,但是用指令方式闪灯有cpu不能做其他工作的缺点。

    这一课,我们将学习如何使用定时器方式使灯闪烁。

    中断的理解。

    这里将涉及到单片机中断的应用,在cpu的一步步按照指令运行的过程中(主程序),可能会有其它的更紧急的需要做的事情(中断服务程序),需要cpu暂时停止当前的程序(主程序),做完了(中断服务程序)之后,又可以继续去运行先前的程序(主程序)。就像你正在吃饭,一边又在给水桶里放水,吃着吃着,水满了,你就得赶快去把水龙头关掉或者换一个空的水桶,再回来吃饭。

    单片机的定时器就像是一个水桶,你让它启动了,也就是水龙头打开了;开始装水了;定时在每个机器周期不断自动加1,最后溢出了;水桶的水不断增加,最也就满出来了;定时器溢出时,你就要去做处理了;水桶的水满了,你也应该处理一下了;处理完后,单片机又可以回到刚刚开停止的地方继续运行;水桶处理了,先前你在做什么也可以继续去做什么了。

    单片机的主程序是从0x0000开始运行的,单片机服务程序从哪里开始运行呢?在51里,有多个中断服务程序入口,0号入口是外中断0,地址在0x0003;1号入口是定时器0,在 0x000B;2号入口是外中断1;地址在0x0013,3号入口是定时器2;地址在0x001B,等等。当中断发生时,程序就记下当前运行的位置,跳到对应的中断入口去运行中断服务程序,运行完之后,又跳回到原来的位置继续运行。

    在C51中,你不用理会中断服务程序放在哪里,会怎么跳转。你只要把某个函数标识为几号中断服务函数就可以了。在发生了对应的中断时,就会自动的运行这个函数。

    请看一下相关的51的硬件的书,对定时器工作的寄存器设置做进一步的了解。也可以做完试验再了解,因为例程中都已经为您设置好了。

    请看程序,主程序里的循环里是个死循环,什么也没有做,在实际应用中这里是放的主程序。

    在定时器服务函数里,需要重新置入定时器的值,这样才能保证每次溢出时,都是你指定的时间。这里置入的是0x0006,还需要走 0x10000-0x0006个机器周期才溢出。换成10进制也就是每65530个机器周期中断一次。我们仿真的晶振是22118400HZ,每12个时钟一个机器周期。65530×12/22118400=0.036秒。也就是差不多28HZ的闪烁频率。

    因为51的定时器最大只有0xffff,溢出的速度很快,无法做出更久的闪烁频率来,这一课就先观察一下这个28HZ左右频率。在下一课我们会用静态变量的办法,做一个长达1秒钟的LED闪烁频率。

    另外,由于51从中断发生到进入中断的时间不定,是3至8个机器周期,我们在进入了中断后才重新置新的定时器初始值,这样就会存在定时误差。也就是不是精确定时,如果要精确定时,需要使用定时器自动装载方式,也就是在定时器溢出的同时,硬件逻辑就自动把定时器初始值装载进去了,而不是在中断服务程序里赋初始值,这样就可以实现精确定时,误差只出现晶振的频率上。这是下一颗的内容。

    现在请仔细研究一下程序,并编译,进入仿真,全速运行,观察运行结果。我们可以看到P10上的LED在快速闪烁。

    顺便,也请再练习一下停止,单步,断点等等的调试方法。

    一个特殊的地方,使用DX516在单步时运行时,可能无法进入到中断服务函数中。这是因为中断函数可能在单步处理的瞬间已经运行过去了。如果要单步调试中断服务函数,请在中断服务函数内设置断点,再点全速。稍后就会停止在断点上,就可以继续单步运行了。

    转载于:https://www.cnblogs.com/lifan3a/articles/4739856.html

    展开全文
  • 仅用TR0打开(这一段话为给定程序注释,暂时没有理解) 对CMOD赋值,以确定T0,T1的工作方式 计算初值,并将其写入TH0、TL0或TH1、TL1//前者高八位,后者低八位  ET0=1; //打开定时器0中断允许  EA=1; ...

    摘要:难点就在于各个端口的理解与定义,这个程序用到的端口有

    TMOD是判断选定为定时器模式还是计数模式,

    工作方式1;仅用TR0打开(这一段话为给定程序的注释,暂时没有理解)

    对CMOD赋值,以确定T0,T1的工作方式

    计算初值,并将其写入TH0、TL0或TH1、TL1//前者高八位,后者低八位

     ET0=1;              //打开定时器0中断允许
     EA=1;                //打开总中断
    TR0=1;               //定时器 / 计数器启动 C/T=0表示定时器模式,C/T=1表示计数器模式

     在编写中断函数时,**为1时,需要填写以下代码,为3则不必   

    TH0=0XFC;    //给定时器赋初值,定时1ms

    TL0=0X18;

    代码如下:

    #include	"reg52.h"
    
    typedef	unsigned	int		u16;	//int类型才可以有16;
    typedef	unsigned	char	u8;	   //u8为char类型
    
    sbit	led=P2^0;	//不要忘了定义端口!!!!!!
    
    void	Timer0Init()
    {
    	 TMOD|=0x01; 	//选定为定时器模式,工作方式1;仅用TR0打开
    	 
    	 TH0=0xFC; 		//TH0为高八位
    	 TL0=0X18;		//TL0为低八位
    	 ET0=1;			//打开定时器0中断允许
    	 EA=1;			//打开总中断
    	 TR0=1;			 //定时器 / 计数器启动 C/T=0表示定时器模式,C/T=1表示计数器模式
    
    }
    
    void	main()
    {
    	Timer0Init(); //定时器初始化
    	while(1);
    }
    
    
    void	Timer0()	interrupt 1
    {
    	 static u16 i;
    	 TH0=0XFC;
    	 TL0=0X18;
    	 //i++;		//少了这一句,i为0或1皆不亮,
    	 if(i==1000)
    	 {
    	 i=1;	//少了这一句D1小灯会长亮
    	 led=~led;
    	 }
    }

     

    展开全文
  • 定时器与中断系统小白极客的51单片机笔记(自用)定时器介绍STC89C52定时器资源定时器框图定时器工作模式定时器时钟中断系统中断程序流程STC89C52中断资源定时器和中断系统创建一个自定义列表如何创建一个注脚注释也...
  • 51单片机定时器0中断方式点亮LED灯 此程序采用的模块化编程,模块化在编程中很重要。要想学号单片机,请务必掌握。案例实际使用的STC15单片机,但是对于51单片机也同样的使用。只需要将15单片机的头文件更改为51...
  • 51单片机产生1mS方波keil工程文件C源文件,包含keil的工程文件,C语言源码,头文件等。程序注释非常详细,用keil5可以直接打开。
  • 代码如下,设置断点后发现,程序不进入定时器中断函数 #include #include #define uchar unsigned char #define uint unsigned int sbit key=P3^7; uchar display[8][8]; /*rank:Z,H,B,I,T,I,心,U*/ uchar code ...
  • 定时器的初步认识时钟周期:时钟周期t是时序中最小的时间单位具体计算的方法就是1/时钟源,如果大家用的晶振是11.0592m,那么对于这个单片机系统来说,时钟周期=1/11059200秒。机器周期:我们的单片机完成一个操作的...
  • 一、基本定时器介绍在STM32中,基本定时器有TIM6、TIM7等。基本定时器主要包含时基单元,提供16位的计数,能计数0~65535。基本定时器除了计数功能以外,还能输出给DAC模块一个TRGO信号。基本定时器框图如下:二、时...
  • 一、基本定时器介绍在STM32中,基本定时器有TIM6、TIM7等。基本定时器主要包含时基单元,提供16位的计数,能计数0~65535。基本定时器除了计数功能以外,还能输出给DAC模块一个TRGO信号。基本定时器框图如下:二、时...
  • 定时器编码模式的配置 基本配置
  • 基于51内核的 STC89C52RC 单片机常用的例程,包含:流水灯程序,数码管静态显示,数码管动态显示,LCD1602显示程序,LCD12864程序,AC0804模拟信号...红外遥控试验,定时器运用,外部中断程序,初学单片机必备试验代码。
  • 单片机定时器中断原理和C语言代码详解   <br />  <br />我之前都是用ARM7,单片机基本不会。但一个项目要用到51,所以克了一下51还是有点模糊,今天调了这个代码之后,对51定时器中断有些...
  • 代码如下: ...//打开定时器模式并选择方式2 TL0=TH0=0x00;//设置初值 TR0=1;//打开定时器0 } void intConf(void)//中断初始化 { EA=1; EX0=1; ET0=1; } void inte() interrupt 0 { GPIO_LED=
  • 【已完成】51单片机定时器制作日志

    千次阅读 2014-03-01 19:34:57
    【2014.1.12】 拍下51开发板及4位8段液晶屏,准备在...水银开关未在本地买到,准备网购,先写定时器和显示部分的程序。 使用水银开关进行位置检测,更改定时时间,以分为单位在数码管上显示。 不定期更新日志。 【2
  • 3)ProteusSDCC是免费开源的编译器,可以用来编译8051系列的芯片,也就是我们平时使用的51单片机可以用此编译,而不是使用KEIL商业软件,IDE配合Codeblocks,最终验证用proteus仿真验证,手头上没有51开发板。...
  • 开篇说明:开发板平台是普中的A7开发板,实验代码及相关注意事项以及精度不精确原因在下面代码注释中有说明。 /******************************************************************************* *实验现象:...
  • 内部中断:单片机内部达到某种情况就触发中断(定时) 中断函数 首先是一个平时我们写的函数名再加上一个中断号 void Timer0() interrupt 1 中断号0 2 4…表示外部中断 中断号1 3 5…表示定时器/计数中断 01表示...
  • 虽然舵机的控制原理比较简单统一,但是PWM控制舵机的程序实现方式多种多样,有的使用延时(delay(ms)),有的使用定时器(time),而网上搜到的大部分控制代码却质量一般,控制精度都需要提高,就要对单片机定时器有...
  • 程序经过本人调试,定时相当准确,注释详细,对单片机入门很有帮助。
  • 基于STC89C52RC单片机,利用光电传感器设置定时器。通过这个文档,你可以从整体上掌握单片机的控制理论以及外围电路的设计方法。对初学单片机者是个很好的考察。例子程序,提供详细的注释,很难得!
  • 51单片机定时器0实现流水灯

    万次阅读 多人点赞 2016-05-13 21:05:10
    51单片机定时器0实现流水灯的代码如下,用P1口接led灯,代码如下都有注释就不具体解释了,英语不怎么好,有的地方将就一下了,本次主要讲一下P1口怎么赋值的。原先写的都是用查表来移位的,个人感觉不怎么好,麻烦...
  • 但是很多程序都缺少模块化的思想,之前以为只要把单个的功能封装在一个函数里面就是模块化,但是在公司经过了十多天实习,才真正有了模块化的编程思想,这里将我编写的51单片机控制定时器中断的程序共享一下,...
  • 最近失业在家心情郁闷,想想又很久没更新了,把这个相对比较“复杂”的多任务定时器写写吧,之前在csdn的帖子里(《单片机C语言程序该这样写!不是教科书上教的那样!》)就是用的这个定时器来支持我的论点的。又经过...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,989
精华内容 1,195
关键字:

单片机定时器程序注释