单片机综合练习 - 多功能时钟

2019-04-15 15:08发布

结合前几天来写过的文章, 今天总算写了一个功能较多的应用 - 多功能时钟, 集时钟, 秒表, 温度计一体.

基础文章:
1. 单片机练习 - DS18B20温度转换与显示
2. 用C51编写单片机延时函数
3. 单片机练习 - 定时器
4. 单片机练习 - 计时器

实验板: TX-1B实验板

6位数码管与单片机的连接电路图


按键S2, S3与单片机的连接电路图: 其中S2与P3.4连, S3与P3.5连接...


DS18B20与单片机连接电路图:


具体按键功能分配请看源代码注释部分:
ContractedBlock.gifExpandedBlockStart.gif多功能时钟
  1None.gif//多功能时钟, 精确到小数0.01秒, 即10ms
  2None.gif//功能: 时钟, 秒表, 温度计
  3None.gif
  4ExpandedBlockStart.gifContractedBlock.gif/**//*
  5InBlock.gifS5键为功能选择键, 上电默认使用时钟功能
  6InBlock.gif功能顺序为: 时钟, 温度计, 秒表
  7InBlock.gif
  8InBlock.gifmode = 1. 时钟(每次掉电后都要重新设置时间)
  9InBlock.gif1)当选中时钟功能时, 具体按键功能如下:
 10InBlock.gif
 11InBlock.gif2)可设置时分秒, 时利用发光二极管显示, 分秒用数码管显示
 12InBlock.gif
 13InBlock.gif3)时钟: 采用定时器0计时, 工作方式1
 14InBlock.gif
 15InBlock.gifmode = 2. 时钟设置模式
 16InBlock.gif当选中时钟设置模式
 17InBlock.gifS2为位选, S3为增加选中位的值
 18InBlock.gifS4确定更改, S5放弃更改, 进入秒表模式
 19InBlock.gif
 20InBlock.gifmode = 3. 秒表
 21InBlock.gif1)当选中秒表功能时, 具体按键功能如下:
 22InBlock.gifS2为开始/暂停, S3为清零
 23InBlock.gif
 24InBlock.gif2)采用定时器1计时, 工作方式1
 25InBlock.gif
 26InBlock.gifmode = 4. 温度计
 27InBlock.gif1)利用DS18B20检测环境温度;
 28InBlock.gif2)最小温度值为0.01℃, 可表示温度范围: -55℃~+125℃
 29InBlock.gif
 30ExpandedBlockEnd.gif*/

 31None.gif
 32None.gif#include <reg52.H>
 33None.gif#include <intrins.H>
 34None.gif#include <math.h>
 35None.gif
 36None.gif//0-F数码管的编码(共阴极)
 37ExpandedBlockStart.gifContractedBlock.gifunsigned char code table[]=dot.gif{0x3f,0x06,0x5b,0x4f,0x66,
 38ExpandedBlockEnd.gif    0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}
;
 39None.gif//0-9数码管的编码(共阴极), 带小数点
 40ExpandedBlockStart.gifContractedBlock.gifunsigned char code tableWidthDot[]=dot.gif{0xbf0x860xdb0xcf0xe60xed0xfd
 41ExpandedBlockEnd.gif    0x870xff0xef}
;
 42None.gif
 43None.gifsbit wela = P2^7;  //数码管位选
 44None.gifsbit dula = P2^6;  //数码管段选
 45None.gifsbit ds = P2^2;
 46None.gifunsigned char th, tl, mode = 1//mode存放功能模式, 默认在模式1 时钟
 47None.gifunsigned char clockPosition = 0;  //时钟设置模式下, 光标所在的位置; 默认在0
 48None.gifunsigned char clockTmp = 0//用于时钟模式下临时计数
 49None.gifbit clockTmpBit = 0//用于时钟模式下临时标志位
 50None.gif
 51None.gif//秒4字节, 分2字节, 时1字节
 52ExpandedBlockStart.gifContractedBlock.gifunsigned char datas[] = dot.gif{0000000};//保存计时器数据
 53ExpandedBlockStart.gifContractedBlock.gifunsigned char clockDatas[] = dot.gif{0000000};//保存时钟数据
 54None.gifunsigned char * values = clockDatas;  //根据mode选择适当的数据数组指针
 55None.gifint tempValue; //存放温度值
 56None.gifunsigned char tempCount = 0//用于记录显示了多少次温度值, 用于定时
 57None.gif
 58None.gifsbit S2 = P3^4;  //键S2, 作开始/暂停 
 59None.gifsbit S3 = P3^5;     //键S3, 清零
 60None.gifsbit S4 = P3^6;     //键S4
 61None.gifsbit S5 = P3^7;     //键S5
 62ExpandedBlockStart.gifContractedBlock.gifunsigned char tmpDatas[] = dot.gif{0000000};  //存放临时设置值
 63None.gifunsigned char icount;
 64None.gif
 65None.gif//延时函数, 对于11.0592MHz时钟, 例i=5,则大概延时5ms.
 66None.gifvoid delay(unsigned int i)
 67ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 68InBlock.gif    unsigned int j;
 69InBlock.gif    while(i--)
 70ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 71InBlock.gif        for(j = 0; j < 125; j++);
 72ExpandedSubBlockEnd.gif    }

 73ExpandedBlockEnd.gif}

 74None.gif
 75ExpandedBlockStart.gifContractedBlock.gif/**//***********************温度计模式******************************/
 76None.gif
 77None.gif//初始化DS18B20
 78None.gif//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
 79None.gifvoid dsInit()
 80ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 81InBlock.gif    //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于为8us
 82InBlock.gif    unsigned int i;  
 83InBlock.gif    ds = 0;
 84InBlock.gif    i = 100;   //拉低约800us, 符合协议要求的480us以上
 85InBlock.gif    while(i>0) i--;
 86InBlock.gif    ds = 1;    //产生一个上升沿, 进入等待应答状态
 87InBlock.gif    i = 4;
 88InBlock.gif    while(i>0) i--;
 89ExpandedBlockEnd.gif}

 90None.gif
 91None.gifvoid dsWait()
 92ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 93InBlock.gif     unsigned int i;
 94InBlock.gif     while(ds);  
 95InBlock.gif     while(~ds);  //检测到应答脉冲
 96InBlock.gif     i = 4;
 97InBlock.gif     while(i > 0) i--;
 98ExpandedBlockEnd.gif}

 99None.gif
100None.gif//向DS18B20读取一位数据
101None.gif//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平, 
102None.gif//之后DS18B20则会输出持续一段时间的一位数据
103None.gifbit readBit()
104ExpandedBlockStart.gifContractedBlock.gifdot.gif{
105InBlock.gif    unsigned int i;
106InBlock.gif    bit b;
107InBlock.gif    ds = 0;
108InBlock.gif    i++;   //延时约8us, 符合协议要求至少保持1us
109InBlock.gif    ds = 1
110InBlock.gif    i++; i++;  //延时约16us, 符合协议要求的至少延时15us以上
111InBlock.gif    b = ds;
112InBlock.gif    i = 8
113InBlock.gif    while(i>0) i--;  //延时约64us, 符合读时隙不低于60us要求
114InBlock.gif    return b;
115ExpandedBlockEnd.gif}

116None.gif
117None.gif//读取一字节数据, 通过调用readBit()来实现
118None.gifunsigned char readByte()
119ExpandedBlockStart.gifContractedBlock.gifdot.gif{
120InBlock.gif    unsigned int i;
121InBlock.gif    unsigned char j, dat;
122InBlock.gif    dat = 0;
123InBlock.gif    for(i=0; i<8; i++)
124ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
125InBlock.gif        j = readBit();
126InBlock.gif        //最先读出的是最低位数据
127InBlock.gif        dat = (j << 7| (dat >> 1);
128ExpandedSubBlockEnd.gif    }

129InBlock.gif    return dat;
130ExpandedBlockEnd.gif}

131None.gif
132None.gif//向DS18B20写入一字节数据
133None.gifvoid writeByte(unsigned char dat)
134ExpandedBlockStart.gifContractedBlock.gifdot.gif{
135InBlock.gif    unsigned int i;
136InBlock.gif    unsigned char j;
137InBlock.gif    bit b;
138InBlock.gif    for(j = 0; j < 8; j++)
139ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
140InBlock.gif        b = dat & 0x01;
141InBlock.gif        dat >>= 1;
142InBlock.gif        //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
143InBlock.gif        if(b)   
144ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
145InBlock.gif            ds = 0;
146InBlock.gif            i++; i++;  //拉低约16us, 符号要求15~60us内
147InBlock.gif            ds = 1;    
148InBlock.gif            i = 8while(i>0) i--;  //延时约64us, 符合写时隙不低于60us要求
149ExpandedSubBlockEnd.gif        }

150InBlock.gif        else  //写"0", 将DQ拉低60us~120us