结合前几天来写过的文章, 今天总算写了一个功能较多的应用 - 多功能时钟, 集时钟, 秒表, 温度计一体.
基础文章:
1.
单片机练习 - DS18B20温度转换与显示 2.
用C51编写单片机延时函数 3.
单片机练习 - 定时器 4.
单片机练习 - 计时器 实验板:
TX-1B实验板
6位数码管与单片机的连接电路图
![](data/attach/1904/txqmirr8zc641x9rxrbmt4vrl815o05v.jpg)
按键S2, S3与单片机的连接电路图: 其中S2与P3.4连, S3与P3.5连接...
![](https://images.cnblogs.com/cnblogs_com/fengmk2/S2S3S4S5_SCM.JPG)
DS18B20与单片机连接电路图:
![](https://images.cnblogs.com/cnblogs_com/fengmk2/DS18B20.gif)
具体按键功能分配请看源代码注释部分:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
多功能时钟
1
//多功能时钟, 精确到小数0.01秒, 即10ms
2
//功能: 时钟, 秒表, 温度计
3![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
4![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//*
5
S5键为功能选择键, 上电默认使用时钟功能
6
功能顺序为: 时钟, 温度计, 秒表
7![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
mode = 1. 时钟(每次掉电后都要重新设置时间)
9
1)当选中时钟功能时, 具体按键功能如下:
10![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
2)可设置时分秒, 时利用发光二极管显示, 分秒用数码管显示
12![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
3)时钟: 采用定时器0计时, 工作方式1
14![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
mode = 2. 时钟设置模式
16
当选中时钟设置模式
17
S2为位选, S3为增加选中位的值
18
S4确定更改, S5放弃更改, 进入秒表模式
19![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
mode = 3. 秒表
21
1)当选中秒表功能时, 具体按键功能如下:
22
S2为开始/暂停, S3为清零
23![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24
2)采用定时器1计时, 工作方式1
25![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
mode = 4. 温度计
27
1)利用DS18B20检测环境温度;
28
2)最小温度值为0.01℃, 可表示温度范围: -55℃~+125℃
29![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
*/
31![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32
#include <reg52.H>
33
#include <intrins.H>
34
#include <math.h>
35![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
36
//0-F数码管的编码(共阴极)
37![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
unsigned char code table[]=
{0x3f,0x06,0x5b,0x4f,0x66,
38
0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
39
//0-9数码管的编码(共阴极), 带小数点
40![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
unsigned char code tableWidthDot[]=
{0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd,
41
0x87, 0xff, 0xef};
42![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
43
sbit wela = P2^7; //数码管位选
44
sbit dula = P2^6; //数码管段选
45
sbit ds = P2^2;
46
unsigned char th, tl, mode = 1; //mode存放功能模式, 默认在模式1 时钟
47
unsigned char clockPosition = 0; //时钟设置模式下, 光标所在的位置; 默认在0
48
unsigned char clockTmp = 0; //用于时钟模式下临时计数
49
bit clockTmpBit = 0; //用于时钟模式下临时标志位
50![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
51
//秒4字节, 分2字节, 时1字节
52![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
unsigned char datas[] =
{0, 0, 0, 0, 0, 0, 0};//保存计时器数据
53![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
unsigned char clockDatas[] =
{0, 0, 0, 0, 0, 0, 0};//保存时钟数据
54
unsigned char * values = clockDatas; //根据mode选择适当的数据数组指针
55
int tempValue; //存放温度值
56
unsigned char tempCount = 0; //用于记录显示了多少次温度值, 用于定时
57![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
58
sbit S2 = P3^4; //键S2, 作开始/暂停
59
sbit S3 = P3^5; //键S3, 清零
60
sbit S4 = P3^6; //键S4
61
sbit S5 = P3^7; //键S5
62![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
unsigned char tmpDatas[] =
{0, 0, 0, 0, 0, 0, 0}; //存放临时设置值
63
unsigned char icount;
64![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
65
//延时函数, 对于11.0592MHz时钟, 例i=5,则大概延时5ms.
66
void delay(unsigned int i)
67![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
68
unsigned int j;
69
while(i--)
70![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
71
for(j = 0; j < 125; j++);
72
}
73
}
74![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
75![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//***********************温度计模式******************************/
76![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
77
//初始化DS18B20
78
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
79
void dsInit()
80![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
81
//对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于为8us
82
unsigned int i;
83
ds = 0;
84
i = 100; //拉低约800us, 符合协议要求的480us以上
85
while(i>0) i--;
86
ds = 1; //产生一个上升沿, 进入等待应答状态
87
i = 4;
88
while(i>0) i--;
89
}
90![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
91
void dsWait()
92![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
93
unsigned int i;
94
while(ds);
95
while(~ds); //检测到应答脉冲
96
i = 4;
97
while(i > 0) i--;
98
}
99![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
100
//向DS18B20读取一位数据
101
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
102
//之后DS18B20则会输出持续一段时间的一位数据
103
bit readBit()
104![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
105
unsigned int i;
106
bit b;
107
ds = 0;
108
i++; //延时约8us, 符合协议要求至少保持1us
109
ds = 1;
110
i++; i++; //延时约16us, 符合协议要求的至少延时15us以上
111
b = ds;
112
i = 8;
113
while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
114
return b;
115
}
116![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
117
//读取一字节数据, 通过调用readBit()来实现
118
unsigned char readByte()
119![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
120
unsigned int i;
121
unsigned char j, dat;
122
dat = 0;
123
for(i=0; i<8; i++)
124![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
125
j = readBit();
126
//最先读出的是最低位数据
127
dat = (j << 7) | (dat >> 1);
128
}
129
return dat;
130
}
131![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
132
//向DS18B20写入一字节数据
133
void writeByte(unsigned char dat)
134![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
135
unsigned int i;
136
unsigned char j;
137
bit b;
138
for(j = 0; j < 8; j++)
139![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
140
b = dat & 0x01;
141
dat >>= 1;
142
//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
143
if(b)
144![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
145
ds = 0;
146
i++; i++; //拉低约16us, 符号要求15~60us内
147
ds = 1;
148
i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
149
}
150
else //写"0", 将DQ拉低60us~120us