专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

51单片机超级闹钟程序设计(有图)

作者:佚名   来源:本站原创   点击数:  更新时间:2010年05月31日   【字体:

/*课程设计终于弄完了,总想共享一下源代码,*/

/*遂在51hei上贴出来,大家看有什么问题吧~如果哪里写得不好还请众亲们指出哦~*/

/*---附:实物图--*/


 


 

/*===Chip:STC12C5A32S2======================*/

/*===Software:Keil 4 C51========================*/

/*===Author:梁鹏===================================*/

/*===Organization:广西民族大学07自动化===========*/

/*===Date:2010年05月26日======================*/

/*===Version:1.0===============================*/

/*===声明:本程序属原创作品,仅供学习交流,不得用于

商业用途,如需转载,请注明出处,谢谢合作!======*/

/*--------文件名:Supper_clock.C-----------*/

#include
#include
#include 
#include
#include
#include
#include
#define  KEY_PORT  P3     //按键端口
sbit  MODE_KEY=KEY_PORT^3;      //模式选择键
sbit  HOU_KEY=KEY_PORT^4;     //时增一键
sbit  MIN_KEY=KEY_PORT^5;     //分增一键
sbit  CLKON_KEY=KEY_PORT^6;    //闹钟ON/OFF控制键
sbit  BUZ_OUT=P2^3;      //蜂鸣器输出口
sbit  DS18B20_PORT=P2^2;     //DS18B20数据接口
sbit  LAMP_PORT=P2^1;      //继电器控制口 
/*=========子函数的声明==============*/
void   init();        //系统初始化
void  display_time();      //显示时间的子函数
void  display_clk();      //显示闹钟的子函数
void  judge();       //判断秒增量是否大于限定值
void  clk_judge();      //检测是否到达闹铃时间
void  beep();        //蜂鸣器响子函数
void  buzzer();        //闹铃响子函数
void  get_adc_data();      //AD采样数据及处理子函数
void  serial_judge();      //串口数据处理子函数
//void delay_ms(uint);       //MS级延时子程序
/*==========变量的声明===============*/
bit  pause_flags=0,clk_flags=0,clk_on=0,clk_on_or_off=1,flash_flags=0;
bit  clk1_off=0,clk2_off=0,clk3_off=1;  //各闹钟是否开启的变量
bit  serial_finish=0;      //串口接收结束标志位
uchar com_send,com_get;       //串口通信相关变量
uchar  hour,min,sec;       //时间变量
uchar dis_hour_clk,dis_min_clk;    //用于显示闹钟时间的变量
uchar hour_clk1,min_clk1;      //闹钟1有关变量
uchar hour_clk2,min_clk2;      //闹钟2有关变量
uchar hour_clk3,min_clk3;      //闹钟3有关变量
uchar mode_flags;        //状态标志位
uint   ovf_cnt=0;        //定时中断次数纪录
uchar first_on_flags=0;      //掉电保存变量
uint ad_data_channal7;      //ADC采样数据1
uint ad_data_channal6;      //ADC采样数据2
float vol_data,vol_data1;      //采样电压值转换
uchar send_temp[10],send_i_cnt;    //发送缓冲
/*===================================*/
/*************************************/
/*************************************/
void main()
{                
 init();          //程序初始化
 LCD_init();         //1602初始化 
 init_24c02();        //24C02掉电保存初始化
 serial_port_init();       //串行通信初始化
 first_on_flags=read_add_24c02(2);
 beep();
 if(first_on_flags!=33){        //首次上电,写首次上电标记
  write_add_24c02(2,33); 
 }
 else{
  hour  =read_add_24c02(3);
  min   =read_add_24c02(4);
  hour_clk1 =read_add_24c02(5);
  min_clk1 =read_add_24c02(6);
  hour_clk2 =read_add_24c02(7);
  min_clk2 =read_add_24c02(8);
  hour_clk3 =read_add_24c02(9);
  min_clk3 =read_add_24c02(10);
  clk1_off =read_add_24c02(11);
  clk2_off =read_add_24c02(12);
  clk3_off =read_add_24c02(13);
 }
 while(1)
 {
  get_adc_data();       //获取AD值
  display_time();       //时间显示
  judge();
 }
}
/*************************************/
/*************************************/
void init()
{ 
 hour=6;min=29;sec=55;  //初始化系统时间
 hour_clk1=6;min_clk1=30; //初始化系统时钟
 hour_clk2=6;min_clk2=31;
 hour_clk3=6;min_clk3=32;
 AURX1|=0x04;  //AD转换结果存储格式控制 
 P1ASF=1<<7;   //模拟通道选择
 P1ASF=1<<6;
 BUZ_OUT=1;   //蜂鸣器不响
 LAMP_PORT=0;  //继电器不吸合
 P0=255;    //LCD数据口状态初始化
 TCON|=0x01;   //INT0下降沿触发
 EX0=1;    //外部中断0中断允许 
 INT0=1;    //P3.2置位
 TMOD|=0x02;   //定时器0工作在方式1
 TH0=5;    //250us计数初值高八位
 TL0=5;    //250us计数初值低八位
 ET0=1;     //定时器0中断允许
 EA=1;    //全局中断允许
 TR0=1;    //定时器0开启
}
/**************************/
void display_time()
{
 Locate(1,1);
 if((mode_flags==1)&&flash_flags) LCD_str_("      ");
 else LCD_str_("Time: ");    //调整模式下,“Time:”闪烁
 LCD_2char(hour);   //显示时
 if(flash_flags&&(!pause_flags)) LCD_char(' ');
 else LCD_char(':');        //非暂停模式下,“:”闪烁
 LCD_2char(min);    //显示分
 if(flash_flags&&(!pause_flags)) LCD_char(' ');
 else LCD_char(':');
 LCD_2char(sec);    //显示秒
 LCD_str_("   ");
 if(mode_flags>0){display_clk();}   //暂停时,显示闹钟   
 else{
  Locate(2,1);
  LCD_float_(vol_data,2);
  LCD_str_("V ");
  LCD_4char(ad_data_channal7);
  LCD_str_("   ");
  Locate(2,13);
  if(!clk_on_or_off)LCD_str_("  ON"); //全局显示闹钟的ON/OFF
  else     LCD_str_(" OFF");
 } 
}
void display_clk()
{
 Locate(2,1);
 if(flash_flags&&(mode_flags>1))LCD_str_("      ");//调整模式下,“Clkx:”闪烁
 else{          
  if(mode_flags>0&&mode_flags<3)
  {LCD_str_("Clk1: ");dis_hour_clk=hour_clk1;dis_min_clk=min_clk1;}
  if(mode_flags==3)
  {LCD_str_("Clk2: ");dis_hour_clk=hour_clk2;dis_min_clk=min_clk2;}
  if(mode_flags==4)
  {LCD_str_("Clk3: ");dis_hour_clk=hour_clk3;dis_min_clk=min_clk3;}
 }//根据不同的状态,显示不同的闹钟时间
 LCD_2char(dis_hour_clk);
 LCD_char(':');
 LCD_2char(dis_min_clk);
 LCD_str_("    ");
 Locate(2,13);
 if(mode_flags<2){ //调整时间的模式下,全局显示闹钟的开或者关
  if(!clk_on_or_off)LCD_str_("  ON");
  else     LCD_str_(" OFF");
 }
 /*根据不同调闹和开关状态显示指定闹钟的开关*/ 
 if( (mode_flags==2&&!clk1_off)||
  (mode_flags==3&&!clk2_off)||
  (mode_flags==4&&!clk3_off)) LCD_str_("  ON");  
 else       LCD_str_(" OFF");
}
/**************************/
void judge()
{
 if(sec>=60){           //秒增量是否超过限定的判断
  sec=0;
  if(++min>=60){
   min=0;
   if(++hour>=24)hour=0;
  }
 }
 if(mode_flags<1) {pause_flags=0;}   //是否暂停的判断
 else    {pause_flags=1;}
 /*以下为时限判断*/
 if(hour>23)hour=0;        //调整时增量是否超限的判断
 if(min>59)min=0;
 if(hour_clk1>23) hour_clk1=0;
 if(min_clk1>59)  min_clk1=0;
 if(hour_clk2>23) hour_clk2=0;
 if(min_clk2>59)  min_clk2=0;
 if(hour_clk3>23) hour_clk3=0;
 if(min_clk3>59)  min_clk3=0;
 /*以上为时限判断*/           

 /*闹铃是否开启判断*/
 if(!clk1_off||!clk2_off||!clk3_off) clk_on_or_off=0;
 else        clk_on_or_off=1;
 /*蜂鸣器是否响判断*/
 if(!pause_flags&&!clk_on_or_off){clk_judge();} //非暂停模式下,闹钟打开情况下,检测闹钟
 if (!clk_flags)         //使用clk_flags和clk_on检测是否闹铃
 { 
  if(((hour!=hour_clk1)||(min!=min_clk1))&&
     ((hour!=hour_clk2)||(min!=min_clk2))&&
     ((hour!=hour_clk3)||(min!=min_clk3)))clk_flags=1;clk_on=0;BUZ_OUT=1;
 }
 else
 { if(clk_on){buzzer();BUZ_OUT=1;}}    //满足闹铃响所需的所有条件,发出闹铃声
 /*以下为EEPROM操作*/
 if(sec==5){//一分钟存一次
  write_add_24c02(3,hour); LCD_delay(100);  
  write_add_24c02(4,min);  LCD_delay(100);
  write_add_24c02(5,hour_clk1);LCD_delay(100);
  write_add_24c02(6,min_clk1);LCD_delay(100);
  write_add_24c02(7,hour_clk2);LCD_delay(100);
  write_add_24c02(8,min_clk2);LCD_delay(100);
  write_add_24c02(9,hour_clk3);LCD_delay(100);
  write_add_24c02(10,min_clk3);LCD_delay(100);
  write_add_24c02(11,clk1_off);LCD_delay(100);
  write_add_24c02(12,clk2_off);LCD_delay(100);
  write_add_24c02(13,clk3_off);LCD_delay(100);
 }
 /*以下为串口接收完成处理*/
 if(serial_finish){
  serial_judge();   //串口数据处理
  serial_finish=0;  //清0接收结束标志
 }
}
void clk_judge()          
{
 if(((hour==hour_clk1)&&(min==min_clk1)&&!clk1_off)||
    ((hour==hour_clk2)&&(min==min_clk2)&&!clk2_off)||
    ((hour==hour_clk3)&&(min==min_clk3)&&!clk3_off))clk_on=1;
 else{clk_on=0;}
}
void beep()
{
  uchar beep_cnt;
 for(beep_cnt=0;beep_cnt<60;beep_cnt++){
  BUZ_OUT=0;     
  LCD_delay(2);
  BUZ_OUT=1;    //确保每次闹铃结束后蜂鸣器不响
  LCD_delay(1);  
 }
}
void buzzer()
{
 uchar i;
 for(i=0;i<2;i++){
  beep();
  LCD_delay(500);
 }
}
/**************************/
void INT0_isr() interrupt 0
{
 LCD_delay(30);
 if(!INT0){
  beep();
  if(!MODE_KEY){       /*MODE_KEY*/
   if(++mode_flags>=5){
    pause_flags=0;
    mode_flags=0;
    flash_flags=0;    
   }
  }     
  if(!HOU_KEY){        /*HOU_KEY*/
   if(mode_flags==1){++hour;}          
   if(mode_flags==2){++hour_clk1;}   
   if(mode_flags==3){++hour_clk2;}
   if(mode_flags==4){++hour_clk3;}
  }
  if(!MIN_KEY){       /*MIN_KEY*/
   if(mode_flags==1){++min;}          
   if(mode_flags==2){++min_clk1;}   
   if(mode_flags==3){++min_clk2;}
   if(mode_flags==4){++min_clk3;}
  }
  if(!CLKON_KEY){
   if(mode_flags==2)clk1_off=~clk1_off;
   if(mode_flags==3)clk2_off=~clk2_off;
   if(mode_flags==4)clk3_off=~clk3_off;
  }
  clk_flags=0;       /*闹钟发生时,按下任意键停止*/
 }
 INT0=1;
}
//================================
void timer0_ovf_isr() interrupt 1
{
 if(ovf_cnt==1846)flash_flags=~flash_flags;
 if(++ovf_cnt==3691){  //12MHZ自动重载4000次为1s,11.071692HZ下为3691
  ovf_cnt=0;
  if(!pause_flags)sec++; //非暂停模式下,秒增一
  flash_flags=~flash_flags;
 }       //每间隔半秒flash_flags取反一次   
}
//================================
void receive_uart() interrupt 4
{
 if(RI){
  RI=0;
  com_get=SBUF;
  serial_finish=1;
 }
 else{
  TI=0;
 }
}
//================================ 
void serial_judge()
{
 switch(com_get){
  case 0x31:
   Uart_send_int(hour,2);
   Uart_send_(':');
   Uart_send_int(min,2);
   Uart_send_(':');
   Uart_send_int(sec,2);
   Uart_send("  \n");
   break;
  case 0x32:
   Uart_send("The brightness:");
   Uart_send_flt(vol_data1,3);
   Uart_send("V  \n");
   break;
  case 0x33:
   Uart_send("The voltage:");
   Uart_send_flt(vol_data,3);
   Uart_send("V  \n");
   break;
  case 0x34:LAMP_PORT=!LAMP_PORT;break;
  default  :
   Uart_send("Command Error! \n");
   Uart_send("1->To get the system time. \n");
   Uart_send("2->To get the brightness. \n");
   Uart_send("3->To get the voltage. \n");
   Uart_send("4->To control the 220V light ON/OFF. \n\n");
 }
 com_get=0;
}
//================================
void get_adc_data()
{
 ad_data_channal7=ADC_GET(7);
 LCD_delay(1000);
 ad_data_channal6=ADC_GET(6);
 LCD_delay(1000);
 vol_data=(float)ad_data_channal6/1024;
 vol_data*=5.0;
 vol_data1=(float)ad_data_channal7/1024;
 vol_data1*=5.0;
}
//================================
/*void delay_ms(uint xms)
{
 uint i,j;
 for(i=0;i< xms;i++)
  for(j=0;j< 990;j++);
}*/
//================================

上面是主程序,已经调试通过,下面是部分.h文件,限于篇幅,完整的代码大家可从下面的链接下载
http://www.51hei.com/ziliao/file/naozhong1602.rar
 , 只要更改一下端口便可适应于其他电路.

/*--------文件名:CLK_LCD1602.H-------*/
#ifndef  _CLK_LCD1602_H_
#define  _CLK_LCD1602_H_
#define  uint unsigned int
#define  uchar unsigned char
#define  LCM_P   P2     //LCD的控制端口
#define  LCM_DATA  P0     //LCD的数据口
#define  LCM_RS_0  LCM_P&=~(1<<5)
#define  LCM_RS_1  LCM_P|=  1<<5
#define  LCM_RW_0  LCM_P&=~(1<<6)
#define  LCM_RW_1  LCM_P|=  1<<6 
#define  LCM_EN_0  LCM_P&=~(1<<7)
#define  LCM_EN_1  LCM_P|=  1<<7
/*========================================*/
#define  LCD_str(x,y,s) Locate(x,y);LCD_str_(s);
#define  LCD_float(x,y,flt) Locate(x,y);LCD_float_(flt);
/*========================================*/
void LCD_init();     //LCM1602的初始化函数,在使用1602之前都必须调用
void Locate(uchar,uchar);   //显示定位函数
void LCD_half(uchar);   //送半字节函数
void LCD_char(uchar);   //写一个字符函数
void LCD_2char(uchar);   //显示两个字符
void LCD_4char(uint);   //显示四个字符
void LCD_cmd(uchar);    //写命令函数
void LCD_str_(uchar str[]);     //写字符串数据函数
void LCD_float_(float,uchar); //写浮点数据函数
void LCD_delay(uint);   //延时子函数
/******************************************/
/*-函数功能:液晶使用初始化---------------*/
/*-入口参数:无*/
/******************************************/
void LCD_init()
{
 LCD_cmd(0x01);
 LCD_delay(10);
 LCD_cmd(0x28);   //4位数据、双行显示、5*7(0x38为八位)
 LCM_EN_1;_nop_();_nop_();_nop_();
 LCM_EN_0;      /*此处必须加上这两句*/
 LCD_delay(10);
 LCD_cmd(0x28);
 LCD_cmd(0x06);
 LCD_cmd(0x0c);
 LCD_cmd(0x01);
 LCD_delay(10);
}
/******************************************/
/*-函数功能:显示数据定位函数-------------*/
/*-入口参数:行坐标x、列坐标y-------------*/
/******************************************/ 
void Locate(uchar x,uchar y)
{
 x&=0x01;
 LCD_cmd((x==0)?(y+0xbf):(y+0x7f));
}
/******************************************/
/*-函数功能:送半字节函数-----------------*/
/*-入口参数:要写到液晶指令或数据寄存器的-*/
/*           字节的高四位或低四位---------*/
/******************************************/
void LCD_half(uchar dataw_)
{
 LCM_DATA=(LCM_DATA&0x0f)|(dataw_);
 LCM_EN_1;_nop_();_nop_();_nop_();
 LCM_EN_0;
 LCD_delay(1);//实际使用中加上10ms的延时
}
/******************************************/
/*-函数功能:写一位数据函数---------------*/
/*-入口参数:数据内容---------------------*/
/******************************************/
void LCD_char(uchar dataw)
{
 LCM_RS_1;LCM_RW_0;LCM_EN_0;_nop_();
 LCD_half(dataw&0xf0);
 LCD_half(dataw<<4);  
}
/*========================================*/
void LCD_cmd(uchar cmd)
{ 
 LCM_RS_0;LCM_RW_0;LCM_EN_0;_nop_();
 LCD_half(cmd&0xf0);
 LCD_half(cmd<<4);
} 
/*========================================*/
void LCD_str_(uchar *str)
{
 while(*str)LCD_char(*str++);
}
/*========================================*/
void LCD_2char(uchar num_2)
{
 uchar num_temp;
 num_temp=num_2/10;
 LCD_char(num_temp+0x30);
 num_temp=num_2%10;
 LCD_char(num_temp+0x30);
}
void LCD_4char(uint num_4)
{
 uint num_tmp;
 num_tmp=num_4/1000;
 LCD_char(num_tmp+0x30);
 num_tmp=num_4/100;
 num_tmp=num_tmp%10;
 LCD_char(num_tmp+0x30);
 num_tmp=num_4/10;
 num_tmp=num_tmp%10;
 LCD_char(num_tmp+0x30);
 num_tmp=num_4%10;
 LCD_char(num_tmp+0x30);
}
/*========================================*/
void LCD_float_(float flt,uchar n)
{
 uchar counter=0,num_str[10],neg_flags=0,n_;
 long int num;
 n_=n; 
 while(n_){n_--;flt*=10;}
 num=flt; 
 if(!num)num_str[counter++]=0x30;
 if(num<0){num=-num,neg_flags=1;}
 while(num!=0)
 {
  num_str[counter++]=num%10+0x30;
  num/=10;
  if(counter==n)num_str[counter++]='.'; 
 } 
 if(neg_flags){num_str[counter++]='-';}
 while(counter--)(LCD_char(num_str[counter]));  
}
/*========================================*/
void LCD_delay(uint xus)
{
 uint i=0,j=0;
 for(i=0;i< xus;i++)
  for(j=0;j< 123;j++);
}
/*========================================*/
#endif 








/*----------文件名:SERIAL_UART.H-------------*/
#ifndef _SERIAL_UART_H_
#define _SERIAL_UART_H_
#define  uint unsigned int
#define  uchar unsigned char
#define  Fosc 11059200
#define  Baud 9600
#define  Reload    (256-((2*Fosc)/12/32/Baud)) //SMOD==1
//#define  Reload (256-(Fosc/12/32/Baud))  //SMOD==0
sfr  AUXR =  0x8e; 
sfr  AUXR1 = 0xA2;
sfr  BRT  = 0x9c; //独立波特率发生器重装载寄存器
void serial_port_init();
void  Uart_send_(uchar);
void Uart_send(uchar *);
void Uart_send_int(int,uchar);
/*=================================*/
void serial_port_init()
{
  SCON=0x50; //串口控制第七第六方式控制,第四位允许接收
 PCON|=0x80; //第七位SMOD 
 AUXR=0x11; //第四位置位允许独立波特率发生器运行
 BRT=Reload; //独立波特率发生器赋值
 AUXR1=0x80; //选择串口位置
 ES=1;  //允许串口中断
// EA=1;  //允许全局中断
}
/*========================================*/
void Uart_send(uchar *str)
{
 while(*str)Uart_send_(*str++);
}
/*========================================*/
void Uart_send_int(int num_send,uchar n_cnt)
{
 uchar num_str[7],num_cnt=0,neg_flags=0;
 if(num_send<0){num_send=-num_send;neg_flags=1;}
 do{
  num_str[num_cnt++]=num_send%10+0x30;
  num_send/=10;  
 }while(num_send);
 while(num_cnt< n_cnt)num_str[num_cnt++]=0x30;
 if(neg_flags)num_str[num_cnt++]='-';
 while(num_cnt--)Uart_send_(num_str[num_cnt]);
}
/*========================================*/
void Uart_send_flt(float flt,uchar n)
{   
 long int num;
 uchar counter=0,num_str[10],n_temp;
 bit small_1=0,neg_flags=0; 
 n_temp=n;
 if(flt< 1.0)small_1=1;
 while(n_temp){n_temp--;flt*=10;}
 num=flt;
 if(num< 0){num=-num,neg_flags=1;}  
 do{
  num_str[counter++]=num%10+0x30;
  num/=10;
  if(counter==n)num_str[counter++]='.'; 
 }while(num!=0);
 if(small_1)num_str[counter++]=0x30; 
 if(neg_flags){num_str[counter++]='-';}
 while(counter--)(Uart_send_(num_str[counter]));  
}
/*========================================*/
void Uart_send_(uchar dat)
{
 ES=0;
 TI=0;
 SBUF=dat;
 while(!TI);
 TI=0;
 ES=1;
}
/*========================================*/
#endif 
关闭窗口

相关文章