实现定时功能,比较方便的方法是利用单片机内部的定时器/计数器。也可以采用下面的三种方法
1.软件定时:软件定时不占用硬件资源,但是占用了cpu的利用率
2.采用时基电路定时:列采用555电路,外接必要的元器件(电阻和电容),即可构成硬件定时电路,但在硬件连接好以后,定时的范围不能由软件进行控制和修改,即不可编程
3.采用可编程的芯片定时:这种定时芯片的定时值及定时范围很容易用软件来确定和修改,此种芯片定功能强,使用灵活。在单片机的定时/计数器不够用时,可以考虑进行扩展。
中断服务程序的写法
void 函数名()interrupt 中断号 using 工作组
{
中断服务程序内容
}
在写单片机的定时器程序时,在程序开始处需要对定时器及中断寄存器做初始化设置,通常定时器初始化过程如下:
(1)对TMOD赋值,以确定T0和 T1的工作方式。
(2)计算初值,并将初值写入TH0、TL0或TH1、TL1。
(3)中断方式时,则对IE赋值,开放中断。
(4)使TR0和TR1置位,启动定时器/计数器定时或计数。
例:利用定时器0工作方式1,实现一个发光管以1s亮灭闪烁。
程序代码如下:
#include《reg52.h》
#define uchar unsigned char
#define uint unsigned int
sbit led1=P1^0;
uchar num;
void main()
{
TMOD=0x01; //设置定时器0位工作模式1(M1,M0位0,1)
TH0=(65536-45872)/256; //装初值11.0592M晶振定时50ms数为45872
TL0=(65536-45872)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
while(1)
{
if(num==20) //如果到了20次,说明1秒时间
{
led1=~led1; //让发光管状态取反
num=0;
}
}
}
void T0_time()interrupt 1
{
TH0=(65536-45872)/256; //重新装载初值
TL0=(65536-45872)%256;
num++;
}
以下为一个比较简单易懂的单片机定时器中断程序,只要自行更改端口就可以使用!大家可以参考一下!
#include《reg51.h》
#define uchar unsigned char
#define uint unsigned int
sbit RING1=P3^7; //P3^7接蜂鸣
sbit OPEN=P3^1; //闹钟开时LED亮
uchar idata buffer[8]={0,0,0,0,0,0,10,11};//定义两段缓冲区,buffer用于过程中时间BCD码暂存并初始化
uchar code LED[]={0X3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F,0X40,0X40}; //LED段译存储于程序存储区
uchar miao=0;fen=58;shi=10; //定义全局变量用于miao,fen,shi用于存储过程时间
uchar _20ms;//定义全局变量_20ms用于计数中断个数,50个为1秒
uchar hour2,minutes2,second2;//闹铃设置时间存储区
uchar hour1,minutes1,second1;//修改时间时暂存区
bit hour,minutes,second;//修改相应时的位标志
bit add,dec;//加减位标志
bit openring,cancelring;//闹铃开、关、取消标志
bit setring,settime;//闹铃设置、时间设置标志
bit ok;//确定变量
void delay_1ms(uchar x)//延时1ms
{
uchar j;
while(x--)
{
for(j=0;j《123;j++){;}
}
}
void inital(void)//定时器初始化函数
{ RING1=1; //这里RING等于0时蜂鸣器响;
TMOD=0x01; //定时器0工作于方式1,采用12M晶振,定时20ms
TH0=(65536-20000)/256;
TL0=(65536-20000)%256;
TR0=1; //TR0=1 启动定时器
EA=1; //开总中断
ET0=1; //开定时器中断
}
void timer0 (void) interrupt 1 using 1 //定时0中断函数
{ TH0=(65536-20000)/256;
TL0=(65536-20000)%256;
_20ms++;
if(50==_20ms) //判断是否到了一秒
{ miao++; //到了一秒,秒++
_20ms=0;
if(miao==60) //六十秒到了吗
{ fen++; //到了份++
miao=0;
if(fen==60) //六十分到了吗
{ shi++; //到了时++
fen=0;
if(shi==24) //24小时到了吗
{ shi=0; //时清零
fen=0;
miao=0;
}
}
}
}
if(openring==1) //闹钟开了吗
{ if((shi==hour2)&&(fen==minutes2)&&(miao==second2)) //定时时间到 闹铃响
RING1=0;
if(cancelring==1) //闹钟关
{RING1=1;cancelring=0;}
}
}
void timebcd (uchar m,uchar f,uchar s) //时间变动函数,当计时到达1秒时进行时间变动
{
buffer[0]=m%10; //shi、fen、miao转换成BCD码,主要为了数码管的显示
buffer[1]=m/10;
buffer[2]=f%10;
buffer[3]=f/10;
buffer[4]=s%10;
buffer[5]=s/10;
}
void keyscan(void) //键扫描并确定键值函数,该部分是时钟各种功能实现的核心
{
uchar scode,recode,value; //定义行列变量
P2=0XF0; // 注意键盘与P2的接法,4*4键盘
if ((P2 & 0XF0)!=0XF0)
{
delay_1ms(10);
if ((P2&0XF0)!=0XF0)
{
scode=0xfe;
while((scode & 0x10)!=0)
{ P2=scode;
if ((P2&0XF0)!=0XF0)
{recode=(P2 & 0XF0)|0X0f;
value=((~scode)+(~recode));
switch(value)
{ case 0x11: hour=1;minutes=0;second=0;break;//时,按到的键是修改时的功能键,hour是修改时的标志位
case 0x21: hour=0;minutes=1;second=0;break;//分,按到的键是修改分的功能键,minutes是修改分的标志位;
case 0x41: hour=0;minutes=0;second=1;break;//秒 与上面类似;
case 0x81: add=1;dec=0;break;// 加
case 0x12: dec=1;add=0;break;//减
case 0x22: setring=1;settime=0;second1=second2;minutes1=minutes2;hour1= hour2;break;//闹钟设置,
case 0x42: settime=1;setring=0;second1=miao;minutes1=fen;hour1=shi;break;//时间设置
case 0x82: setring=0;settime=0;break;//返回
case 0x14: ok=1;break;//确定
case 0x24: openring=1;OPEN=0;break;//开闹钟
case 0x44: openring=0;OPEN=1;break;//关闹钟
case 0x84:cancelring=1;break;// 取消响铃
default: break;
}
}
else scode=(scode《《1)|0x01;
}
}
}
}
注意:这里将键盘的值进行了编码,12个键盘进行了编码 ,特别注意 闹钟设置和时间设置的实现方法 ,他们共用了函数 resettime,没什么难的。
void resettime (viod)
{
if(hour==1)
{
if (add==1)
{hour1++;add=0;}
if( hour1==24)
hour1=0;
if (dec==1)
{hour1--;dec=0;}
if (hour1==-1)
hour1=23;
}
if(minutes==1)
{
if (add==1)
{minutes1++;add=0;}
if (minutes1==60)
minutes1=0;
if(dec==1)
{ minutes1--;dec=0;}
if (minutes1==-1)
minutes1=59;
}
if(second==1)
{
if (add==1)
{second1++;add=0;}
if(second1==60)
second1=0;
if (dec==1)
{second1--;dec=0;}
if(second1==-1)
second1=59;
}
}
display (void) //显示函数子程序
{
uchar j,n;
for(n=0,j=0XFE;n《8;j=((j《《1)|0X01),n++)
{P1=j; //P1接数码管位选
P0=LED[buffer[n]]; //P0接数码管段选
delay_1ms(5);
}
}
void main (void)
{
inital(); // 调用定时器初始化
for(;;)
{
timebcd(miao,fen,shi);
keyscan();
//调用键扫描,确定功能
if(settime==1) //当按下的键是时间设置时
{
resettime();
timebcd ( second1, minutes1,hour1);
if(ok==1) //当确定被按下时,表明重设时间要覆盖原来的时间,所以将miao,fen,shi重置,_20ms清零
{ shi=hour1;
fen=minutes1;
miao=second1;
_20ms=0;
}
}
if(setring==1)
{
resettime();
timebcd( second1, minutes1,hour1);
if(ok==1)
{ hour2=hour1;
minutes2=minutes1;
second2=second1;
}
}
display(); //调用显示函数
}
}
单片机C语言定时中断程序
#include《reg51.h》 //包含51单片机寄存器定义的头文件
#define x 65536
#define y 256
sbit sound=P2^0; //将sound位定义为P3.7
unsigned int C; //储存定时器的定时常数
unsigned int code f[]={399,1900,1800,1700,1600,1500,1400,1300,1200,1100,1000,900,0xff};
unsigned char code JP[]={4,1,1,4,1,1,2,2,2,2,2,8};
void delay()
{
unsigned char i,j;
for(i=0;i《250;i++)
for(j=0;j《250;j++)
;
}
void main()
{
unsigned char i,j;
EA=1; //开总中断
ET0=1;
TMOD=0x01; // 使用定时器T0的模式1(13位计数器)
while(1) //无限循环
{
while(f[i]!=0xff) //只要没有读到结束标志就继续播放
{
C=500000/f[i];
TH0=(x-C)/y; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(x-C)%y; //可证明这是13位计数器TL0低5位的赋初值方法
TR0=1; //启动定时器T0
for(j=0;j《JP[i];j++) //控制节拍数
delay(); //延时1个节拍单位
TR0=0; //关闭定时器T0
i++; //播放下一个音符
}
}
}
void Tim() interrupt 1
{
sound=!sound; //将P3.7引脚输出电平取反,形成方波
TH0=(x-C)/y; //可证明这是13位计数器TH0高8位的赋初值方法
TL0=(x-C)%y; //可证明这是13位计数器TL0低5位的赋初值方法
}
评论
查看更多