基于51单片机的电子时钟设计(含温度检测和报警功能)

 时钟闹钟代码参考:单片机实现时钟闹钟

本学期单片机课程要求做课程设计,我选取的课题如下:
基于单片机的电子时钟设计,包含功能:
(1)实时显示当前时间,且在任何状态下都不能中断计时。

(2)能够对时钟以及闹钟进行时间的设置。

(3)包括小时,分钟,秒以及小数点作为分隔。

(4)整点报时功能。

(5)闹钟响铃功能。

(6)显示环境温度,且超出设定范围时亮l对应led灯并报警。

需要材料:

单片机(AT89C52),AD,四个独立按钮,矩阵键盘,6位共阴数码管,蜂鸣器,led灯,

需要软件:

 Keil uVision5

 下面是代码,已通过实物验证,可完美实现功能,所以就不放protues仿真了。

/*按键功能说明:
矩阵键盘:
第1到第10个按键分别对应数字0-9;
独立按键:
Key1短按切换模式;
Key2按下则进行时钟和闹钟的设置;
Key3短按确认输入时间,长按清零;
Key4按下则停止闹铃*/
#include <reg52.h> 
#include <stdio.h>
#include <intrins.h> 
#define uchar unsigned char 
#define uint unsigned int 
sbit DS = P2 ^ 2;   //DS18B20单总线
sbit key1 = P3 ^ 4;//按键
sbit key2 = P3 ^ 5;
sbit key3 = P3 ^ 6;
sbit key4 = P3 ^ 7;
sbit buff = P2 ^ 3;//蜂鸣器
sbit DU = P2 ^ 6;//段选
sbit WE = P2 ^ 7;//位选
sbit led0 = P1 ^ 0;/*指示灯用于报警控制*/
sbit led1 = P1 ^ 1;
sbit led2 = P1 ^ 2;
sbit led3 = P1 ^ 3;
uint warn_11 = 270;//温度值乘以10的结果
uint warn_12 = 250;
uint warn_h1 = 300;
uint warn_h2 = 320;
uchar bitdata[] = { 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f };//数码管1-8
uchar segdata[] = { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40 };//段选0-9以及-
uchar segdata_dp[] = { 0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef };//带小数点数段选0-9
uchar table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f,//共阴 极数码管0到9编码不带小数点
0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xef };//共阴 极数码管0到9编码不带小数点
uchar dis_arr[] = { 10,10,10,10,10,10 };//时钟显示数组 默认为-
uchar time[] = { 0,0,0 };//时钟 时分秒
uchar time_In[] = { 0,0,0,0,0,0 };
uchar time_clk[] = { 0,0,0 };//闹钟 时分秒
uchar t = 0;
uchar num = 0;
uchar mode = 0;
uchar keydown = 0;
uchar keyIn, keyvalue, i, temp;//矩阵键盘读入
uint temp_t;
float f_temp;
void key();
void init();
uchar keyscan();//矩阵键盘扫描函数
void delayms(uint x);//延时函数
void display(uchar duan1, uchar duan2, uchar duan3, uchar duan4, uchar duan5, uchar duan6);
void display_1(uchar wei, uchar duan);
void display_2(uchar wei, uchar duan);
void input();
void soundTime();
void dis_temp(uint t);
void deal(uint t);
void comm(char* parr);
void tempchange();
uint get_temp();
void init_com();
void main()
{
	input();
	if (mode == 0)
	{ 
		init();
	}
	else if (mode == 1)
	{ 
		init();
	}
	else if (mode == 2)
	{ 
		init_com(); 
	}
	while (1)
	{
		key();
		if (mode == 0)//时钟
		{
			display(time[0] / 10, time[0] % 10, time[1] / 10, time[1] % 10, time[2] / 10, time[2] % 10);
		}
		else if (mode == 1)//闹钟
		{
			display(time_clk[0] / 10, time_clk[0] % 10, time_clk[1] / 10, time_clk[1] % 10, time_clk[2] / 10, time_clk[2] % 10);
		}	
		else if (mode == 2)//温度
		{
			uchar buff[4], k;
			DU = 0; WE = 0;
			tempchange();
			for (k = 10; k > 0; k--)
			{
				dis_temp(get_temp());
			}
			deal(temp_t); 
			sprintf(buff, "%f", f_temp);
			for (k = 10; k > 0; k--)
			{
				dis_temp(get_temp());
			}
			comm(buff);
			for (k = 10; k > 0; k--)
			{
				dis_temp(get_temp());
			}
			if (key1==0)
			{
				delayms(5);
				if (key1==0)
				mode = -1;
			}
		}
	}
}
void init_com(void)
{
	TMOD = 0x20;//串口初始化函数 T1工作在方式2
	PCON = 0x00;
	SCON = 0x50;
	TH1 = 0xfd;//波特率9600
	TL1 = 0xfd;
	TR1 = 1;
}
void init()//初始化函数
{
	P3 = 0xff;//给高电平
	TMOD = 0x01;//定时器工作方式选择1 T0工作在方式1
	TH0 = (65536 - 45872) / 256;
	TL0 = (65536 - 45872) % 256;
	EA = 1; //开总中断
	ET0 = 1;//允许定时器0中断
	TR0 = 1;//开始计数
	//P1=1;
}
void delayms(uint x)//延时函数
{
	uint i, j;
	for (i = x; i > 0; i--)
		for (j = 110; j > 0; j--);
}
void key()/*模式切换函数*/
{
	if (key1 == 0)
	{
		delayms(200);
		if (key1 == 0)//按压时不进行任何操作
		{
			delayms(1);
		}
		else if (key1 == 1)//松开后切换模式
		{
			mode++;
			if (mode == 3)mode = 0;
		}
	}
	if (key2 == 0)
	{
		delayms(100);
		if (key2 == 0)
		{
			delayms(500);
			input();
		}
	}
	if (key3 == 0)
	{
		delayms(200);
		if (key3 == 0)
		{
			if (mode == 0) {
				time[0] = 0;
				time[1] = 0;
				time[2] = 0;
				num = 0;
				while (!key3)display(time[0] / 10, time[0] % 10, time[1] / 10, time[1] % 10, time[2] / 10, time[2] % 10);
			}
			else if (mode == 1) {
				time_clk[0] = 0;
				time_clk[1] = 0;
				time_clk[2] = 0;
				while (!key3)display(time_clk[0] / 10, time_clk[0] % 10, time_clk[1] / 10, time_clk[1] % 10, time_clk[2] / 10, time_clk[2] % 10);
			}
		}
	}
	if (key4 == 0)
	{
		delayms(200);
		if (key4 == 0)
		{
			buff = 1;
		}
	}
}
uchar keyscan()//矩阵键盘扫描函数
{
	keyvalue = 99;
	P3 = 0xfe;
	temp = P3;
	temp = temp & 0xf0;//判断是否还等于0xf0
	while (temp != 0xf0)
	{
		delayms(5);
		temp = P3;
		temp = temp & 0xf0;
		while (temp != 0xf0)
		{
			temp = P3;
			switch (temp)
			{
			case 0xee: {keyvalue = 0; keydown = 1; break; }
			case 0xde: {keyvalue = 1; keydown = 1; break; }
			case 0xbe: {keyvalue = 2; keydown = 1; break; }
			case 0x7e: {keyvalue = 3; keydown = 1; break; }
			}
			while (temp != 0xf0)
			{
				temp = P3;
				temp = temp & 0xf0;
			}
		}
	}
	P3 = 0xfd;
	temp = P3;
	temp = temp & 0xf0;//判断是否还等于0xf0
	while (temp != 0xf0)
	{
		delayms(5);
		temp = P3;
		temp = temp & 0xf0;
		while (temp != 0xf0)
		{
			temp = P3;
			switch (temp)
			{
			case 0xed: {keyvalue = 4; keydown = 1; break; }
			case 0xdd: {keyvalue = 5; keydown = 1; break; }
			case 0xbd: {keyvalue = 6; keydown = 1; break; }
			case 0x7d: {keyvalue = 7; keydown = 1; break; }
			}
			while (temp != 0xf0)
			{
				temp = P3;
				temp = temp & 0xf0;
			}
		}
	}
	P3 = 0xfb;
	temp = P3;
	temp = temp & 0xf0;//判断是否还等于0xf0
	while (temp != 0xf0)
	{
		delayms(5);
		temp = P3;
		temp = temp & 0xf0;
		while (temp != 0xf0)
		{
			temp = P3;
			switch (temp)
			{
			case 0xeb: {keyvalue = 8; keydown = 1; break; }
			case 0xdb: {keyvalue = 9; keydown = 1; break; }
			case 0xbb: {keyvalue = 10; keydown = 1; break; }
			case 0x7b: {keyvalue = 11; keydown = 1; break; }
			}
			while (temp != 0xf0)
			{
				temp = P3;
				temp = temp & 0xf0;
			}
		}
	}
	P3 = 0xf7;
	temp = P3;
	temp = temp & 0xf0;//判断是否还等于0xf0
	while (temp != 0xf0)
	{
		delayms(5);
		temp = P3;
		temp = temp & 0xf0;
		while (temp != 0xf0)
		{
			temp = P3;
			switch (temp)
			{
			case 0xe7: {keyvalue = 12; keydown = 1; break; }
			case 0xd7: {keyvalue = 13; keydown = 1; break; }
			case 0xb7: {keyvalue = 14; keydown = 1; break; }
			case 0x77: {keyvalue = 15; keydown = 1; break; }
			}
			while (temp != 0xf0)
			{
				temp = P3;
				temp = temp & 0xf0;
			}
		}
	}
	return keyvalue;
}
void display(uchar duan1, uchar duan2, uchar duan3, uchar duan4, uchar duan5, uchar duan6)
{
	display_1(0, duan1);
	delayms(1);
	display_2(1, duan2);
	delayms(1);
	display_1(2, duan3);
	delayms(1);
	display_2(3, duan4);
	delayms(1);
	display_1(4, duan5);
	delayms(1);
	display_1(5, duan6);
	delayms(1);
}

void display_1(uchar wei, uchar duan)/*用于控制数码管显示。*/
{
	DU = 1;
	P0 = segdata[duan];
	DU = 0;
	P0 = 0xff;
	WE = 1;
	P0 = bitdata[wei];
	WE = 0;
	P0 = 0x00;
}
void display_2(uchar wei, uchar duan)/*同上 段选带小数点*/
{
	DU = 1;
	P0 = segdata_dp[duan];
	DU = 0;
	P0 = 0xff;
	WE = 1;
	P0 = bitdata[wei];
	WE = 0;
	P0 = 0x00;
}
void input()/*输入 input()函数,其作用是接收用户从数字键盘输入的时间数据,并存储在数组time_In[]中*/
{
	for (i = 0; i < 8; i++)//重置为-便于下次使用
	{
		dis_arr[i] = 10;
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)//检测到按键被按下
		{
			keydown = 0;
			dis_arr[0] = keyIn;
			time_In[0] = keyIn;
			if (time_In[0] >= 0 && time_In[0] <= 2)
				break;
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)
		{
			keydown = 0;
			dis_arr[1] = keyIn;
			time_In[1] = keyIn;
			if ((time_In[1] >= 0 && time_In[1] <= 9) && (time_In[0] * 10 + time_In[1]) < 24)
				break;
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)
		{
			keydown = 0;
			dis_arr[2] = keyIn;
			time_In[2] = keyIn;
			if (time_In[2] >= 0 && time_In[2] <= 5)
				break;
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)
		{
			keydown = 0;
			dis_arr[3] = keyIn;
			time_In[3] = keyIn;
			if ((time_In[3] >= 0 && time_In[3] <= 9) && (time_In[2] * 10 + time_In[3]) < 60)
				break;
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)
		{
			keydown = 0;
			dis_arr[4] = keyIn;
			time_In[4] = keyIn;
			if (time_In[4] >= 0 && time_In[4] <= 5)
				break;
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		keyIn = keyscan();
		if (keydown == 1)
		{
			keydown = 0;
			dis_arr[5] = keyIn;
			time_In[5] = keyIn;
			if ((time_In[5] >= 0 && time_In[5] <= 9) && (time_In[4] * 10 + time_In[5]) < 60)
			{
				if (mode == 0)
				{
					time[0] = time_In[0] * 10 + time_In[1];
					time[1] = time_In[2] * 10 + time_In[3];
					time[2] = time_In[4] * 10 + time_In[5];
				}
				else if (mode == 1)
				{
					time_clk[0] = time_In[0] * 10 + time_In[1];
					time_clk[1] = time_In[2] * 10 + time_In[3];
					time_clk[2] = time_In[4] * 10 + time_In[5];
				}
				break;
			}
		}
	}
	while (1)
	{
		display(dis_arr[0], dis_arr[1], dis_arr[2], dis_arr[3], dis_arr[4], dis_arr[5]);
		if (key3 == 0)
		{
			delayms(10);
			if (key3 == 0)
			{
				EA = 1;
				break;
			}
		}
	}
}
void T0_time() interrupt 1//中断函数 此部分实现时钟的基本功能
{
	TH0 = (65536 - 45872) / 256;
	TL0 = (65536 - 45872) % 256;
	num++;
	if (num == 20)//循环20次为一秒
	{
		num = 0;
		time[2]++;//秒加一
		if (time[2] == 60)//秒到60进位
		{
			time[2] = 0;//秒清零分钟加一
			time[1]++;
			if (time[1] == 60)//分钟到60进位
			{
				time[1] = 0;//分钟清零小时加一
				time[0]++;
				soundTime();//整点报时
				if (time[0] == 24)//小时满24清零
					time[0] = 0;
			}
		}
		if ((time[0] == time_clk[0]) && (time[1] == time_clk[1]) && (time[2] == time_clk[2]))//闹钟响起
		{
			buff = 0;/*P1=0;*/
		}
	}
}
void soundTime()//蜂鸣响一次
{
	buff = 0;
	delayms(500);
	buff = 1;
}
void dsreset()//复位函数(温度传感器)初始化
{
	uint k;
	DS = 0;
	k = 103;
	while (k > 0) k--;
	DS = 1;
	k = 4;
	while (k > 0) k--;
}
bit tempreadbit(void) //读一位数据函数
{
	uint k;
	bit dat;
	DS = 0;
	k++;
	DS = 1;
	k++;//k++起延时作用
	dat = DS;
	k = 8;
	while (k > 0)k--;
	return (dat);
}
uchar tempread()//读一个字节函数
{
	uchar k, l, dat;
	dat = 0;
	for (k = 1; k <= 8; k++)
	{
		l = tempreadbit();
		dat = (l << 7) | (dat >> 1);// 读出的数据最低位在最前面,这样刚好一一个字节在DAT里
	}
	return (dat);
}
void tempwritebyte(uchar dat)//向DS18B20写一个字节数据
{
	uint k;
	uchar l;
	bit testb;
	for (l = 1; l <= 8; l++)
	{
		testb = dat & 0x01;
		dat = dat >> 1;
		if (testb)//写1
		{
			DS = 0;
			k++; k++;
			DS = 1;
			k = 8; while (k > 0)k--;
		}
		else//写0
		{
			DS = 0;
			k = 8; while (k > 0)k--;
			DS = 1;
			k++; k++;
		}
	}
}
void tempchange()//获取温度并转换
{
	dsreset();
	delayms(1);
	tempwritebyte(0xcc);//写跳过读ROM指令
	tempwritebyte(0x44);//写温度转换指令
}
uint get_temp()
{
	uchar a, b;
	dsreset();
	delayms(1);
	tempwritebyte(0xcc);
	tempwritebyte(0xbe);
	a = tempread(); //读低八位
	b = tempread();//读高八位
	temp_t = b;
	temp_t <<= 8;//两个字节组合为一个字
	temp_t = temp_t | a;
	f_temp = temp_t * 0.0625;// 温度在寄存器中为12位,分辨率为0.0625度
	temp_t = f_temp * 10 + 0.5;// 乘以10表示小数点后面只取1位,加0.5是四舍五入
	f_temp = f_temp + 0.05;
	return temp_t;// temp_t是整型
}
void display_t(char num, uchar dat)
{
	uchar k; 
	DU = 0;
	P0 = table[dat];
	DU = 1;
	DU = 0;
	WE = 0;
	k = 0XFF; 
	k = k & (~((0X01) << (num)));
	P0 = k;
	WE = 1;
	WE = 0;
	delayms(1);
}
void dis_temp(uint t)
{
	uchar k; 
	k = t / 100;//温度数值的十位
	display_t(0, k);
	k = t % 100 / 10;//温度显示的个位
	display_t(1, k + 10);
	k = t % 100 % 10;//温度显示的小数点后一位
	display_t(2, k);
}
void warn(uint s, uchar led)//蜂鸣器报警,灯闪烁
{
	uchar k; k = s;//S控制音调,LED 控制灯
	buff = 0;
	P1 = ~(led);//控制相应的灯亮
	while (k--);
	{
		dis_temp(get_temp());//温度 函数起延时作用
	}
	buff = 1;///蜂鸣器不响
	P1 = 0xff;//控制相应的灯
	k = s;
	while (k--);
	{
		dis_temp(get_temp());//温度函数起延时作用
	}
}
void deal(uint t)
{
	uchar k;
	if ((t > warn_12) && (t <= warn_11))//温度 处理函数
	{
		warn(40, 0x01);//温度大于25度, 小于27度,第一个灯亮,蜂鸣器发出“滴”声
	}

	else if (t < warn_12)//温度小于25度
	{
		warn(40, 0x03);//第一个和第二个灯亮,蜂鸣器发出“滴”声
	}
	else if (t < warn_h2 && (t > warn_h1))//温度 小于32度而大于30度
	{
		warn(40, 0x04);//第三个灯亮,蜂鸣器发出“滴”声
	}
	else if (t > warn_h2)//温度大于32度
	{
		warn(10, 0x0c);//第三个灯亮,蜂鸣器发出“滴”声
	}
	else
	{
		k = 40;//在27到30度之间只是调用显示函数延时
		while (k--)
		{
			dis_temp(get_temp());
		}
	}
}
void comm(char* parr)//串口 数据发送
{
	do
	{
		SBUF = *parr++;//发送数据
		while (!TI);//等待 发送完成标志为1
		TI = 0;//标志清零
	} while (*parr);//保持循环直到字符为'\0’
}

时间显示效果:

 温度显示效果:

 ps:温度显示可能会有些紊乱,已排除代码问题,如有不明白的可以加q:1561997914讨论。

  • 11
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 单片机C51电子钟整点报时的实现思路如下: 1. 首先,需要连接一个实时时钟模块(RTC)到单片机C51上。实时时钟模块能够提供精确的时间信息。 2. 在C51的程序中,设置一个定时器,用来定时检查当前时间,判断是否整点。 3. 在每次定时器中断发生时,读取实时时钟模块的时间,并判断是否整点。如果当前时间的分钟和秒数均为0,则表示当前为整点。 4. 如果判断为整点,将调用相应的函数进行报时操作。可以通过连接扬声器或者蜂鸣器来发出报时声音。 5. 报时函数中,可以使用C51的IO口来控制扬声器或者蜂鸣器的输出,产生报时的声音。 6. 报时函数还可以通过连接LCD显示屏,在屏幕上显示当前的整点时间。 7. 如果希望报时声音更加清晰、响亮,还可以通过连接放大器等外部电路元件来提升音量。 8. 最后,将以上所有功能整合到C51的程序中,并通过编译和下载,将程序烧录到单片机中。 通过上述步骤,就可以实现单片机C51电子钟整点报时功能。这样的电子钟不仅可以显示当前的时间,还能够在整点时刻精确地发出报时声音,为用户提供准确的时间参考。 ### 回答2: 单片机C51电子钟整点报时是通过设置定时器和中断来实现的。 首先,需要定义一个变量用来记录当前时间,可以使用一个结构体来保存时、分、秒的值。 接下来,我们需要初始化定时器和中断。选择一个适当的定时器,设置定时器的计数器初值和工作模式。同时,还需要开启定时器中断,以便定时器溢出时触发中断函数。 在中断函数中,首先判断当前时间是否为整点,如果是整点则进行报时操作。报时操作可以通过控制LED灯显示相应的数字,或者通过蜂鸣器发出相应的声音来实现。 接着,需要在主函数中添加一个无限循环,以保持程序能够一直运行。在循环中可以添加一些其他的功能,比如按键检测等。 最后,需要注意编写代码时要考虑到各种情况的处理,比如在整点报时期间如果有按键操作怎么处理等。 总之,单片机C51电子钟整点报时的实现可以通过定时器和中断来完成,通过设置定时器的计数值和工作模式以及中断函数的编写来实现整点报时功能。 ### 回答3: 单片机C51电子钟整点报时是通过设置一个定时器来实现的。首先,在程序中设置一个定时器,将其定时器中断设为1秒钟一次。然后,编写一个函数来处理定时器中断,并在其中判断是否为整点。 在处理中断函数中,通过获取当前的小时值,判断是否为整点。如果是整点,就通过显示屏或喇叭等输出设备输出相应的报时信息。可以将整点时间以字符串的形式存储在程序中,比如每个整点时间对应一个字符数组,通过判断当前时间与数组中的时间是否相等,来确定是否整点报时。 另外,为了保证准确性,可以在每个整点报时后,对定时器进行复位,并设置下一个整点时间的定时器中断。这样可以确保整点报时每次都是准确的。 此外,还可以根据需求添加其他功能,比如可以设置闹钟功能,通过编写相应的函数,在设定的时间到来时,触发相应的报警信号。 总结起来,通过单片机C51的定时器和中断处理功能,可以实现整点报时电子钟。通过编写相应的程序和函数,可以准确地判断整点时间并输出相应的报时信息,使得电子钟具备整点报时功能

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值