此程序是基于51hei單片機(jī)開發(fā)板上面寫的,如需要移植到自己的電路上,修改相應(yīng)的端口即可,開發(fā)板完整的電路圖下載: 點(diǎn)這里 (注意:只需要看相關(guān)部分即可如矩陣鍵盤 數(shù)碼管 紅外等,其他部分可以忽略)
/**
************************************************************************
* @file : main.c
* @author : xr
* @date : 2014年4月21日 22:23:12 - 2014年4月26日21:22:29
* @version : V1.2.3
* @brief : 按鍵可調(diào)時(shí)電子鐘(矩陣按鍵+紅外遙控按鍵進(jìn)行調(diào)時(shí)) 單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
************************************************************************
*/
#include "main.h"
struct Time {
unsigned char year; //DS1302中只存放的是年的低兩位字節(jié)
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char week;
};
struct Time timeBuf; //此處必須用結(jié)構(gòu)體變量,不能用結(jié)構(gòu)體指針否則寫入失敗!
unsigned char thr0, tlr0;
unsigned char code IrdCodeMap[] = {0x45, 0x46, 0x47, //開關(guān),Mode, 靜音
0x44, 0x40, 0x43, //播放/暫停 快退, 快進(jìn)
0x07, 0x15, 0x09, //EQ, 減, 加
0x16, 0x19, 0x0D, //0, 返回, U/SD
0x0C, 0x18, 0x5E, //1, 2, 3
0x08, 0x1C, 0x5A, //4, 5, 6
0x42, 0x52, 0x4A};//7, 8, 9
extern bit flagIrd; //紅外數(shù)據(jù)碼值接收完畢標(biāo)志位
extern unsigned char irdCode[4]; //保存NEC協(xié)議解碼的四個(gè)字節(jié)的數(shù)據(jù)碼(用戶碼+用戶反碼,鍵碼+鍵碼反碼)
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str);
extern void LcdSetCoursor(unsigned char x, unsigned char y);
extern void LcdOpenCoursor();
extern void InitDS1302();
extern void GetTimeFromDS1302(struct Time * time);
extern void SetTimeToDS1302(struct Time * time);
extern void KeyDriver();
extern void KeyScan();
extern void LcdCoursorLeft();
void RefreshLcdShowTime();
extern void ConfigIrdByTimer1();
void IrdDrive();
void IrdKeyAction();
extern void SetTimeBcdByte(unsigned char keyNum);
void main()
{
unsigned char psec = 0xFF;//用于檢測(cè)sec秒是否變化,若變化則刷新時(shí)間顯示
ConfigIrdByTimer1();//配置紅外通信
InitLCD1602();
InitDS1302();
/*液晶初始化顯示*/
LcdShowStr(1, 0, "*");
LcdShowStr(2, 0, "20 - - ");
LcdShowStr(12, 0, "*");
LcdShowStr(14, 0, "--");
LcdShowStr(0, 1, "time: --:--:--");
while (1)
{
KeyDriver();//檢測(cè)按鍵動(dòng)作
if (flagIrd)
{
flagIrd = 0;
IrdKeyAction();//檢測(cè)紅外按鍵動(dòng)作
}
if (flag200ms == 1 && (setTimeIndex == 0)) //每200ms且setTimeIndex==0處于非設(shè)定時(shí)間狀態(tài)時(shí)刷新一次時(shí)間顯示
{
flag200ms = 0;
GetTimeFromDS1302(&timeBuf); //從DS1302中獲取時(shí)間到timeBuf結(jié)構(gòu)體指針變量的成員中
if (timeBuf.sec != psec) //當(dāng)前秒值和上一次的秒值不相等
{
RefreshLcdShowTime();//刷新時(shí)間顯示
psec = timeBuf.sec;//備份當(dāng)前的秒值(秒寄存器值)
}
}
}
}
void ConfgiTimer0(unsigned int xms)
{
unsigned long tmp;
tmp = 11059200/12;//周期頻率
tmp = (tmp * xms) / 1000;//定時(shí)xms需要的計(jì)數(shù)值
tmp = 65536-tmp;//定時(shí)裝入的初值
thr0 = (unsigned char)(tmp >> 8);
tlr0 = (unsigned char)tmp;
TMOD &= 0xF0;//清零T0控制位
TMOD |= 0x01;//T0方式1,16位可設(shè)定時(shí)模式
TH0 = thr0;
TL0 = tlr0;
TR0 = 1;
ET0 = 1;
EA = 1;
}
void LcdShowBCDByte(unsigned char x, unsigned char y, unsigned char bcdbyte)
{
unsigned char str[4];
str[0] = (bcdbyte >> 4) + '0';//取BCD碼的高四位字節(jié)
str[1] = (bcdbyte & 0x0F) + '0';//取BCD碼的第四位字節(jié)
str[2] = '\0';
LcdShowStr(x, y, str);
}
void RefreshLcdShowTime()
{
LcdShowBCDByte(4, 0, timeBuf.year); //顯示年
LcdShowBCDByte(7, 0, timeBuf.month);
LcdShowBCDByte(10, 0, timeBuf.day);
LcdShowBCDByte(6, 1, timeBuf.hour);
LcdShowBCDByte(9, 1, timeBuf.min);
LcdShowBCDByte(12, 1, timeBuf.sec);
LcdShowBCDByte(14, 0, timeBuf.week); //顯示星期
}
/*遞增BCD碼的高位數(shù)字*/
unsigned char IncrementBCDByteHigh(unsigned char bcdbyte)
{
if ((bcdbyte & 0xF0) < 0x90) //取bcdbyte的高四位字節(jié)是否小于9
{
bcdbyte += 0x10;//高四位字節(jié)+1
}
else
{
//高四位字節(jié)數(shù)值到9歸零
bcdbyte &= 0x0F;//0000 1111
}
return (bcdbyte); //返回修改后的BCD碼值
}
unsigned char IncrementBCDByteLow(unsigned char bcdbyte)
{
if ((bcdbyte & 0x0F) < 0x09) //取bcdbyte的低四位字節(jié)數(shù)字
{
bcdbyte += 0x01; //低位字節(jié)+1
}
else
{
//到9歸零
bcdbyte &= 0xF0;//低四位清零
}
return (bcdbyte);
}
unsigned char DescBCDByteHigh(unsigned char bcdbyte)
{
if ((bcdbyte & 0xF0) > 0) //取BCD碼字節(jié)的高四位字節(jié)
{
bcdbyte -= 0x10; //高四位字節(jié)數(shù)字-1
}
else
{
//到0歸9
bcdbyte |= 0x90; //或bcdbyte &= 0x9F
}
return (bcdbyte);
}
unsigned char DescBCDByteLow(unsigned char bcdbyte)
{
if ((bcdbyte & 0x0F) > 0)
{
bcdbyte -= 0x01;//低位數(shù)字-1
}
else
{
//到0歸9
bcdbyte |= 0x09;
}
return (bcdbyte);
}
/*根據(jù)setTimeIndex的值來設(shè)置光標(biāo)閃爍的位置*/
void LcdRefreshSetCoursor()
{
switch (setTimeIndex)
{
case 1: LcdSetCoursor(4, 0); break;//設(shè)置年的十位數(shù)字
case 2: LcdSetCoursor(5, 0); break;
case 3: LcdSetCoursor(7, 0); break;
case 4: LcdSetCoursor(8, 0); break;
case 5: LcdSetCoursor(10, 0); break;
case 6: LcdSetCoursor(11, 0); break;
case 7: LcdSetCoursor(6, 1); break;
case 8: LcdSetCoursor(7, 1); break;
case 9: LcdSetCoursor(9, 1); break;
case 10: LcdSetCoursor(10, 1); break;
case 11: LcdSetCoursor(12, 1); break;
case 12: LcdSetCoursor(13, 1); break;
default: break;
}
LcdOpenCoursor();
}
void IncTimeBysetTimeIndex()
{
switch (setTimeIndex)
{
case 1: timeBuf.year = IncrementBCDByteHigh(timeBuf.year); break;//year10++年的十位數(shù)字++
case 2: timeBuf.year = IncrementBCDByteLow(timeBuf.year); break;//年的個(gè)位數(shù)字++
case 3: timeBuf.month = IncrementBCDByteHigh(timeBuf.month); break;//月十位++
case 4: timeBuf.month = IncrementBCDByteLow(timeBuf.month); break;//月個(gè)位++
case 5: timeBuf.day = IncrementBCDByteHigh(timeBuf.day); break;
case 6: timeBuf.day = IncrementBCDByteLow(timeBuf.day); break;
case 7: timeBuf.hour = IncrementBCDByteHigh(timeBuf.hour); break;
case 8: timeBuf.hour = IncrementBCDByteLow(timeBuf.hour); break;
case 9: timeBuf.min = IncrementBCDByteHigh(timeBuf.min); break;
case 10: timeBuf.min = IncrementBCDByteLow(timeBuf.min); break;
case 11: timeBuf.sec = IncrementBCDByteHigh(timeBuf.sec); break;
case 12: timeBuf.sec = IncrementBCDByteLow(timeBuf.sec); break;
default: break;
}
RefreshLcdShowTime();//刷新時(shí)間顯示
LcdRefreshSetCoursor();//刷新光標(biāo)閃爍顯示
}
void DecTimeBySetTimeIndex()
{
switch (setTimeIndex)
{
case 1: timeBuf.year = DescBCDByteHigh(timeBuf.year); break;//年十位數(shù)字遞減
case 2: timeBuf.year = DescBCDByteLow(timeBuf.year); break;//年個(gè)位數(shù)字遞減
case 3: timeBuf.month = DescBCDByteHigh(timeBuf.month); break;
case 4: timeBuf.month = DescBCDByteLow(timeBuf.month); break;
case 5: timeBuf.day = DescBCDByteHigh(timeBuf.day); break;
case 6: timeBuf.day = DescBCDByteLow(timeBuf.day); break;
case 7: timeBuf.hour = DescBCDByteHigh(timeBuf.hour); break;
case 8: timeBuf.hour = DescBCDByteLow(timeBuf.hour); break;
case 9: timeBuf.min = DescBCDByteHigh(timeBuf.min); break;
case 10: timeBuf.min = DescBCDByteLow(timeBuf.min); break;
case 11: timeBuf.sec = DescBCDByteHigh(timeBuf.sec); break;
case 12: timeBuf.sec = DescBCDByteLow(timeBuf.sec); break;
default: break;
}
/*先刷新時(shí)間顯示,再刷新光標(biāo)閃爍顯示*/
RefreshLcdShowTime();
LcdRefreshSetCoursor();
}
void IrdKeyAction()
{
if (irdCode[2] == 0x44) // >>||
{
if (setTimeIndex == 0) //正常運(yùn)行狀態(tài)
{
setTimeIndex = 1;
LcdRefreshSetCoursor();//刷新光標(biāo)設(shè)置顯示
}
else
{
SetTimeToDS1302(&timeBuf); //將時(shí)間寫入到DS1302中
setTimeIndex = 0;
RefreshLcdShowTime();
}
}
else if (irdCode[2] == 0x40) //|<<
{
if (setTimeIndex != 0)
{
LcdCoursorLeft();
}
}
else if (irdCode[2] == 0x43) // >>|
{
if (setTimeIndex != 0)
{
LcdCoursorRight();
}
}
else if (irdCode[2] == 0x15) //-
{
DecTimeBySetTimeIndex();
}
else if (irdCode[2] == 0x09) //+
{
IncTimeBysetTimeIndex();
}
else if (irdCode[2] == 0x19) //EQ
{
setTimeIndex = 0;
RefreshLcdShowTime();
}
else if (irdCode[2] == 0x16) //數(shù)字鍵0
{
SetTimeBcdByte(0);
}
else if (irdCode[2] == 0x0C) //數(shù)字鍵1
{
SetTimeBcdByte(1);
}
else if (irdCode[2] == 0x18) //數(shù)字鍵2
{
SetTimeBcdByte(2);
}
else if (irdCode[2] == 0x5E)
{
SetTimeBcdByte(3);
}
else if (irdCode[2] == 0x08)
{
SetTimeBcdByte(4);
}
else if (irdCode[2] == 0x1C)
{
SetTimeBcdByte(5);
}
else if (irdCode[2] == 0x5A)
{
SetTimeBcdByte(6);
}
else if (irdCode[2] == 0x42)
{
SetTimeBcdByte(7);
}
else if (irdCode[2] == 0x52)
{
SetTimeBcdByte(8);
}
else if (irdCode[2] == 0x4A)
{
SetTimeBcdByte(9);
}
else
{
}
void Timer0_ISP() interrupt 1
{
static unsigned char counter = 0;
TH0 = thr0;
TL0 = tlr0; //1ms
counter++;
KeyScan();//按鍵掃描
if (counter >= 200)
{
counter = 0;
flag200ms = 1;//200ms
}
}
#ifndef _MAIN_H_
#define _MAIN_H_
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
/**
************************************************************************
* @file : Lcd1602.c
* @author : xr
* @date : 2014年4月21日 22:23:12
* @version : V1.2.3
* @brief : LCD1602底層驅(qū)動(dòng) 單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
************************************************************************
*/
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_EN = P1^5;
void LCD1602Wait()
{
unsigned char sta;//讀取LCD1602狀態(tài)字
/*讀取液晶狀態(tài)字之前必須將P0口全部拉高*/
LCD1602_DB = 0xFF;
LCD1602_RS = 0;
LCD1602_RW = 1;
LCD1602_EN = 0;
do
{
LCD1602_EN = 1;
sta = LCD1602_DB;//讀狀態(tài)字
LCD1602_EN = 0;
} while (sta & 0x80); //檢測(cè)最高位是否為1,1忙碌,0空閑
}
void LCD1602WriteCmd(unsigned char cmd)
{
//讀寫前要進(jìn)行液晶的忙碌等待
LCD1602Wait();
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_EN = 0;
LCD1602_DB = cmd;
LCD1602_EN = 1;//高脈沖
LCD1602_EN = 0;//關(guān)閉液晶輸出
}
void LCD1602WriteData(unsigned char dat)
{
LCD1602Wait();
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_EN = 0;
LCD1602_DB = dat;//送入數(shù)據(jù)
LCD1602_EN = 1;//高脈沖
LCD1602_EN = 0;//關(guān)閉液晶輸出
}
void InitLCD1602()
{
LCD1602WriteCmd(0x38); //寫指令38H
LCD1602WriteCmd(0x0C); //開顯示不顯示光標(biāo)
LCD1602WriteCmd(0x06); //寫入字符時(shí)字符指針++且光標(biāo)++
LCD1602WriteCmd(0x01); //顯示清屏
}
void LcdShowStr(unsigned char x, unsigned char y, unsigned char * str)
{
unsigned char addr;
if (y == 0)
{
addr = 0x00 + x; //第一行的x位置顯示
}
else
{
addr = 0x40 + x; //第二行x的位置顯示
}
{
LCD1602WriteData(*str++);
}
}
void LcdSetCoursor(unsigned char x, unsigned char y)
{
unsigned char addr;
if (y == 0)
{
addr = 0x00 + x;
}
else
{
addr = 0x40 + x;
}
LCD1602WriteCmd(addr | 0x80); //寫入光標(biāo)閃爍地址
}
void LcdOpenCoursor()
{
LCD1602WriteCmd(0x0F); //顯示光標(biāo)病使光標(biāo)閃爍
}
void LcdCloseCoursor()
{
LCD1602WriteCmd(0x0C); //開顯示但不顯示光標(biāo)
}
/**
************************************************************************
* @file : Ds1302.c
* @author : xr
* @date : 2014年4月21日 22:23:12
* @version : V1.2.3
* @brief : DS1302底層驅(qū)動(dòng) 單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
************************************************************************
*/
#include <reg52.h>
sbit DS1302_SIO = P3^4;//數(shù)據(jù)IO
sbit DS1302_SCK = P3^5;//時(shí)鐘線
sbit DS1302_CE = P1^7;//片選使能
struct Time {
unsigned char year;//年在DS1302中只存放的是低兩位,這里用unsigned char型
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char week;
};
void DS1302WriteByte(unsigned char byte)
{
unsigned char mask = 0x01;//低位在前,逐位發(fā)送
/*初始化DS1302時(shí),將SIO和SCK引腳拉低,空閑*/
for (mask = 0x01; mask != 0; mask <<= 1)
{
if ((byte & mask) != 0) //上升沿DS1302進(jìn)行數(shù)據(jù)的采樣鎖存
{
DS1302_SIO = 1;
}
else
{
DS1302_SIO = 0;
}
DS1302_SCK = 1;
DS1302_SCK = 0;//下降沿主機(jī)進(jìn)行數(shù)據(jù)輸出
}
//主機(jī)發(fā)送數(shù)據(jù)完成后要進(jìn)行釋放SIO數(shù)據(jù)線
DS1302_SIO = 1;
}
unsigned char DS1302ReadByte()
{
unsigned char mask = 0x01;//低位在先,逐位接收
unsigned char byte = 0;
for (mask = 0x01; mask != 0; mask <<= 1)
{
if (DS1302_SIO != 0) //上升沿主機(jī)進(jìn)行數(shù)據(jù)采樣鎖存
{
byte |= mask; //相應(yīng)位置1
}
else
{
byte &= (~mask);//相應(yīng)位清零
}
DS1302_SCK = 1;
DS1302_SCK = 0;//DS1302在下降沿進(jìn)行數(shù)據(jù)的輸出
}
return (byte);
}
void DS1302WriteSingleByte(unsigned char reg, unsigned char dat)
{
/*首先打開DS1302片選端,然后寫寄存器地址reg,然后再寫入數(shù)據(jù)dat*/
DS1302_CE = 1;
DS1302WriteByte((reg << 1) | 0x80);//寫入寄存器地址,reg<<1留出讀寫方向位,reg的高位是1,次高位為0
DS1302WriteByte(dat); //寫入數(shù)據(jù)
DS1302_CE = 0;
DS1302_SIO = 0;//因?yàn)榘遄由蠜]有SIO口沒有加上拉電阻,開漏輸出不定態(tài),將SIO=0,單片機(jī)IO口會(huì)輸出穩(wěn)定的0態(tài)
}
unsigned char DS1302ReadSingleByte(unsigned char reg)
{
unsigned char byte = 0;
DS1302_CE = 1;
DS1302WriteByte((reg << 1) | 0x81); //寫入寄存器地址reg并在讀寫方向上選擇讀
byte = DS1302ReadByte();
DS1302_CE = 0;
DS1302_SIO = 0; //SIO輸出穩(wěn)定的0狀態(tài)
return (byte);
}
void DS1302BurstWrite(unsigned char * date)
{
unsigned char i = 0;
DS1302_CE = 1;
DS1302WriteByte(0xBE); //寫入突發(fā)模式指令(Burst模式)
for (i = 0; i < 8; i++)
{
DS1302WriteByte(date[i]);
}
DS1302_CE = 0;
DS1302_SIO = 0;
}
void DS1302BurstRead(unsigned char * date)
{
unsigned char i = 0;
DS1302_CE = 1; //片選使能
DS1302WriteByte(0xBF); //突發(fā)讀指令
for (i = 0; i < 8; i++)
{
date[i] = DS1302ReadByte();
}
DS1302_CE = 0;
DS1302_SIO = 0;
}
void GetTimeFromDS1302(struct Time * time)
{
unsigned char buff[8];//保存八個(gè)寄存器中的數(shù)據(jù)
DS1302BurstRead(buff); //將DS1302寄存器中的數(shù)據(jù)讀入buff數(shù)組中
time->year = buff[6];//將年寄存器中的bcd碼取出來存入結(jié)構(gòu)體time->year中
time->month = buff[4];
time->week = buff[5];
time->day = buff[3];
time->hour = buff[2];
time->min = buff[1];
time->sec = buff[0];
}
void SetTimeToDS1302(struct Time * time)
{
unsigned char buff[8]; //保存當(dāng)前修改后的time結(jié)構(gòu)體成員的值
buff[0] = time->sec; //將秒寄存器中的值存入buff[0
buff[1] = time->min;
buff[2] = time->hour;
buff[3] = time->day;
buff[4] = time->month;
buff[5] = time->week;
buff[6] = time->year;
buff[7] = 0x00; //WP寫保護(hù)寄存器
DS1302BurstWrite(buff); //將buff中的值以Burst模式寫入DS1302中
}
void InitDS1302()
{
struct Time code InitTime[] = {0x14, 0x04, 0x22, 0x23, 0x59, 0x59, 0x02}; //2014年4月22日23:59:59
DS1302_SCK = 0;
DS1302_CE = 0;
psec = DS1302ReadSingleByte(0x00); //0x00<<1 | 0x81=0x81, 讀取秒寄存器
if ((psec & 0x80) != 0) //最高位CH=1,時(shí)鐘停止
{
DS1302WriteSingleByte(7, 0x00); //去除寫保護(hù)
SetTimeToDS1302(InitTime); //將初始時(shí)間設(shè)置到DS1302中
}
}
/**
**************************************************************************
* @file : Infrared.c
* @author : xr
* @date : 2014年4月23日22:01:12
* @version : V1.2.3
* @brief : 紅外通信解碼-NEC協(xié)議解碼
**************************************************************************
*/
#include <reg52.h>
sbit IRD = P3^3;//紅外通信引腳,外部中斷1引腳
void ConfigIrdByTimer1()
{
TMOD &= 0x0F;//清零T1控制位
TMOD |= 0x10;//使用T1方式1,16位可設(shè)定模式
TH1 = 0;
TL1 = 0;//開始時(shí)沒有紅外信號(hào),清零T1計(jì)數(shù)
TR1 = 0;//開始時(shí)關(guān)閉T1計(jì)數(shù)
ET1 = 0;//關(guān)閉T1中斷,只用T1計(jì)數(shù)功能
/*外部中斷1配置*/
IE1 = 0;//外部中斷1標(biāo)志位清零
IT1 = 1;//設(shè)置外部中斷1為下降沿觸發(fā)
EX1 = 1;//開啟外部中斷
EA = 1;//開總中斷
}
unsigned int GetHighTimers()
{
IRD = 1;//在檢測(cè)紅外引腳之前,要先將IRD引腳拉高釋放
TH1 = 0;
TL1 = 0;//先清零上一次的T1計(jì)數(shù)值
TR1 = 1;//開啟T1計(jì)數(shù)
{ //高電平T1進(jìn)行計(jì)數(shù)
if (TH1 > 0x40) //0x40 * 256 * (12/11059200) * 1000 = 17.7ms
{
break; //當(dāng)時(shí)間>17.7ms時(shí)我們認(rèn)為是誤碼,強(qiáng)制退出
}
}
TR1 = 0; //關(guān)閉T1計(jì)數(shù)
return (TH1 * 256 + TL1); //返回IRD引腳高電平時(shí)T1的計(jì)數(shù)值
}
unsigned int GetLowTimers()
{
IRD = 1;//在檢測(cè)紅外引腳之前,要先將IRD引腳釋放
TH1 = 0;
TL1 = 0; //清零T1計(jì)數(shù)值
TR1 = 1; //開啟T1計(jì)數(shù)
while (!IRD)
{
//超時(shí)判斷
if (TH1 > 0x40) //超出17.7ms就退出
{
break;
}
}
TR1 = 0;//關(guān)閉T1計(jì)數(shù)
return (TH1 * 256 + TL1);//返回T1計(jì)數(shù)值
}
void EXINT1_ISP() interrupt 2 //EXINT1中斷標(biāo)號(hào)為2
{
unsigned char byte = 0;//接收解碼數(shù)據(jù)
unsigned int time = 0;//接收引導(dǎo)碼和空閑與載波的時(shí)間
unsigned char i, j;
time = GetLowTimers();//載波 引導(dǎo)碼(9ms的載波+4.5ms的空閑):范圍(8.5ms-9.5ms)
if ((time < 7833) ||(time > 8755)) //計(jì)數(shù)周期=12/11059200 計(jì)數(shù)時(shí)間=(TH1*256+TL1)*12/11059200
{
//誤碼,清零中斷標(biāo)志并退出中斷
IE1 = 0;
return;
}
time = GetHighTimers();//空閑 4.5ms的空閑:范圍:4ms-5ms
if ((time < 3686) || (time > 4608)) //判斷時(shí)必須加上()
{
//不符合
IE1 = 0;//外部中斷標(biāo)志位
return; //退出中斷函數(shù)
}
//引導(dǎo)碼正確,開始循環(huán)接收用戶碼和鍵碼
for (i = 0; i < 4; i++) //接收4個(gè)字節(jié)數(shù)據(jù)
{
for (j = 0; j < 8; j++) //接收8位
{
time = GetLowTimers();//載波:560us載波+560us/1.68ms空閑:340us 760us
if ((time < 313) || (time > 700))
{
//誤碼
IE1 = 0;//清零外部中斷標(biāo)志
return;
}
time = GetHighTimers();//空閑
if ((time > 313) && (time < 700)) //560us的空閑,比特值'0'time大于340us并且time<780us
{
byte >>= 1;//低位在先,逐位接收,將數(shù)據(jù)位右移到低位
}
else if ((time > 1271) && (time < 1658)) //1.68ms空閑:范圍:1.38ms-1.8ms,比特值是'1'
{
byte >>= 1;//先右移一位,將這一位移到byte的最高位
byte |= 0x80;//再將這一位置1
}
else
{
//接收的是誤碼
IE1 = 0;//清零外部中斷1標(biāo)志位
return;//退出中斷函數(shù)
}
}
irdCode[i] = byte;//接收碼值
}
flagIrd = 1;//接收完成標(biāo)志置1
IE1 = 0;//清零外部中斷標(biāo)志
}
/**
************************************************************************
* @file : Keyboard.c
* @author : xr
* @date : 2014年4月21日 22:23:12
* @version : V1.2.3
* @brief : 按鍵底層驅(qū)動(dòng) 單片機(jī)STC89C52RC MCU 晶振 11.0592MHZ
************************************************************************
*/
#include <reg52.h>
sbit KEY_IN_1 = P2^4;
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
{1, 1, 1, 1}, {1, 1, 1, 1}}; //16個(gè)按鍵當(dāng)前狀態(tài)
unsigned char pdata keyCodeMap[4][4] = { //按鍵編碼根據(jù)ASCII碼進(jìn)行編碼
{'1', '2', '3', 0x26}, //數(shù)字鍵1,2,3和向上鍵
{'4', '5', '6', 0x25}, //數(shù)字鍵4,5,6和向左鍵
{'7', '8', '9', 0x28}, //數(shù)字鍵7,8,9和向下鍵
{'0', 0x1B, 0x0D, 0x27} //數(shù)字鍵0和ESC鍵,回車鍵,向右鍵
};
/*需要使用main.c文件中的struct Time類型的結(jié)構(gòu)體變量timeBuf,需要在重新進(jìn)行聲明*/
struct Time {
unsigned char year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char min;
unsigned char sec;
unsigned char week;
};
extern unsigned char setTimeIndex;//外部變量聲明
void LcdCoursorRight();
void LcdCoursorLeft();
void SetTimeBcdByte(unsigned char keyNum);
void KeyAction(unsigned char keycode);
extern void LcdRefreshSetCoursor();
extern void LcdCloseCoursor();
extern void IncTimeBysetTimeIndex();
extern void DecTimeBySetTimeIndex();
extern GetTimeFromDS1302(struct Time * time);
extern void SetTimeToDS1302(struct Time * time);
extern void RefreshLcdShowTime();
void KeyDriver()
{
static unsigned char pdata keyBackup[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}}; //按鍵的備份即上一次按鍵的狀態(tài)值
unsigned char i, j;
{
for (j = 0; j < 4; j++)
{
if (keySta[i][j] != keyBackup[i][j])
{
//按鍵有動(dòng)作
if (keyBackup[i][j] != 0) //根據(jù)上一次的備份值來確定本次的按鍵值,即按鍵的動(dòng)作
{
//按鍵按下,執(zhí)行動(dòng)作
KeyAction(keyCodeMap[i][j]); //傳遞相應(yīng)的鍵碼
}
//備份本次按鍵的值
keyBackup[i][j] = keySta[i][j];
}
}
}
}
void KeyScan()
{
static unsigned char keyout = 0;//按鍵行索引,每次都要用到上一次變化的keyout值所以定義為靜態(tài)變量
static unsigned char keybuff[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}}; //按鍵掃描緩沖區(qū)
unsigned char i = 0;
/*掃描按鍵的值,并將按鍵的狀態(tài)值存入keybuff緩沖區(qū)中*/
keybuff[keyout][0] = (keybuff[keyout][0] << 1) | KEY_IN_1; //將第keyout行的第一個(gè)按鍵的掃描值存入keybuff[keyout][0]緩沖區(qū)中
keybuff[keyout][1] = (keybuff[keyout][1] << 1) | KEY_IN_2;
keybuff[keyout][2] = (keybuff[keyout][2] << 1) | KEY_IN_3;
keybuff[keyout][3] = (keybuff[keyout][3] << 1) | KEY_IN_4;
/*更新掃描消抖后按鍵的狀態(tài)*/
for (i = 0; i < 4; i++) //每行有四個(gè)按鍵需要進(jìn)行判斷
{
if ((keybuff[keyout][i] & 0x1F) == 0x00) //5次按鍵掃描值都是0,表示按鍵是穩(wěn)定按下
{
keySta[keyout][i] = 0;
}
else if ((keybuff[keyout][i] & 0x1F) == 0x1F) //5次按鍵的掃描值都是1,表示按鍵是穩(wěn)定彈起
{
keySta[keyout][i] = 1;
}
}
//行++
keyout++;
keyout &= 0x03;//實(shí)現(xiàn)到4歸零
/*根據(jù)keyout的值來確定選擇哪一行按鍵進(jìn)行掃描*/
switch (keyout)
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;//掃描第1行
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;//掃描第2行
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;//掃描第3行
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;//掃描第4行
default: break;
}
}
void KeyAction(unsigned char keycode)
{
if (keycode >= '0' && keycode <= '9')
{
if (setTimeIndex != 0) //處于設(shè)置狀態(tài)才相應(yīng)
SetTimeBcdByte(keycode - '0'); //數(shù)字鍵設(shè)置時(shí)間
}
else if (keycode == 0x26) //向上鍵進(jìn)行光標(biāo)閃爍位置上的數(shù)值的++
{
IncTimeBysetTimeIndex();//遞增BCD碼的高位或低位數(shù)字
}
else if (keycode == 0x27) //向右鍵進(jìn)行進(jìn)行光標(biāo)位置的右移
{
if (setTimeIndex != 0) //處于設(shè)置狀態(tài)才相應(yīng)
LcdCoursorRight();//遞減BCD碼的高位或低位數(shù)字
}
else if (keycode == 0x25) //向左鍵進(jìn)行光標(biāo)閃爍位置的左移
{
if (setTimeIndex != 0)
LcdCoursorLeft();
}
else if (keycode == 0x28) //向下鍵光標(biāo)閃爍位置上的數(shù)值的遞減
{
DecTimeBySetTimeIndex();
}
else if (keycode == 0x1B) //ESC鍵,取消當(dāng)前的設(shè)置
{
setTimeIndex = 0;//時(shí)鐘正常運(yùn)行索引=0
LcdCloseCoursor();//關(guān)閉光標(biāo)閃爍
}
else if (keycode == 0x0D) //回車鍵,進(jìn)行設(shè)置時(shí)間和恢復(fù)時(shí)鐘運(yùn)行的狀態(tài)的切換
{
if (setTimeIndex == 0) //正常運(yùn)行狀態(tài),開始切換到設(shè)置狀態(tài)
{
setTimeIndex = 1;
LcdRefreshSetCoursor();//刷新光標(biāo)閃爍位置并讓光標(biāo)閃爍
}
else
{
//寫入設(shè)置的時(shí)間值,并切換到正常運(yùn)行狀態(tài)
SetTimeToDS1302(&timeBuf);
GetTimeFromDS1302(&timeBuf);
setTimeIndex = 0;
LcdCloseCoursor();//關(guān)閉光標(biāo)閃爍
}
}
}
void LcdCoursorRight()
{
if (setTimeIndex < 12)
setTimeIndex++;//光標(biāo)設(shè)置索引++
else
setTimeIndex = 1;
LcdRefreshSetCoursor();
}
void LcdCoursorLeft()
{
if (setTimeIndex > 1)
setTimeIndex--;//光標(biāo)設(shè)置索引--
else
setTimeIndex = 12;
LcdRefreshSetCoursor();
}
unsigned char SetBCDHighByte(unsigned char bcd, unsigned char keyNum)
{
bcd &= 0x0F;//清零高位
bcd |= (keyNum << 4); //keyNum移至高位
return (bcd);
}
unsigned char SetBCDLowByte(unsigned char bcd, unsigned char keyNum)
{
bcd &= 0xF0;//低位清零
bcd |= keyNum; //將keyNum數(shù)字放到低位
return (bcd); //返回改變后的bcd字節(jié)數(shù)據(jù)
}
void SetTimeBcdByte(unsigned char keyNum) //傳遞按鍵的數(shù)值
{
switch (setTimeIndex)
{
case 1: timeBuf.year = SetBCDHighByte(timeBuf.year, keyNum); break;//設(shè)置年的高位BCD字節(jié)
case 2: timeBuf.year = SetBCDLowByte(timeBuf.year, keyNum); break; //設(shè)置年的低位BCD字節(jié)
case 3: timeBuf.month = SetBCDHighByte(timeBuf.month, keyNum); break;
case 4: timeBuf.month = SetBCDLowByte(timeBuf.month, keyNum); break;
case 5: timeBuf.day = SetBCDHighByte(timeBuf.day, keyNum); break;
case 6: timeBuf.day = SetBCDLowByte(timeBuf.day, keyNum); break;
case 7: timeBuf.hour = SetBCDHighByte(timeBuf.hour, keyNum); break;
case 8: timeBuf.hour = SetBCDLowByte(timeBuf.hour, keyNum); break;
case 9: timeBuf.min = SetBCDHighByte(timeBuf.min, keyNum); break;
case 10: timeBuf.min = SetBCDLowByte(timeBuf.min, keyNum); break;
case 11: timeBuf.sec = SetBCDHighByte(timeBuf.sec, keyNum); break;
case 12: timeBuf.sec = SetBCDLowByte(timeBuf.sec, keyNum); break;
}
RefreshLcdShowTime(); //刷新時(shí)間值顯示
LcdCoursorRight(); //光標(biāo)閃爍右移
LcdRefreshSetCoursor(); //刷新光標(biāo)閃爍
}