求大侠给小弟编写一个电子钟的源程序

(1).具有时间设置(小时和分钟)、闹钟时间设置、闹钟开、闹钟关功能。
(2)数字显示小时、分钟,有AM、PM指示器,闹钟就绪灯,蜂鸣器。
(3)键盘切换现场环境温度显示。(0~60℃误差1℃)
单片机采用STC12C5A60S2 +12MHZ晶振 数码管:4位共阳型 DS18B20温度传感器
DS1302时钟芯片+32.768MHZ晶振 蜂鸣器 AM,PM闹铃指示灯,高分求!

第1个回答  2011-04-06
#pragma ot(6,SIZE)
#include <REGX51.H>
#include <intrins.h>
#define ErrorCount 10

//IIC总线名称
sbit SDA=P3^1;
sbit SCL=P3^0;
//定义一个枚举
enum EepromType {M2401,M2402,M2404,M2408,M2416,M2432,M2464,M24128,M24256};
enum EepromType EEPROM_Type;
//对应芯片容量
unsigned int M24_N[]={0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF}; //M24_N[EEPROM_Type]

//////////////////IIC总线操作函数开始/////////////////////////
/*****************启动总线**********************/
void I2CStart(void){
SCL=0; //锁住总线
SDA=1; SCL=1; //准备
_nop_();_nop_();_nop_();
SDA=0; //起动
_nop_();_nop_();_nop_();_nop_();
SCL=0; //准备发送
SDA=1;
}
/*****************停止I2C总线****************/
void I2CStop(void){
SCL=0; //准备
SDA=0;
SCL=1;
_nop_();_nop_ ();_nop_();
SDA=1; //停止总线
_nop_();_nop_();_nop_();
SCL=0; //锁住总线
}
/**************检查应答位*******************/
bit I2CRecAck(void){
SCL=0;
SDA=1;
SCL=1;
_nop_();_nop_();_nop_();_nop_();
CY=SDA; //因为返回值总是放在CY中的
SCL=0;
return(CY);
}
/***************对I2C总线产生应答*******************/
void I2CAck(void){
SDA=0;
SCL=1;
_nop_();_nop_();_nop_();_nop_();
SCL=0;
_nop_();
SDA=1;
}
/*****************不对I2C总线产生应答***************/
void I2CNoAck(void){
SDA=1;
SCL=1;
_nop_();_nop_();_nop_();_nop_();
SCL=0;
}
/*******************向I2C总线写数据*********************/
void I2CSendByte(unsigned char sendbyte){
unsigned char data j=8;
for(;j>0;j--){
SCL=0;
sendbyte<<=1; //无论C51怎样实现这个操作,始终会使CY=sendbyte^7;
SDA=CY;
SCL=1;
}
SCL=0;
}
/****************从I2C总线上读数据子程序****************/
unsigned char I2CReceiveByte(void){
register receivebyte,i=8;
SCL=0;
while(i--){
SCL=1;
receivebyte=(receivebyte<<1)|SDA;
SCL=0;
}
return(receivebyte);
}
/***********一个简单延时程序****************/
void Delay_E(unsigned int DelayCount){
while(DelayCount--);
}
/**************24XX读写主函数*****************************************
DataBuff 为读写数据输入/输出缓冲区的首址
ByteQuantity 为要读写数据的字节数量
Address 为EEPROM的片内地址
ControlByte 为EEPROM的控制字节,具体形式为(1)(0)(1)(0)(A2)(A1)(A0)(R/W),其中R/W=1,
表示读操作,R/W=0为写操作,A2,A1,A0为EEPROM的页选或片选地址;
EEPROM_Type 为枚举变量,需为M2401至M24256中的一种,分别对应24C01至24C256;
函数返回值: 位变量,1=次操作失效,0=操作成功;
ErrorCount 为允许最大次数,若出现ErrorCount次操作失效后,则函数中止操作,并返回1
SDA和SCL由用户自定义,这里暂定义为P0^0和P0^1;
其余的用户不用管,只要把只子程序放在你的程序中并调用它就可以了;
*******************************************************************************/

bit RW24XX(unsigned char *DataBuff, unsigned char ByteQuantity, unsigned int Address,unsigned char ControlByte, enum EepromType EEPROM_Type)
{
unsigned char data j,i=ErrorCount;
bit errorflag=1;
while(i--){
I2CStart();
I2CSendByte(ControlByte&0xfe);
if(I2CRecAck()) continue;
if(EEPROM_Type>M2416){
I2CSendByte((unsigned char)(Address>>8));
if(I2CRecAck()) continue;
}
I2CSendByte((unsigned char)Address);
if(I2CRecAck()) continue;
if(!(ControlByte&0x01)){
j=ByteQuantity;
errorflag=0; //********clr errorflag
while(j--){
I2CSendByte(*DataBuff++);
if(!I2CRecAck()) continue;
errorflag=1;
break;
}
if(errorflag==1) continue;
break;
}else{
I2CStart();
I2CSendByte(ControlByte);
if(I2CRecAck()) continue;
while(--ByteQuantity){
*DataBuff++=I2CReceiveByte();
I2CAck();
}
*DataBuff=I2CReceiveByte(); //read last byte data
I2CNoAck();
errorflag=0;
break;
}
}
I2CStop();
if(!(ControlByte&0x01)){
Delay_E(1000);
}
return(errorflag);
}
上面是电子钟带闹铃的
/************************************/
/*http://www.saxmcu.com */
/*DS1302测试程序 */
/*目标器件:AT89S51 */
/*晶振:11.0592MHZ */
/*编译环境:Keil 7.50A */
/************************************/

/*********************************包含头文件********************************/
#include "reg51.h"
#include <intrins.h>

/*********************************端口定义**********************************/
sbit DS1302_CLK = P1^0;
sbit DS1302_IO = P1^1;
sbit DS1302_RST = P1^2;

/*******************************共阳LED段码表*******************************/
unsigned char code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

/******************************定义全局变量*********************************/
unsigned char second,minute,hour,week,day,month,year; //秒、分、时、星期、日、月、年
unsigned char time[]={0x06,0x03,0x14,0x03,0x12,0x30,0x00}; //初始时间数组
/****************************************************************************
函数功能:数码管扫描延时子程序
入口参数:
出口参数:
****************************************************************************/
void delay1(void)
{
int k;
for(k=0;k<400;k++);
}

/****************************************************************************
函数功能:数码管显示子程序
入口参数:k
出口参数:
****************************************************************************/
void display(void)
{
P2=0xfe;
P0=tab[hour/16];
delay1();

P2=0xfd;
P0=tab[hour%16];
delay1();

P2=0xfb;
P0=0xbf; //显示"-"
delay1();

P2=0xf7;
P0=tab[minute/16];
delay1();

P2=0xef;
P0=tab[minute%16];
delay1();

P2=0xdf;
P0=0xbf; //显示"-"
delay1();

P2=0xbf;
P0=tab[second/16];
delay1();

P2=0x7f;
P0=tab[second%16];
delay1();
}

/*****************************************************************************
函数功能:向DS1302送一字节数据子程序
入口参数:
出口参数:
*****************************************************************************/
void InputByte(unsigned char byte1)
{
char i;
for(i=8;i>0;i--)
{
DS1302_IO=(bit)(byte1&0x01);
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;
byte1>>=1;
}
return;
}

/*****************************************************************************
函数功能:读DS1302一个字节子程序
入口参数:
出口参数:
*****************************************************************************/
unsigned char outputbyte(void)
{
unsigned char i;
unsigned ucdat=0;
for(i=8;i>0;i--)
{
DS1302_IO=1;
ucdat>>=1;
if(DS1302_IO)ucdat|=0x80;
DS1302_CLK=1;
_nop_();
DS1302_CLK=0;
}
return(ucdat);
}

/*****************************************************************************
函数功能:向DS1302某地址写一字节数据子程序
入口参数:addr,TDat
出口参数:
*****************************************************************************/
void write_ds1302(unsigned char addr,unsigned char TDat)
{
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
InputByte(addr);
_nop_();
InputByte(TDat);
DS1302_CLK=1;
_nop_();
DS1302_RST=0;
}

/*****************************************************************************
函数功能:读DS1302地址子程序
入口参数:add
出口参数:timedata
*****************************************************************************/
unsigned char read_ds1302(unsigned char addr)
{
unsigned char timedata;
DS1302_RST=0;
_nop_();
DS1302_CLK=0;
_nop_();
DS1302_RST=1;
InputByte(addr);
timedata=OutputByte();
DS1302_CLK=1;
_nop_();
DS1302_RST=0;
return(timedata);
}

/*****************************************************************************
函数功能:初始化DS1302子程序
入口参数:time[](全局变量)
出口参数:
*****************************************************************************/
void initial_ds1302()
{
write_ds1302(0x8e,0x00); //写保护寄存器,在对时钟或RAM写前WP一定要为0
write_ds1302(0x8c,time[0]); //年
write_ds1302(0x88,time[1]); //月
write_ds1302(0x86,time[2]); //日
write_ds1302(0x8A,time[3]); //星期
write_ds1302(0x84,time[4]); //时
write_ds1302(0x82,time[5]); //分
write_ds1302(0x80,time[6]); //秒
write_ds1302(0x8e,0x80); //写保护寄存器
}

/*****************************************************************************
函数功能:读DS1302时间子程序
入口参数:
出口参数:全局变量(second,minute,hour,week,day,month,year)
*****************************************************************************/
void read_time()
{
second=read_ds1302(0x81); //秒寄存器
minute=read_ds1302(0x83); //分
hour=read_ds1302(0x85); //时
week=read_ds1302(0x8B); //星期
day=read_ds1302(0x87); //日
month=read_ds1302(0x89); //月
year=read_ds1302(0x8d); //年
}

/*****************************************************************************
函数功能:主程序
入口参数:
出口参数:
*****************************************************************************/
void main(void)
{
initial_ds1302(); //初始化DS1302
while(1)
{
read_time(); //读取时间
display(); //显示时间
}
}

#include <reg51.h>

sbit DQ = P3^3; //定义DS18B20端口DQ
sbit BEEP=P3^7 ;

unsigned char presence ;

unsigned char code LEDData[ ] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0xff};
unsigned char data temp_data[2] = {0x00,0x00};
unsigned char data display[5] = {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};
void beep();
sbit DIN = P0^7; //小数点
bit flash=0; //显示开关标记

/**********************************************************/
void Delay(unsigned int num)//延时函数
{
while( --num );
}

/**********************************************************/
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)
{ beep();flash=1;} //DS18B20不正常,蜂鸣器报警
else
{
flash=0;
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换

Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器

temp_data[0] = ReadOneChar(); //温度低8位
temp_data[1] = ReadOneChar(); //温度高8位
}
}
/*********************************************************/
Disp_Temperature()//显示温度
{
unsigned char n=0;

display[4]=temp_data[0]&0x0f;
display[0]=ditab[display[4]]; //查表得小数位的值

display[4]=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);
display[3]=display[4]/100;
display[1]=display[4]%100;
display[2]=display[1]/10;
display[1]=display[1]%10;

if(!display[3]) //高位为0,不显示
{
display[3]=0x0a;
if(!display[2]) //次高位为0,不显示
display[2]=0x0a;
}

P0 = 0xc6; //显示 C
P2 = 0x7f;
Delay(300);

P0 = 0x9c; //显示 °
P2 = 0xbf;
Delay(300);

P0 =LEDData[display[0]] ; //显示小数位
P2 = 0xdf;
Delay(300);

P0 =LEDData[display[1]]; //显示个位
DIN = 0;
P2 = 0xef;
Delay(300);

P0 =LEDData[display[2]]; //显示十位
P2 = 0xf7;
Delay(300);

P0 =LEDData[display[3]]; //显示十位
P2 = 0xfb;
Delay(300);

P2 = 0xff; //关闭显示
}

/*********************************************************/
void beep()
{
unsigned char i;
for (i=0;i<100;i++)
{
Delay(60);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //关闭蜂鸣器
}

/*********************************************************/
void main(void)
{
while(1)
{
Read_Temperature();
if(flash==0)
{Disp_Temperature();}
else P2 = 0xff ; //DS18B20不正常,关闭显示
}
}

/*********************************************************/
三个自己改一下吧,C函数调用就可以了,自己加按键吧本回答被提问者采纳
相似回答