51单片机定时器学习(实操训练:定时器时钟!!)

1.定时器介绍

51单片机的定时器属于单片机的内部资源,电路连接和运转均在单片机内部完成。

1.1定时器作用

                (1)用于计时系统,可实现软件计时,是程序每隔一段时间完成一项操作。

                (2)替代长时间的delay,提高cpu运行速度。

1.2定时器个数

定时器总共有三个(T0,T1,T2),T0和T1与传统的单片机兼容,T2是89C52增加的资源。T0和T1的操作方式是51单片机所共有的。

1.3定时器框图

时钟提供计数单位脉冲,每隔“1s"(自定义设定时间)计数单元的数值加1,当计数单元增加到设定的闹钟提醒时间时,计数单元就会像中断发出中断申请,使程序跳转到中断服务函数执行。

2.定时器工作模式

STC89C52的T0和T1有四种工作模式

模式0:13位定时器/计数器

模式1:16位定时器/计数器(常用)

模式2:8位自动重装模式

模式3:两个8位计数器

3.中断系统

3.1中断系统概念

CPU对外部紧急事件进行处理的能力

当CPU处理某件事时,外界发生紧急事件请求,要求CPU停下当前工作,转而去处理紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统。

3.2中断嵌套

4.STC89C52中断资源

中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3)

中断优先级个数:4个(STC89C52有四个中断优先级)

中断优先级基本规则:(1)低优先级中断可被高优先级中断所中断,反之不能。

                                   (2)任何一种中断(不管是高级还是低级),一旦得到相应,不会被同级中断所中断。

5.定时器和中断系统

5.定时器相关寄存器

5.1TCON定时器控制寄存器(可位寻址)

TCON为定时器/计数器T0,T1的控制寄存器同时也锁存T0,T1溢出中断源,外部请求中断源

TR0=1;代表定时器开始计数,这里只标注与定时器T0相关的参数TF0,TR0。

5.2TMOD定时器模式寄存器(不可位寻址)

定时和计数功能均由TMOD的控制位C/T位进行选择。两个定时/计数器有四种模式,均由TMOD的M0和M1进行操作。

C/T=0,用作定时器,单片机内部时钟

C/T=1,用作计数器,外部接入晶振

6.定时器控制(按键左右控制流水灯模式)

这里只写了main函数,key.c和key.h其他函数在定时器8均有展示

6.1main函数

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>


unsigned char KeyNum,LEDMode;//LEDMode即为LED模式
void main()
{
	P2=0xFE;//P2LED灯初始状态1111 1110,最左边小灯亮
	Timer0_Init();//定时器一定要初始化
	while(1)
	{
		KeyNum=Key();
		if(KeyNum)
		{
		  if(KeyNum==1)//按键1控制流水灯左右移动
			{
				LEDMode++;
				if(LEDMode>=2)LEDMode=0;
			}
    }
 }
	}

Timer0_Routine(void)   interrupt 1//定时器0中断中显示了流水灯左右移动
{
	static unsigned  int  T0count;//staitic循环一次后不清零,仍占据内存空间
	//静态局部变量,只能由本函数引用
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0count++;//中断来一次就加一次;
	if(T0count>=500) //1ms*500=500ms
	{
		T0count=0;
		if(LEDMode==0)//LED模式为0
			   P2=_crol_ (P2,1);//LED灯向左移动
		if(LEDMode==1)//模式2
			   P2=_cror_(P2,1);//LED灯向右移动
	}
}

6.2key.c函数

#include <REGX52.H>
#include "Delay.h"

//获取独立按键键码
//无参数
//按下按键的键码范围1-4,无按键按下返回值为0
unsigned char Key()
{
	unsigned char KeyNumber=0;
	if(P3_1==0){Delay(2);while(P3_1==0);Delay(2);KeyNumber=1;}//按键1为P3_1端口
	if(P3_0==0){Delay(2);while(P3_0==0);Delay(2);KeyNumber=2;}//按键2为P3_0端口
	if(P3_2==0){Delay(2);while(P3_2==0);Delay(2);KeyNumber=3;}//按键3为P3_2端口
	if(P3_3==0){Delay(2);while(P3_3==0);Delay(2);KeyNumber=4;}//按键4为P3_3端口
	
	return KeyNumber;//返回按键值
}

7.3key.h函数

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();


#endif

7.定时器时钟

定时器时钟需要的函数如下

7.1main函数

//main函数
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "Timer0.h"


unsigned char sec=55,min=59,hour=23;
void main()
{
	LCD_Init();
	Timer0_Init();
	LCD_ShowString(1,1,"Clock:");
	LCD_ShowString(2,1,"  :  :");
	while(1)
	{
		LCD_ShowNum(2,1,hour,2);
		LCD_ShowNum(2,4,min,2);
		LCD_ShowNum(2,7,sec,2);
	}
}
//定时器中断模板 用的时候复制到main函数中
Timer0_Routine(void)   interrupt 1//定时器0中断
{
	static unsigned  int  T0count;//staitic循环一次后不清零,仍占据内存空间
	//静态局部变量,只能由本函数引用
	TH0=64535/256;
	TL0=64535%256;
	T0count++;//中断来一次就加一次;
	if(T0count>=1000)// 1ms*1000=1s
	{
		T0count=0;
		 sec++;//每隔一秒sec加加
		if(sec>=60)
		{
			sec=0;
			min++;
			if(min>=60)
			{
				min=0;
				hour++;
				if(hour>=24)
				{
					hour=0;	
				}
				
			
		}//中断只能显示短的逻辑程序。
		
	}
}
	}

7.2Delay.c函数(延迟函数)

void Delay(unsigned char xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms)
	{
	i = 195;
	j = 138;
	do
	{
		while (--j);
	} while (--i);
	xms--;
}
}

7.3Delay.h函数

#ifndef  __DELAY_H__
#define  __DELAY_H__

void Delay(unsigned char xms);

#endif

7.4LCD1602.c函数

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

7.5LCD1602.h函数

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

7.6Timer0.c函数(定时器函数)

  TMOD=TMOD & 0xF0;//把TMOD的低四位清0,高四位保持不变 TMOD =TMOD & 0xF0;//TMOD原来的是与1111 0000进行“与”运算。
    TMOD=TMOD | 0x01;//把TMOD的最低位置置1,高四位保持不变//TMOD原来的是与0000 0001进行“或”运算。 与置0,或置1
    与置0,或置1.不影响高四位而对低四位置1.含义为定时器0寄存器且01代表是16位定时器

void Timer0Init(void)
{
	//TMOD=0x01;//0000 0001   01代表16位定时器 不可位寻址需要整体赋值寻址
    TMOD=TMOD & 0xF0;//把TMOD的低四位清0,高四位保持不变 TMOD =TMOD & 0xF0;//TMOD原来的是与1111 0000进行“与”运算。
	TMOD=TMOD | 0x01;//把TMOD的最低位置置1,高四位保持不变//TMOD原来的是与0000 0001进行“或”运算。 与置0,或置1
	// 与置0,或置1.不影响高四位而对低四位置1.含义为定时器0寄存器且01代表是16位定时器
 	TF0=0;//中断溢出标志位
    TR0=1;	//定时器开始  开始TCON可位寻址,可以对单独位进行赋值寻址
	
     TH0=64535/256;//把高八位拿出开 定时器计数(2*16=65536,65535-64535=1000)TH0将1ms的高八位拿出
	 TL0=64535%256;//把低八位拿出来 定时器计数

	 ET0=1;//允许T0中断
	 EA=1;//总中断允许控制位 
	 PT0=0;
//}	
#include <REGX52.H>

//定时器0初始化1ms  12MHz
//无返回值

void Timer0_Init()		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;   //设置定时器模式
	
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0=1;//允许T0中断
	EA=1;//总中断允许控制位 
	PT0=0;//中断优先级
	
}

//定时器中断模板 用的时候复制到main函数中
//Timer0_Routine(void)   interrupt 1//定时器0中断
//{
//	static unsigned  int  T0count;//staitic循环一次后不清零,仍占据内存空间
	//静态局部变量,只能由本函数引用
	//TH0=64535/256;
	//TL0=64535%256;
	//T0count++;//中断来一次就加一次;
	//if(T0count>=1000) 1ms*1000=1s
//	{
//		T0count=0;
//		P2_0=~P2_0;
//	}
//}


7.7Timer0.h函数

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

8.成果展示(定时器时钟)

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值