|
1、說明圖
2、代碼
3、小結(jié)(ATC4C02無法連續(xù)讀取的問題)
1、說明圖

在本制作中關(guān)于DS1302的詳細(xì)資料可參考:http://www.torrancerestoration.com/bbs/dpj-22465-1.html ,還有紅外和DS18B20資料:http://www.torrancerestoration.com/bbs/dpj-22807-1.html
2、代碼
#include <reg51.h>
#include<intrins.h>
/*時(shí)鐘芯片*/
sbit st = P2^1; //使能(RST)
sbit da = P2^2; //i/o管腳(數(shù)據(jù)管腳)(i/o)
sbit cl = P2^3; //時(shí)鐘管腳(CLK)
/*1602屏*/
sbit RS = P2^4; //定義端口
sbit RW = P2^5;
sbit EN = P2^6;
/*EEPROM--AT24C02*/
sbit scl = P1^0; //時(shí)鐘管腳
sbit sda = P1^1; //數(shù)據(jù)管腳
/*其他*/
sbit spk = P2^7; //蜂鳴器
sbit DQ = P2^0; //ds18b20溫度傳感器
//下面的常量是一些寄存器的地址
#define addr_m 0x80 //秒
#define addr_f 0x82 //分
#define addr_x 0x84 //小時(shí)
#define addr_r 0x86 //日期
#define addr_y 0x88 //月
#define addr_xq 0x8a //星期
#define addr_n 0x8c //年
#define addr_xbh 0x8e //寫保護(hù)
#define addr_ram 0xc0 //時(shí)鐘芯片RAM 開始地址(這款芯片有31個(gè)8位的RAM起始地址是C0)
#define addr_ram2 0xc2 //時(shí)鐘芯片RAM2
#define addr_atx 0xae //AT24C02 設(shè)備地址+寫命令
#define addr_atd 0xaf //AT24C02 設(shè)備地址+讀命令
unsigned char sj[33]; //接收脈沖時(shí)間數(shù)組
unsigned char jmsj[4]; //客戶碼,客戶碼,數(shù)據(jù),數(shù)據(jù)反碼
unsigned char zt[8]; //秒,分,時(shí),日,月,周,年,世紀(jì)
//unsigned char nz[3]; //秒,分,時(shí)
unsigned char ac; //l602AC值,(顯示緩存地址)
unsigned char i; //脈沖個(gè)數(shù)記錄
unsigned char mcsj; //脈沖時(shí)間(大于0.56ms小于1.125ms為0,大于1.125ms小于2.25ms)
bit ack;
bit MC=0; //接收紅外脈沖開始標(biāo)志(0:脈沖已經(jīng)結(jié)束,1:脈沖剛開始)
bit JS=0; //脈沖接收結(jié)束標(biāo)志位(1標(biāo)志接收結(jié)束)
bit JM=0; //解碼完成標(biāo)志位(1:解碼完成)
void zf_1602(unsigned char x,unsigned char y,unsigned dat);
unsigned char rn(int n); //判斷閏年(參數(shù):年)返回0:平年,返回1:閏年
void szjc(unsigned char *p); //設(shè)置數(shù)據(jù)檢查
void csh_wnl(); //初始化萬年歷
void fmq(); //按鍵聲音
void dnz(unsigned char *p); //讀取鬧鐘數(shù)據(jù)
void dsq_0() interrupt 1 using 1 //定時(shí)器T0中斷服務(wù)函數(shù)
{
mcsj++; //256
}
void wbzd_0() interrupt 0 //外部中斷服務(wù)函數(shù)
{
if(MC)
{
if(mcsj>32) //判斷是不是引導(dǎo)碼。(如果是i=0)
i=0;
sj[ i]=mcsj; //把脈沖時(shí)間存入sj這個(gè)數(shù)組里
mcsj=0; //清空脈沖時(shí)間準(zhǔn)備接收下一個(gè)脈沖時(shí)間
i++;
if(i==33) //判斷是否接收完脈沖時(shí)間
{
i=0;
JS = 1; //接收完成標(biāo)志位置1
MC=0; //紅外脈沖結(jié)束
}
}
else
{
MC=1; //紅外脈沖開始
mcsj=0; //清空脈沖時(shí)間
}
}
void csh_dsq_0() //初始化定時(shí)器0
{
TMOD = 0x02;
TH0=0x00; //定時(shí)器0的重裝數(shù)據(jù)
TL0=0x00; //初始化
ET0=1; //打開定時(shí)器0中斷
TR0=1; //啟用定時(shí)器0
}
void csh_wbzd_0() //初始化外部中斷0
{
IT0=1; //外部中斷0下降沿觸發(fā)
EX0=1; //啟用外部中斷0
EA=1; //打開總中斷
}
void hwjm() //紅外解碼函數(shù)
{
unsigned char i,j,k=1;
for(i=0;i<4;i++) //4組數(shù)據(jù)的計(jì)數(shù)
{
for(j=0;j<8;j++) //每組數(shù)據(jù)中的8位數(shù)據(jù)計(jì)算
{
jmsj[ i] >>= 1; //數(shù)據(jù)右移一位
if(sj[k]>7) //脈沖時(shí)間大于7的就是1
jmsj[ i] |= 0x80;
k++;
}
}
JS = 0; //分析完成清零JS
JM = 1; //解碼完成JM置1
}
void DelayUs2x(unsigned char t) // us級(jí)別延時(shí)
{
while(--t);
}
void DelayMs(unsigned char t)// ms級(jí)別延時(shí)
{
while(t--)
{
//大致延時(shí)1mS
DelayUs2x(245);
DelayUs2x(245);
}
}
/*DS18b20溫度傳感器*/
bit d18b20_qs() //18b20 起始
{
bit dat;
DQ = 1; //DQ復(fù)位
DQ = 0; //拉低總線
DelayUs2x(175);
DQ = 1; //拉高總線
DelayUs2x(45); //這里延時(shí)大概 45us
dat = DQ; //讀取返回值(0:有18b20存在 1:是沒有)
DelayUs2x(20); //這里延時(shí)大概 20us
return dat; //返回?cái)?shù)值
}
void d18b20_x(unsigned char dat) //寫 8 位 數(shù) 據(jù)
{
unsigned char i;
for(i=0;i<8;i++) //8位計(jì)數(shù)器
{
DQ = 0; //拉低總線
DQ = dat & 0x01; //取最低位賦值給總線
DelayUs2x(45); //延時(shí)45us
DQ = 1; //拉過總線準(zhǔn)備寫下一個(gè)數(shù)據(jù)(或者總線復(fù)位)
dat >>= 1; //數(shù)據(jù)右移一位
}
}
unsigned char d18b20_d() //讀 8 位 數(shù) 據(jù)
{
unsigned char i,dat=0;
for(i=0;i<8;i++) //8位計(jì)數(shù)器
{
DQ = 0; //拉低總線
dat >>= 1; //數(shù)據(jù)右移一位
DQ = 1; //拉過總線(準(zhǔn)備讀取數(shù)據(jù))
if(DQ) //判斷是否是 1 如果是就把數(shù)據(jù)賦值給變量的高位
dat |= 0x80;
DelayUs2x(25); //這里延時(shí)大概 25us
}
return dat; //返回讀取到數(shù)據(jù)數(shù)據(jù)
}
unsigned int wd() //讀取溫度函數(shù)
{
unsigned char i = 0; //低8位數(shù)據(jù)
unsigned char j = 0; //高8位數(shù)據(jù)
unsigned int k = 0; //無符號(hào)16整形用來存儲(chǔ)讀回來的 16位溫度數(shù)據(jù)(j和i組合后的數(shù)據(jù))
d18b20_qs(); //初始化
d18b20_x(0xCC); //跳過序列號(hào)的操作(因?yàn)?8b20在總線上可以掛很多個(gè),這個(gè)序列號(hào)和網(wǎng)卡MAC地址類似)
d18b20_x(0x44); //開啟溫度轉(zhuǎn)換
//Delay(200); //開啟溫度轉(zhuǎn)換需要時(shí)間這里延時(shí)一下
d18b20_qs(); //初始化
d18b20_x(0xCC); //跳過序列號(hào)的操作(因?yàn)?8b20在總線上可以掛很多個(gè),這個(gè)序列號(hào)和網(wǎng)卡MAC地址類似)
d18b20_x(0xBE); //讀取溫度寄存器等(共可讀9個(gè)寄存器) 前兩個(gè)就是溫度
i = d18b20_d(); //讀取低8位
j = d18b20_d(); //讀取高8位
k = j;
k <<= 8;
k = k + i;
return k; //返回讀取到的16位數(shù)據(jù)
}
void zh(unsigned int i) //1602顯示緩存寫入函數(shù)
{
unsigned char x,z;
x = i & 0x0f; //取出小數(shù)
i >>=4;
switch(x) //小數(shù)位轉(zhuǎn)換
{
case 0: z=0;break;
case 1: z=1;break;
case 2: z=1;break;
case 3: z=2;break;
case 4: z=3;break;
case 5: z=3;break;
case 6: z=4;break;
case 7: z=4;break;
case 8: z=5;break;
case 9: z=6;break;
case 10: z=6;break;
case 11: z=7;break;
case 12: z=8;break;
case 13: z=8;break;
case 14: z=9;break;
case 15: z=9;break;
}
z = z +48; //轉(zhuǎn)換成ascii碼
zf_1602(13,1,z); //寫入1602緩存
z = i & 0xff; //取出整數(shù)
x = z/10; //取出十位
x= x+48; //轉(zhuǎn)換成ascii碼
zf_1602(10,1,x); //寫入1602緩存
x = z%10; //取出個(gè)位
x= x+48; //轉(zhuǎn)換成ascii碼
zf_1602(11,1,x); //寫入1602緩存
}
/*DS18b20溫度傳感器*/
/*EEPOM---AT24C02*/
void i2_qs() //起始信號(hào)
{
sda = 1; //拉高數(shù)據(jù)
scl = 1; //拉高時(shí)鐘
_nop_(); //空閑一條指令
_nop_();
_nop_();
_nop_();
sda = 0; //拉低數(shù)據(jù)產(chǎn)生起始信號(hào)(下降沿)
_nop_(); //空閑一條指令
scl = 0; //拉低時(shí)鐘
_nop_(); //空閑一條指令
}
void i2_tz() //停止信號(hào)
{
sda = 0; //拉低數(shù)據(jù)
scl = 1; //拉高時(shí)鐘
_nop_(); //空閑一條指令
sda = 1; //拉高時(shí)鐘產(chǎn)生結(jié)束信號(hào)(上升沿)
_nop_(); //空閑一條指令
}
void i2_ack(bit _ack) //入口產(chǎn)生 0 ack 1 nak
{
sda = _ack; //ack或者nak
scl = 1; //拉高時(shí)鐘
_nop_(); //空閑一條指令
scl = 0; //拉低時(shí)鐘
_nop_(); //空閑一條指令
}
void i2_fs(unsigned char Data) //發(fā)送8位數(shù)據(jù)
{
unsigned char i;
for(i=0;i<8;i++) //8位計(jì)數(shù)
{
Data <<= 1; //把最高位移送到進(jìn)制標(biāo)志位中(CY)
sda = CY; //把進(jìn)制位中的數(shù)據(jù)賦值給數(shù)據(jù)線
scl = 1; //拉高時(shí)鐘
_nop_(); //空閑一條指令
scl = 0; //拉低時(shí)鐘
//這里
}
//下面代碼是接收ACK的代碼
_nop_();//空閑一條指令
sda = 1; //拉高數(shù)據(jù)準(zhǔn)備接收ACK
scl = 1; //拉高時(shí)鐘產(chǎn)生穩(wěn)定的有效的數(shù)據(jù)(相對(duì)的)
if(sda==1) //確認(rèn)接收的是ACK還是NAK
ack = 0;//ack
else
ack = 1;//nak
scl = 0; //拉低時(shí)鐘
_nop_(); //延時(shí)大于 4us
}
unsigned char i2_js() //接收8位數(shù)據(jù)
{
unsigned char i,Data = 0;
sda = 1; //使能內(nèi)部上拉,準(zhǔn)備讀取數(shù)據(jù)
for(i=0;i<8;i++) //8位計(jì)數(shù)器
{
Data <<= 1; //移出數(shù)據(jù)的最高位
scl = 1; //拉高時(shí)鐘
_nop_(); //延時(shí)大于 4us
Data |= sda;//接收數(shù)據(jù)
scl = 0; //拉低時(shí)鐘
_nop_(); //延時(shí)大于 4us
}
return Data;
}
void i2_sj_x(unsigned char addr,unsigned char Data) //往設(shè)備內(nèi)寫入數(shù)據(jù)(參數(shù) 1、寄存器地址 2、寫入的數(shù)據(jù))
{
i2_qs(); //起始信號(hào)
i2_fs(addr_atx); //設(shè)備地址+寫信號(hào)
i2_fs(addr); //寄存器內(nèi)部地址
i2_fs(Data); //寫入設(shè)備的數(shù)據(jù)
i2_tz(); //停止信號(hào)
}
unsigned char i2_sj_d(unsigned char addr) //讀取數(shù)據(jù)(參數(shù) 寄存器地址)
{
unsigned char Data; //用于接收讀取回來的數(shù)據(jù)
i2_qs(); //起始信號(hào)
i2_fs(addr_atx); //設(shè)備地址+寫信號(hào)
i2_fs(addr); //寄存器內(nèi)部地址
i2_qs(); //起始信號(hào)
i2_fs(addr_atd); //設(shè)備地址+讀信號(hào)
Data = i2_js(); //讀取數(shù)據(jù)
i2_ack(1); //NAK應(yīng)答(無應(yīng)答)
i2_tz(); //停止信號(hào)
return Data; //返回讀取的數(shù)據(jù)
}
/*EEPROM---AT24c02*/
/*DS1302時(shí)鐘芯片*/
/*下面這個(gè)函數(shù)是ds1302的最低層函數(shù)也是最重要的*/
void x_1302(unsigned char addr,unsigned char q,unsigned char l) //寫入8個(gè)bit(參數(shù)1:地址,參數(shù)2:數(shù)據(jù),參數(shù)3:啟用BCD處理)
{
unsigned char i;
if(l) //BCD處理(處理成BCD格式)
{
i=q/10;
q=q%10;
q=q+i*16;
}
addr = addr & 0xFE; //最低位置零
cl = 0; //拉低時(shí)鐘
da = 0; //復(fù)位數(shù)據(jù)
st = 1; //使能芯片。寫入開始
for(i=0;i<8;i++) //寫入地址
{
addr >>= 1;
da = CY;
cl = 1;
cl = 0;
}
for(i=0;i<8;i++) //寫入數(shù)據(jù)
{
q >>= 1;
da = CY;
cl = 1;
cl = 0;
}
st = 0; //寫入結(jié)束
}
/*下面這個(gè)函數(shù)是ds1302的最低層函數(shù)也是最重要的*/
unsigned char d_1302(unsigned char addr,unsigned char l) //讀取8個(gè)bit(參數(shù)1:地址,參數(shù)2:啟用BCD處理)
{
unsigned char i,dat;
addr = addr | 0x01;//最低位置高
cl = 0; //拉低時(shí)鐘
da = 0; //復(fù)位數(shù)據(jù)
st = 1; //使能芯片,讀取開始
for(i=0;i<8;i++) //寫入地址
{
addr >>= 1;
da = CY;
cl = 1;
cl = 0;
}
for(i=0;i<8;i++) //讀取數(shù)據(jù)
{
dat >>= 1;
if(da)
dat = dat | 0x80;
cl = 1;
cl = 0;
}
st = 0; //讀取結(jié)束
if(l) //BCD處理(還原成10進(jìn)制)
{
i = dat / 16;
dat = dat % 16;
dat = dat +i*10;
}
return dat;
}
/*DS1302時(shí)鐘芯片*/
/*1602屏*/
bit m_1602(bit i) //判斷1602是否忙(參數(shù)i=1:讀取AC值。i=0:不讀AC值)
{
P0 = 0xFF; //準(zhǔn)備讀取
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1; //產(chǎn)生高電平
if(i)
ac = P0 & 0x7f; //讀取AC值
return (bit)(P0 & 0x80);
}
void x_1602(bit i,unsigned char j) //參數(shù)一是寫(0、寫指令 1、寫數(shù)據(jù)),參數(shù)二是寫入的8位數(shù)據(jù)
{
while(m_1602(0))
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
RS = i;
RW = 0;
EN = 1;
P0 = j;
_nop_();
EN = 0; //產(chǎn)生下降沿
}
void qp_1602() //清屏函數(shù)
{
x_1602(0,0x01); //第一個(gè)參數(shù)是:寫入的類型(0、寫指令 1、寫數(shù)據(jù)),第一個(gè)參數(shù)是:寫入的數(shù)據(jù)
DelayMs(5);
}
//顯示字符
void zf_1602(unsigned char x,unsigned char y,unsigned dat) //參數(shù)一是顯示的列,參數(shù)二是顯示的行,參數(shù)三是顯示的數(shù)據(jù)
{
if(y==0)
{
x_1602(0,(0x80+x)); //第一行
}
else
{
x_1602(0,(0xc0+x)); //第二行
}
x_1602(1,dat); //寫入數(shù)據(jù)
}
void zfc_1602(unsigned char x,unsigned char y,unsigned char *dat)//參數(shù)一是顯示的列,參數(shù)二是顯示的行,參數(shù)三是顯示的數(shù)據(jù)(注:數(shù)據(jù)用\0結(jié)尾)
{
if(y==0)
{
x_1602(0,(0x80+x)); //第一行
}
else
{
x_1602(0,(0xc0+x)); //第二行
}
while(*dat) //&:取地址 *:取值
{
x_1602(1,*dat);
dat ++;
}
}
/*1602屏*/
void xrsj(unsigned char i,unsigned char *ls) //寫入設(shè)置數(shù)據(jù)
{
unsigned char j,k,s;
while(m_1602(0)); //判忙(如果不忙就退出循環(huán))
m_1602(1); //讀取光標(biāo)的位置
switch(ac)
{
case 0x00: j = 7;k = 1;break; //世紀(jì)高位
case 0x01: j = 7;k = 0;break; //世紀(jì)低位
case 0x02: j = 6;k = 1;break; //年高位
case 0x03: j = 6;k = 0;break; //年低位
case 0x05: j = 4;k = 1;break; //月份高位
case 0x06: j = 4;k = 0;break; //月份低位
case 0x08: j = 3;k = 1;break; //日高位
case 0x09: j = 3;k = 0;break; //日低位
case 0x40: j = 2;k = 1;break; //小時(shí)高位
case 0x41: j = 2;k = 0;break; //小時(shí)低位
case 0x43: j = 1;k = 1;break; //分鐘高位
case 0x44: j = 1;k = 0;break; //分鐘低位
case 0x46: j = 0;k = 1;break; //秒高位
case 0x47: j = 0;k = 0;break; //秒低位
case 0x0e: j = 5;k = 0;break; //周
}
if(k) //1:是高位,0:s 低位
{
s = ls[j] % 10; //高位1
ls[j] = i * 10 + s;
}
else
{
s = ls[j] % 10; //低位0
ls[j] = ls[j] - s;
ls[j] += i;
}
}
void gbkz(unsigned char i) //控制光標(biāo)去它應(yīng)該去的地方的函數(shù)
{
while(m_1602(0)); //判忙
m_1602(1); //讀取光標(biāo)的位置
if( 0x04 == ac || 0x07 == ac || 0x42 == ac || 0x45 == ac )
{
if(i)
x_1602(0,0x16); //光標(biāo)右移
else
x_1602(0,0x10); //光標(biāo)左移
}
else if(0x48 == ac)
{
x_1602(0,0x10); //光標(biāo)左移
}
else if( 0x0a == ac || 0x0d == ac)
{
if(i)
x_1602(0,0x8e); //移動(dòng)光標(biāo)
else
x_1602(0,0x89); //移動(dòng)光標(biāo)
}
else if(0x0f == ac)
x_1602(0,0x10); //光標(biāo)左移
}
unsigned char rn(int n) //判斷閏年(參數(shù):年)返回0:平年,返回1:閏年
{
//n = p[7]*100 + p[6];
if( n % 400 ==0 ||((n%4) ==0 && (n%100))) //能被400整除與能被4整除且不能被100整除
//四年一閏,百年不閏,四百年再閏
return 1; //閏年
else
return 0; //平年
}
void xhc(unsigned char k) //紅外按鍵設(shè)置函數(shù)(0:修改鬧鐘 1:修改時(shí)間)
{
unsigned char i=10,j; //臨時(shí)變量
unsigned char ls[8]; //臨時(shí)數(shù)組(用來存儲(chǔ)修改后的數(shù)據(jù))
JM = 0;
if(k) //定位光標(biāo)
{
for(j = 0;j<8;j++) //把數(shù)據(jù)存入臨時(shí)數(shù)組用來判斷是否有修改。
ls[j] = zt[j];
x_1602(0,0x80); //把光標(biāo)(ac)移動(dòng)到第一行第一列
}
else
{
/*for(j=0;j<3;j++)
ls[j] = i2_sj_d(j); //秒,分,時(shí)*/
dnz(ls);
x_1602(0,0x01); //清屏
zf_1602(0,1,((ls[2]/10)+48));
zf_1602(1,1,((ls[2]%10)+48));
zf_1602(2,1,'-');
zf_1602(3,1,((ls[1]/10)+48));
zf_1602(4,1,((ls[1]%10)+48));
zf_1602(5,1,'-');
zf_1602(6,1,((ls[0]/10)+48));
zf_1602(7,1,((ls[0]%10)+48));
zfc_1602(0,0,"Set the alarm");
x_1602(0,0xc0); //把光標(biāo)(ac)移動(dòng)到第二行第一列
}
x_1602(0,0x0f); //顯示光標(biāo)
while(i)
{
if(JS) //脈沖接收結(jié)束后調(diào)用解碼函數(shù)解碼
{
hwjm();
}
if(JM) //解碼函數(shù)解碼完成后執(zhí)行代碼
{
switch(jmsj[2]) //匹配按鍵
{
case 0x16: //按鍵0
{
xrsj(0,ls); //寫入數(shù)據(jù)
x_1602(1,'0'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x0c: //按鍵1
{
xrsj(1,ls); //寫入數(shù)據(jù)
x_1602(1,'1'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x18: //按鍵2
{
xrsj(2,ls); //寫入數(shù)據(jù)
x_1602(1,'2'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x5e: //按鍵3
{
xrsj(3,ls); //寫入數(shù)據(jù)
x_1602(1,'3'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x08: //按鍵4
{
xrsj(4,ls); //寫入數(shù)據(jù)
x_1602(1,'4'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x1c: //按鍵5
{
xrsj(5,ls); //寫入數(shù)據(jù)
x_1602(1,'5'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x5a: //按鍵6
{
xrsj(6,ls); //寫入數(shù)據(jù)
x_1602(1,'6'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x42: //按鍵7
{
xrsj(7,ls); //寫入數(shù)據(jù)
x_1602(1,'7'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x52: //按鍵8
{
xrsj(8,ls); //寫入數(shù)據(jù)
x_1602(1,'8'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x4a: //按鍵9
{
xrsj(9,ls); //寫入數(shù)據(jù)
x_1602(1,'9'); //寫入緩存
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x44: //光標(biāo)左移
{
m_1602(1); //讀取AC值(此函數(shù)也是讀忙值函數(shù))
if(ac != 0x00 && ac != 0x40) //限制光標(biāo)左移的邊界
{
x_1602(0,0x10); //光標(biāo)左移 <
gbkz(0); //光標(biāo)控制
}
fmq();
break;
}
case 0x40: //光標(biāo)右移
{
m_1602(1); //讀取AC值(此函數(shù)也是讀忙值函數(shù))
x_1602(0,0x16); //光標(biāo)右移
fmq();
gbkz(1); //光標(biāo)控制
break;
}
case 0x43: //換行
{
if( k )
{
m_1602(1); //讀取ac值
if(0x40 > ac)
x_1602(0,0xc0); //第2行
else
x_1602(0,0x80); //第1行
fmq();
}
break;
}
case 0x09: //退出設(shè)置
{
fmq();
if(k)
{
szjc(ls); //檢查設(shè)置的數(shù)據(jù)是否合理
j = addr_m; //起始地址(秒)
x_1302(addr_xbh,0,0); //關(guān)閉寫保護(hù)
x_1302(addr_ram,ls[7],1); //把世紀(jì)寫入ram1
x_1302(addr_ram2,ls[6],1); //把年寫入ram2
for(i=0;i<7;i++) //循環(huán)寫入秒,分,時(shí),日,月,周,年
{
if(ls[ i] != zt[ i]) //判斷數(shù)據(jù)是否有修改,有修改則寫入數(shù)據(jù)否則不寫數(shù)據(jù)
{
x_1302(j,ls[ i],1); //寫入數(shù)據(jù)
}
j += 2; //地址提升一位
}
x_1302(addr_xbh,0x80,0); //打開寫保護(hù)
csh_wnl(); //初始化萬年歷(作用是重新顯示)
}
else
{
if(ls[0] > 59) //檢查秒是否越界
ls[0] = 59;
if(ls[1] > 59) //檢查分是否越界
ls[1] = 59;
if(ls[2] > 23) //檢查時(shí)是否越界
ls[2] = 23;
for(i=0;i<3;i++)
{
i2_sj_x(i,ls[ i]); //把數(shù)據(jù)寫入EEPROM
DelayMs(1);
}
}
i=0; //退出設(shè)置大循環(huán)
csh_wnl(); //初始化萬年歷(作用是重新顯示)
break;
}
case 0x15: //取消(退出設(shè)置)
{
fmq();
i=0;
csh_wnl();
break;
}
}
JM=0; //按鍵對(duì)應(yīng)的代碼執(zhí)行完畢。
}
}
x_1602(0,0x0c); //關(guān)閉光標(biāo)
}
void szjc(unsigned char *p) //設(shè)置數(shù)據(jù)檢查
{
unsigned char i;
if(p[0]>59) //判斷秒是否超過上限(超過就強(qiáng)制將秒設(shè)置成59)
{
p[0] = 59; //秒的上限
}
if(p[1]>59) //判斷分是否超過上限(超過就強(qiáng)制將分設(shè)置成59)
{
p[1] = 59; //分的上限
}
if(p[2]>23) //判斷小時(shí)是否超過上限(超過就強(qiáng)制將小時(shí)設(shè)置成23)
{
p[2] = 23; //時(shí)的上限
}
if(p[7] > 99) //判斷世紀(jì)是否超過上限(超過就強(qiáng)制將世紀(jì)設(shè)置成99)
{
p[7] = 99; //世紀(jì)的上限
}
if(p[6] > 99) //判斷年是否超過上限(超過就強(qiáng)制將年設(shè)置成99)
{
p[6] = 99; //年的上限
}
if(p[4]>12) //判斷月是否超過上限(超過就強(qiáng)制將月設(shè)置成12)
{
p[4] = 12; //月的上限
}
if(p[4]==4||p[4]==6||p[4]==9||p[4]==11) //設(shè)置日期上限
{
i = 30; //小月份的日期上限
}
else if(p[4] == 2) //設(shè)置日期上限
{
int n;
n = p[7]*100 + p[6];
i=rn(n); //判斷閏年 (如果是閏年返回1)
i += 28; //2月份的日期上限
}
else //設(shè)置日期上限
{
i = 31; //大月份的如期上限
}
if(p[3] > i) //判斷日期是否超過上限(超過就強(qiáng)制將日期設(shè)置成i(i的結(jié)果有后面4種:31,30,29,28))
{
p[3] = i; //日期的上限
}
if(p[5] > 7) //判斷星期是否超過上限(超過就強(qiáng)制將星期設(shè)置成59)
{
p[5] = 7; //星期的上限
}
}
void csh_1602() //初始化1602
{
x_1602(0,0x38); //顯示模式設(shè)置
DelayMs(5);
x_1602(0,0x38);
DelayMs(5);
x_1602(0,0x38);
DelayMs(5);
x_1602(0,0x38);
x_1602(0,0x0c); //顯示光標(biāo)
x_1602(0,0x01); //顯示清屏
//x_1602(0,0x06); //顯示光標(biāo)移動(dòng)設(shè)置
}
void zdy_1602() //1602自定義字符
/*
1602自定義的字符是存儲(chǔ)在CGRAM中的
1、CGRAM的地址是:0x40~0x7f 共有:64bit位,每個(gè)地址對(duì)應(yīng)8bit位,可以存儲(chǔ)8個(gè)自定義字符
2、怎么使用自定義字符:0~7對(duì)應(yīng)8個(gè)自定義字符 zf_1602(10,1,0x00)這條代碼就對(duì)應(yīng)著年;
3、注:1602的小點(diǎn)陣是1點(diǎn)亮的(打開)
*/
{
unsigned char zf[5][8]={{0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02}, //年
{0x0f,0x09,0x0f,0x09,0x0f,0x09,0x11,0x00}, //月
{0x1f,0x11,0x11,0x1f,0x11,0x11,0x1f,0x00}, //日
{0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00}, //攝氏度的點(diǎn)
{0x00,0x0e,0x15,0x1d,0x11,0x0e,0x00,0x00}}; //小鬧鐘圖標(biāo)
unsigned char i,j,k=0x40; //k是CGRAM地址的起始點(diǎn)
for(i=0;i<5;i++) //年,月,入,攝氏度"點(diǎn)"
{
for(j=0;j<8;j++) //年,月,入,攝氏度"點(diǎn)"的數(shù)據(jù)寫入
{
x_1602(0,k); //寫入CGRAM地址
x_1602(1,zf[ i][j]); //寫入數(shù)據(jù)
k++; //CGRAM地址加1(提高一位)
}
}
}
void csh_wnl() //初始化萬年歷
{
unsigned char j,i; //臨時(shí)變量
i = addr_m; //起始讀取地址(秒)
x_1602(0,0x01);
for(j=0;j<7;j++) //循環(huán)讀取秒,分,時(shí),日,月,周,年
{
zt[j] = d_1302(i,1);
i += 2;
}
zt[7] = d_1302(addr_ram,1); //讀取世紀(jì)
zh(wd()); //顯示溫度
zf_1602(12,1,'.');
zf_1602(14,1,0x03); //攝氏度的點(diǎn)
zf_1602(15,1,'C');
zf_1602(0,1,((zt[2]/10)+48)); //寫小時(shí)高位
zf_1602(1,1,((zt[2]%10)+48)); //寫小時(shí)低位
zf_1602(2,1,'-');
zf_1602(3,1,((zt[1]/10)+48)); //寫分鐘高位
zf_1602(4,1,((zt[1]%10)+48)); //寫分鐘低位
zf_1602(5,1,'-');
zf_1602(6,1,((zt[0]/10)+48)); //寫秒高位
zf_1602(7,1,((zt[0]%10)+48)); //寫秒低位
zf_1602(0,0,((zt[7]/10)+48)); //寫世紀(jì)高位
zf_1602(1,0,((zt[7]%10)+48)); //寫世紀(jì)低位
zf_1602(2,0,((zt[6]/10)+48)); //寫年高位
zf_1602(3,0,((zt[6]%10)+48)); //寫年低位
zf_1602(4,0,0x00); //年
zf_1602(5,0,((zt[4]/10)+48)); //寫月高位
zf_1602(6,0,((zt[4]%10)+48)); //寫月底位
zf_1602(7,0,0x01); //月
zf_1602(8,0,((zt[3]/10)+48)); //寫入日高位
zf_1602(9,0,((zt[3]%10)+48)); //寫入日低位
zf_1602(10,0,0x02); //日
zf_1602(13,0,'-');
zf_1602(14,0,((zt[5])+48)); //寫入星期
zf_1602(15,0,'-');
}
void ntb() //年同步(作用是用來同步年和世紀(jì)的)
{
unsigned char i,j;
i = d_1302(addr_n,1); //讀取時(shí)鐘芯片的年
j = d_1302(addr_ram2,1); //讀取ram的年
if(i != j) //判斷是否一樣。一樣說明在單片機(jī)關(guān)機(jī)的時(shí)候年沒有變化
{
x_1302(addr_xbh,0,0); //關(guān)閉寫保護(hù)
if(j == 99) //判斷ram中的年是否是99如果是世紀(jì)加1
{
j = d_1302(addr_ram,1); //讀取RAM中的世紀(jì)
j++; //世紀(jì)加1
if(j == 100) //判斷世紀(jì)是否等于100
{
x_1302(addr_ram,0,1); //等于100世紀(jì)清零然后寫入ram
}
else
{
x_1302(addr_ram,j,1); //否則把加1后的世紀(jì)寫入ram
}
}
x_1302(addr_ram2,i,1); //如果j不等于99則把時(shí)鐘芯片里面的年寫入ram
x_1302(addr_xbh,0x80,0); //關(guān)閉寫保護(hù)
}
}
void dnz(unsigned char *p) //讀取鬧鐘數(shù)據(jù)
{
unsigned char i;
for(i=0;i<4;i++)
{
p[ i] = i2_sj_d(i);
DelayMs(1);
}
p[1] = i2_sj_d(1);
if(p[0] > 59) //檢查秒是否越界
p[0] = 59;
if(p[1] > 59) //檢查分是否越界
p[1] = 59;
if(p[2] > 23) //檢查時(shí)是否越界
p[2] = 23;
}
void fmq() //按鍵聲音
{
unsigned char i = 80;
while(i)
{
DelayUs2x(150);
spk = !spk;
i--;
}
}
void main()
{
unsigned char j,i,nz[4]; //臨時(shí)變量
bit l=0; //l:鬧鐘響鈴標(biāo)志位
csh_1602(); //初始化1602
qp_1602(); //清屏
zdy_1602(); //自定義字符
csh_wbzd_0(); //初始化外部中斷0
csh_dsq_0(); //初始化定時(shí)器0
ntb(); //年份同步
csh_wnl(); //初始化萬年歷所有顯示緩存
dnz(nz); //讀取鬧鐘時(shí)間與鬧鐘的狀態(tài)
if(nz[3])
{
zf_1602(12,0,0x04);
}
while(1)
{
if(JS) //脈沖接收結(jié)束后調(diào)用解碼函數(shù)解碼
{
hwjm();
}
if(JM) //解碼完成后調(diào)用按鍵匹配函數(shù)
{
switch(jmsj[2])
{
case 0x45:fmq();xhc(1);break; //修改時(shí)間
case 0x46:
{
fmq();xhc(0);dnz(nz); //修改鬧鐘
break;
}
case 0x47:
{
fmq();
if(!l) //判斷是否響鈴了。如果響鈴了就先關(guān)閉響鈴
{
if(nz[3]) //判斷是否關(guān)閉鬧鐘
{
zf_1602(12,0,' '); //清除鬧鐘小圖標(biāo)
nz[3] = 0; //關(guān)閉鬧鐘
}
else
{
zf_1602(12,0,0x04); //顯示鬧鐘小圖標(biāo)
nz[3] = 1; //啟用鬧鐘
}
i2_sj_x(3,nz[3]);
}
else
{
l = 0; //關(guān)閉響鈴
}
break;
}
}
JM = 0;
if(nz[3])
{
zf_1602(12,0,0x04);
}
}
if(l) //判斷響鈴是否打開
{
fmq();
}
if((j = d_1302(addr_m,1)) != zt[0]) //讀秒
{
zt[0] = j;
zf_1602(6,1,((zt[0]/10)+48)); //寫秒高位
zf_1602(7,1,((zt[0]%10)+48)); //寫秒低位
if(zt[0] == 0 || zt[0] == nz[0])
{
zt[1] = d_1302(addr_f,1); //讀分鐘
zf_1602(3,1,((zt[1]/10)+48)); //寫分鐘高位
zf_1602(4,1,((zt[1]%10)+48)); //寫分鐘低位
if(zt[1] == 0 || zt[1] == nz[1])
{
zt[2] = d_1302(addr_x,1); //讀小時(shí)
zf_1602(0,1,((zt[2]/10)+48)); //寫小時(shí)高位
zf_1602(1,1,((zt[2]%10)+48)); //寫小時(shí)低位
if( zt[2] == 0 ) //判斷小時(shí)是否等于0
{
i= addr_r;
for(j=3;j<7;j++) //讀取日,月,周,年
{
zt[j] = d_1302(i,1);
i += 2;
}
ntb(); //年份同步
zt[7] = d_1302(addr_ram,1); //讀取世紀(jì)
zf_1602(0,0,((zt[7]/10)+48)); //寫世紀(jì)高位
zf_1602(1,0,((zt[7]%10)+48)); //寫世紀(jì)低位
zf_1602(2,0,((zt[6]/10)+48)); //寫年高位
zf_1602(3,0,((zt[6]%10)+48)); //寫年低位
zf_1602(5,0,((zt[4]/10)+48)); //寫月高位
zf_1602(6,0,((zt[4]%10)+48)); //寫月底位
zf_1602(8,0,((zt[3]/10)+48)); //寫入日高位
zf_1602(9,0,((zt[3]%10)+48)); //寫入日低位
zf_1602(14,0,((zt[5])+48)); //寫入星期
}
if(zt[2] == nz[2]) //判斷小時(shí)是否等于鬧鐘小時(shí)
{
if(nz[3])
l = 1; //打開響鈴
}
}
}
else
{
zh(wd()); //顯示溫度
}
}
}
}
3小結(jié)
1、1602出現(xiàn)數(shù)據(jù)顯示或光標(biāo)移動(dòng)出現(xiàn)有時(shí)顯示或者操作正確有時(shí)錯(cuò)誤
{ 原因:1、程序出現(xiàn)流程或者算法問題
2、1602在忙的時(shí)候是寫入不了指令或命令的
出現(xiàn)第二種情況可以用判忙
}
2、RRPROM 讀取單字節(jié)時(shí)應(yīng)答ack,在下一次讀取單字節(jié)時(shí)會(huì)出錯(cuò)。
所以 在讀單字節(jié)時(shí)應(yīng)答應(yīng)該是NAK。
3、寫代碼時(shí)一定要了解芯片的資料,原理。
本例完整代碼下載地址:http://www.torrancerestoration.com/f/shiz1602.rar
|
評(píng)分
-
查看全部評(píng)分
|