//用于PIC16F887的程序
//T1CON = 0b00001001;调试成功后改为0b00001011;
//在RC0和RC1上连接32.768kHz的晶体)
#include <pic.h>
//常数定义
#define HZ 16 //16X16,全角汉字
#define SZ 8 //8X16,半角数字或字符
//HGD12864F-1的命令定义
#define RESET 0b11100010 //复位指令
#define DISP_ON 0b10101111 //显示开
#define DISP_OFF 0b10101110 //显示关
#define DISP_ALL 0b10100100 //显示所有的点,+1为显示
#define DISP_NORMAL 0b10100110 //正常显示,+1为反相
#define LINE0 0b01000000 //行0,加上0-63,共64行,由此可实现滾动
#define PAGE0 0b10110000 //页0,加上0-7,共7页
#define COLHI 0b00010000 //列的高4位
#define COLLO 0b00000000 //列的低4位,共有16列
#define ADC 0b10100000 //横向方向,+1为向右
#define COM_DIR 0b11000000 //纵向方向,+8为方向向下
//LCD引脚定义
#define SCK RC3
#define A0 RC4
#define SDO RC5
#define RESET_LCD RC6
#define CS RC7
//在指定的行Y=0~3,列X显示1个16×16汉字或16×8字符,数据存放在一维数组A[]中
//当HZ_SZ=16时显示汉字,HZ_SZ=8时显示半角字符数字
//X=0~15,程序将其转换为实际的列0~112。
void DISP_ONE(char X,char Y,const char * A,char HZ_SZ);
void CSH(void);
void WRITE_COMMAND(char TYPE);//写一字节命令TYPE
void WRITE_DATA(char DATA);//写一字节数据DATA
void INT_TO_BCD(unsigned int);
void CHAR_TO_BCD(char);
//#define MOTOR RB2
//16×16点阵字模信息
const char HANZI_NIAN[32]={ //年
0x00,0x20,0x10,0xCC,0x47,0x44,0x44,0xFC,0x44,0x44,0x44,0x64,0x46,0x04,0x00,0x00,
0x04,0x04,0x04,0x07,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00};
const char HANZI_YUE[32]={ //月
0x00,0x00,0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0x22,0xFF,0x02,0x00,0x00,0x00,
0x00,0x80,0x40,0x30,0x0F,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x00,0x00,0x00,0x00};
const char HANZI_RI[32]={ //日
0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFF,0x02,0x00,0x00,0x00,
0x00,0x00,0x00,0x7F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7F,0x00,0x00,0x00,0x00};
const char HANZI_SHI[32]={ //时
0x00,0xFC,0x84,0x84,0x84,0xFE,0x14,0x10,0x90,0x10,0x10,0x10,0xFF,0x10,0x10,0x00,
0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x00,0x23,0x40,0x80,0x7F,0x00,0x00,0x00};
const char HANZI_FEN[32]={ //分
0x00,0x80,0x40,0x20,0x98,0x86,0x80,0x80,0x83,0x8C,0x90,0x20,0xC0,0x80,0x80,0x00,
0x01,0x00,0x80,0x40,0x20,0x1F,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x01,0x00,0x00};
const char HANZI_MIAO[32]={//秒
0x20,0x24,0x24,0xA4,0xFE,0xA3,0x22,0x80,0x70,0x00,0xFF,0x00,0x10,0x20,0x60,0x00,
0x10,0x08,0x06,0x01,0xFF,0x00,0x81,0x80,0x40,0x20,0x17,0x08,0x04,0x03,0x00,0x00};
//半角数字和字符,下标0-9分别为0-9的16×8点阵字模信息
const char ASCII[10][16]={
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},
{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00},
{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},
{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00},
{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00},
{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},
{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00},
{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00},
{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},
{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00}
};
char WW,QW,BW,SW,GW;
struct
{
unsigned int Year;
char Month;
char Day;
char Hour;
char Minute;
char Secoend;
}Clock;
void DELAY(unsigned int);
void INITIAL_ALL(void); //初始化声明
void interrupt INT_ALL_ISR(void); //所有中断的声明
void TMR1_ISR(void); //TIMER1中断专用的声明
char Isr_Inc_Minute(void); //if Minute+1=0 return 1,else return 0
char Isr_Inc_Hour(void); //if Hour+1=0 return 1,else return 0
char Isr_Inc_Day(void); //if Day+1=0 return 1,else return 0
char Isr_Inc_Month(void); //if Month+1=0 return 1,else return 0
void Isr_Inc_Year(void);
main(void)
{
RESET_LCD=0;
TRISC=3;
TMR1H = 0X80; //timer1赋初始值
TMR1L = 0;
T1CON = 0b00001001;//(调试成功后改为0b00001011;使用32.768kHz的晶体连接到RC0和RC1上)
TMR1IF = 0;
TMR1IE = 1;
RESET_LCD=1;
PEIE=1;
GIE=1;
Clock.Year=2012; //2012年
Clock.Month=10; //1月
Clock.Day=27; //1号
Clock.Hour=22; //12时
Clock.Minute=57; //30分
Clock.Secoend=0; //0秒
CSH();
//X=0~15,Y=0~3
DISP_ONE(4,0,HANZI_NIAN,HZ);DISP_ONE(8,0,HANZI_YUE,HZ); DISP_ONE(12,0,HANZI_RI,HZ);
DISP_ONE(4,1,HANZI_SHI,HZ);//时
DISP_ONE(8,1,HANZI_FEN,HZ);//分
DISP_ONE(12,1,HANZI_MIAO,HZ);//秒
while(1)
{ DELAY(50);
CLRWDT();//清除看门狗定时器
INT_TO_BCD(Clock.Year);
DISP_ONE(0,0,ASCII[QW],SZ);//X=0~15,Y=0~3
DISP_ONE(1,0,ASCII[BW],SZ);//X=0~15,Y=0~3
DISP_ONE(2,0,ASCII[SW],SZ);//X=0~15,Y=0~3
DISP_ONE(3,0,ASCII[GW],SZ);//X=0~15,Y=0~3
CHAR_TO_BCD(Clock.Month);
DISP_ONE(6,0,ASCII[SW],SZ);//X=0~15,Y=0~3
DISP_ONE(7,0,ASCII[GW],SZ);//X=0~15,Y=0~3
CHAR_TO_BCD(Clock.Day);
DISP_ONE(10,0,ASCII[SW],SZ);
DISP_ONE(11,0,ASCII[GW],SZ);
CHAR_TO_BCD(Clock.Hour);
DISP_ONE(2,1,ASCII[SW],SZ);
DISP_ONE(3,1,ASCII[GW],SZ);
CHAR_TO_BCD(Clock.Minute);
DISP_ONE(6,1,ASCII[SW],SZ);
DISP_ONE(7,1,ASCII[GW],SZ);
CHAR_TO_BCD(Clock.Secoend);
DISP_ONE(10,1,ASCII[SW],SZ);
DISP_ONE(11,1,ASCII[GW],SZ);
}
}
//======延时(n)ms
void DELAY(unsigned int n)
{
unsigned int j;
char k;
for (j=0;j<n;j++)
for (k=246;k>0;k--)
NOP();
}
void interrupt INT_ALL_ISR(void)
{
if(TMR1IF) TMR1_ISR();
}
//TIMER1专用中断的定义(用于实时时钟计时,产生:年-月-日-时-分-秒)
void TMR1_ISR(void)
{
TMR1IF=0;
TMR1H = 0X80;
TMR1L = 0x00;
if(Clock.Secoend++>=59)
{ Clock.Secoend=0;
if(Isr_Inc_Minute())
if(Isr_Inc_Hour())
if(Isr_Inc_Day())
if(Isr_Inc_Month())
Isr_Inc_Year();
}
}
char Isr_Inc_Minute(void) //if Minute+1=0 return 1,else return 0
{ Clock.Minute++;
if(Clock.Minute>59)
{Clock.Minute=0;return 1;}
else return 0;
}
char Isr_Inc_Hour(void) //if Hour+1=0 return 1,else return 0
{ Clock.Hour++;
if(Clock.Hour > 23)
{Clock.Hour=0;return 1;}
else return 0;
}
char Isr_Inc_Day(void) //if Day+1=0 return 1,else return 0
{char Days;
Days=30;
if(Clock.Month==2)
{ if(((Clock.Year%4==0)&&(Clock.Year%400!=0))||(Clock.Year%400==0))
Days=29;
else Days=28;
}
switch(Clock.Month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
Days = 31;
break;
default:
break;
}
Clock.Day++;
if(Clock.Day>Days)
{ Clock.Day=1;return 1;}
else return 0;
}
char Isr_Inc_Month(void) //if Month+1=0 return 1,else return 0
{ Clock.Month++;
if (Clock.Month>12)
{Clock.Month=1;return 1;}
else
return 0;
}
void Isr_Inc_Year(void)
{Clock.Year++;}
//...................................
void INT_TO_BCD(unsigned int n)
{
WW=0;QW=0;BW=0;SW=0;GW=0;
while(n>=10000)
{n-=10000;WW++;}
while(n>=1000)
{n-=1000;QW++;}
while(n>=100)
{n-=100;BW++;}
while(n>=10)
{n-=10;SW++;}
GW=n;
}
void CHAR_TO_BCD(char n)
{ BW=0;SW=0;GW=0;
while(n>=100)
{n-=100;BW++;}
while(n>=10)
{n-=10;SW++;}
GW=n;
}
void CSH(void)
{ WRITE_COMMAND(RESET); //复位
WRITE_COMMAND(DISP_ON); //显示开
WRITE_COMMAND(ADC+1); //+1为自动向右
WRITE_COMMAND(DISP_ALL);
WRITE_COMMAND(DISP_NORMAL); //正常显示,DISP_NORMAL+1为反相显示
WRITE_COMMAND(COM_DIR);
}
//在指定的行Y,列X显示1个16×16汉字或16×8字符,数据存放在一维数组A[]中
//当HZ_SZ=16时显示汉字,HZ_SZ=8时显示半角字符数字
////X=0~15,程序将其转换为实际的列0~112。Y=0~3
void DISP_ONE(char X,char Y,const char * A,char HZ_SZ)
{ char i,j,a,b;
b=X<<3; //如果是SZ乘以8,将X=0~15转换为实际的列0~112
//if(HZ_SZ==HZ)b=X<<4; //如果是HZ,乘以16,将X=0~7转换为实际的列0~112
a=b>>4;
a=COLHI+a; //得到列的高4位命令字
b=b & 0x0F;
b=COLLO+b; //得到列的低4位命令字
WRITE_COMMAND(a); //写列高4�
评论0