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