IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 51单片机入门——(新)简易数字时钟 -> 正文阅读

[嵌入式]51单片机入门——(新)简易数字时钟

设计要求

  1. 实现正确稳定地显示小时(两位数)、分钟(两位数)、秒钟(两位数),同时数码管应无闪烁问题。
  2. 通过按键分别实现时、分信息的调整,方便用户对时间的校准。
  3. 加入闹铃功能在(本设计中用LED代替)。

原理图

在这里插入图片描述

按键部分介绍

在这里插入图片描述
key1用于切换时分秒的加减。例:第一次按下后,按key2\key3时“秒”加\减,第二次按下后,按key2\key3时“分”加\减,第三次按下后,按key2\key3时“时”加\减,第四次按下后,按key2\key3不起作用,依次循环。

key2用于加。

key3用于减。

key4用于切换时间显示和闹钟显示切换。

代码解析

mian.c

#include <reg52.h>
#include "SMG.H"

sbit KEY1 = P3^0;
sbit KEY2 = P3^1;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;  
sbit LED = P3^4;

uchar T0RH = 0 ; // T0 重载值的高字节
uchar T0RL = 0 ; // T0 重载值的低字节

uchar sec =10, min = 10, hour = 10; // 初始化时分秒
uchar alarmSec, alarmMin, alarmHour; // 闹铃时间
bit alarm = 0; // 闹铃标志位
bit key1,key2,key3,key4; // 按键标志位
uchar b = 0; // 切换标志位

void ConFigTimer0(uchar ms);
void LedDriver();
void KeyDriver();

void main()
{
	EA = 1;
	ConFigTimer0(2);
	while (1)
	{
		LedDriver();
		KeyDriver();
		(alarmMin == min && alarmHour == hour) ? (LED = 1) : (LED = 0);
	}
}

void LedDriver()
{
	static unsigned char i;
	if (!alarm)
	{
		switch (i)
		{
			case 0 : ledBuff[0] = ledChar[sec % 10]; break;
			case 1 : ledBuff[1] = ledChar[sec / 10]; break;
			case 2 : ledBuff[2] = ledChar[10]; break;
			case 3 : ledBuff[3] = ledChar[min % 10]; break;
			case 4 : ledBuff[4] = ledChar[min / 10]; break;
			case 5 : ledBuff[5] = ledChar[10]; break;
			case 6 : ledBuff[6] = ledChar[hour % 10]; break;
			case 7 : ledBuff[7] = ledChar[hour / 10]; break;			
		}	
	}
	else
	{
		switch (i)
		{
			case 0 : ledBuff[0] = ledChar[alarmSec % 10]; break;
			case 1 : ledBuff[1] = ledChar[alarmSec / 10]; break;
			case 2 : ledBuff[2] = ledChar[10]; break;
			case 3 : ledBuff[3] = ledChar[alarmMin % 10]; break;
			case 4 : ledBuff[4] = ledChar[alarmMin / 10]; break;
			case 5 : ledBuff[5] = ledChar[10]; break;
			case 6 : ledBuff[6] = ledChar[alarmHour % 10]; break;
			case 7 : ledBuff[7] = ledChar[alarmHour / 10]; break;			
		}
	}
	i ++;
	i &= 0x07;
}
	
void KeyDriver()
{

	if (KEY1 == 0 && key1 == 0)
	{
		key1 = 1;
	}
	else if (KEY1 == 1 && key1 == 1)
	{
		key1 = 0;
		b ++;
		b &= 0x03;
	}

	if (KEY2 == 0 && key2 == 0)
	{
		key2 = 1;
	}
	else if (KEY2 == 1 && key2 == 1 )
	{
		key2 = 0;
		if(!alarm)
		{
			switch (b)
			{
				case 1 : sec ++; break;
				case 2 : min ++; break;
				case 3 : hour ++; break;
			}
		}
		else
		{
			switch (b)
			{
				case 1 : alarmSec ++; break;
				case 2 : alarmMin ++; break;
				case 3 : alarmHour ++; break;
			}
		}	
	}

	if (KEY3 == 0 && key3 == 0)
	{
		key3 = 1;
	}
	else if (KEY3 == 1 && key3 == 1 )
	{
		key3 = 0;
		if(!alarm)
		{
			switch (b)
			{
				case 1 : sec --; break;
				case 2 : min --; break;
				case 3 : hour --; break;
			}
		}
		else
		{
			switch (b)
			{
				case 1 : alarmSec --; break;
				case 2 : alarmMin --; break;
				case 3 : alarmHour --; break;
			}
		}	
	}

	if (KEY4 == 0 && key4 == 0)
	{
		key4 = 1;
	}
	else if (KEY4 == 1 && key4 == 1)
	{
		key4 = 0;
		alarm = ~alarm;
	}

}

/* 配置并启动T0 ,12MHz */
void ConFigTimer0(uchar ms)
{
	ulong tmp ;

	tmp = 12000000 / 12;
	tmp = (tmp * ms) / 1000;
	tmp = 65536 - tmp;
	tmp += 2;
	T0RH = (uchar)(tmp >> 8);
	T0RL = (uchar)tmp;
	TMOD &= 0xF0;
	TMOD |= 0x01;
	TH0 = T0RH;
	TL0 = T0RL;
	ET0 = 1;
	TR0 = 1;
}

void InterruptTimer0() interrupt 1 
{
	uint i;
	TH0 = T0RH;
	TL0 = T0RL;
	LedScan();
	i ++;
	if (i >= 500)
	{
		i = 0;
		sec ++;
		if (sec >= 60)
		{
			sec = 0;
			min ++;
			if (min >= 60)
			{
				min = 0;
				hour ++;
				if (hour >= 24)
					hour = 0;
			}
		}
	}
} 

SMG.H

#ifndef _SMG_H_
#define _SMG_H_

#include<REG52.h>

typedef unsigned char uchar ;
typedef unsigned int uint ;
typedef	unsigned long ulong ;

extern uchar ledChar[12], ledBuff[8];

extern void LedScan();

#endif

SMG.C

#include"SMG.H"

uchar ledChar[12] = { //共阴极数码管显示字符转换表
	0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x40, 0x00
};

uchar ledBuff[8] = { //数码管显示缓冲区
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* 数码管动态扫描刷新函数,需在定时中断中调用 */
void LedScan()
{
	static uchar i = 0; //动态扫描的索引
 想·
	P0 = ledChar[11]; //显示消隐
	P2 = ~(0x80 >> i);
	P0 = ledBuff[i];
	i ++;
	i &= 0x07;
}

在学习数码管动态扫描的时候,为了方便大家理解,我们程序写的细致一些,给大家引入了 switch 的用法,随着编程能力与领悟能力的增强,我们在编程上也可以改进一下逻辑算法,让程序变的更简洁。这种逻辑算法,通常不是靠学一下可以全部掌握的,而是通过不断的编写程序以及研究他人程序的过程中一点点积累起来的。

前边动态扫描刷新函数我们是这么写的:

P0 = 0x00;
switch (i)
	{
		case 0 : P2 = 0xfe; P0 = ledTemp[0]; break;
		case 1 : P2 = 0xfd; P0 = ledTemp[1]; break;
		case 2 : P2 = 0xfb; P0 = ledTemp[2]; break;
		case 3 : P2 = 0xf7; P0 = ledTemp[3]; break;
		case 4 : P2 = 0xef; P0 = ledTemp[4]; break;
		case 5 : P2 = 0xdf; P0 = ledTemp[5]; break;
		case 6 : P2 = 0xbf; P0 = ledTemp[6]; break;
		case 7 : P2 = 0x7f; P0 = ledTemp[7]; break;
	}
	i ++;
	i &= 0x07;

我们来分析每一个 case 分支,它们的结构是相同的,即改变 P2、改变索引 i、取数据写入 P0,只要把 case 后的常量与 P2和 LedBuff 的下标对比,就可以发现它们其实是相等的,那么我们可以直接把常量值(实际上就是 i 在改变前的值)赋值给它们即可,而不必写上 6 遍。还剩下一个 i 的操作,它进行了 7 次相同的++与一次归 0 操作,那么很明显用++和 if 判断就可以替代这些操作。下面就是我们据此改进后的代码:

	P0 = 0x00; //显示消隐
	P2 = ~(0x80 >> i);
	P0 = ledBuff[i];
	i ++;
	i &= 0x07;

大家看一下,P2 = ~(0x80 >> i);这行代码就利用了上面讲到的~和>>,利用右移运算符来实现1的右移,因为我们使用的是共阴数码管,所以有一个取反来实现0的右移,而 P0 的赋值也只需要一行代码,i 的处理也很简单。这样写成的代码是不是要简洁的多,也巧妙的多,而功能与前面的 switch 是一样的,同样可以完美实现动态显示刷新的功能。

而且一般的if在该代码中我们也换成了&=,例如i &= 0x07;b &= 0x03;在这里我是要让b 在 0~3 之间变化,加到 4 就自动归零,i在0~7之间变化,加到8就自动清零按照常规你可以用前面讲过的 if 语句轻松实现,但是你现在看一下这样程序是不是同样可以做到这一点呢?因为 0、1、2、3 这四个数值正好占用 2 个二进制的位(0~7刚好占3个),所以我们把一个字节的高 6 (5)位一直清零的话,这个字节的值自然就是一种到 4 (8)归零的效果了。看一下,这样一句代码比 if 语句要更为简洁吧,而效果完全一样。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-15 11:40:37  更:2022-05-15 11:41:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:17:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码