一、题目分析:
初始化需要的外设:
数码管,DS18B20,DS1302,LED,独立按键,定时器
根据按键功能建立初步的模式雏形:
二、参考代码:
主函数:
#include "Public.h"
#include "Timer.h"
#include "stdio.h"
#include "Seg.h"
#include "onewire.h"
#include "ds1302.h"
#define timer_show 1
#define timer_set 2
#define clock_set 3
#define temper_show 4
//定时器
u8 key_delay,led_delay;
u16 seg_delay;
//数码管
u8 COT[9],COD[8],PSI;
//DS1302,时分秒
u8 s_time[3]={23,59,50},r_time[3];
//
u8 mode=1,clock_show;
u8 high_limit[3]={24,60,60};
u8 count_500ms;
u16 count_ms;
u8 l_dat;
//时钟设置模式
u8 timer_mode=1;
//闹钟设置模式
u8 clock_mode=1,c_time[3];
void Key_Proc();
void SEG_Kroc();
void LED_Proc();
void main()
{
All_Close();
Timer0_Init();
DS1302_Set(s_time);
rd_temperature();
while(1)
{
Key_Proc();
SEG_Kroc();
LED_Proc();
}
}
void Key_Proc()
{
u8 key_now,key_down,key_up;
static u8 key_old;
if(key_delay)return;
key_delay = 1;
key_now = M_key();
key_down = key_now & (key_now ^ key_old);
key_up = (~key_now) & (key_now ^ key_old);
key_old = key_now;
//时钟显示模式
if(mode == timer_show)
{
if(key_down == 7)
mode = timer_set;
else if(key_down == 6)
mode = clock_set;
else if(key_down == 4)
mode = temper_show;
}
//温度显示模式
else if(mode == temper_show)
{
if(key_up == 4)
mode = timer_show;
}
//时钟设置模式
else if(mode == timer_set)
{
if(key_down == 7)
{
if(++timer_mode == 4)
{
timer_mode = 1;
mode = timer_show;
DS1302_Set(s_time);
count_500ms = 0;
}
}
else if(key_down == 5)
{
switch(timer_mode)
{
case 1:s_time[0]++;break;
case 2:s_time[1]++;break;
case 3:s_time[2]++;break;
}
if(s_time[timer_mode-1] == high_limit[timer_mode-1])
s_time[timer_mode-1] = 0;
}
else if(key_down == 4)
{
switch(timer_mode)
{
case 1:s_time[0]--;break;
case 2:s_time[1]--;break;
case 3:s_time[2]--;break;
}
if(s_time[timer_mode-1] == 255)
s_time[timer_mode-1] = high_limit[timer_mode-1]-1;
}
}
//闹钟设置模式
else if(mode == clock_set)
{
if(key_down == 6)
if(++clock_mode == 4)
{
clock_mode = 1;
mode = timer_show;
}
if(key_down == 5)
{
switch(clock_mode)
{
case 1:c_time[0]++;break;
case 2:c_time[1]++;break;
case 3:c_time[2]++;break;
}
if(c_time[clock_mode-1] == high_limit[clock_mode-1])
c_time[clock_mode-1] = 0;
}
if(key_down == 4)
{
switch(clock_mode)
{
case 1:c_time[0]--;break;
case 2:c_time[1]--;break;
case 3:c_time[2]--;break;
}
if(c_time[clock_mode-1] == 255)
c_time[clock_mode-1] = high_limit[clock_mode-1]-1;
}
}
if(clock_show)
{
if(key_down)
{
clock_show = 0;
l_dat = 0x00;
}
}
}
void SEG_Kroc()
{
u8 show_num;
if(seg_delay)return;
seg_delay = 1;
//时钟显示模式
if(mode == timer_show)
{
DS1302_Read(r_time);
sprintf(COT,"%02u-%02u-%02u",(u16)r_time[0],(u16)r_time[1],(u16)r_time[2]);
if((r_time[0] == c_time[0]) && (r_time[1] == c_time[1]) && (r_time[2] == c_time[2]))
clock_show = 1;
}
//温度显示模式
else if(mode == temper_show)
{
show_num = rd_temperature()>>4;
sprintf(COT," %2uC",(u16)show_num);
}
//时钟设置模式
else if(mode == timer_set)
{
if(count_500ms == 5)
count_500ms = 0;
count_500ms++;
if(count_500ms == 1)
sprintf(COT,"%02u-%02u-%02u",(u16)s_time[0],(u16)s_time[1],(u16)s_time[2]);
else if(count_500ms == 3)
{
switch(timer_mode)
{
case 1:sprintf(COT," -%02u-%02u",(u16)s_time[1],(u16)s_time[2]);break;
case 2:sprintf(COT,"%02u- -%02u",(u16)s_time[0],(u16)s_time[2]);break;
case 3:sprintf(COT,"%02u-%02u- ",(u16)s_time[0],(u16)s_time[1]);break;
}
}
}
//闹钟设置模式
else if(mode == clock_set)
{
if(count_500ms == 5)
count_500ms = 0;
count_500ms++;
if(count_500ms == 1)
sprintf(COT,"%02u-%02u-%02u",(u16)c_time[0],(u16)c_time[1],(u16)c_time[2]);
else if(count_500ms == 3)
{
switch(clock_mode)
{
case 1:sprintf(COT," -%02u-%02u",(u16)c_time[1],(u16)c_time[2]);break;
case 2:sprintf(COT,"%02u- -%02u",(u16)c_time[0],(u16)c_time[2]);break;
case 3:sprintf(COT,"%02u-%02u- ",(u16)c_time[0],(u16)c_time[1]);break;
}
}
}
SEG_TSL(COT,COD);
}
void LED_Proc()
{
if(led_delay)return;
led_delay = 1;
if(clock_show)
{
if(count_ms % 200 == 0)
{
l_dat ^= 0x01;
if(count_ms == 5000)
{
count_ms = 0;
clock_show = 0;
l_dat = 0x00;
}
}
}
}
void Timer0_Isr(void) interrupt 1
{
count_ms++;
led_delay = 0;
if(++key_delay == 10)key_delay = 0;
if(++seg_delay == 500)seg_delay = 0;
SEG_Show(COD[PSI],PSI);
if(++PSI == 8)PSI = 0;
LED_Set(l_dat);
}
公共函数:
#ifndef PUBLIC_H
#define PUBLIC_H
#include <STC15F2K60S2.H>
#define u8 unsigned char
#define u16 unsigned int
void All_Close();
void LED_Set(u8 l_dat);
u8 M_key();
void Select(u8 s_dat,u8 cs);
#endif
#include "Public.h"
/*
选择工作的锁存器
*/
void Select(u8 s_dat,u8 cs)
{
P0 = s_dat;
P2 = P2 & 0x1f | (cs<<5);
P2 &= 0x1f;
}
/*
关闭无关设备
*/
void All_Close()
{
//关闭蜂鸣器和继电器
Select(0x00,5);
//关闭LED
Select(0xff,4);
}
/*
根据输入的八位数亮灯,1为亮灯
*/
void LED_Set(u8 l_dat)
{
Select(~l_dat,4);
}
/*
独立按键按键检测
*/
u8 M_key()
{
u8 i;
for(i=0;i<4;i++)
{
if(!(P3 & (0x08>>i)))
return i+4;
}
return 0;
}
定时器:
#ifndef TIMER_H
#define TIMER_H
#include "Public.h"
void Timer0_Init(void);
#endif
#include "Timer.h"
void Timer0_Init(void) //1毫秒@12MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA = 1;
}
数码管:
#ifndef SEG_H
#define SEG_H
#include "Public.h"
void SEG_TSL(u8 *input,u8 *output);
void SEG_Show(u8 COD,u8 PSI);
#endif
#include "Seg.h"
code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};
/*
将字符串转化成数码管代码
*/
void SEG_TSL(u8 *input,u8 *output)
{
u8 i;
for(i=0;i<8;i++)
{
switch(input[i])
{
case '0':output[i] = Seg_Table[0];break;
case '1':output[i] = Seg_Table[1];break;
case '2':output[i] = Seg_Table[2];break;
case '3':output[i] = Seg_Table[3];break;
case '4':output[i] = Seg_Table[4];break;
case '5':output[i] = Seg_Table[5];break;
case '6':output[i] = Seg_Table[6];break;
case '7':output[i] = Seg_Table[7];break;
case '8':output[i] = Seg_Table[8];break;
case '9':output[i] = Seg_Table[9];break;
case 'C':output[i] = Seg_Table[12];break;
case '-':output[i] = ~0x40;break;
default:output[i] = 0xff;
}
}
}
/*
数码管显示函数
*/
void SEG_Show(u8 COD,u8 PSI)
{
//消隐
Select(0xff,7);
//位选
Select(0x01<<PSI,6);
//段选
Select(COD,7);
}
DS1302:
#ifndef __DS1302_H
#define __DS1302_H
#include "Public.h"
#include <intrins.h>
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void DS1302_Set(u8 *s_time);
void DS1302_Read(u8 *r_time);
#endif
#include "ds1302.h"
//
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
SDA = temp&0x01;
temp>>=1;
SCK=1;
}
}
//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
/*
设置初始的时分秒
*/
void DS1302_Set(u8 *s_time)
{
u8 i,s_temp[3];
//处理数据
for(i=0;i<3;i++)
{
s_temp[i] = ((s_time[i]/10)<<4) | (s_time[i]%10);
}
//关闭写保护
Write_Ds1302_Byte(0x8e,0x00);
//发送数据
for(i=0;i<3;i++)
{
Write_Ds1302_Byte(0x84-i*2,s_temp[i]);
}
//开启写保护
Write_Ds1302_Byte(0x8e,0x80);
}
/*
读取时分秒
*/
void DS1302_Read(u8 *r_time)
{
u8 i;
//接收数据
for(i=0;i<3;i++)
{
r_time[i] = Read_Ds1302_Byte(0x85-i*2);
}
//处理数据
for(i=0;i<3;i++)
{
r_time[i] = ((r_time[i]>>4)*10) + (r_time[i]&0x0f);
}
}
DS18B20:
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include "Public.h"
#include "intrins.h"
sbit DQ = P1^4;
unsigned int rd_temperature(void);
#endif
#include "onewire.h"
//
void Delay_OneWire(unsigned int t)
{
u8 i;
while(t--)
for(i=0;i<10;i++);
}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
void Delay100ms() //@12MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 5;
j = 144;
k = 71;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
unsigned int rd_temperature(void)
{
u8 LSB,MSB;
//温度转化
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
//读取温度
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB = Read_DS18B20();
MSB = Read_DS18B20();
return (MSB<<8) | LSB;
}
三、收获:
建立其他模块文件时,记得在左边的Poject栏中引用该文件
烧录时记得设置内部晶振频率为12MHZ
使用onewire文件时记得修改时序
DS18B20传输数据是低位先行
读取到的DS1302数据记得进行处理
DS1302写入数据记得关闭写保护
因为每按一次模式是不会突变的,所以不同的模式之间最好用else if间隔开,实现完全独立