51单片机C语言程序100例分析(2)定时器+中断

2022-12-07  

#include //包含 51 单片机寄存器定义的头文件

void main(void)

{

  TMOD=0x01;// 使用定时器 T0 的模式 1

  TH0=(65536-46083)/256; // 定时器 T0的高 8 位赋初值

  TL0=(65536-46083)%256; // 定时器 T0的低 8 位赋初值

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

  TF0=0; //清定时器溢出标志位

  P2=0xff;  

  while(1)// 无限循环等待查询  

  {  

    while(TF0==0);  

    TF0=0;  

    P2=~P2;//按位取反  

    TH0=(65536-46083)/256; // 定时器 T0 的高 8 位赋初值  

    TL0=(65536-46083)%256; // 定时器 T0 的低 8 位赋初值

  }

}


分析:新的寄存器出现了,它们分别是TMOD、TH0、TL0、TR0、TF0,只要掌握调用顺序就可以玩好定时器了。

实例 43 :用定时器 T1 查询方式控制单片机发出 1KHz 音频

#include // 包含 51 单片机寄存器定义的头文件

sbit sound=P3^7; 

void main(void)

  { 

    TMOD=0x10;// 使用定时器 T1 的模式 1

    TH1=(65536-921)/256; // 定时器 T1 的高 8 位赋初值

    TL1=(65536-921)%256; // 定时器 T1 的低 8 位赋初值

    TR1=1; 

    TF1=0; // 启动定时器 T1

    while(1)// 无限循环等待查询

    {

      while(TF1==0);

      TF1=0;

      sound=~sound; // 将 P3.7引脚输出电平取反

      TH1=(65536-921)/256; // 定时器 T0的高 8 位赋初值

      TL1=(65536-921)%256; // 定时器 T0的低 8 位赋初值

    }

  }  

实例 44:将计数器 T0 计数的结果送 P1 口 8 位 LED 显示

#include // 包含 51 单片机寄存器定义的头文件

sbit S=P3^4; // 将 S位定义为 P3.4引脚

void main(void)

{

  // EA=1; // 开总中断

  // 定时器 T0 中断允许  

  // ET0=1; 

  TMOD=0x02;// 使用定时器 T0 的模式 2

  TH0=256-156; // 定时器 T0的高 8 位赋初值

  TL0=256-156; // 定时器 T0 的高 8 位赋初值

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

  while(1)// 无限循环等待查询

  {

    while(TF0==0) // 如果未计满就等待

    {

      if(S==0) // 按键 S按下接地,电平为 0

      P1=TL0; //计数器 TL0加 1 后送 P1口显示

    }

    TF0=0; // 计数器溢出后,将 TF0清 0

  }

}  

分析:理论结合实例,效果很好吧。


实例 45:用定时器 T0 的中断控制 1 位 LED 闪烁

#include // 包含 51 单片机寄存器定义的头文件

sbit D1=P2^0; // 将 D1 位定义为 P2.0引脚

void main(void)

{

  EA=1;// 开总中断 

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

  TMOD=0x01;// 使用定时器 T0 的模式 1

  TH0=(65536-46083)/256; //定时器 T0 的高 8 位赋初值

  TL0=(65536-46083)%256; //定时器 T0的高 8 位赋初值

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

  while(1);

}

  

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

函数功能:定时器 T0 的中断服务程序

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

void Time0(void) interrupt 1 using 0 //寄存器

{

  D1=~D1; // 按位取反操作,将 P2.0引脚输出电平取反

  TH0=(65536-46083)/256; //定时器 T0 的高 8 位重新赋初值

  TL0=(65536-46083)%256; //定时器 T0的高 8 位重新赋初值

}  

实例 46:用定时器 T0 的中断实现长时间定时

#include // 包含 51 单片机寄存器定义的头文件

sbit D1=P2^0; // 将 D1 位定义为 P2.0引脚

unsigned char Countor; //设置全局变量,储存定时器 T0 中断次数

void main(void)

{

  EA=1; 

  ET0=1; 

  TMOD=0x01;

  TH0=(65536-46083)/256; //定时器 T0的高 8 位赋初值

  TL0=(65536-46083)%256; //定时器 T0的低 8 位赋初值

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

  Countor=0; // 从 0 开始累计中断次数

  while(1);

}

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

函数功能:定时器 T0 的中断服务程序

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

void Time0(void) interrupt 1 using 0

{

  Countor++; // 中断次数自加 1

  if(Countor==20) // 若累计满 20 次,即计时满 1s

  {

    D1=~D1; // 按位取反操作,将 P2.0引脚输出电平取反

    Countor=0; // 将 Countor 清 0,重新从 0 开始计数

  }

  TH0=(65536-46083)/256; //定时器 T0 的高 8 位重新赋初值

  TL0=(65536-46083)%256; //定时器 T0的高 8 位重新赋初值

}  

分析:这就是外存库,之前整理的中断和定时器没想到就是这里的片段。


实例 47:用定时器 T1 中断控制两个 LED 以不同周期闪烁

#include // 包含 51 单片机寄存器定义的头文件

sbit D1=P2^0; // 将 D1 位定义为 P2.0引脚

sbit D2=P2^1; // 将 D2 位定义为 P2.1引脚

unsigned char Countor1; //设置全局变量,储存定时器 T1 中断次数

unsigned char Countor2; //设置全局变量,储存定时器 T1 中断次数

void main(void)

{

  EA=1;// 开总中断 

  ET1=1; // 定时器 T1 中断允许

  TMOD=0x10; // 使用定时器 T1 的模式 1

  TH1=(65536-46083)/256; //定时器 T1 的高 8 位赋初值

  TL1=(65536-46083)%256; //定时器 T1的高 8 位赋初值

  TR1=1; // 启动定时器 T1  

  Countor1=0; // 从 0 开始累计中断次数

  Countor2=0; 

  while(1);

}

void Time1(void) interrupt 3 using 0

{

  Countor1++; //Countor1 自加 1

  Countor2++;//Countor2 自加 1

  if(Countor1==2) // 若累计满 2 次,即计时满 100ms

  {

    D1=~D1; // 按位取反操作,将 P2.0引脚输出电平取反

    Countor1=0; // 将 Countor1 清 0,重新从 0 开始计数

  }

  if(Countor2==8) // 若累计满 8 次,即计时满 400ms

  {

    D2=~D2; // 按位取反操作,将 P2.1引脚输出电平取反

    Countor2=0; // 将 Countor1 清 0,重新从 0 开始计数

  }

  TH1=(65536-46083)/256; //定时器 T1 的高 8 位重新赋初值

  TL1=(65536-46083)%256; //定时器 T1的高 8 位重新赋初值

}  

分析:慢慢欣赏吧,有问题欢迎评论。


实例 50-1 :输出 50 个矩形脉冲

#include // 包含 51 单片机寄存器定义的头文件

sbit u=P1^4; // 将 u 位定义为 P1.4

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

函数功能:延时约 30ms (3*100*100=30 000μ s =30m

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

void delay30ms(void)

{

  unsigned char m,n;

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

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

}

void main(void)

{

  unsigned char i;

  u=1; // 初始化输出高电平

  for(i=0;i<50;i++) //输出 50 个矩形脉冲

  {

    u=1;

    delay30ms();

    u=0;

    delay30ms(); 

  }

  while(1); 

}  

啦啦啦


实例 50-2:计数器 T0统计外部脉冲数

#include 

void main(void)

{

  TMOD=0x06; // TMOD=0000 0110B,使用计数器 T0 的模式 2

  EA=1; 

  ET0=0; // 不使用定时器 T0 的中断

  TR0=1;  // 启动 T0

  TH0=0; // 计数器 T0 高 8 位赋初值

  TL0=0;// 计数器 T0 低 8 位赋初值

  while(1) // 无限循环,不停地将 TL0计数结果送 P1口

  P1=TL0;

}

啊啊啊


实例 51-2 :定时器 T0 的模式 2 测量正脉冲宽度

#include // 包含 51 单片机寄存器定义的头文件

sbit ui=P3^2; // 将 ui 位定义为 P3.0( INT0)引脚,表示输入电压

void main(void)

{

  TMOD=0x0a; // TMOD=0000 1010B,使用定时器 T0 的模式 2, GATE置 1

  EA=1; // 开总中断

  ET0=0;// 不使用定时器 T0 的中断 

  TR0=1;// 启动 T0 

  TH0=0; // 计数器 T0 高 8 位赋初值

  TL0=0;  // 计数器 T0 低 8 位赋初值

  while(1)  // 无限循环,不停地将 TL0计数结果送 P1口

  {  

    while(ui==0)  //INT0 为低电平, T0 不能启动

    TL0=0; //INT0 为高电平,启动 T0 计时,所以将 TL0清 0

    while(ui==1) // 在 INT0 高电平期间,等待,计时

    P1=TL0; // 将计时结果送 P1口显示

  } 

}


哈哈哈


实例 53:用外中断 0 的中断方式进行数据采集

#include 

sbit S=P3^2;// 将 S位定义为 P3.2 

void main(void) // 包含 51 单片机寄存器定义的头文件

{

  EA=1; // 开放总中断

  EX0=1; // 允许使用外中断

  IT0=1; // 选择负跳变来触发外中断

  P1=0xff;

  while(1); 

}

void int0(void) interrupt 0 using 0 // 外中断 0 的中断编号为 0

{

  P1=~P1; // 每产生一次中断请求, P1取反一次。

}  

呐呐呐


实例 54-1 :输出负脉宽为 200 微秒的方波

#include // 包含 51 单片机寄存器定义的头文件

sbit u=P1^4;// 将u位定义为P1.4 

void main(void)

{

  TMOD=0x02; //TMOD=0000 0010B,使用定时器 T0 的模式 2

  EA=1;// 开总中断 

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

  TH0=256-200; // 定时器 T0 的高 8 位赋初值

  TL0=256-200; // 定时器 T0 的高 8 位赋初值

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

  while(1);// 无限循环,等待中断

}

void Time0(void) interrupt 1 using 0 //"interrupt" 声明函数为中断服务函数

{

  u=~u; // 将 P1.4引脚输出电平取反,产生方波

}  

嗯嗯嗯


实例 54-2 :测量负脉冲宽度

#include // 包含 51 单片机寄存器定义的头文件

sbit u=P3^2;// 将 u 位定义为 P3.2 

void main(void)

{

  TMOD=0x02; //TMOD=0000 0010B,使用定时器 T0 的模式 2

  EA=1; // 开放总中断

  EX0=1; // 允许使用外中断

  IT0=1; // 选择负跳变来触发外中断

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

  TH0=0; // 定时器 T0 赋初值 0

  TL0=0; // 定时器 T0 赋初值 0

  TR0=0; // 先关闭 T0

  while(1) ; // 无限循环, 不停检测输入负脉冲宽度

}

void int0(void) interrupt 0 using 0 // 外中断 0 的中断编号为 0

{

  TR0=1; // 外中断一到来,即启动 T0 计时

  TL0=0; // 从 0 开始计时

  while(u==0)// 低电平时,等待 T0 计时

  P1=TL0; //将结果送 P1口显示

  TR0=0; // 关闭 T0

}  

咯咯咯


实例 55:方式 0 控制流水灯循环点亮

#include // 包含 51 单片机寄存器定义的头文件

#include // 包含函数 _nop_()定义的头文件

unsigned char code Tab[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

// 流水灯控制码,该数组被定义为全局变量

sbit P17=P1^7;

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

函数功能:延时约 150ms

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

void delay(void)

{

  unsigned char m,n;

  for(m=0;m<200;m++)

  for(n=0;n<250;n++);

}

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

函数功能:发送一个字节的数据

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

void Send(unsigned char dat)

{

  P17=0;//P1.7 引脚输出清 0 信号,对 74LS164清 0  

  _nop_(); // 延时一个机器周期,保证清 0 完成

  P17=1; // 结束对 74LS164的清 0

  _nop_(); // 延时一个机器周期

  SBUF=dat; // 将数据写入发送缓冲器,启动发送

  while(TI==0); // 若没有发送完毕,等待

  TI=0;// 发送完毕, TI被置“ 1”,需将其清 0

}

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

函数功能:主函数

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

void main(void)

{

  unsigned char i;

  SCON=0x00; //SCON=0000 0000B,使串行口工作于方式 0

  while(1)

  {

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

    {

      Send(Tab[i]); // 发送数据

      delay(); // 延时

    }

  }

}  

略略略


打开串口调试程序,将波特率设置为9600,无奇偶校验晶振11.0592MHz,发送和接收使用的格式相同,如都使用字符型格式,在发送框输入hello, I Love MCU ,在接收框中同样可以看到相同字符,说明设置和通信正确,

include   

void main (void)

{

  SCON = 0x50; //SCON:模式 1,8-bit UART,使能接收V 

  TMOD = 0x20; /*TMOD: timer 1, mode 2,8-bit reload*/

  TH1 =0xFD;// TH1:重新加载值为9600波特

  TR1 = 1;// 启动定时器1

  EA = 1; //幵总中断

  ES = 1; //打开串口中断

  while (1); //主循环不做任何动作

}

void UART_SER (void) interrupt 4 //串行中断服务程序

{

  unsigned char Temp; //定义临吋变量 

  if(RI) //判断是接收中断产生

  {

    RI = 0;//标志位清零

    Temp = SBUF;//读入缓存区的值

    P1=Temp;//把值输出到P1口,用于观察

    SBUF = Temp;//把接收到的值再发回电脑端

  }

  if(TI) //如果是发送标志位,淸零

  TI = 0;

}

#include

void ConfigUART(unsigned int baud);

void main ()

{

   ConfigUART(9600);  //配置波特率为9600

   while(1)

   {

       while (!RI);     //等待接收完成

       RI = 0;          //清零接收中断标志位

       SBUF = SBUF + 1; //接收到的数据+1后,发送回去;

       //等号左边的SBUF实际上就是发送SBUF,因为对它的操作是“写”;

       //等号右边的是接收SBUF,因为对它的操作是“读”。

       while (!TI);     //等待发送完成

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。