一匹狼 发表于 2013-3-31 00:34:41

求助:关于LCD12864万年历的c程序

原理图



代码:
/************************************mian.c********************************/********************************************************************
文件名:万年历.c
晶振频率:12MHz
芯片:STC89C52
*********************************************************************/
#include "reg52.h"
#include "intrins.h"
#include "string.h"
#include "LCD_12864.c"
#define uchar unsigned char
#define uint unsigned int
/*extern void LCD_Initialize(void);
extern void Display_A_Char_8X16(uchar P,uchar L,uchar *M);
extern void Display_A_WORD(uchar P,uchar L,uchar *M);
//在调整日期时间时,用该位决定是否反白显示
extern bit Reverse_Display=0;
*/
sbit SDA=P1^0;//DS1302数据线
sbit CLK=P1^1;//DS1302时钟线
sbit RST=P1^2;//DS1302复位线
sbit k1=P3^4;//选择
sbit k2=P3^5;//加
sbit k3=P3^6;//减
sbit k4=P3^7;//确定
uchar tCount=0;
//一年中每个月的天数,2月的天数由年份决定
uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
//所读取的日期时间
uchar DateTime;
//当前调整的时间对象:秒,分,时,日,月,年(0,1,2,3,4,6)
//5对应星期,星期调节由年月日调整自动完成
char Adjust_Index=-1;
//水平与垂直偏移
uchar H_Offset=10,V_Page_Offset=0;
//年月日,星期,时分秒汉字点阵(16*16)-------------------------------
uchar code DATE_TIME_WORDS[]={
/*--文字:年--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x20,0x18,0xC7,0x44,0x44,0x44,0x44,0xFC,0x44,0x44,0x44,0x44,0x04,0x00,0x00,
0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x04,0x00,
/*--文字:月--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0xFE,0x00,0x00,0x00,
0x80,0x40,0x30,0x0F,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x00,0x00,0x00,
/*--文字:日--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x00,0x00,0x00,0x00,
/*--文字:星--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x00,0x00,0xBE,0x2A,0x2A,0x2A,0xEA,0x2A,0x2A,0x2A,0x3E,0x00,0x00,0x00,0x00,
0x00,0x44,0x42,0x49,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x49,0x41,0x40,0x00,0x00,
/*--文字:期--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x04,0xFF,0x24,0x24,0x24,0xFF,0x04,0x00,0xFE,0x22,0x22,0x22,0xFE,0x00,0x00,
0x88,0x48,0x2F,0x09,0x09,0x19,0xAF,0x48,0x30,0x0F,0x02,0x42,0x82,0x7F,0x00,0x00,
/*--文字:时--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0xFC,0x84,0x84,0x84,0xFC,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x00,
0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x01,0x06,0x40,0x80,0x7F,0x00,0x00,0x00,
/*--文字:分--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x40,0x80,0x00,
0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x00,0x00,0x00,
/*--文字:秒--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x24,0x24,0xA4,0xFE,0x23,0x22,0x00,0xC0,0x38,0x00,0xFF,0x00,0x08,0x10,0x60,0x00,
0x08,0x06,0x01,0xFF,0x01,0x06,0x81,0x80,0x40,0x40,0x27,0x10,0x0C,0x03,0x00,0x00,
};
//星期几的汉字点阵(16*16)----------------------------------
uchar code WEEDDAY_WORDS[]={
/*--文字:日--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x00,0x00,0x00,0x00,
/*--文字:一--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/*--文字:二--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,
/*--文字:三--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x04,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x04,0x00,0x00,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
/*--文字:四--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0xFC,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0xFC,0x00,0x00,
0x00,0x7F,0x28,0x24,0x23,0x20,0x20,0x20,0x20,0x21,0x22,0x22,0x22,0x7F,0x00,0x00,
/*--文字:五--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x00,0x02,0x42,0x42,0x42,0xC2,0x7E,0x42,0x42,0x42,0x42,0xC2,0x02,0x02,0x00,0x00,
0x40,0x40,0x40,0x40,0x78,0x47,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x00,
/*--文字:六--*/
/*--宋体12;此字体下对应的点阵为:宽x高=16x16   --*/
0x20,0x20,0x20,0x20,0x20,0x20,0x21,0x22,0x2C,0x20,0x20,0x20,0x20,0x20,0x20,0x00,
0x00,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x01,0x02,0x04,0x18,0x60,0x00,0x00,
};
//半角数字点阵(8*16)----------------------------------------------------
uchar code DIGITS[]={
/*--文字:0--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,
/*--文字:1--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
/*--文字:2--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,
/*--文字:3--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,
/*--文字:4--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,
/*--文字:5--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,
/*--文字:6--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,
/*--文字:7--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,
/*--文字:8--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,
/*--文字:9--*/
/*--宋体12;此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,
};


//向DS1302写入一字节
void Write_A_Byte_TO_DS1302(uchar x)
{        uchar i;
        for(i=0;i<8;i++)
        {        SDA=x&1; CLK=1; CLK=0; x>>=1;
        }
}
//从DS1302读取一字节
uchar Get_A_Byte_FROM_DS1302(void)
{        uchar i,b,t;
        for(i=0;i<8;i++)
        {        b>>=1; t=SDA; b|=t<<7; CLK=1; CLK=0;
        }
        //BCD码转换
        return(b/16*10+b%16);
}
//从DS1302指定位置读数据
uchar Read_Data(uchar addr)
{        uchar dat;
        RST=0; CLK=0; RST=1;
        Write_A_Byte_TO_DS1302(addr);
        dat=Get_A_Byte_FROM_DS1302();
        CLK=1; RST=0;
        return(dat);
}
//向DS1302某地址写入数据
void Write_DS1302(uchar addr,uchar dat)
{        CLK=0; RST=1;
        Write_A_Byte_TO_DS1302(addr);
        Write_A_Byte_TO_DS1302(dat);
        CLK=0; RST=0;
}



//设置时间
void SET_DS1302(void)
{        uchar i;
        Write_DS1302(0x8e,0x00);
        //秒分时日月年依次写入
        for(i=0;i<7;i++)
        {        //秒的起始地址1000 0000(0x80)
                //后续依次是分,时,月,周,年,写入地址每次递增2
                Write_DS1302(0x80+2*i,(DateTime/10<<4)|(DateTime%10));
        }
        Write_DS1302(0x8e,0x80);
}
//读取当前日期时间
void GetTime(void)
{        uchar i;
        for(i=0;i<7;i++)
        {        DateTime=Read_Data(0x81+2*i);
        }
}


//半断是否为闰年
uchar isLeapYear(uint y)
{        return((y%4==0&&y%100!=0)||(y%400==0));
}
//--------------------------------------------
//求自2000.1.1开始的任何一天是星期几
//函数没有通过,求出总天数后在求出星期几
//因为求总天数可能会月出uint的范围
//--------------------------------------------
void RefreshWeekDay(void)
{        uint i,d,w=5;//已知1999.12.31是周五
        for(i=2000;i<2000+DateTime;i++)
        {        d=isLeapYear(i)?366:365;
                w=(w+d)%7;
        }
        d=0;
        for(i=1;i<DateTime;i++)d+=MonthsDays;
        d+=DateTime;
        //保存星期,0~6表示星期日,星期一,二,、、、六,为了与DS1302的星期格式匹配,返回值需要加1
        DateTime=(w+d)%7+1;
}


//年月日时分秒++/--
void DateTime_Adjust(char x)
{        switch(Adjust_Index)
        {        case 6://年00-99
                        if(x==1&&DateTime<99)DateTime++;
                        if(x==-1&&DateTime>0)DateTime--;
                        //获取2月天数
                        MonthsDays=isLeapYear(2000+DateTime)?29:28;
                        //如果年份变化后当前月份的天数大于上限则设为上限
                        if(DateTime>MonthsDays])DateTime=MonthsDays];
                        RefreshWeekDay();//刷新星期
                        break;
                case 4:   //月01-12
                        if(x==1&&DateTime<12)DateTime++;
                        if(x==-1&&DateTime>1)DateTime--;
                        //获取2月份天数
                        MonthsDays=isLeapYear(2000+DateTime)?29:28;
                        //如果月份变化后当前月份的天数大于上限则设为上限
                        if(DateTime>MonthsDays])DateTime=MonthsDays];
                        RefreshWeekDay();//刷新星期
                        break;
                case 3://日00-28/29/30/31;调节之前首先根据年份得出该年中2月的天数
                        MonthsDays=isLeapYear(2000+DateTime)?29:28;
                        //根据当前月份决定调节日期的上限
                        if(x==1&&DateTime<MonthsDays])DateTime++;
                        if(x==-1&&DateTime>1)DateTime--;
                        RefreshWeekDay();//刷新星期
                        break;
                case 2://时
                        if(x==1&&DateTime<23)DateTime++;
                        if(x==-1&&DateTime>1)DateTime--;
                        break;
                case 1://分
                        if(x==1&&DateTime<59)DateTime++;
                        if(x==-1&&DateTime>1)DateTime--;
                        break;
                case 0://秒
                        if(x==1&&DateTime<59)DateTime++;
                        if(x==-1&&DateTime>1)DateTime--;
        }
}


//定时器0每秒刷新LCD显示
void T0_INT(void) interrupt 1
{        TH0=-50000/256;
        TL0=-50000%256;
        if(++tCount!=2)return;
        tCount=0;
        if(Adjust_Index==-1)GetTime();        //如果未执行调整操作则正常读取当前时间
        //年后两位
        Reverse_Display=Adjust_Index==6;   /*等同于
        {        if(Adjust_Index==6)Reverse_Display=1;
                else Reverse_Display=0;                }        */
        Display_A_Char_8X16(V_Page_Offset,16+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset,24+H_Offset,DIGITS+DateTime%10*16);
        //月
        Reverse_Display=Adjust_Index==4;
        Display_A_Char_8X16(V_Page_Offset,48+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset,56+H_Offset,DIGITS+DateTime%10*16);
        //日
        Reverse_Display=Adjust_Index==3;
        Display_A_Char_8X16(V_Page_Offset,80+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset,88+H_Offset,DIGITS+DateTime%10*16);
        //星期
        Reverse_Display=Adjust_Index==5;
        Display_A_WORD(V_Page_Offset+2,96+H_Offset,WEEDDAY_WORDS+(DateTime-1)*32);
        //时
        Reverse_Display=Adjust_Index==2;
        Display_A_Char_8X16(V_Page_Offset+5,16+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset+5,24+H_Offset,DIGITS+DateTime%10*16);
        //分
        Reverse_Display=Adjust_Index==1;
        Display_A_Char_8X16(V_Page_Offset+5,48+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset+5,56+H_Offset,DIGITS+DateTime%10*16);
        //秒
        Reverse_Display=Adjust_Index==0;
        Display_A_Char_8X16(V_Page_Offset+5,80+H_Offset,DIGITS+DateTime/10*16);
        Display_A_Char_8X16(V_Page_Offset+5,88+H_Offset,DIGITS+DateTime%10*16);
}


//键盘中断(INT0)
void EX_INT0(void) interrupt 0
{        if(k1==0)//选择调整对象
        {        if(Adjust_Index==-1||Adjust_Index==0)Adjust_Index=7;
                Adjust_Index--;
                if(Adjust_Index==5)Adjust_Index=4;//跳过对星期的调整
        }
        else if(k2==0)DateTime_Adjust(1);//加
        else if(k3==0)DateTime_Adjust(-1);//减
        else if(k4==0)//确定
        {        SET_DS1302();//将调整后的时间写入DS1302
                Adjust_Index=-1;//操作索引重设为-1,时间继续正常显示
        }
}


//主程序
void main()
{        //液晶初始化
        LCD_Initialize();
        //显示年的固定前两位
        Display_A_Char_8X16(V_Page_Offset,0+H_Offset,DIGITS+2*16);
        Display_A_Char_8X16(V_Page_Offset,8+H_Offset,DIGITS);
        //显示固定汉字:年月日,星期,时分秒
        Display_A_WORD(V_Page_Offset,32+H_Offset,DATE_TIME_WORDS+0*32);
        Display_A_WORD(V_Page_Offset,64+H_Offset,DATE_TIME_WORDS+1*32);
        Display_A_WORD(V_Page_Offset,96+H_Offset,DATE_TIME_WORDS+2*32);
        Display_A_WORD(V_Page_Offset+2,64+H_Offset,DATE_TIME_WORDS+3*32);
        Display_A_WORD(V_Page_Offset+2,80+H_Offset,DATE_TIME_WORDS+4*32);
        Display_A_WORD(V_Page_Offset+5,32+H_Offset,DATE_TIME_WORDS+5*32);
        Display_A_WORD(V_Page_Offset+5,64+H_Offset,DATE_TIME_WORDS+6*32);
        Display_A_WORD(V_Page_Offset+5,96+H_Offset,DATE_TIME_WORDS+7*32);
        //允许INT0,T0中断
        IE=0x83;
        IP=0x01;
        IT0=0x01;
        TH0=-50000/256;
        TL0=-50000%256;
        TR0=1;
        while(1);
}
/******************************LCD12864.c*******************************************/#include "reg52.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int

#define LCD_DB_PORT P0//液晶DB0~DB7
#define LCD_START_ROW 0xc0//起始行
#define LCD_PAGE 0xb8//页指令
#define LCD_COL 0x40//列指令
//液晶引脚定义
sbit LCD_DI=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_E=P2^2;
sbit LCD_CS1=P2^3;
sbit LCD_CS2=P2^4;
sbit LCD_RST=P2^5;

bit Reverse_Display=0;
//检查LCD是否忙
bit LCD_Check_Busy(void)
{        LCD_DB_PORT=0xff;
        LCD_RW=1; _nop_(); LCD_DI=0;
        LCD_E=1; _nop_(); LCD_E=0;
        return(bit)(P0&0x80);
}
//向LCD发送命令
void LCD_Write_Command(uchar c)
{        while(LCD_Check_Busy());
        LCD_DB_PORT=0xff; LCD_RW=0; _nop_(); LCD_DI=0;
        LCD_DB_PORT=c; LCD_E=1; _nop_(); LCD_E=0;
}
//向LCD发送数据
void LCD_Write_Data(uchar d)
{        while(LCD_Check_Busy());
        LCD_DB_PORT=0xff;
        LCD_RW=0;_nop_();LCD_DI=1;
        //根据Reverse_Display决定是否反相显示
        if(!Reverse_Display)LCD_DB_PORT=d;else LCD_DB_PORT=~d;
        LCD_E=1;_nop_();LCD_E=0;
}
//初始化LCD
void LCD_Initialize(void)
{        LCD_CS1=1;LCD_CS2=1;
        LCD_Write_Command(0x38);
        LCD_Write_Command(0x0f);
        LCD_Write_Command(0x01);
        LCD_Write_Command(0x06);
        LCD_Write_Command(LCD_START_ROW);
}
//通用显示函数
//从第P页第L列开始显示W个字节数据,数据在r所指向的缓冲
//每字节8位是垂直显示的,高位在下,低位在上
//每个8*128的矩形区域为一页
//整个LCD右由64*64的左半屏和64*64的右半屏构成
void Common_Show(uchar P,uchar L,uchar W,uchar *r)
{        uchar i;
        if(L<64)//显示在左半屏或左右半屏
        {        LCD_CS1=1;LCD_CS2=0;
                LCD_Write_Command(LCD_PAGE+P);
                LCD_Write_Command(LCD_COL+L);
                if(L+W<64)//全部显示在左右半屏
                {        for(i=0;i<W;i++)LCD_Write_Data(r);
                }
                else   //如果越界则跨左右半屏显示
                {        for(i=0;i<64-L;i++)LCD_Write_Data(r);//左半屏显示
                        LCD_CS1=0;LCD_CS2=1;//右半屏显示
                        LCD_Write_Command(LCD_PAGE+P);
                        LCD_Write_Command(LCD_COL);
                        for(i=64;i<W;i++)LCD_Write_Data(r);
                }
        }
        else //全部显示在右半屏
        {        LCD_CS1=0;LCD_CS2=1;
                LCD_Write_Command(LCD_PAGE+P);
                LCD_Write_Command(LCD_COL+L-61);
                for(i=0;i<W;i++)LCD_Write_Data(r);
        }
}
//显示8*16点阵字符
void Display_A_Char_8X16(uchar P,uchar L,uchar *M)
{        Common_Show(P,L,8,M);
        Common_Show(P+1,L,8,M+8);
}
//显示一个16*16点阵汉字
void Display_A_WORD(uchar P,uchar L,uchar *M)
{        Common_Show(P,L,16,M);//显示汉字上半部分
        Common_Show(P+1,L,16,M+16);
}
编译无法通过,error and warning


附件






一匹狼 发表于 2013-3-31 11:16:32

自顶一下,
页: [1]
查看完整版本: 求助:关于LCD12864万年历的c程序