PIC单片机实例五:基于PROTEUS模拟的精美万年历

发布者:小悟空111最新更新时间:2016-11-02 来源: eefocus关键字:PIC单片机  PROTEUS模拟  精美万年历 手机看文章 扫描二维码
随时随地手机看文章
为了把KS0108系列的液晶吃透,特别制作了这款万年历,感觉效果还是不错的.希望大家分享我的喜悦,毕竟有了更多志同道合的朋友支持,我才能更进一步提高.

一,原理介绍

说明:

1.单片机还是采用PIC中最经典的PIC16F877A,端口多,功能全,特别是他有8K的ROM,这是我选择的主要原因,因为储存液晶的字库需要很大的空间.

2.液晶显示还是用的KS0108系列,主要是他性价比高,指令简单,特别是公司也在用.

3.时钟/日历芯片用的DALLOS的DS1302芯片,他可以储存从2000-2099年的日历,及实时时钟,可以方便的读写.

4.温度测量还是用的DS18B20,这在我上一实例中已经用过,有兴趣可以查阅.

5.本万年历可以显示实时时钟,精确到秒,年,月,日,星期,阴历,温度,生肖等,显示的信息量大.

6,可以通过按键自由设定时钟及日历,按"设置"键可以在秒,分,时,日,月,星期,年之间来回切换,要设置的单元以闪烁提醒.通过"+"."-"按键可以把要设置的单元设定到预想状态.

二,程序说明:

本程序有许多小的模块,现分列如下:

1.主程序

/***************************************************
* 标题:万年历                                        *
* 作者:Wujieflash                                  *
* 日期:2008年1月13日                          *
* 说明:包含文件, 

                         ,

                         ,  *                                 
***************************************************/
#include
#include "ziku.h"
#include "lcd_init.h"
#include "ds1302.h"
#include "ds18b20.h"
#include "keyscan.h"
#include "yinli.h"

//子程序
//LCD显示空白边框子程序
void LCDShowTable()
{
 uch i;
 SlectScreen(1);     //写左半屏
 SetLine(0);         //起使页
 SetColumn(0);       //起使列
 for(i=0;i<64;i++)
 {
  if((i==0)||(i==63))WriteData(0xff);//第1、63列竖线
  else WriteData(0x01);              //最上面一行线
 }
 for(i=1;i<7;i++)
 {
  SetLine(i);
  SetColumn(0);
  WriteData(0xff); //竖线
  SetColumn(63);
  WriteData(0xff); //竖线 
 }
 SetLine(7);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if((i==0)||(i==63))WriteData(0xff);
  else WriteData(0x80);             //最下面的横线
 }
 
 SlectScreen(2);//写右半屏
 SetLine(0);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x01);
 }
 SetLine(4);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x01);
 }
 for(i=1;i<7;i++)
 {
  SetLine(i);
  SetColumn(63);
  WriteData(0xff); 
 }
 SetLine(7);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x80);
 } 
}
/*----------------------------------------------------------*/

//显示固定字符子程序
void LCDShowGudingWord()
{
 Show8X16_2(0,24,s0);
 Show8X16_2(0,32,s0);
 Show8X16(2,1,s0);
 Show8X16(2,9,s0);
 Show16X16_3(6,40,ri);
 Show16X32(2,24,ss0);
 Show16X32(2,40,ss0);
 Show8X16_2(0,64,s0);
 Show8X16_2(0,72,s0);
 Show8X16_2(0,80,maohao);
 Show8X16_2(0,88,s0);
 Show8X16_2(0,96,s0);
 Show8X16_2(0,104,maohao);
 Show8X16_2(0,112,s0);
 Show8X16_2(0,119,s0);
 Show8X16(2,80,s0);
 Show8X16(2,88,s0);
 Show16X16_2(4,64,shiyi);
 Show16X16_2(4,80,yue);
 Show16X16_2(4,95,chu);
 Show16X16_2(4,111,yi);
 Show16X16_3(6,72,sheng);
 Show16X16_3(6,88,xiao);
 Show16X16_3(6,104,shu);
 
 Show16X16_2(0,40,nian);
 Show16X16(4,2,yue);
 Show16X16_3(6,8,xing);
 Show16X16_3(6,24,qi);
 Show16X16(2,96,danwei1);
 Show8X16_2(0,8,s2);
 Show8X16_2(0,16,s0);
}
/*----------------------------------------------------------*/

//TRM1初始化子程序
void TMR1init()
{
 //TRM1 INITIAL
   T1CON=0X30;       //8分频
   TMR1IF=0;         //清中断标志
   TMR1IE=1;         //使能定时器1中断
   TMR1L=0XDB;       //初始值(定时0.5S)
   TMR1H=0X0B;
   TMR1ON=1;         //开定时器1
}

//冒号闪烁子程序
void FlashMaohao()
{
 static uch timecount=0;
 if(TMR1IF==1)
 {
  TMR1ON=0;
  TMR1IF=0;
  TMR1L=0XDB;     //重新付初值
     TMR1H=0X0B;
     flag++;
     flag=flag%2;    //闪烁标志在0-1间翻转
     TMR1ON=1;
  timecount++;
  if(timecount==120)//1分钟采样一次温度
  {
   timecount=0;
   get_temp();   //温度转换子程序
  }
 }
 if(flag==0)
 {
  Show8X16_2(0,80,maohao);
  Show8X16_2(0,104,maohao);
 }
 if(flag==1)
 {
  Show8X16_2(0,80,noshu);//清除
  Show8X16_2(0,104,noshu);
 }
}

//主程序
void main()
{
 TMR1init();             //定时器1初始化
 keyinit();              //键盘初始化
 LCDinit();              //LCD操作初始化
 LCDShowTable();         //显示空白表格
 LCDShowGudingWord();    //显示固定字符
 //Set1302(DisCash);     //设置初始时间(默认写入我写程序的时间)
 get_temp();             //读取温度
 while(1)
 {
  v_Get1302(clock);   //读取时间、日历
  display();
  YangToYin(clock[6]/16*10+clock[6]&0x0f,clock[4]/16*10+clock[4]&0x0f,clock[3]/16*10+clock[3]&0x0f);
  FlashMaohao();      //冒号闪烁
  KeyScan();         //键盘扫描
 }
}

2.测温程序:

/***************************************************
* 标题:DS18B20测温                             *
* 作者:Wujieflash                                   *
* 日期:2008年1月13日                           *
* 说明:使用DS18B20芯片测温                *
***************************************************/
# define DQ RC3                                //定义18B20数据端口 
# define DQ_DIR TRISC3                         //定义18B20D口方向寄存器 
# define DQ_HIGH() DQ_DIR =1                   //设置数据口为输入
# define DQ_LOW() DQ = 0; DQ_DIR = 0           //设置数据口为输出
 unsigned char  TLV=0 ;                        //采集到的温度高8位
 unsigned char  THV=0;                         //采集到的温度低8位
 unsigned char TZ=0;                           //转换后的温度值整数部分
 
 //------------------------------------------------
//延时函数


//系统初始化函数
void init()
{
  ADCON1=0X07;                                //设置A口为普通数字口
  TRISA=0X00;                                 //设置A口方向为输出
  //TRISC3=0;                                 //设置D口方向为输出
}

//-----------------------------------------------
//复位DS18B20函数
reset(void)
{
  char presence=1;
  while(presence)
  { 
    DQ_LOW() ;                                //主机拉至低电平
    delay(2,90);                              //延时503us
    DQ_HIGH();                                //释放总线等电阻拉高总线,并保持15~60us
    delay(2,8);                               //延时70us
    if(DQ==1) presence=1;                     //没有接收到应答信号,继续复位
    else presence=0;                          //接收到应答信号
    delay(2,70);                              //延时430us
   }
  }

//-----------------------------------------------
//写18b20写字节函数
void write_byte(uch val)
{
 uch i;
 uch temp;
 for(i=8;i>0;i--)
 {
   temp=val&0x01;                            //最低位移出
   DQ_LOW(); 
   NOP();
   NOP();
   NOP();
   NOP();
   NOP();                                    //从高拉至低电平,产生写时间隙
   if(temp==1)  DQ_HIGH();                   //如果写1,拉高电平
   delay(2,7);                               //延时63us
   DQ_HIGH(); 
   NOP();
   NOP();
   val=val>>1;                               //右移一位
  }
}

//------------------------------------------------
//18b20读字节函数
uch read_byte(void)
{
 uch i;
 uch value=0;                                //读出温度
 static bit j;
 for(i=8;i>0;i--)
 {
   value>>=1; 
   DQ_LOW();
   NOP();
   NOP();
   NOP();
   NOP();                                   //6us
   DQ_HIGH();                               //拉至高电平
   NOP(); 
   NOP(); 
   NOP();                                //4us
   j=DQ;
   if(j) value|=0x80;
   delay(2,7);                             //63us
  }
  return(value);
}

//-------------------------------------------------
//启动温度转换函数
void get_temp()

int i;
DQ_HIGH();
reset();                                 //复位等待从机应答 
write_byte(0XCC);                        //忽略ROM匹配 
write_byte(0X44);                        //发送温度转化命令  
for(i=10;i>0;i--)
    {
        
        delay(201,132);                       //调用多次显示函数,确保温度转换完成所需要的时间
    }
reset();                                 //再次复位,等待从机应答 
write_byte(0XCC);                        //忽略ROM匹配 
write_byte(0XBE);                        //发送读温度命令 
TLV=read_byte();                         //读出温度低8 
THV=read_byte();                         //读出温度高8位 
DQ_HIGH();                               //释放总线 
TZ=(TLV>>4)|(THV<<4)&0X3f;               //温度整数部分
ChangeToLCD(2,80,TZ);
}

3.日历显示程序

/***************************************************
* 标题:DS1302读写                                *
* 作者:Wujieflash                                   *
* 日期:2008年1月14日                           *
* 说明:日历显示范围:2000年--2099年  *
***************************************************/
#define  RST  RC0
#define  SCLK RC1 
#define  IO   RC2
uch flag=0;
uch second=1,minute=1,hour=1,year=1,month=1,date=1,day=1;
uch clock[]={0};
uch DisCash[]={0x00,0x30,0x09,0x16,0x01,0x03,0x09}; 
/////往1302写入1Byte数据////////////////////////
void RTInputByte(uch d) 

    uch i;
    TRISC=0x00;
    for(i=8; i>0; i--)
    {
      IO = d&0x01;      //取最低位
      SCLK = 1;         //上升沿发送
      SCLK = 0;         //恢复
      d = d >> 1;       
    } 
}
///////从1302读取1Byte数据////////////////////////
uch RTOutputByte(void) 

    uch i,val=0;
    TRISC2=1;            //设置为输入
    for(i=8; i>0; i--)
    {
      val = val >>1;         
      if(IO)val=val|0x80;// 从最低位开始接收
      SCLK = 1;          //下降沿接收
      SCLK = 0; 
    } 
     return(val); 
}
///////先写地址,后写命令/数据//////////////////////////
void W1302(uch ucAddr, uch ucDa)
{
    RST = 0;
    SCLK = 0;
    RST = 1;                  //打开DS1302
    RTInputByte(ucAddr);      // /* 地址,命令 */
    RTInputByte(ucDa);        // /* 写1Byte数据*/
    SCLK = 1;
    RST = 0;                  //关闭DS1302
}
///////先写地址,后读命令/数据////////////////////////
uch R1302(uch ucAddr)
{
    uch ucData;
    RST = 0;
    SCLK = 0;
    RST = 1;
    RTInputByte(ucAddr);            // /* 地址,命令 */
    ucData = RTOutputByte();        // /* 读1Byte数据 */
    SCLK = 1;
    RST = 0;
    return(ucData);
}
/////////向1302写入 秒 分 时 日 月 星期 年 */////////////
void Set1302(uch *pClock) 
{
    uch i;
    uch ucAddr = 0x80;          //起使地址
    W1302(0x8e,0x00);           ///* 控制命令,WP=0,允许写操作*/
    for(i =7; i>0; i--)
    { 
      W1302(ucAddr,*pClock);    ///* 秒 分 时 日 月 星期 年 */ 
      pClock++;
      ucAddr +=2;               //写地址加2
    }
     W1302(0x8e,0x80);          // /* 控制命令,WP=1,写保护*/
}
////////从1302读出 秒 分 时 日 月 星期 年 *//////////////////
void v_Get1302(unsigned char  ucCurtime[]) 
{
unsigned char i;
unsigned char ucAddr = 0x81;
for(i=0;i<7;i++)
   {
      ucCurtime[i] = R1302(ucAddr);///*格式为: 秒 分 时 日 月 星期 年 */
      ucAddr += 2;
   }
}

/////////与LCD的显示接口//////////////////////
void display()
{
 uch i;
 for(i=0;i<7;i++)
 {
  clock[i]=clock[i]/16*10+clock[i]%16;//转换为十六进制
 }
 if(second==1)ChangeToLCD2(0,111,clock[0]);//显示秒
    if(minute==1)ChangeToLCD2(0,88,clock[1]); //显示分
    if(hour==1)ChangeToLCD2(0,64,clock[2]);   //显示时
    if(year==1)ChangeToLCD2(0,24,clock[6]);   //显示年
 if(month==1)ChangeToLCD(2,2,clock[4]);    //显示月
 if(date==1)ChangeToLCD3(2,24,clock[3]);   //显示日
 if(day==1)ChangeToLCD4(6,40,clock[5]);   //显示星期
 ChangeToLCD5(6,104,clock[6]);             //显示生肖
 

4.按键扫描与服务程序

/***************************************************
* 标题:按键扫描和服务                             *
* 作者:Wujieflash                                     *         
* 日期:2008年1月17日                             *
* 说明:当按键按下,选中的单元就会闪烁 *
***************************************************/
uch k=0;

//键盘初始化子程序
void keyinit()
{
 TRISD0=1;
 TRISD0=1;
 TRISD0=1;
}
/*----------------------------------------------------------*/

//键盘扫描子程序
void KeyScan()
{
 int d;
 if(RD0==0)  //设置键按下
 {
  k++;    //选定入口值
  k=k%8;
 }
 while(1)
 {
  if(RD0==1)break;//等待按键松开
 }
 switch(k)//键盘服务入口
 {
  case 1://设置秒
  {
   d=R1302(0x81);//读取秒
   d=d/16*10+d%16;//转换为16进制
   second=flag;   //设置秒的闪烁标志
   minute=1;      //其余变量不闪烁
   hour=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(second==0)  //闪烁
   {
    Show8X16_2(0,111,noshu);
    Show8X16_2(0,119,noshu);
   }
   if(RD1==0)     //秒数值加1
   {
    d++;
    if(d>0x3b)d=0;//大于59就为0
    d=d/10*16+d%10;
    W1302(0x80,d);//写入DS1302
    while(1)
    {
     if(RD1==1)break;//等待键松开
    }
   }
   if(RD2==0)//数值减1
   {
    d--;
    if(d<0)d=0x3b;//小于0就写59
    d=d/10*16+d%10;
    W1302(0x80,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 2://设置分
  {
   d=R1302(0x83);
   d=d/16*10+d%16;
   minute=flag;
   second=1;
   hour=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(minute==0)
   {
    Show8X16_2(0,96,noshu);
    Show8X16_2(0,88,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x3b)d=0;
    d=d/10*16+d%10;
    W1302(0x82,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x3b;
    d=d/10*16+d%10;
    W1302(0x82,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 3://设置时
  {
   d=R1302(0x85);
   d=d/16*10+d%16;
   hour=flag;
   second=1;
   minute=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(hour==0)
   {
    Show8X16_2(0,64,noshu);
    Show8X16_2(0,72,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x17)d=0;
    d=d/10*16+d%10;
    W1302(0x84,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x17;
    d=d/10*16+d%10;
    W1302(0x84,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 4://设置日期
  {
   d=R1302(0x87);
   d=d/16*10+d%16;
   date=flag;
   second=1;
   minute=1;
   year=1;
   month=1;
   hour=1;
   day=1;
   if(date==0)
   {
    Show16X32(2,24,noshu2);
    Show16X32(2,40,noshu2);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x1f)d=1;
    d=d/10*16+d%10;
    W1302(0x86,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x1f;
    d=d/10*16+d%10;
    W1302(0x86,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 5://设置月
  {
   d=R1302(0x89);
   d=d/16*10+d%16;
   month=flag;
   second=1;
   minute=1;
   year=1;
   hour=1;
   date=1;
   day=1;
   if(month==0)
   {
    Show8X16(2,2,noshu);
    Show8X16(2,10,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x0c)d=1;
    d=d/10*16+d%10;
    W1302(0x88,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x0c;
    d=d/10*16+d%10;
    W1302(0x88,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 6://设置星期
  {
   d=R1302(0x8b);
   d=d/16*10+d%16;
   day=flag;
   second=1;
   minute=1;
   year=1;
   hour=1;
   date=1;
   month=1;
   if(day==0)
   {
    Show16X16_3(6,40,noshu3);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x07)d=1;
    d=d/10*16+d%10;
    W1302(0x8a,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x07;
    d=d/10*16+d%10;
    W1302(0x8a,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 7://设置年
  {
   d=R1302(0x8d);
   d=d/16*10+d%16;
   year=flag;
   second=1;
   minute=1;
   month=1;
   hour=1;
   date=1;
   day=1;
   if(year==0)
   {
    Show8X16_2(0,24,noshu);
    Show8X16_2(0,32,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x63)d=0;
    d=d/10*16+d%10;
    W1302(0x8c,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x63;
    d=d/10*16+d%10;
    W1302(0x8c,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 0://设置完毕,不闪烁
  {
   second=1;
   minute=1;
   month=1;
   hour=1;
   date=1;
   day=1;
   year=1;
   break;
  }
 }
}

5.液晶显示程序

/***************************************************
* 标题:LCD操作                                    *
* 作者:Wujieflash                                  *
* 日期:2008年1月12日                          *
* 说明:KS0108系列液晶不带字库          *
***************************************************/
#include

#define E    RA0        //液晶使能端
#define RW   RA1        //读写控制端
#define DI   RA2        //数据/指令通道
#define CSA  RA5        //片选
#define CSB  RA3        //片选
#define nop() asm("nop")

////////////////////////基本子函数///////////////////////
//延时
void delay(char x,char y) 
{
  char z;
  do{
      z=y;
      do{;}while(--z);
     }while(--x);
 }
//其指令时间为:7+(3*(Y-1)+7)*(X-1)如果再加上函数调用的call 指令、页面设定、传递参数花掉的7 个指令。
//则是:14+(3*(Y-1)+7)*(X-1)。

//--------------------------------------------------
void LCDdelay()
{
 unsigned int i=500;
 while(i--)
 {;}
}
/*----------------------------------------------------*/

//状态检查
void CheckState()
{
 unsigned int dat;
 RW=1;                             //读状态
 DI=0;
 TRISB=0xff;                       //设置口为输入
 while(1)
 {
  E=1;                          //高电平读数据
  dat=PORTB&0x90;               //当4、7位为0时为正常状态
  E=0;
  if(dat==0x00)break;
 }
 TRISB=0x00;                       //恢复口为输出
}
/*----------------------------------------------------*/

//写显示数据
//dat:显示数据
void WriteData(unsigned char dat)
{
 CheckState();
 DI=1;                            //写数据
 RW=0;
 PORTB=dat;
 E=1;
 E=0;
}
/*---------------------------------------------------*/

//写指令
//command:操作LCD的指令
void WriteCommand(unsigned char dat)
{
 CheckState();
 RW=0;                          //写指令
 PORTB=dat;
 E=1;
 E=0;
}
/*---------------------------------------------------*/

//设定页地址----X:0--7
void SetLine(unsigned char line)
{
 line=line&0x07;               //0<=line<=7 
 line=line|0xb8;
 WriteCommand(line);
}
/*---------------------------------------------------*/

//设定列地址----Y:0--63
void SetColumn(unsigned char column)
{
 column=column&0x3f;          //0<=column<=63
 column=column|0x40;
 WriteCommand(column);
}
/*--------------------------------------------------*/

//设定开始行
void SetStartLine(unsigned char startline)
{
 startline=startline&0x3f;   //0<=startline<=63
 startline=startline|0xc0;
 WriteCommand(startline);
}
/*--------------------------------------------------*/

//开关显示
//1:开显示  0:关显示
void SetOnOff(unsigned char state)
{
 state=state|0x3e;
 WriteCommand(state);
}
/*--------------------------------------------------*/

//选择屏幕
//screen: 1:左屏 2:右屏
void SlectScreen(unsigned char screen)
{
 switch(screen)
 {
  case 1: CSA=0;
     CSB=1;//左屏
     break;
  case 2: CSA=1;
    CSB=0;//右屏
    break;
 }
}
/*--------------------------------------------------*/

//清屏
//screen: 1:左屏 2:右屏
void ClearScreen(unsigned char screen)
{
 unsigned char i,j;
 SlectScreen(screen);
 for(i=0;i<8;i++)
 {
  SetLine(i);
  for(j=0;j<64;j++)
  {
   WriteData(0x00);
   WriteData(0x00);
  }
 }
}
/*---------------------------------------------------*/

//显示一个16X16的汉字
void Show16X16(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                  //写数据
  *pt++;//
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X16的汉字带上划线
void Show16X16_2(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt|0x01);                  //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X16的汉字带下划线
void Show16X16_3(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                  //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt|0x80);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个8X16的字符
void Show8X16(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                          //选通左屏
 SetColumn(column);                       //设置起始列
 SetLine(line);                           //设置行
 for(i=0;i<8;i++)
 {
  if(column>=64)                       //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;                //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                      //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                         //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<8;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个8X16的字符带上划线
void Show8X16_2(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                          //选通左屏
 SetColumn(column);                       //设置起始列
 SetLine(line);                           //设置行
 for(i=0;i<8;i++)
 {
  if(column>=64)                       //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;                //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt|0x01);                      //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                         //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<8;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X32的字符
void Show16X32(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp1,column_temp2,column_temp3;
 column_temp1=column;
 column_temp2=column;
 column_temp3=column;
 SlectScreen(1);                         //选通左屏
 SetColumn(column);                      //设置起始列
 SetLine(line);                          //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                      //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;               //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                     //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);
 column=column_temp1;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+2);
 column=column_temp2;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+2);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+3);
 column=column_temp3;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+3);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//LCD初始化子程序
void LCDinit()
{
 ADCON1=0x06;
 TRISA=0x00;
 TRISB=0x00;
 PORTB=0x00;
 SetOnOff(1);
}
/*----------------------------------------------------------*/

//调用LCD显示子程序
void ChangeToLCD(uch line,uch column,uch data)
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show8X16(line,column+8,s0);break;}
  case 1:{Show8X16(line,column+8,s1);break;}
  case 2:{Show8X16(line,column+8,s2);break;}
  case 3:{Show8X16(line,column+8,s3);break;}
  case 4:{Show8X16(line,column+8,s4);break;}
  case 5:{Show8X16(line,column+8,s5);break;}
  case 6:{Show8X16(line,column+8,s6);break;}
  case 7:{Show8X16(line,column+8,s7);break;}
  case 8:{Show8X16(line,column+8,s8);break;}
  case 9:{Show8X16(line,column+8,s9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show8X16(line,column,s0);break;}
  case 1:{Show8X16(line,column,s1);break;}
  case 2:{Show8X16(line,column,s2);break;}
  case 3:{Show8X16(line,column,s3);break;}
  case 4:{Show8X16(line,column,s4);break;}
  case 5:{Show8X16(line,column,s5);break;}
  case 6:{Show8X16(line,column,s6);break;}
  case 7:{Show8X16(line,column,s7);break;}
  case 8:{Show8X16(line,column,s8);break;}
  case 9:{Show8X16(line,column,s9);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD2(uch line,uch column,uch data)//带上划线
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show8X16_2(line,column+8,s0);break;}
  case 1:{Show8X16_2(line,column+8,s1);break;}
  case 2:{Show8X16_2(line,column+8,s2);break;}
  case 3:{Show8X16_2(line,column+8,s3);break;}
  case 4:{Show8X16_2(line,column+8,s4);break;}
  case 5:{Show8X16_2(line,column+8,s5);break;}
  case 6:{Show8X16_2(line,column+8,s6);break;}
  case 7:{Show8X16_2(line,column+8,s7);break;}
  case 8:{Show8X16_2(line,column+8,s8);break;}
  case 9:{Show8X16_2(line,column+8,s9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show8X16_2(line,column,s0);break;}
  case 1:{Show8X16_2(line,column,s1);break;}
  case 2:{Show8X16_2(line,column,s2);break;}
  case 3:{Show8X16_2(line,column,s3);break;}
  case 4:{Show8X16_2(line,column,s4);break;}
  case 5:{Show8X16_2(line,column,s5);break;}
  case 6:{Show8X16_2(line,column,s6);break;}
  case 7:{Show8X16_2(line,column,s7);break;}
  case 8:{Show8X16_2(line,column,s8);break;}
  case 9:{Show8X16_2(line,column,s9);break;}
 } 
}
/*-----------------------------------------------------------------*/
void ChangeToLCD3(uch line,uch column,uch data)//带下划线
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show16X32(line,column+16,ss0);break;}
  case 1:{Show16X32(line,column+16,ss1);break;}
  case 2:{Show16X32(line,column+16,ss2);break;}
  case 3:{Show16X32(line,column+16,ss3);break;}
  case 4:{Show16X32(line,column+16,ss4);break;}
  case 5:{Show16X32(line,column+16,ss5);break;}
  case 6:{Show16X32(line,column+16,ss6);break;}
  case 7:{Show16X32(line,column+16,ss7);break;}
  case 8:{Show16X32(line,column+16,ss8);break;}
  case 9:{Show16X32(line,column+16,ss9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show16X32(line,column,ss0);break;}
  case 1:{Show16X32(line,column,ss1);break;}
  case 2:{Show16X32(line,column,ss2);break;}
  case 3:{Show16X32(line,column,ss3);break;}
  case 4:{Show16X32(line,column,ss4);break;}
  case 5:{Show16X32(line,column,ss5);break;}
  case 6:{Show16X32(line,column,ss6);break;}
  case 7:{Show16X32(line,column,ss7);break;}
  case 8:{Show16X32(line,column,ss8);break;}
  case 9:{Show16X32(line,column,ss9);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD4(uch line,uch column,uch data)//星期转换
{                     
 switch(data)
 {
  case 1:{Show16X16_3(line,column,ri);break;}
  case 2:{Show16X16_3(line,column,yi);break;}
  case 3:{Show16X16_3(line,column,er);break;}
  case 4:{Show16X16_3(line,column,san);break;}
  case 5:{Show16X16_3(line,column,si);break;}
  case 6:{Show16X16_3(line,column,wu);break;}
  case 7:{Show16X16_3(line,column,liu);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD5(uch line,uch column,uch data)//生肖转换
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_3(line,column,llong);break;}
  case 1:{Show16X16_3(line,column,she);break;}
  case 2:{Show16X16_3(line,column,ma);break;}
  case 3:{Show16X16_3(line,column,yang);break;}
  case 4:{Show16X16_3(line,column,hou);break;}
  case 5:{Show16X16_3(line,column,ji);break;}
  case 6:{Show16X16_3(line,column,gou);break;}
  case 7:{Show16X16_3(line,column,zhu);break;}
  case 8:{Show16X16_3(line,column,shu);break;}
  case 9:{Show16X16_3(line,column,niu);break;}
  case 10:{Show16X16_3(line,column,hu);break;}
  case 11:{Show16X16_3(line,column,tu);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD6(uch line,uch column,uch data)//阴历月转换
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,zheng);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
  case 3:{Show16X16_2(line,column,si);break;}
  case 4:{Show16X16_2(line,column,wu);break;}
  case 5:{Show16X16_2(line,column,liu);break;}
  case 6:{Show16X16_2(line,column,qqi);break;}
  case 7:{Show16X16_2(line,column,ba);break;}
  case 8:{Show16X16_2(line,column,jiu);break;}
  case 9:{Show16X16_2(line,column,shi);break;}
  case 10:{Show16X16_2(line,column,shiyi);break;}
  case 11:{Show16X16_2(line,column,la);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD7(uch line,uch column,uch data)//阴历日
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,yi);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
  case 3:{Show16X16_2(line,column,si);break;}
  case 4:{Show16X16_2(line,column,wu);break;}
  case 5:{Show16X16_2(line,column,liu);break;}
  case 6:{Show16X16_2(line,column,qqi);break;}
  case 7:{Show16X16_2(line,column,ba);break;}
  case 8:{Show16X16_2(line,column,jiu);break;}
  case 9:{Show16X16_2(line,column,shi);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD8(uch line,uch column,uch data)//阴历日十位
{   
 data=data%3;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,chu);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
 } 
}
/*-----------------------------------------------------------------*/

程序结束

三,总结

           到现在为止,我对KS0108系列液晶的操作已经基本掌握了,并可以熟练应用.

但是本程序中阳历转阴历的程序还是不对,我想不出更好的转换办法,希望大家能提供方法完善.为了把KS0108系列的液晶吃透,特别制作了这款万年历,感觉效果还是不错的.希望大家分享我的喜悦,毕竟有了更多志同道合的朋友支持,我才能更进一步提高.

一,原理介绍

说明:

1.单片机还是采用PIC中最经典的PIC16F877A,端口多,功能全,特别是他有8K的ROM,这是我选择的主要原因,因为储存液晶的字库需要很大的空间.

2.液晶显示还是用的KS0108系列,主要是他性价比高,指令简单,特别是公司也在用.

3.时钟/日历芯片用的DALLOS的DS1302芯片,他可以储存从2000-2099年的日历,及实时时钟,可以方便的读写.

4.温度测量还是用的DS18B20,这在我上一实例中已经用过,有兴趣可以查阅.

5.本万年历可以显示实时时钟,精确到秒,年,月,日,星期,阴历,温度,生肖等,显示的信息量大.

6,可以通过按键自由设定时钟及日历,按"设置"键可以在秒,分,时,日,月,星期,年之间来回切换,要设置的单元以闪烁提醒.通过"+"."-"按键可以把要设置的单元设定到预想状态.

二,程序说明:

本程序有许多小的模块,现分列如下:

1.主程序

/***************************************************
* 标题:万年历                                        *
* 作者:Wujieflash                                  *
* 日期:2008年1月13日                          *
* 说明:包含文件, 

                         ,

                         ,  *                                 
***************************************************/
#include
#include "ziku.h"
#include "lcd_init.h"
#include "ds1302.h"
#include "ds18b20.h"
#include "keyscan.h"
#include "yinli.h"

//子程序
//LCD显示空白边框子程序
void LCDShowTable()
{
 uch i;
 SlectScreen(1);     //写左半屏
 SetLine(0);         //起使页
 SetColumn(0);       //起使列
 for(i=0;i<64;i++)
 {
  if((i==0)||(i==63))WriteData(0xff);//第1、63列竖线
  else WriteData(0x01);              //最上面一行线
 }
 for(i=1;i<7;i++)
 {
  SetLine(i);
  SetColumn(0);
  WriteData(0xff); //竖线
  SetColumn(63);
  WriteData(0xff); //竖线 
 }
 SetLine(7);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if((i==0)||(i==63))WriteData(0xff);
  else WriteData(0x80);             //最下面的横线
 }
 
 SlectScreen(2);//写右半屏
 SetLine(0);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x01);
 }
 SetLine(4);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x01);
 }
 for(i=1;i<7;i++)
 {
  SetLine(i);
  SetColumn(63);
  WriteData(0xff); 
 }
 SetLine(7);
 SetColumn(0);
 for(i=0;i<64;i++)
 {
  if(i==63)WriteData(0xff);
  else WriteData(0x80);
 } 
}
/*----------------------------------------------------------*/

//显示固定字符子程序
void LCDShowGudingWord()
{
 Show8X16_2(0,24,s0);
 Show8X16_2(0,32,s0);
 Show8X16(2,1,s0);
 Show8X16(2,9,s0);
 Show16X16_3(6,40,ri);
 Show16X32(2,24,ss0);
 Show16X32(2,40,ss0);
 Show8X16_2(0,64,s0);
 Show8X16_2(0,72,s0);
 Show8X16_2(0,80,maohao);
 Show8X16_2(0,88,s0);
 Show8X16_2(0,96,s0);
 Show8X16_2(0,104,maohao);
 Show8X16_2(0,112,s0);
 Show8X16_2(0,119,s0);
 Show8X16(2,80,s0);
 Show8X16(2,88,s0);
 Show16X16_2(4,64,shiyi);
 Show16X16_2(4,80,yue);
 Show16X16_2(4,95,chu);
 Show16X16_2(4,111,yi);
 Show16X16_3(6,72,sheng);
 Show16X16_3(6,88,xiao);
 Show16X16_3(6,104,shu);
 
 Show16X16_2(0,40,nian);
 Show16X16(4,2,yue);
 Show16X16_3(6,8,xing);
 Show16X16_3(6,24,qi);
 Show16X16(2,96,danwei1);
 Show8X16_2(0,8,s2);
 Show8X16_2(0,16,s0);
}
/*----------------------------------------------------------*/

//TRM1初始化子程序
void TMR1init()
{
 //TRM1 INITIAL
   T1CON=0X30;       //8分频
   TMR1IF=0;         //清中断标志
   TMR1IE=1;         //使能定时器1中断
   TMR1L=0XDB;       //初始值(定时0.5S)
   TMR1H=0X0B;
   TMR1ON=1;         //开定时器1
}

//冒号闪烁子程序
void FlashMaohao()
{
 static uch timecount=0;
 if(TMR1IF==1)
 {
  TMR1ON=0;
  TMR1IF=0;
  TMR1L=0XDB;     //重新付初值
     TMR1H=0X0B;
     flag++;
     flag=flag%2;    //闪烁标志在0-1间翻转
     TMR1ON=1;
  timecount++;
  if(timecount==120)//1分钟采样一次温度
  {
   timecount=0;
   get_temp();   //温度转换子程序
  }
 }
 if(flag==0)
 {
  Show8X16_2(0,80,maohao);
  Show8X16_2(0,104,maohao);
 }
 if(flag==1)
 {
  Show8X16_2(0,80,noshu);//清除
  Show8X16_2(0,104,noshu);
 }
}

//主程序
void main()
{
 TMR1init();             //定时器1初始化
 keyinit();              //键盘初始化
 LCDinit();              //LCD操作初始化
 LCDShowTable();         //显示空白表格
 LCDShowGudingWord();    //显示固定字符
 //Set1302(DisCash);     //设置初始时间(默认写入我写程序的时间)
 get_temp();             //读取温度
 while(1)
 {
  v_Get1302(clock);   //读取时间、日历
  display();
  YangToYin(clock[6]/16*10+clock[6]&0x0f,clock[4]/16*10+clock[4]&0x0f,clock[3]/16*10+clock[3]&0x0f);
  FlashMaohao();      //冒号闪烁
  KeyScan();         //键盘扫描
 }
}

2.测温程序:

/***************************************************
* 标题:DS18B20测温                             *
* 作者:Wujieflash                                   *
* 日期:2008年1月13日                           *
* 说明:使用DS18B20芯片测温                *
***************************************************/
# define DQ RC3                                //定义18B20数据端口 
# define DQ_DIR TRISC3                         //定义18B20D口方向寄存器 
# define DQ_HIGH() DQ_DIR =1                   //设置数据口为输入
# define DQ_LOW() DQ = 0; DQ_DIR = 0           //设置数据口为输出
 unsigned char  TLV=0 ;                        //采集到的温度高8位
 unsigned char  THV=0;                         //采集到的温度低8位
 unsigned char TZ=0;                           //转换后的温度值整数部分
 
 //------------------------------------------------
//延时函数


//系统初始化函数
void init()
{
  ADCON1=0X07;                                //设置A口为普通数字口
  TRISA=0X00;                                 //设置A口方向为输出
  //TRISC3=0;                                 //设置D口方向为输出
}

//-----------------------------------------------
//复位DS18B20函数
reset(void)
{
  char presence=1;
  while(presence)
  { 
    DQ_LOW() ;                                //主机拉至低电平
    delay(2,90);                              //延时503us
    DQ_HIGH();                                //释放总线等电阻拉高总线,并保持15~60us
    delay(2,8);                               //延时70us
    if(DQ==1) presence=1;                     //没有接收到应答信号,继续复位
    else presence=0;                          //接收到应答信号
    delay(2,70);                              //延时430us
   }
  }

//-----------------------------------------------
//写18b20写字节函数
void write_byte(uch val)
{
 uch i;
 uch temp;
 for(i=8;i>0;i--)
 {
   temp=val&0x01;                            //最低位移出
   DQ_LOW(); 
   NOP();
   NOP();
   NOP();
   NOP();
   NOP();                                    //从高拉至低电平,产生写时间隙
   if(temp==1)  DQ_HIGH();                   //如果写1,拉高电平
   delay(2,7);                               //延时63us
   DQ_HIGH(); 
   NOP();
   NOP();
   val=val>>1;                               //右移一位
  }
}

//------------------------------------------------
//18b20读字节函数
uch read_byte(void)
{
 uch i;
 uch value=0;                                //读出温度
 static bit j;
 for(i=8;i>0;i--)
 {
   value>>=1; 
   DQ_LOW();
   NOP();
   NOP();
   NOP();
   NOP();                                   //6us
   DQ_HIGH();                               //拉至高电平
   NOP(); 
   NOP(); 
   NOP();                                //4us
   j=DQ;
   if(j) value|=0x80;
   delay(2,7);                             //63us
  }
  return(value);
}

//-------------------------------------------------
//启动温度转换函数
void get_temp()

int i;
DQ_HIGH();
reset();                                 //复位等待从机应答 
write_byte(0XCC);                        //忽略ROM匹配 
write_byte(0X44);                        //发送温度转化命令  
for(i=10;i>0;i--)
    {
        
        delay(201,132);                       //调用多次显示函数,确保温度转换完成所需要的时间
    }
reset();                                 //再次复位,等待从机应答 
write_byte(0XCC);                        //忽略ROM匹配 
write_byte(0XBE);                        //发送读温度命令 
TLV=read_byte();                         //读出温度低8 
THV=read_byte();                         //读出温度高8位 
DQ_HIGH();                               //释放总线 
TZ=(TLV>>4)|(THV<<4)&0X3f;               //温度整数部分
ChangeToLCD(2,80,TZ);
}

3.日历显示程序

/***************************************************
* 标题:DS1302读写                                *
* 作者:Wujieflash                                   *
* 日期:2008年1月14日                           *
* 说明:日历显示范围:2000年--2099年  *
***************************************************/
#define  RST  RC0
#define  SCLK RC1 
#define  IO   RC2
uch flag=0;
uch second=1,minute=1,hour=1,year=1,month=1,date=1,day=1;
uch clock[]={0};
uch DisCash[]={0x00,0x30,0x09,0x16,0x01,0x03,0x09}; 
/////往1302写入1Byte数据////////////////////////
void RTInputByte(uch d) 

    uch i;
    TRISC=0x00;
    for(i=8; i>0; i--)
    {
      IO = d&0x01;      //取最低位
      SCLK = 1;         //上升沿发送
      SCLK = 0;         //恢复
      d = d >> 1;       
    } 
}
///////从1302读取1Byte数据////////////////////////
uch RTOutputByte(void) 

    uch i,val=0;
    TRISC2=1;            //设置为输入
    for(i=8; i>0; i--)
    {
      val = val >>1;         
      if(IO)val=val|0x80;// 从最低位开始接收
      SCLK = 1;          //下降沿接收
      SCLK = 0; 
    } 
     return(val); 
}
///////先写地址,后写命令/数据//////////////////////////
void W1302(uch ucAddr, uch ucDa)
{
    RST = 0;
    SCLK = 0;
    RST = 1;                  //打开DS1302
    RTInputByte(ucAddr);      // /* 地址,命令 */
    RTInputByte(ucDa);        // /* 写1Byte数据*/
    SCLK = 1;
    RST = 0;                  //关闭DS1302
}
///////先写地址,后读命令/数据////////////////////////
uch R1302(uch ucAddr)
{
    uch ucData;
    RST = 0;
    SCLK = 0;
    RST = 1;
    RTInputByte(ucAddr);            // /* 地址,命令 */
    ucData = RTOutputByte();        // /* 读1Byte数据 */
    SCLK = 1;
    RST = 0;
    return(ucData);
}
/////////向1302写入 秒 分 时 日 月 星期 年 */////////////
void Set1302(uch *pClock) 
{
    uch i;
    uch ucAddr = 0x80;          //起使地址
    W1302(0x8e,0x00);           ///* 控制命令,WP=0,允许写操作*/
    for(i =7; i>0; i--)
    { 
      W1302(ucAddr,*pClock);    ///* 秒 分 时 日 月 星期 年 */ 
      pClock++;
      ucAddr +=2;               //写地址加2
    }
     W1302(0x8e,0x80);          // /* 控制命令,WP=1,写保护*/
}
////////从1302读出 秒 分 时 日 月 星期 年 *//////////////////
void v_Get1302(unsigned char  ucCurtime[]) 
{
unsigned char i;
unsigned char ucAddr = 0x81;
for(i=0;i<7;i++)
   {
      ucCurtime[i] = R1302(ucAddr);///*格式为: 秒 分 时 日 月 星期 年 */
      ucAddr += 2;
   }
}

/////////与LCD的显示接口//////////////////////
void display()
{
 uch i;
 for(i=0;i<7;i++)
 {
  clock[i]=clock[i]/16*10+clock[i]%16;//转换为十六进制
 }
 if(second==1)ChangeToLCD2(0,111,clock[0]);//显示秒
    if(minute==1)ChangeToLCD2(0,88,clock[1]); //显示分
    if(hour==1)ChangeToLCD2(0,64,clock[2]);   //显示时
    if(year==1)ChangeToLCD2(0,24,clock[6]);   //显示年
 if(month==1)ChangeToLCD(2,2,clock[4]);    //显示月
 if(date==1)ChangeToLCD3(2,24,clock[3]);   //显示日
 if(day==1)ChangeToLCD4(6,40,clock[5]);   //显示星期
 ChangeToLCD5(6,104,clock[6]);             //显示生肖
 

4.按键扫描与服务程序

/***************************************************
* 标题:按键扫描和服务                             *
* 作者:Wujieflash                                     *         
* 日期:2008年1月17日                             *
* 说明:当按键按下,选中的单元就会闪烁 *
***************************************************/
uch k=0;

//键盘初始化子程序
void keyinit()
{
 TRISD0=1;
 TRISD0=1;
 TRISD0=1;
}
/*----------------------------------------------------------*/

//键盘扫描子程序
void KeyScan()
{
 int d;
 if(RD0==0)  //设置键按下
 {
  k++;    //选定入口值
  k=k%8;
 }
 while(1)
 {
  if(RD0==1)break;//等待按键松开
 }
 switch(k)//键盘服务入口
 {
  case 1://设置秒
  {
   d=R1302(0x81);//读取秒
   d=d/16*10+d%16;//转换为16进制
   second=flag;   //设置秒的闪烁标志
   minute=1;      //其余变量不闪烁
   hour=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(second==0)  //闪烁
   {
    Show8X16_2(0,111,noshu);
    Show8X16_2(0,119,noshu);
   }
   if(RD1==0)     //秒数值加1
   {
    d++;
    if(d>0x3b)d=0;//大于59就为0
    d=d/10*16+d%10;
    W1302(0x80,d);//写入DS1302
    while(1)
    {
     if(RD1==1)break;//等待键松开
    }
   }
   if(RD2==0)//数值减1
   {
    d--;
    if(d<0)d=0x3b;//小于0就写59
    d=d/10*16+d%10;
    W1302(0x80,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 2://设置分
  {
   d=R1302(0x83);
   d=d/16*10+d%16;
   minute=flag;
   second=1;
   hour=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(minute==0)
   {
    Show8X16_2(0,96,noshu);
    Show8X16_2(0,88,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x3b)d=0;
    d=d/10*16+d%10;
    W1302(0x82,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x3b;
    d=d/10*16+d%10;
    W1302(0x82,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 3://设置时
  {
   d=R1302(0x85);
   d=d/16*10+d%16;
   hour=flag;
   second=1;
   minute=1;
   year=1;
   month=1;
   date=1;
   day=1;
   if(hour==0)
   {
    Show8X16_2(0,64,noshu);
    Show8X16_2(0,72,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x17)d=0;
    d=d/10*16+d%10;
    W1302(0x84,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x17;
    d=d/10*16+d%10;
    W1302(0x84,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 4://设置日期
  {
   d=R1302(0x87);
   d=d/16*10+d%16;
   date=flag;
   second=1;
   minute=1;
   year=1;
   month=1;
   hour=1;
   day=1;
   if(date==0)
   {
    Show16X32(2,24,noshu2);
    Show16X32(2,40,noshu2);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x1f)d=1;
    d=d/10*16+d%10;
    W1302(0x86,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x1f;
    d=d/10*16+d%10;
    W1302(0x86,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 5://设置月
  {
   d=R1302(0x89);
   d=d/16*10+d%16;
   month=flag;
   second=1;
   minute=1;
   year=1;
   hour=1;
   date=1;
   day=1;
   if(month==0)
   {
    Show8X16(2,2,noshu);
    Show8X16(2,10,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x0c)d=1;
    d=d/10*16+d%10;
    W1302(0x88,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x0c;
    d=d/10*16+d%10;
    W1302(0x88,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 6://设置星期
  {
   d=R1302(0x8b);
   d=d/16*10+d%16;
   day=flag;
   second=1;
   minute=1;
   year=1;
   hour=1;
   date=1;
   month=1;
   if(day==0)
   {
    Show16X16_3(6,40,noshu3);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x07)d=1;
    d=d/10*16+d%10;
    W1302(0x8a,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<1)d=0x07;
    d=d/10*16+d%10;
    W1302(0x8a,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 7://设置年
  {
   d=R1302(0x8d);
   d=d/16*10+d%16;
   year=flag;
   second=1;
   minute=1;
   month=1;
   hour=1;
   date=1;
   day=1;
   if(year==0)
   {
    Show8X16_2(0,24,noshu);
    Show8X16_2(0,32,noshu);
   }
   if(RD1==0)
   {
    d++;
    if(d>0x63)d=0;
    d=d/10*16+d%10;
    W1302(0x8c,d);
    while(1)
    {
     if(RD1==1)break;
    }
   }
   if(RD2==0)
   {
    d--;
    if(d<0)d=0x63;
    d=d/10*16+d%10;
    W1302(0x8c,d);
    while(1)
    {
     if(RD2==1)break;
    }
   }
   break;
  }
  case 0://设置完毕,不闪烁
  {
   second=1;
   minute=1;
   month=1;
   hour=1;
   date=1;
   day=1;
   year=1;
   break;
  }
 }
}

5.液晶显示程序

/***************************************************
* 标题:LCD操作                                    *
* 作者:Wujieflash                                  *
* 日期:2008年1月12日                          *
* 说明:KS0108系列液晶不带字库          *
***************************************************/
#include

#define E    RA0        //液晶使能端
#define RW   RA1        //读写控制端
#define DI   RA2        //数据/指令通道
#define CSA  RA5        //片选
#define CSB  RA3        //片选
#define nop() asm("nop")

////////////////////////基本子函数///////////////////////
//延时
void delay(char x,char y) 
{
  char z;
  do{
      z=y;
      do{;}while(--z);
     }while(--x);
 }
//其指令时间为:7+(3*(Y-1)+7)*(X-1)如果再加上函数调用的call 指令、页面设定、传递参数花掉的7 个指令。
//则是:14+(3*(Y-1)+7)*(X-1)。

//--------------------------------------------------
void LCDdelay()
{
 unsigned int i=500;
 while(i--)
 {;}
}
/*----------------------------------------------------*/

//状态检查
void CheckState()
{
 unsigned int dat;
 RW=1;                             //读状态
 DI=0;
 TRISB=0xff;                       //设置口为输入
 while(1)
 {
  E=1;                          //高电平读数据
  dat=PORTB&0x90;               //当4、7位为0时为正常状态
  E=0;
  if(dat==0x00)break;
 }
 TRISB=0x00;                       //恢复口为输出
}
/*----------------------------------------------------*/

//写显示数据
//dat:显示数据
void WriteData(unsigned char dat)
{
 CheckState();
 DI=1;                            //写数据
 RW=0;
 PORTB=dat;
 E=1;
 E=0;
}
/*---------------------------------------------------*/

//写指令
//command:操作LCD的指令
void WriteCommand(unsigned char dat)
{
 CheckState();
 RW=0;                          //写指令
 PORTB=dat;
 E=1;
 E=0;
}
/*---------------------------------------------------*/

//设定页地址----X:0--7
void SetLine(unsigned char line)
{
 line=line&0x07;               //0<=line<=7 
 line=line|0xb8;
 WriteCommand(line);
}
/*---------------------------------------------------*/

//设定列地址----Y:0--63
void SetColumn(unsigned char column)
{
 column=column&0x3f;          //0<=column<=63
 column=column|0x40;
 WriteCommand(column);
}
/*--------------------------------------------------*/

//设定开始行
void SetStartLine(unsigned char startline)
{
 startline=startline&0x3f;   //0<=startline<=63
 startline=startline|0xc0;
 WriteCommand(startline);
}
/*--------------------------------------------------*/

//开关显示
//1:开显示  0:关显示
void SetOnOff(unsigned char state)
{
 state=state|0x3e;
 WriteCommand(state);
}
/*--------------------------------------------------*/

//选择屏幕
//screen: 1:左屏 2:右屏
void SlectScreen(unsigned char screen)
{
 switch(screen)
 {
  case 1: CSA=0;
     CSB=1;//左屏
     break;
  case 2: CSA=1;
    CSB=0;//右屏
    break;
 }
}
/*--------------------------------------------------*/

//清屏
//screen: 1:左屏 2:右屏
void ClearScreen(unsigned char screen)
{
 unsigned char i,j;
 SlectScreen(screen);
 for(i=0;i<8;i++)
 {
  SetLine(i);
  for(j=0;j<64;j++)
  {
   WriteData(0x00);
   WriteData(0x00);
  }
 }
}
/*---------------------------------------------------*/

//显示一个16X16的汉字
void Show16X16(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                  //写数据
  *pt++;//
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X16的汉字带上划线
void Show16X16_2(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt|0x01);                  //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X16的汉字带下划线
void Show16X16_3(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                      //选通左屏
 SetColumn(column);                   //设置起始列
 SetLine(line);                       //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                   //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;            //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                  //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                    //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt|0x80);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个8X16的字符
void Show8X16(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                          //选通左屏
 SetColumn(column);                       //设置起始列
 SetLine(line);                           //设置行
 for(i=0;i<8;i++)
 {
  if(column>=64)                       //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;                //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                      //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                         //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<8;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个8X16的字符带上划线
void Show8X16_2(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp;
 column_temp=column;
 SlectScreen(1);                          //选通左屏
 SetColumn(column);                       //设置起始列
 SetLine(line);                           //设置行
 for(i=0;i<8;i++)
 {
  if(column>=64)                       //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;                //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt|0x01);                      //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);                         //设置汉字下半部分显示页
 column=column_temp;
 SetColumn(column);
 for(i=0;i<8;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//显示一个16X32的字符
void Show16X32(unsigned char line,unsigned char column,const unsigned char *pt)
{
 unsigned char i,column_temp1,column_temp2,column_temp3;
 column_temp1=column;
 column_temp2=column;
 column_temp3=column;
 SlectScreen(1);                         //选通左屏
 SetColumn(column);                      //设置起始列
 SetLine(line);                          //设置行
 for(i=0;i<16;i++)
 {
  if(column>=64)                      //如果列>=64,则选通右屏
  {
   SlectScreen(2);
   column=column%64;               //设置右屏起始列
   SetColumn(column);
   SetLine(line);
  } 
  WriteData(*pt);                     //写数据
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+1);
 column=column_temp1;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+1);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+2);
 column=column_temp2;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+2);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
 SlectScreen(1);
 SetLine(line+3);
 column=column_temp3;
 SetColumn(column);
 for(i=0;i<16;i++)
 {
  if(column>=64)
  {
   SlectScreen(2);
   column=column%64;
   SetColumn(column);
   SetLine(line+3);
  } 
  WriteData(*pt);
  *pt++;
  column++;
 }
}
/*-------------------------------------------------------*/

//LCD初始化子程序
void LCDinit()
{
 ADCON1=0x06;
 TRISA=0x00;
 TRISB=0x00;
 PORTB=0x00;
 SetOnOff(1);
}
/*----------------------------------------------------------*/

//调用LCD显示子程序
void ChangeToLCD(uch line,uch column,uch data)
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show8X16(line,column+8,s0);break;}
  case 1:{Show8X16(line,column+8,s1);break;}
  case 2:{Show8X16(line,column+8,s2);break;}
  case 3:{Show8X16(line,column+8,s3);break;}
  case 4:{Show8X16(line,column+8,s4);break;}
  case 5:{Show8X16(line,column+8,s5);break;}
  case 6:{Show8X16(line,column+8,s6);break;}
  case 7:{Show8X16(line,column+8,s7);break;}
  case 8:{Show8X16(line,column+8,s8);break;}
  case 9:{Show8X16(line,column+8,s9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show8X16(line,column,s0);break;}
  case 1:{Show8X16(line,column,s1);break;}
  case 2:{Show8X16(line,column,s2);break;}
  case 3:{Show8X16(line,column,s3);break;}
  case 4:{Show8X16(line,column,s4);break;}
  case 5:{Show8X16(line,column,s5);break;}
  case 6:{Show8X16(line,column,s6);break;}
  case 7:{Show8X16(line,column,s7);break;}
  case 8:{Show8X16(line,column,s8);break;}
  case 9:{Show8X16(line,column,s9);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD2(uch line,uch column,uch data)//带上划线
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show8X16_2(line,column+8,s0);break;}
  case 1:{Show8X16_2(line,column+8,s1);break;}
  case 2:{Show8X16_2(line,column+8,s2);break;}
  case 3:{Show8X16_2(line,column+8,s3);break;}
  case 4:{Show8X16_2(line,column+8,s4);break;}
  case 5:{Show8X16_2(line,column+8,s5);break;}
  case 6:{Show8X16_2(line,column+8,s6);break;}
  case 7:{Show8X16_2(line,column+8,s7);break;}
  case 8:{Show8X16_2(line,column+8,s8);break;}
  case 9:{Show8X16_2(line,column+8,s9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show8X16_2(line,column,s0);break;}
  case 1:{Show8X16_2(line,column,s1);break;}
  case 2:{Show8X16_2(line,column,s2);break;}
  case 3:{Show8X16_2(line,column,s3);break;}
  case 4:{Show8X16_2(line,column,s4);break;}
  case 5:{Show8X16_2(line,column,s5);break;}
  case 6:{Show8X16_2(line,column,s6);break;}
  case 7:{Show8X16_2(line,column,s7);break;}
  case 8:{Show8X16_2(line,column,s8);break;}
  case 9:{Show8X16_2(line,column,s9);break;}
 } 
}
/*-----------------------------------------------------------------*/
void ChangeToLCD3(uch line,uch column,uch data)//带下划线
{
 int D_ge,D_shi;
 
 D_ge=data%10;                           //取个位
 D_shi=data%100/10;                      //取十位
 
 switch(D_ge)
 {
  case 0:{Show16X32(line,column+16,ss0);break;}
  case 1:{Show16X32(line,column+16,ss1);break;}
  case 2:{Show16X32(line,column+16,ss2);break;}
  case 3:{Show16X32(line,column+16,ss3);break;}
  case 4:{Show16X32(line,column+16,ss4);break;}
  case 5:{Show16X32(line,column+16,ss5);break;}
  case 6:{Show16X32(line,column+16,ss6);break;}
  case 7:{Show16X32(line,column+16,ss7);break;}
  case 8:{Show16X32(line,column+16,ss8);break;}
  case 9:{Show16X32(line,column+16,ss9);break;}
 }
 switch(D_shi)
 {
  case 0:{Show16X32(line,column,ss0);break;}
  case 1:{Show16X32(line,column,ss1);break;}
  case 2:{Show16X32(line,column,ss2);break;}
  case 3:{Show16X32(line,column,ss3);break;}
  case 4:{Show16X32(line,column,ss4);break;}
  case 5:{Show16X32(line,column,ss5);break;}
  case 6:{Show16X32(line,column,ss6);break;}
  case 7:{Show16X32(line,column,ss7);break;}
  case 8:{Show16X32(line,column,ss8);break;}
  case 9:{Show16X32(line,column,ss9);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD4(uch line,uch column,uch data)//星期转换
{                     
 switch(data)
 {
  case 1:{Show16X16_3(line,column,ri);break;}
  case 2:{Show16X16_3(line,column,yi);break;}
  case 3:{Show16X16_3(line,column,er);break;}
  case 4:{Show16X16_3(line,column,san);break;}
  case 5:{Show16X16_3(line,column,si);break;}
  case 6:{Show16X16_3(line,column,wu);break;}
  case 7:{Show16X16_3(line,column,liu);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD5(uch line,uch column,uch data)//生肖转换
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_3(line,column,llong);break;}
  case 1:{Show16X16_3(line,column,she);break;}
  case 2:{Show16X16_3(line,column,ma);break;}
  case 3:{Show16X16_3(line,column,yang);break;}
  case 4:{Show16X16_3(line,column,hou);break;}
  case 5:{Show16X16_3(line,column,ji);break;}
  case 6:{Show16X16_3(line,column,gou);break;}
  case 7:{Show16X16_3(line,column,zhu);break;}
  case 8:{Show16X16_3(line,column,shu);break;}
  case 9:{Show16X16_3(line,column,niu);break;}
  case 10:{Show16X16_3(line,column,hu);break;}
  case 11:{Show16X16_3(line,column,tu);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD6(uch line,uch column,uch data)//阴历月转换
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,zheng);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
  case 3:{Show16X16_2(line,column,si);break;}
  case 4:{Show16X16_2(line,column,wu);break;}
  case 5:{Show16X16_2(line,column,liu);break;}
  case 6:{Show16X16_2(line,column,qqi);break;}
  case 7:{Show16X16_2(line,column,ba);break;}
  case 8:{Show16X16_2(line,column,jiu);break;}
  case 9:{Show16X16_2(line,column,shi);break;}
  case 10:{Show16X16_2(line,column,shiyi);break;}
  case 11:{Show16X16_2(line,column,la);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD7(uch line,uch column,uch data)//阴历日
{   
 data=data%12;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,yi);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
  case 3:{Show16X16_2(line,column,si);break;}
  case 4:{Show16X16_2(line,column,wu);break;}
  case 5:{Show16X16_2(line,column,liu);break;}
  case 6:{Show16X16_2(line,column,qqi);break;}
  case 7:{Show16X16_2(line,column,ba);break;}
  case 8:{Show16X16_2(line,column,jiu);break;}
  case 9:{Show16X16_2(line,column,shi);break;}
 } 
}
/*-----------------------------------------------------------------*/

void ChangeToLCD8(uch line,uch column,uch data)//阴历日十位
{   
 data=data%3;                  
 switch(data)
 {
  case 0:{Show16X16_2(line,column,chu);break;}
  case 1:{Show16X16_2(line,column,er);break;}
  case 2:{Show16X16_2(line,column,san);break;}
 } 
}
/*-----------------------------------------------------------------*/

程序结束

三,总结

           到现在为止,我对KS0108系列液晶的操作已经基本掌握了,并可以熟练应用.

但是本程序中阳历转阴历的程序还是不对,我想不出更好的转换办法,希望大家能提供方法完善.

关键字:PIC单片机  PROTEUS模拟  精美万年历 引用地址:PIC单片机实例五:基于PROTEUS模拟的精美万年历

上一篇:PIC单片机实例一:PROTEUS模拟豆浆机
下一篇:PIC单片机实例三:基于PROTEUS模拟的双机异步通信

推荐阅读最新更新时间:2024-03-16 15:19

PIC单片机软件模拟IIC读写例程
;I2C总线程序 ;this is eeprom read & write programm ;the special store ram unit w equ 0 f0 equ 0 rt CC equ 1 pc equ 2 f2 equ 2 f3 equ 3 f4 equ 4 ra equ 5 rb equ 6 rc equ 7 pclath equ 0ah i NTC on equ 0bh pir1 equ 0ch tmr1l equ 0eh tmr1h equ 0fh t1con equ 10h tmr2 equ 11h t2con equ 12h sspbuf equ 13h ss
[单片机]
基于PIC单片机设计的RLC智能测量仪
在使用电子元器件时,首先需要了解其参数,这就要求能够对元器件的参数进行精确测量。采用传统的仪表进行测量时,首先要从电路板上焊开器件,再根据元件的类型,手动选择量程档位进行测量,这样不仅麻烦而且破坏了电路板的美观。经过理论分析和实验研究,采用正交采样算法,并由单片机控制实现在线测量、智能识别、量程自动转换等多种功能,可大大提高测量仪的测量速度和精度,扩大测量范围。因此这种RLC测量仪既可改善系统测量的性能,又保持了印刷电路的美观,较传统的测量仪还具有高度的智能化和功能的集成化,在未来的应用中将具有广阔的前景。 1 硬件电路设计 此测量仪硬件设计思路如图1所示。 由于PIC单片机只能正确采集0~5 V之间的电压,而输入的
[单片机]
基于<font color='red'>PIC单片机</font>设计的RLC智能测量仪
基于PIC单片机的家用电器电话遥控装置
随着社会的发展和人们生活水平的提高,越来越多的家用电器进入了人们的生活,这些家用电器给人们的生活带来了很多的方便和享受,同时随着电话在家庭中的普及,利用电话实现家用电器遥控是家用电器未来的发展方向[1]。本文介绍一种基于单片机的电话遥控装置。利用该装置,用户可以通过任意一部双音频电话(包括手机和固定电话)遥控家中的电器。当用户要下班时,可以通过电话,提前打开空调、电饭锅,用户回到家里时,饭煮好了,房子里温度刚刚好。用户也可以通过电话随时开关、检查家里电器的使用情况等等。总之,电话通到哪里,用户就可以从哪里遥控家中的电器。 1 遥控装置的工作原理 基于PIC单片机控制家用电器电话遥控装置的工作原理是:当有电话打入时,振铃
[单片机]
基于<font color='red'>PIC单片机</font>的家用电器电话遥控装置
PIC单片机实用教程基础篇
PIC单片机(Peripheral Interface Controller)是一种用来开发的去控制外围设备的集成电路(IC)。一种具有分散作用(多任务)功能的CPU。与人类相比,大脑就是CPU,PIC 共享的部分相当于人的神经系统。 PIC 单片机是一个小的计算机 PIC单片机有计算功能和记忆内存像CPU并由软件控制允行。然而,处理能力—存储器容量却很有限,这取决于PIC的类型。但是它们的最高操作频率大约都在20MHz左右,存储器容量用做写程序的大约1K—4K字节。 时钟频率与扫描程序的时间和执行程序指令的时间有关系。但不能仅以时钟频率来判断程序处理能力,它还随处理装置的体系结构改变(1*)。如果是同样的体系结构,时钟频
[单片机]
基于PIC单片机的六挡调控电涡流缓速器的设计
针对国内重卡的制造工艺,设计了一种基于PIC单片机的新型电涡流缓速器。该缓速器分六挡位调控,可很好地实现恒速、现场编程以及声光提示挡位等功能。 电涡流缓速器是一种高效汽车制动辅助装置,它既可以使汽车在坡道行驶时,方便地实行缓速和恒速行驶,也可以在高速公路或者路况较差的情况下,及时轻松地进行缓速,因此可极大提高汽车行驶时的安全性与舒适性。 目前国外使用的缓速器有两种形式,一种是利用液体的压力来实现的,称为“液力缓速器”,液力缓速器存在着结构复杂,维护困难等诸多缺点。另一种是“电涡流缓速器”,相比液力缓速器,它结构简单,维护方便。但国外的电涡流缓速器大多采用继电器作为控制元件(如法国的TELMA等),由于继电器频繁吸合,
[应用]
STM32示波器程序ILI9341_IO模拟源程序+Proteus仿真
uint8 x_1= 0,y_1 = 0; uint8 x_2= 0,y_2 = 0; uint8 x_3= 0,y_3 = 0; uint8 x_4= 0,y_4 = 0; uint8 x_5= 0,y_5 = 0; uint8 t4_PianYi_x = 0,t4_PianYi_y = 0; uint8 t5_PianYi_x = 0,t5_PianYi_y = 0; int i = 0 ; for( i= 0;i t1*3;i++) { x_1 = 10+ i;
[单片机]
STM32示波器程序ILI9341_IO<font color='red'>模拟</font>源程序+<font color='red'>Proteus</font>仿真
PIC单片机C语言设计
  前言   学习PIC单片机设计,除了理论学习之外,主要就是依靠实践,离开了实践的学习只能是纸上谈兵。这里我们使用下面的低成本实验器材进行PIC单片机的学习及设计。   1.MPLABIDE集成开发环境。   2.PICCC语言编译器。   3PICDEMO单片机综合试验板。4,ICD2在线调试器/程序下载器。5.5V高稳定专用稳压电源。下面简介一下这些实验工具及器材。   1.MPLABIDE集成开发环境   MPLABIDE是MicroChip公司开发的用于PIC单片机的集成开发环境,包括工程项目管理器、源程序编辑器、汇编器、软件调试器、在线调试器等,并且支持第三方的C语言开发工具。下图为MPLABIDE的工作界面。  
[单片机]
<font color='red'>PIC单片机</font>C语言设计
PIC单片机串口发送与按键
这是我学习PIC单片机调试过程中尝试的PIC单片机串口发送实验,当按键RB0有按下时,num自加,同时RC0端口接的LED翻转,并把num的数传给发送寄存器发送至电脑端,波特率为9600,4M晶振. 代码如下: #include pic.h __CONFIG(0x3B31); unsigned int num=0; void GPIO_init() { TRISB=0xff; TRISC=0xfe; TRISC0=0; OPTION_REG=0x07; } void delay(unsigned int x) { unsigned int i,j; for(i=x;i 0;i–) for(j=110;j 0;j–
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved