51单片机——定时器综合训练

目录

实验内容

功能要求:

protues原理图

Keil代码

不加入按键功能

加入按键功能 


实验内容

基于protues8.13、51单片机,使用定时器制作一个秒表,四位显示(00.00)

功能要求:

1、最低显示0.01秒

2、两个显示模式(分-秒,秒-毫秒),用按键随时切换(K2)。

3、一个按键控制开始、暂停、清零(K1)。

protues原理图

 与上一个实验一样,数码管连接在P0和P3上,在P1.0\P1.1上连接两个按键(K1为开始、暂停、清零,K2为切换模式)。

Keil代码

不加入按键功能

让它实现简单的秒表功能(即上电就开始计时,不会停止),为了查看分-秒模式显示是否正常,我建立了一个t_flag标志位,开始时t_s<60s,t_flag=0,显示秒-毫秒模式,当t_s>60s,则切换为分-秒模式。


#include<reg51.h> 
#define uchar unsigned char
#define uint unsigned int
 
/***********参数定义**********************************/	
uchar t_f = 0;//f
uchar t_s = 0;//s
uchar t_001s = 0;//ms
uint t_flag = 0;

//uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66, //共阴型段码表0~9
//									 0x6d,0x7d,0x07,0x7f,0x6f};//让我恶心的共阴数码管段码

//共阳数码管,最后两个段码是-和.									 
unsigned char code SMG_duanma[18]=   //共阳段码0~F  -  .
{
  0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,
  0X80,0X90,0X88,0X80,0XC6,0XC0,0X86,0X8E,
  0XBF,0X7F
};
/*************函数声名*****************************************/
void delay();

void InitTimer0();//定时器初始化
void Timer0();//定时器中断
									 

void ShowSMG_Bit_No(unsigned char value, unsigned int pos);//无点段选位选
void ShowSMG_Bit(unsigned char value, unsigned int pos);//有点段选位选
void Display_SMG();//数码管显示函数

/****************主函数******************************************************/									 
void main()
{
	InitTimer0();
	while(1)
	{
		Display_SMG();
	}
	
}

void delay()	//延时函数
{		
	uint i;
	for(i=0;i<1000;i++);
}  	 


/******************************定时器********************************************/
//====定时器初始化=============================//
void InitTimer0()
{
  TMOD  = 0X01;
  TH0 = (65535 - 10000) /256;//要求最低显示0.01s,即定时器10ms
  TL0 = (65535 - 10000) %256;
  
  ET0 = 1;
  EA = 1;
  TR0 = 1; 
}
//====定时器中断=============================//
void Timer0() interrupt 1
{
	TH0 = (65535 - 10000) /256;
  TL0 = (65535 - 10000) %256; 
  
  t_001s++;
  if(t_001s == 100)//10ms++100次=1s
  {
    t_s++;
    t_001s = 0;
    if(t_s == 60)
    {
			t_f++;
			t_flag=1;
      t_s = 0;
    }
  }
}

/******************************数码管********************************************/
//====数码管位选段选=============================//
void ShowSMG_Bit_No(unsigned char value, unsigned int pos)//无点
{
	//共阴数码管,位选接P3为低,段选接P0为高
  //数码管位选
  P3 = ~(0X01 << pos);//通过移位选位
  //数码管段选
  P0 = ~(SMG_duanma[value]);
}
void ShowSMG_Bit(unsigned char value, unsigned int pos)//有点
{
	//共阴数码管,位选接P3为低,段选接P0为高
  //数码管位选
  P3 = ~(0X01 << pos);//通过移位选位
  //数码管段选
  P0 = ~(SMG_duanma[value]&0X7f);
}
//====数码管显示=============================//
void Display_SMG()
{
	switch(t_flag)
	{
		case 0 ://时间在60s以内,模式1,秒-毫秒显示
			//ms
			ShowSMG_Bit_No(t_001s%10,3);//00.01
			delay();
			ShowSMG_Bit_No(t_001s/10,2);//00.10
			delay();
			
			//S
			ShowSMG_Bit(t_s%10,1);//01.00
			delay();
			ShowSMG_Bit_No(t_s/10,0);//10.00
			delay();
		break;
		case 1 ://当时间超过60s,数码管不够显示,则转为模式2,分-秒显示
			//s
			ShowSMG_Bit_No(t_s%10,3);//00.01
			delay();
			ShowSMG_Bit_No(t_s/10,2);//00.10
			delay();
			
			//f
			ShowSMG_Bit(t_f%10,1);//01.00
			delay();
			ShowSMG_Bit_No(t_f/10,0);//10.00
			delay();
		break;
	}
	
	
}

*注:通过这么多次的实验,我发现共阴数码管的段码是真不好用,不如直接用共阳数码管的段码,然后对其进行取反即可。

分享一个我在使用共阴数码管段码时遇到的个小问题,属于是我自己没注意:

        因为平时做的内容不需要用上小数点,所以并没住。以前我用的都是共阳(段码给低电平点亮)的,在加上小数点时,我不喜欢重新写一个带有点的数组,所以会在P0 = SMG_duanma[value];的后面直接与上一个0X7F,即P0 = ~(SMG_duanma[value]&0X7f);0X7F=0111 1111,假如数字段码是0,0XC0=1100 0000。将他们与上\frac{01111111}{11000000},结果为0100 0000=0X40;这是成功显示(0.)的。

        刚开始我想共阴一样,只点亮小数点是0X80,所以我在P0 = table[value]上直接与上0x80,但是发现数码管都不亮了,后面才发现0X80=1000 0000,同样数字段码假如0是0X3F=0011 1111,他们两个与上就变成了\frac{1000 0000}{00111111},与0=0故最后段码变成0000 0000=0X00,共阴数码管给0是不亮的。

加入按键功能 

*注:不将数码管显示调用在while(k1==0)循环中,在按下按键后数码管会闪烁一下(K2同理)。


#include<reg51.h> 
#define uchar unsigned char
#define uint unsigned int 
#define SB sbit	
uchar t_f = 0;//f
uchar t_s = 0;//s
uchar t_001s = 0;//ms
uint K1_flag = 0;
uint K2_flag = 0;
uint mod;
SB K1=P1^0;
SB K2=P1^1;
									 
unsigned char code SMG_duanma[18]=   //共阳段码0~F  -  .
{
  0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,
  0X80,0X90,0X88,0X80,0XC6,0XC0,0X86,0X8E,
  0XBF,0X7F
};

void delay();
void Delay_key();

void InitTimer0();
void Timer0();
									 

void ShowSMG_Bit_No(unsigned char value, unsigned int pos);//无点
void ShowSMG_Bit(unsigned char value, unsigned int pos);//有点
void Display_SMG();
void key_scan();

									 
void main()
{
	InitTimer0();
	while(1)
	{
		Display_SMG();
		key_scan();
	}
	
}
/******************************延时函数*******************************************************/
void delay()	//数码管延时函数
{		
	uint i;
	for(i=0;i<1000;i++);
}  	 

void Delay_key()//按键延时
{
	uint t=200;
	while(t--);
}
/******************************定时器********************************************/
//====定时器初始化=============================//
void InitTimer0()
{
  TMOD  = 0X01;
  TH0 = (65535 - 10000) /256;//要求最低显示0.01s,即定时器10ms
  TL0 = (65535 - 10000) %256;
  
  ET0 = 1;
  EA = 1;
  TR0 = 0; 
}
//====定时器中断=============================//
void Timer0() interrupt 1
{
	TH0 = (65535 - 10000) /256;
  TL0 = (65535 - 10000) %256; 
  
  t_001s++;
  if(t_001s == 100)//10ms++100次=1s
  {
    t_s++;
    t_001s = 0;
    if(t_s == 60)
    {
			t_f++;
      t_s = 0;
    }
  }
}

/******************************数码管********************************************/
//====数码管位选段选=============================//
void ShowSMG_Bit_No(unsigned char value, unsigned int pos)//无点
{
	//共阴数码管,位选接P3为低,段选接P0为高
  //数码管位选
  P3 = ~(0X01 << pos);//通过移位选位
  //数码管段选
  P0 = ~(SMG_duanma[value]);
}
void ShowSMG_Bit(unsigned char value, unsigned int pos)//有点
{
	//共阴数码管,位选接P3为低,段选接P0为高
  //数码管位选
  P3 = ~(0X01 << pos);//通过移位选位
  //数码管段选
  P0 = ~(SMG_duanma[value]&0X7f);
}
//====数码管显示=============================//
void Display_SMG()
{
	switch(mod)
	{
		case 0 ://时间在60s以内,模式1,秒-毫秒显示
			//ms
			ShowSMG_Bit_No(t_001s%10,3);//00.01
			delay();
			ShowSMG_Bit_No(t_001s/10,2);//00.10
			delay();
			
			//S
			ShowSMG_Bit(t_s%10,1);//01.00
			delay();
			ShowSMG_Bit_No(t_s/10,0);//10.00
			delay();
		break;
		case 1 ://当时间超过60s,数码管不够显示,则转为模式2,分-秒显示
			//s
			ShowSMG_Bit_No(t_s%10,3);//00.01
			delay();
			ShowSMG_Bit_No(t_s/10,2);//00.10
			delay();
			
			//f
			ShowSMG_Bit(t_f%10,1);//01.00
			delay();
			ShowSMG_Bit_No(t_f/10,0);//10.00
			delay();
		break;
	}
}

/******************************KEY********************************************/
void key_scan()
{
	if(K1== 0)
	{
		Delay_key();
		if(K1==0)
		{
			K1_flag++;
			switch(K1_flag)
			{
				case 1:TR0=~TR0;break;
				case 2:TR0=~TR0;break;
				case 3:t_f = 0;//f
							 t_s = 0;//s
							 t_001s = 0;//ms
							 K1_flag=0;break;
			}
			while(K1==0){Display_SMG();}
		}
		
	}
	if(K2==0)
	{
		Delay_key();
		
		if(K2==0&&K2_flag==0)
		{
			K2_flag=1;
			mod=K2_flag;
		}
		else if(K2==0&&K2_flag==1)
		{
			K2_flag=0;
			mod=K2_flag;
		}
		
		while(K2==0){Display_SMG();}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值