main函數:
void main()
{
Time0_Init(10);
Init_LCD1616();
Clear_Screen(0);
Write_6x16Font_N(1,0,0,);
while(1)
{
GetKeyValue(); //讀取按鍵數據
GotoDisplay(); //顯示時鐘芯片的數據
}
}
顯示模塊函數:
void write(bit flag,uchar dat)
{
LCD1616_CS=0;
LCD1616_RS=flag; //flag=1,write command;flag=0,write data
LCD1616_WR=0;
LCD1616_RD=1;
LCDPort=dat;
LCD1616_WR=1;
}
/**************LCD160160初始化***************************/
void Init_LCD1616()
{
LCD1616_RST = 0;
LCD_Delay(10); //power on reset
LCD1616_RST = 1;
LCD_Delay(800);
write(0,0x25); //設置溫度補償系數-0.05%/C
write(0,0x2b); //內部 DC-DC
write(0,0xc4); // LCD 映像 MY=1,MX=0,LC0=0
write(0,0xa1); //設置行掃描頻率 FR=62.5Hz
write(0,0xd1); //彩色數據格式 R-G-B
write(0,0xd5); //設置數據位為 12 位 RRRR-GGGG-BBBB
write(0,0xc8); write(0,0x00); //設置 M 信號為幀翻轉
write(0,0xe9); //設置偏壓比 1/10
write(0,0xa6); //正性顯示
write(0,0xa4); //正常顯示
write(0,0x81); write(0,0xef); //設置對比度 bf
write(0,0xd8); //設置掃描模式
write(0,0xad); //開顯示
LCD_Delay(50);
}
/****************************清屏or全顯************************
Input :Dat;Dat=0,清屏;Dat =1,全顯.
1 column = 3 pixel; 1 pixel = 4bit;
UC1698的column:0X00-0X7F-->0-127;line: 0X00-0X9F-->0-159
但是160*160單色液晶的column為第37列到90列-->0X25-0X5A
行地址范圍0-159行-->0X00-0X9F,實際是160*162,160行,54列
由于2 column = 6 pixel =24 bit = 3Byte,所以一行有27組(3Byte)
**************************************************************/
void Clear_Screen(uchar dat1)
{
uchar i,j;
write(0,0x60); //row address LSB 最低有效位
write(0,0x70); //row address MSB 最高有效位
write(0,0x05); //culomn address LSB 最低有效位
write(0,0x12); //culomn address MSB 最高有效位
for(j=0;j<160;j++)
{
for(i=0;i<27;i++)
{
write(1,dat1); //見手冊中的第21條命令格式 將RGB的每3個字節存到16位寄存器中
write(1,dat1);
write(1,dat1);
}
}
}
/****************寫一個宋體 小四***16*16*******************
16/3=5---1,補充兩,湊齊6列,6列x16行
*******************************************************/
void Write_6x16Font(u8 x,y,u8 *cn)
{
u8 i=0;
u8 WordNum=0; //字符個數
u8 ZiKuDat,YingSheDat;
u16 x1,x2,y1,y2,L;
//--設置顯示區域
x+=0X25; //此款LCD160的列是從第0X25列開始
write(0,0XF4); //列起始地址
write(0,x); //start: 37
write(0,0XF6); //列結束地址
write(0,x+5); //end: 90
//因為列開始到結尾共90-37=53個數所以 一個數代表160/53=3個像素
write(0,0XF5); //行起始地址
write(0,y); //start:0
write(0,0XF7); // 行結束地址
write(0,y+15); //end:159
write(0,0XF8);
//--設置起始列,行地址
x1=0X00 |(x&0X0F);
x2=0X10 |(x>>4);
y1=0X60 |(y&0X0F);
y2=0X70 |(y>>4);
write(0,x1);write(0,x2);
write(0,y1);write(0,y2);
write(0,0XA6);
for(WordNum=0;WordNum<WordNumMax;WordNum++) //掃描漢字字庫
{
//--匹配字庫數據
if(*cn == HanZi16X16[WordNum].Index[0] && *(cn+1)==HanZi16X16[WordNum].Index[1])
{
for(i=0;i<16;i++)
{
ZiKuDat=HanZi16X16[WordNum].Msk[2*i];
//--完成8bit字庫數據的寫
for(L=0;L<4;L++)
{
switch(ZiKuDat&0XC0) //判斷2bit字庫數據
{
//--將2bit字庫數據轉換成8bit映射數據
case 0X00:YingSheDat=0X00;break;
case 0X40:YingSheDat=0X0F;break;
case 0X80:YingSheDat=0XF0;break;
case 0XC0:YingSheDat=0XFF;break;
}
write(1,YingSheDat); //寫映射數據
ZiKuDat<<=2;
}
ZiKuDat=HanZi16X16[WordNum].Msk[2*i+1];
for(L=0;L<4;L++)
{
switch(ZiKuDat&0XC0) //判斷2bit字庫數據
{
//--將2bit字庫數據轉換成8bit映射數據
case 0X00:YingSheDat=0X00;break;
case 0X40:YingSheDat=0X0F;break;
case 0X80:YingSheDat=0XF0;break;
case 0XC0:YingSheDat=0XFF;break;
}
write(1,YingSheDat); //寫映射數據
ZiKuDat<<=2;
}
write(1,0X00); //補最后的一字節空白
}
}
}
}
/*****************寫N個小四宋體**********
9列10行,x:0-9;y:0-10;
****************************************/
void Write_6x16Font_N(u8 x,y,z,u8 *cn)
{
u8 Cnnum=0;
x=x*3;
y=y*16;
if(z) //豎著寫
{
while(*cn != '\0')
{
Write_6x16Font(x,y+8*Cnnum,cn);
Cnnum++;
cn++;
}
}
else //橫著寫 //6列16行
{
while(*cn != '\0')
{
Write_6x16Font(x+3*Cnnum,y,cn); //漢字占兩個字符
Cnnum++;
cn++;
}
}
}
void Write_ASCII3X16(u8 x,y,u8 *p)
{
u8 i=0;
u8 WordNum=0; //字符個數
u8 ZiKuDat,YingSheDat;
u16 x1,x2,y1,y2,L;
//--設置顯示區域
x+=0X25; //此款LCD160的列是從第0X25列開始
write(0,0XF4); //列起始地址
write(0,x); //start: 37
write(0,0XF6); //列結束地址
write(0,x+3); //end: 90 //橫著寫 //write(0,x+3); //豎著寫
//因為列開始到結尾共90-37=53個數所以 一個數代表160/53=3個像素
write(0,0XF5); //行起始地址
write(0,y); //start:0
write(0,0XF7); // 行結束地址
write(0,y+15); //end:159 //write(0,y+15*WordNum); //豎著寫
write(0,0XF8);
//--設置起始列,行地址
x1=0X00 |(x&0X0F);
x2=0X10 |(x>>4);
y1=0X60 |(y&0X0F);
y2=0X70 |(y>>4);
write(0,x1);write(0,x2);
write(0,y1);write(0,y2);
write(0,0XA6);
WordNum = *p-32;
for(i=0;i<16;i++)
{
ZiKuDat=ASCII8X16[WordNum][ i];
//--完成8bit字庫數據的寫
for(L=0;L<4;L++) //寫3(前面2列)+1(補充1列的第一字節)
{
switch(ZiKuDat&0XC0) //判斷2bit字庫數據
{
//--將2bit字庫數據轉換成8bit映射數據
case 0X00:YingSheDat=0X00;break;
case 0X40:YingSheDat=0X0F;break;
case 0X80:YingSheDat=0XF0;break;
case 0XC0:YingSheDat=0XFF;break;
}
write(1,YingSheDat); //寫映射數據
ZiKuDat<<=2;
}
//--對補充的1列的最后一字節的寫
write(1,0X00);
write(1,0X00);
}
}
/*******************寫一串字符串***3*16************
10行x18列
Input: x起始列地址,y起始行地址,*P 字符串,
z:=0,橫著寫,=1豎著寫
**************************************************/
void Write_ASCII3X16_N(u8 x,y,z,u8 *p)
{
u8 WordNum=0;
x=x*3;
y=y*16;
if(z)
{
while(*p != '\0')
{
Write_ASCII3X16(x,y+16*WordNum,p);
WordNum++;
p++;
}
}
else
{
while(*p != '\0')
{
Write_ASCII3X16(x+3*WordNum,y,p);
WordNum++;
p++;
}
}
}
ds1302時鐘函數:
#include "DS1302.h"
u8 DS1302sec=1,DS1302min=1,DS1302hour=8;
u8 DS1302day=26,DS1302month=4,DS1302week,DS1302year=20;
/**********向1302寫某一地址和數據(指令)**************/
void Write_Byte_1302(u8 add,u8 dat)
{
u8 i;
DS1302SCL = 0;
DS1302RST = 1;
add = add & 0xfe; //將控制指令的最低位清零,數據能夠輸入
for(i=0;i<8;i++)
{
DS1302SDA = add &0X01;
DS1302SCL = 1; //上升沿輸入數據
DS1302SCL = 0;
add >>= 1;
}
for(i=0;i<8;i++)
{
DS1302SDA = dat &0X01;
DS1302SCL=1; //上升沿輸入數據
DS1302SCL=0;
dat>>=1;
}
DS1302RST = 0; //寫完數據后將rst清零,終止數傳輸
}
/*************讀取1302的數據**********/
u8 Read_Byte_1302(u8 add)
{
u8 i,dat;
DS1302SCL = 0;
DS1302RST = 1; //開啟數據傳輸
add = add |0x01; //將最低位置一,保證數據是輸出
for(i=0;i<8;i++)
{
DS1302SDA = add &0X01;
DS1302SCL=1;
DS1302SCL=0;
add >>=1;
}
for(i=0;i<8;i++)
{
dat >>=1;
if(DS1302SDA) dat = dat | 0x80;
else dat = dat & 0x7f;
DS1302SCL=1;
DS1302SCL=0;
}
DS1302RST = 0; //終止數據傳輸
dat=dat/16*10+dat%16;
return dat;
}
void Write_1302()
{
Write_Byte_1302(0x8e,0x00); //關閉寫保護
Write_Byte_1302(0x80,0x80);
Write_Byte_1302(0x80,DS1302sec/10*16+DS1302sec%10);
Write_Byte_1302(0x82,DS1302min/10*16+DS1302min%10);
Write_Byte_1302(0x84,DS1302hour/10*16+DS1302hour%10);
Write_Byte_1302(0x86,DS1302day/10*16+DS1302day%10);
Write_Byte_1302(0x88,DS1302month/10*16+DS1302month%10);
Write_Byte_1302(0x8c,DS1302year/10*16+DS1302year%10);
Write_Byte_1302(0x8e,0x80); //開啟寫保護
}
/***********************顯示周*********************/
//=====計算2000~2099年任一天星期幾
// year:00-99
// month:01-12
// day:01-31
u8 GetWeekFromDay(u8 y,u8 m,u8 d)
{
u8 value;
if(m==1||m==2)
{
m+=12;
if(y>0) y--;
else y=4;
}
value=(d+2*m+3*(m+1)/5+y+y/4)%7;
return value;
}
void Read_1302()
{
DS1302sec =Read_Byte_1302(0x80);
DS1302min =Read_Byte_1302(0x82);
DS1302hour =Read_Byte_1302(0x84);
DS1302day =Read_Byte_1302(0x86);
DS1302month =Read_Byte_1302(0x88);
DS1302year =Read_Byte_1302(0x8c);
DS1302week = GetWeekFromDay(DS1302year,DS1302month,DS1302day);
}
按鍵函數:
#include "KEYBord.h"
#include "DisplayTime.h"
void DelayKey(u16 t)
{
u16 i,j;
for(i=0;i<t;i++)
for(j=0;j<250;j++);
}
u8 Menu=0; //菜單
u8 Flicker=0; //閃爍位置
char xdata KeyValue[10]={0}; //按鍵操作數組
void DealKeyValue(u8 KeyValu)
{
switch(KeyValu)
{
case 0XA5: //設置
if(Menu==0)
{
//--年
KeyValue[0]=DS1302year/10;
KeyValue[1]=DS1302year%10;
//--月
KeyValue[2]=DS1302month/10;
KeyValue[3]=DS1302month%10;
//--日
KeyValue[4]=DS1302day/10;
KeyValue[5]=DS1302day%10;
//--時
KeyValue[6]=DS1302hour/10;
KeyValue[7]=DS1302hour%10;
//--分
KeyValue[8]=DS1302min/10;
KeyValue[9]=DS1302min%10;
//--秒
KeyValue[10]=0;
KeyValue[11]=0;
Clear_Screen(0); //清屏
Write_6x16Font_N(5,0,0,"時間設置");
Flicker=1;
Menu=1;
}
else if(Menu==1) //保存時間
{
DS1302year = KeyValue[0]*10 +KeyValue[1];
DS1302month = KeyValue[2]*10 +KeyValue[3];
DS1302day = KeyValue[4]*10 +KeyValue[5];
DS1302hour = KeyValue[6]*10 +KeyValue[7];
DS1302min = KeyValue[8]*10 +KeyValue[9];
DS1302sec = 0;
Clear_Screen(0); //清屏
Menu=0;
}
break;
case 0XA6: //返回
Menu=0;
Flicker=0;
break;
case 0XA1: //左
if(Menu==1)
{
Flicker--;
if(Flicker<1) Flicker=10;
}
break;
case 0XA2: //上
if(Menu==1)
{
KeyValue[Flicker-1]++;
if(KeyValue[2]>1) KeyValue[2]=0;
if((KeyValue[3]>2)&&(KeyValue[2]==1)) KeyValue[3]=0;
if(KeyValue[4]>3) KeyValue[4]=0;
if((KeyValue[5]>1)&&(KeyValue[4]==3)) KeyValue[5]=0;
if(KeyValue[6]>2) KeyValue[6]=0;
if(KeyValue[8]>5) KeyValue[8]=0;
if( KeyValue[Flicker-1]>9) KeyValue[Flicker-1]=0;
}
break;
case 0XA3: //下
if(Menu==1)
{
KeyValue[Flicker-1]--;
if(KeyValue[Flicker-1] <0 )
{
if(Flicker==3) KeyValue[2]=1;
else if((Flicker==4) &&(KeyValue[2] == 1) )KeyValue[3]=2;
else if( Flicker==5) KeyValue[4] =3;
else if( Flicker==7) KeyValue[6] =2;
else if( Flicker==9) KeyValue[8] =5;
else KeyValue[Flicker-1] =9;
}
}
break;
case 0XA4: //右
if(Menu==1)
{
Flicker++;
if(Flicker>10) Flicker=1;
}
break;
default :break;
}
}
void GetKeyValue()
{
u8 KeyValue=0;
static bit Keyclok=0;
if(!K1)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K1)
{
KeyValue = 0XA1;
Keyclok = 1;
}
}
}
else if(!K2)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K2)
{
KeyValue = 0XA2;
Keyclok = 1;
}
}
}
else if(!K3)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K3)
{
KeyValue = 0XA3;
Keyclok = 1;
}
}
}
else if(!K4)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K4)
{
KeyValue = 0XA4;
Keyclok = 1;
}
}
}
else if(!K5)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K5)
{
KeyValue = 0XA5;
Keyclok = 1;
}
}
}
else if(!K6)
{
if(Keyclok==0)
{
DelayKey(10);
if(!K6)
{
KeyValue = 0XA6;
Keyclok = 1;
}
}
}
else
{
Keyclok=0;
KeyValue=0;
}
DealKeyValue(KeyValue);
}
void GotoDisplay()
{
switch(Menu)
{
case 0:
DisplayTime();
break;
case 1:
DisplayState1();
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
default:break;
}
}
顯示函數:
#include "DisplayTime.h"
#include "stdio.h"
#include "string.h"
#include "KEYBord.h"
u8 xdata DS1302YMD[]="2020-04-26";
u8 xdata DS1302HMS[]="07:50:30";
u8 xdata WeekD[]="星期一";
u8 xdata DisplayYMD[]="2020-05-01";
u8 xdata DisplayHMS[]="18:00:00";
u8 xdata DisplayWeek[]="星期五";
void GetWeekDat()
{
u8 WEEK;
WEEK = DS1302week;
switch(WEEK)
{
case 0:
strcpy (WeekD,"星期一");
break;
case 1:
strcpy (WeekD,"星期二");
break;
case 2:
strcpy (WeekD,"星期三");
break;
case 3:
strcpy (WeekD,"星期四");
break;
case 4:
strcpy (WeekD,"星期五");
break;
case 5:
strcpy (WeekD,"星期六");
break;
case 6:
strcpy (WeekD,"星期日");
break;
}
}
void DisplayTime()
{
Write_6x16Font_N(1,0,0,"實時時鐘精度測試");
//---顯示DS1302的時間
Read_1302();
DS1302YMD[2] = DS1302year/10 +0X30;
DS1302YMD[3] = DS1302year%10 +0X30;
DS1302YMD[5] = DS1302month/10 +0X30;
DS1302YMD[6] = DS1302month%10 +0X30;
DS1302YMD[8] = DS1302day/10 +0X30;
DS1302YMD[9] = DS1302day%10 +0X30;
DS1302HMS[0] = DS1302hour/10 +0X30;
DS1302HMS[1] = DS1302hour%10 +0X30;
DS1302HMS[3] = DS1302min/10 +0X30;
DS1302HMS[4] = DS1302min%10 +0X30;
DS1302HMS[6] = DS1302sec/10 +0X30;
DS1302HMS[7] = DS1302sec%10 +0X30;
GetWeekDat();
Write_ASCII3X16_N(0,1,0,"T1:DS1302");
Write_ASCII3X16_N(0,2,0,DS1302YMD);
Write_ASCII3X16_N(2,3,0,DS1302HMS);
Write_6x16Font_N(12,3,0,WeekD);
}
//----設置時間------
void DisplayState1()
{
DisplayYMD[2] = KeyValue[0] +0X30;
DisplayYMD[3] = KeyValue[1] +0X30;
DisplayYMD[5] = KeyValue[2] +0X30;
DisplayYMD[6] = KeyValue[3] +0X30;
DisplayYMD[8] = KeyValue[4] +0X30;
DisplayYMD[9] = KeyValue[5] +0X30;
DisplayHMS[0] = KeyValue[6] +0X30;
DisplayHMS[1] = KeyValue[7] +0X30;
DisplayHMS[3] = KeyValue[8] +0X30;
DisplayHMS[4] = KeyValue[9] +0X30;
if(Flicker<3)
{
if(TimeRun<2) DisplayYMD[Flicker+1] = 32; //空格
else DisplayYMD[Flicker+1] = KeyValue[Flicker-1] +0X30;
}
else if(Flicker<5)
{
if(TimeRun<2) DisplayYMD[Flicker+2] = 32; //空格
else DisplayYMD[Flicker+2] = KeyValue[Flicker-1] +0X30;
}
else if(Flicker<7)
{
if(TimeRun<2) DisplayYMD[Flicker+3] = 32; //空格
else DisplayYMD[Flicker+3] = KeyValue[Flicker-1] +0X30;
}
else if(Flicker<9)
{
if(TimeRun<2) DisplayHMS[Flicker-7] = 32; //空格
else DisplayHMS[Flicker-7] = KeyValue[Flicker-1] +0X30;
}
else if(Flicker<11)
{
if(TimeRun<2) DisplayHMS[Flicker-6] = 32; //空格
else DisplayHMS[Flicker-6] = KeyValue[Flicker-1] +0X30;
}
Write_ASCII3X16_N(0,2,0,DisplayYMD);
Write_ASCII3X16_N(2,3,0,DisplayHMS);
}
中斷函數:
#include "STC12_INT.H"
u16 T0_xMS; //定時器T0的初值變量,現定義10ms 的初值,注意要與FOSC統一單位標準
//u8 RS485LEDTimeMax=10;
/***********定時器0初始化******************
T0XMS : 一個溢出周期的時間,單位 ms
1T 時 <=5ms;12T 時 <=71ms
方式1 16位
*******************************************/
void Time0_Init(u8 T0XMS)
{
TMOD |= 0x01; //設置定時器模式1 16位非自動重裝
//=====裝載初值
#ifdef T0_1T //1T模式
T0_xMS =(65536-T0XMS*FOSC/1000); //FOSC的定義在 STC8.H中
#else //12T模式
T0_xMS =(65536-T0XMS*FOSC/12/1000);
#endif
TL0 = T0_xMS;
TH0 = T0_xMS >> 8;
TR0 = 1;
ET0 = 1; //開啟T0中斷
EA = 1;
}
/***********定時器1初始化******************
T0XMS : 一個溢出周期的時間,單位 ms
1T 時 <=5ms;12T 時 <=71ms
方式1 16位
//*******************************************/
/*void Time0_Init(u8 T1XMS)
{
u16 T1_xMS; //定時器T0的初值變量,現定義10ms 的初值,注意要與FOSC統一單位標準
TMOD |= 0x10; //設置定時器模式1 16位非自動重裝
////=====裝載初值
#ifdef T1_1T //1T模式
T1_xMS =(65536-T1XMS*FOSC/1000); //FOSC的定義在 STC8.H中
#else //12T模式
T1_xMS =(65536-T1XMS*FOSC/12/1000);
#endif
TL1 = T1_xMS;
TH1 = T1_xMS >> 8;
TR1 = 1;
//ET1 = 1; //開啟T1中斷
EA = 1;
}
*/
/*********************外部中斷0程序***************************/
void Int0_Isr() interrupt 0
{}
u8 Timeaa=0;
u8 TimeRun=0;
/*********************定時器0中斷程序*************************/
void Time0() interrupt 1
{
TL0 = T0_xMS;
TH0 = T0_xMS >> 8;
Timeaa++;
if(Timeaa>10)
{
Timeaa=0;
TimeRun++;
if(TimeRun>5)TimeRun=0;
}
}
/*********************外部中斷1程序***************************/
void Int1_Isr() interrupt 2
{}
/*********************定時器1中斷程序*************************/
void Time1() interrupt 3
{
}
/***************UART1中斷程序*********************
與定時器1配合,組成一個能接收一串數據的串口,
并能計算出接收到的數據的個數。
*************************************************/
void UART1() interrupt 4
{
}
/********************ADC中斷程序*****************************/
void ADC_Isr() interrupt 5
{
}
/********************LVD中斷程序****************************/
void LVD_Isr() interrupt 6
{}
/********************PCA中斷程序****************************/
void PCA_Isr() interrupt 7
{}
/*********************** UART2 中斷程序*********************/
void Uart2() interrupt 8
{}
/**********************SPI中斷程序*************************/
void SPI_Isr() interrupt 9
{} |