|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2011-2-11 21:55:15
|
显示全部楼层
/*******************************************************************
* *
* 数码管时钟 *
* *
* 工作芯片:AT89S52 晶振频率:11.0592MHz *
* 其他芯片:时钟:DS1302 温度:DS18B20 *
* 显示:8位数码管 4位8段带: 和 4位普通8段 *
* 功能:4位显示 小时:分钟 4位置显示温度/定时 *
* *
* *
* 作者:阿晖 QQ13819989 最后更新:2011.02.04 *
* *
*******************************************************************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define bit7 0x80
#define bit6 0x40
#define bit5 0x20
#define bit4 0x10
#define bit3 0x08
#define bit2 0x04
#define bit1 0x02
#define bit0 0x01
//开发板
/*
sbit DQ = P3^3; //定义DS18B20端口DQ
sbit BEEP = P3^7; //蜂鸣器
sbit reset = P1^2;
sbit sclk = P1^0;
sbit io = P1^1;
sbit K1 = P1^4; //温度
sbit K2 = P1^5; //定时
*/
//实际电路
sbit DQ = P3^6; //定义DS18B20端口DQ
sbit BEEP = P3^7; //蜂鸣器
sbit sclk = P1^2; //DS1302时钟控制线
sbit io = P1^1; //DS1302时钟控制线
sbit reset = P1^0; //DS1302时钟控制线
sbit K1 = P1^3; //温度
sbit K2 = P1^4; //定时
unsigned char presence ;
unsigned char data temp_data[2] = {0x00,0x00};
//unsigned char data display[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char code ditab[16] = {0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,
0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
bit bDS18B20OK=0; //温度正常开关标记 0正常 1出错
unsigned char h = 0; //整数
unsigned char l = 0; //小数
bit flag = 1;
uint timecount = 0;
uint count = 0;
uchar data init [] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //
//秒, 分, 时, 日, 月,星期,年
uchar display_pos = 0;
//uchar code display[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
uchar code pos_data[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
//开发板 - 共阳
//uchar code led_display[]=
//{
// 0xc0, /*0*/
// 0xf9, /*1*/
// 0xa4, /*2*/
// 0xb0, /*3*/
// 0x99, /*4*/
// 0x92, /*5*/
// 0x82, /*6*/
// 0xf8, /*7*/
// 0x80, /*8*/
// 0x90 /*9*/
//};
//实际电路 - 共阴
uchar code led_display[]=
{
0x3F, /*0*/
0x06, /*1*/
0x5B, /*2*/
0x4F, /*3*/
0x66, /*4*/
0x6D, /*5*/
0x7D, /*6*/
0x07, /*7*/
0x7F, /*8*/
0x6F /*9*/
};
//uchar shift;
//按键处理
#define MAX_KEY_TIMES 80 //每次1ms 10次为10ms
uchar key_times = 0;
uchar old_key = 0; //0无按键 1上次按K1 2上次按K2
bit play_temperature = 1; //显示温度开关
uint alarmMinute = 0; //定时分钟
uint left_alarmMinute = 0; //定时剩余分钟
uint now_minute, old_minute;
bit alarm_beep = 0; //定时到:响铃开关
/**********************************************************/
void delay(unsigned int num)//延时函数
{
while( --num );
}
/********************************************************
延时子函数
/********************************************************/
void delayms(unsigned char ms)
{
unsigned char i;
while(ms--)
{
for(i = 0; i < 125; i++); //old 120
}
}
void play_hour()
{
BEEP = 0;
delayms(255);
BEEP = 1;
delayms(255);
delayms(255);
BEEP = 0;
delayms(255);
BEEP = 1;
delayms(255);
delayms(255);
BEEP = 0;
delayms(255);
BEEP = 1;
delayms(255);
delayms(255);
BEEP = 0;
delayms(255);
BEEP = 1;
delayms(255);
delayms(255);
BEEP = 0;
delayms(255);
delayms(255);
delayms(255);
delayms(255);
BEEP = 1;
}
/**********************************************************/
Init_DS18B20(void)//初始化ds1820
{
DQ = 1; //DQ复位
delay(8); //稍做延时
DQ = 0; //单片机将DQ拉低
delay(90); //精确延时 大于 480us
DQ = 1; //拉高总线
delay(8);
presence = DQ; //如果=0则初始化成功 =1则初始化失败
delay(100);
DQ = 1;
return(presence); //返回信号,0=presence,1= no presence
}
/**********************************************************/
ReadOneChar(void)//读一个字节
{
unsigned char i = 0;
unsigned char dat = 0;
for (i = 8; i > 0; i--)
{
DQ = 0; // 给脉冲信号
dat >>= 1;
DQ = 1; // 给脉冲信号
if(DQ)
dat |= 0x80;
delay(4);
}
return (dat);
}
/**********************************************************/
WriteOneChar(unsigned char dat)//写一个字节
{
unsigned char i = 0;
for (i = 8; i > 0; i--)
{
DQ = 0;
DQ = dat&0x01;
delay(5);
DQ = 1;
dat>>=1;
}
}
/*********************************************************/
Read_Temperature(void)//读取温度
{
Init_DS18B20();
if(presence==1)
{ bDS18B20OK = 1;} //DS18B20不正常,蜂鸣器报警
else
{
bDS18B20OK=0;
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
temp_data[0] = ReadOneChar(); //温度低8位
temp_data[1] = ReadOneChar(); //温度高8位
}
}
/*********************************************************/
Disp_Temperature()//显示温度
{
/*
l = ditab[temp_data[0]&0x0f]; //查表得小数位的值
display[4] = l + 0x30;
display[3] = '.';
h = ((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);
display[0] = (h / 100) + 0x30;
if (display[0] == '0')
display[0] = ' ';
display[1] = ((h%100) / 10) + 0x30;
display[2] = (h % 10) + 0x30;
write_str(1,1,display);
*/
// lcd_wdat(0x00); //显示自定义字符
// lcd_wdat('C'); //显示C
}
/**********************************************************/
void write_byte(uchar inbyte)
{
uchar i;
for(i=0;i<8;i++)
{
sclk=0; //写的时候低电平改变数据
if(inbyte&0x01)
io=1;
else
io=0;
sclk=1; //写的时候高电平,把数据写入ds1302
_nop_();
inbyte=inbyte>>1;
}
}
/**********************************************************/
uchar read_byte() //sclk的下跳沿读数据
{
uchar i,temp=0;
io=1; //设置为输入口
for(i=0;i<7;i++)
{
sclk=0;
if(io==1)
temp=temp|0x80;
else
temp=temp&0x7f;
sclk=1; //产生下跳沿
temp=temp>>1;
}
return (temp);
}
/**********************************************************/
// 往ds1302的某个地址写入数据
/**********************************************************/
void write_ds1302(uchar cmd,uchar indata)
{
sclk=0;
reset=1;
write_byte(cmd);
write_byte(indata);
sclk=0;
reset=0;
}
/**********************************************************/
// 读ds1302某地址的的数据
/**********************************************************/
uchar read_ds1302(uchar addr)
{
uchar backdata;
sclk=0;
reset=1;
write_byte(addr); //先写地址
backdata=read_byte(); //然后读数据
sclk=0;
reset=0;
return (backdata);
}
/**********************************************************/
// 设置初始时间
/**********************************************************/
void set_ds1302(uchar addr,uchar *p,uchar n) //写入n个数据
{
write_ds1302(0x8e,0x00); //写控制字,允许写操作
for(;n>0;n--)
{
write_ds1302(addr,*p);
p++;
addr=addr+2;
}
write_ds1302(0x8e,0x80); //写保护,不允许写
}
/**********************************************************/
// 读取当前时间
/**********************************************************/
void read_nowtime(uchar addr,uchar *p,uchar n)
{
for(;n>0;n--)
{
*p=read_ds1302(addr);
p++;
addr=addr+2;
}
}
/**********************************************************/
// 初始化DS1302
/**********************************************************/
void init_ds1302()
{
reset=0;
sclk=0;
write_ds1302(0x80,0x00);
// write_ds1302(0x90,0xa6); //一个二极管+4K电阻充电
write_ds1302(0x90,0x00); //禁止涓流充电
write_ds1302(0x8e,0x80); //写保护控制字,禁止写
}
/**********************************************************/
// Time0中断函数
/**********************************************************/
void Time0(void) interrupt 1 using 0
{
uchar disp[8]; //8位数码管
EA = 0;
//按键处理
if (K2 == 0) //定时 按下K2
{
if (old_key == 2)
{
key_times ++;
if (key_times >= MAX_KEY_TIMES) //确认按下键
{
if (play_temperature) //目前显示温度模式
play_temperature = 0; //切换为定时模式
if (alarmMinute < left_alarmMinute + 1) //说明定时已经执行了不到二分钟,还可以改
{
if (alarmMinute < 999) //最大999分钟 [3位]
{
alarmMinute ++;
left_alarmMinute ++;
key_times = 0;
now_minute = ((init[1]&0xf0)>>4) * 10 + init[1]&0x0f;
old_minute = now_minute;
}
}
alarm_beep = 0; //取消报警
BEEP = 1; //关蜂鸣器
}
}
else
{
old_key = 2;
key_times = 1;
}
}
else if (K1 == 0) //温度 按下K1
{
if (old_key == 1)
{
key_times ++;
if (key_times >= MAX_KEY_TIMES) //确认按下键
{
if (!play_temperature) //目前显示定时模式
play_temperature = 1; //切换为温度模式
alarmMinute = 0;
left_alarmMinute = 0;
key_times = 0;
alarm_beep = 0; //取消报警
BEEP = 1; //关蜂鸣器
}
}
else
{
old_key = 1;
key_times = 1;
}
}
else
key_times = 0;
//半秒标志
timecount ++;
if(timecount > 499) //500ms
{
timecount = 0;
flag = ~flag;
}
count ++;
count ++;
if (count > 60000)
count = 0;
//温度处理
if (count % 10000 == 0) // 10秒
{
if (play_temperature) //处理温度
{
Read_Temperature();
if (bDS18B20OK == 1) //18B20 err
{
h = 0x00;
l = 0x00;
}
else
{
h = ((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);
l = ditab[temp_data[0]&0x0f]; //查表得小数位的值
}
}
}
//时间处理 定时处理
if (count % 10000 == 0) // 10秒
{
read_nowtime(0x81,init,7); //读出当前时间,读出7个字节
if (!play_temperature) //处理定时
{
now_minute = ((init[1]&0xf0)>>4) * 10 + init[1]&0x0f;
if (now_minute != old_minute) //分钟发生变化,说明过了一分钟了
{
if (left_alarmMinute > 0)
left_alarmMinute --;
old_minute = now_minute;
}
if (left_alarmMinute == 0) //定时到!!! 持续响铃
alarm_beep = 1;
}
}
//响铃控制
if (alarm_beep)
{
if (flag)
BEEP = 0;
else
BEEP = 1;
}
//数码管 段选
if (display_pos == 0)
P0 = led_display[(init[2]&0xf0)>>4]; //小时高位
else if (display_pos == 1)
P0 = led_display[init[2]&0x0f]; //小时低位
else if (display_pos == 2)
{
P0 = led_display[(init[1]&0xf0)>>4]; //分钟高位
if (flag)
P0 |= 0x80; // add point
// P0 &= 0x7f; // add point
}
else if (display_pos == 3)
{
P0 = led_display[init[1]&0x0f]; //分钟低位
if (flag)
P0 |= 0x80; // add point
// P0 &= 0x7f; // add point
}
else if (display_pos == 4)
{
// if ((h/100) > 0)
// P0 = led_display[h/100];
// else
P0 = 0x00;
// P0 = 0xff;
}
else if (display_pos == 5)
{
if (play_temperature)
P0 = led_display[(h%100)/10];
else
{
if ((left_alarmMinute == alarmMinute) || (flag && left_alarmMinute != alarmMinute))
{
if (left_alarmMinute >= 100)
P0 = led_display[left_alarmMinute/100];
else
P0 = 0x00;
// P0 = 0xff;
}
else
P0 = 0x00;
// P0 = 0xff;
}
}
else if (display_pos == 6)
{
if (play_temperature)
{
P0 = led_display[h%10];
P0 |= 0x80; // add point
// P0 &= 0x7f; // add point
}
else
{
if ((left_alarmMinute == alarmMinute) || (flag && left_alarmMinute != alarmMinute))
P0 = led_display[(left_alarmMinute%100)/10];
else
P0 = 0x00;
// P0 = 0xff;
}
}
else if (display_pos == 7)
{
if (play_temperature)
P0 = led_display[l]; //查表得小数位的值
else
{
if ((left_alarmMinute == alarmMinute) || (flag && left_alarmMinute != alarmMinute))
P0 = led_display[left_alarmMinute%10];
else
P0 = 0x00;
// P0 = 0xff;
}
}
//数码管 位选
P2 = pos_data[display_pos];
// delayms(1);
//换位 每1ms中断只显示一位
display_pos ++;
if (display_pos == 4) //第4位不显示,直接跳过,这样可以提高亮度
display_pos ++;
if (display_pos > 7)
display_pos = 0;
// TH0 = 0x4c; //50ms定时
// TL0 = 0x00;
TH0 = 0xfc; //1ms定时
TL0 = 0x66;
EA = 1;
}
/*********************************************************/
void beep()
{
unsigned char i;
for (i=0;i<100;i++)
{
delay(60);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //关闭蜂鸣器
}
main()
{
uint i;
// uchar date_init[] = {0x00,0x41,0x14,0x03,0x02,0x04,0x11}; //用于设置初始时间
//秒, 分, 时, 日, 月,星期,年
P0 = 0xff;
P2 = 0xff;
// EA = 0;
TMOD = 0x01;
// TH0 = 0x4c; //50ms定时
// TL0 = 0x00;
TH0 = 0xfc; //1ms定时
TL0 = 0x66;
ET0 = 1;
TR0 = 1;
beep();
delayms(200);
beep();
delayms(200);
init_ds1302(); //初始化ds1302
// set_ds1302(0x80,date_init,7); //设置初始时间,日期,年月 第一次设置过后屏蔽掉 DS1302用备用电继续走
read_nowtime(0x81,init,7); //读出当前时间,读出7个字节
//18B20刚开始会读出很高的值,不知为什么?所以先读几次就正常了
i = 0;
while (i < 5)
{
Read_Temperature();
if (bDS18B20OK == 1) //18B20 err
{
h = 0;
l = 0;
BEEP = 0;
delayms(100);
BEEP = 1;
}
else
{
h = ((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);
l = ditab[temp_data[0]&0x0f]; //查表得小数位的值
}
delayms(200);
i ++;
}
delayms(200);
// play_hour();
EA = 1;
while (1)
{
;
/*
read_nowtime(0x81,init,7); //读出当前时间,读出7个字节
Read_Temperature();
if (bDS18B20OK == 0) //18B20 err
{
h = 0x00;
l = 0x00;
}
else
{
h = ((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);
l = ditab[temp_data[0]&0x0f]; //查表得小数位的值
}
procFlag = 0;
for (i = 0; i < 50; i ++)
delayms(200);
*/
}
} |
|