目录
- 一、实验目的
- 二、实验仪器
- 三、实验效果预览
- 1.显示效果
- 2.调节效果
- 四、实验原理
- 五、单片机代码
- 1.头文件包含
- 2.类型定义
- 3.时钟模块
- 4. 液晶显示模块
- 5.温度传感器模块
- 6. 红外通讯模块
- 7.开机初始化
- 8.特殊功能函数
- 9.代码段常量
- 10.完整代码
一、实验目的
使用51单片机作为主控芯片,制作可调万年历
二、实验仪器
主控芯片 STC89C52
时钟芯片 DS1302
温度传感器 DS18B20
1602液晶 LCD12864
任意红外遥控器
晶振 11.0952M x1,32.768K x1
电阻、电容若干(详见实验原理图)
三、实验效果预览
1.显示效果
1602液晶屏显示:
年/月/日 星期
时:分:秒 AM/PM 温度
图1 1602液晶屏显示效果
2.调节效果
红外遥控器任意按键进入调节模式
图2 调节模式显示效果
调节模式被选中的数值下方出现光标,按 < 键和 > 键移动光标,按 + 键和 - 键改变光标选中数值,按 = 键退出调节模式(键值需要自行设置)。
图3 调节模式中将星期四改变为星期五
四、实验原理
LCD12864液晶屏VO端接电位器R21,调节R21,使液晶对比度最佳。
图4 可调万年历实验原理图
五、单片机代码
1.头文件包含
#include <reg52.h>
#include <intrins.h>
2.类型定义
定义字节型变量BYTE和字变量WORD
typedef unsigned char BYTE;
typedef unsigned short WORD;
3.时钟模块
sbit TSCLK = P1 ^ 0; // 时钟线
sbit TIO = P1 ^ 1; // 数据线
sbit TEN = P1 ^ 2; // 使能端
// 读一字节
BYTE DS1302_read_byte(BYTE _Cmd)
{
BYTE i;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Cmd & 0x01;
TSCLK = 1;
_Cmd >>= 1;
}
for (i = 0; i < 8; i++) {
TSCLK = 0;
_Cmd >>= 1;
if (TIO)
_Cmd |= 0x80;
TSCLK = 1;
}
return _Cmd;
}
// 写一字节
void DS1302_write_byte(BYTE _Cmd, BYTE _Dat)
{
BYTE i;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Cmd & 0x01;
TSCLK = 1;
_Cmd >>= 1;
}
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Dat & 0x01;
TSCLK = 1;
_Dat >>= 1;
}
}
// 时钟突发突发模式读
void clock_brust_read(BYTE *_Buf)
{
BYTE i, j = 0xbf;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = j & 0x01;
TSCLK = 1;
j >>= 1;
}
for (i = 0; i < 7; i++)
for (j = 0; j < 8; j++) {
TSCLK = 0;
_Buf[i] >>= 1;
if (TIO)
_Buf[i] |= 0x80;
TSCLK = 1;
}
}
// 时钟突发突发模式写
void clock_brust_write(const BYTE *_Buf)
{
BYTE i, j = 0xbe, k;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = j & 0x01;
TSCLK = 1;
j >>= 1;
}
for (i = 0; i < 7; i++) {
k = _Buf[i];
for (j = 0; j < 8; j++) {
TSCLK = 0;
TIO = k & 0x01;
TSCLK = 1;
k >>= 1;
}
}
}
4. 液晶显示模块
#define LCD_DATA P0 // 液晶数据线
sbit LCD_RS = P3 ^ 5; // 数据/命令选择端
sbit LCD_WR = P3 ^ 6; // 读/写选择端
sbit LCD_EN = P3 ^ 4; // 使能端
// 读状态
BYTE LCD_read_state()
{
BYTE state;
LCD_RS = 0;
LCD_WR = 1;
LCD_EN = 1;
state = LCD_DATA;
LCD_EN = 0;
return state;
}
// 写指令
void LCD_write_cmd(BYTE _Cmd)
{
LCD_EN = 0;
LCD_EN = 1;
LCD_RS = 0;
LCD_WR = 0;
LCD_DATA = _Cmd;
LCD_EN = 0;
}
// 读数据
BYTE LCD_read_data()
{
BYTE i;
LCD_RS = 1;
LCD_WR = 1;
LCD_EN = 1;
i = LCD_DATA;
LCD_EN = 0;
return i;
}
// 写数据
void LCD_write_data(BYTE _Dat)
{
LCD_EN = 0;
LCD_EN = 1;
LCD_RS = 1;
LCD_WR = 0;
LCD_DATA = _Dat;
LCD_EN = 0;
}
// 等待写指令
void LCD_wait_cmd(BYTE _Cmd)
{
while (LCD_read_state() & 0x80)
;
LCD_write_cmd(_Cmd);
}
// 等待写数据
void LCD_wait_write_data(BYTE _Dat)
{
while (LCD_read_state() & 0x80)
;
LCD_write_data(_Dat);
}
// 等待读数据
BYTE LCD_wait_read_data()
{
while (LCD_read_state() & 0x80)
;
return LCD_read_data();
}
// 写入字符串
void LCD_write_string(const char *_Str)
{
BYTE i = 0;
while (_Str[i])
LCD_wait_write_data(_Str[i++]);
}
#define _LCD_CLS 0x01 // 显示清屏
5.温度传感器模块
sbit DS18B20 = P2 ^ 2; // 温度传感器1-wire线
// 1-wire初始化时序
void init_DS18B20()
{
do {
DS18B20 = 1;
_nop_();
DS18B20 = 0;
timer0_delay(65074); // delay 499.45 us
DS18B20 = 1;
timer0_delay(65500); // delay 37.95 us
} while (DS18B20);
timer0_delay(65404); // delay 141.95 us
DS18B20 = 1;
_nop_();
}
// 1-wire写时序
void write_byte_1wire(BYTE _Dat)
{
BYTE i;
for (i = 0; i < 8; i++) {
DS18B20 = 0;
_nop_();
DS18B20 = _Dat & 0x01 ? 1 : 0;
timer0_delay(65464); // delay 76.95 us
DS18B20 = 1;
_nop_();
_Dat >>= 1;
}
}
// 1-wire读时序
BYTE read_byte_1wire()
{
BYTE dat = 0, i;
for (i = 0; i < 8; i++) {
dat >>= 1;
DS18B20 = 0;
_nop_(); // 产生读时序
DS18B20 = 1;
_nop_(); // 释放总线
if (DS18B20)
dat |= 0x80;
timer0_delay(65464); // delay 76.95 us
}
return dat;
}
// ROM指令
#define _SEARCH_ROM 0xf0 // 搜索 ROM 指令
#define _READ_ROM 0x33 // 读取 ROM 指令
#define _MATH_ROM 0x55 // 匹配 ROM 指令
#define _SIKP_ROM 0xcc // 忽略 ROM 指令
#define _ALARM_ROM 0xec // 报警搜索指令
// DS18B20功能指令
#define _CONVERT_T 0x44 // 温度转换指令
#define _WRITE_SCRATCHPAD 0x4e // 写暂存器指令
#define _READ_SCRATCHPAD 0xbe // 读暂存器指令
#define _COPY_SCRATCHPAD 0x48 // 拷贝暂存器指令
#define _RECALL_E2 0xb8 // 召回 EEPROM 指令
#define _READ_POWER_SUPPLY 0xb4 // 读电源模式指令
6. 红外通讯模块
BYTE IRtime; // 红外高低电平持续时间
BYTE IRcord[2]; // 8位地址+8位数据
bit IRdone = 0; // 数据接收完成标志位
// 定时器1中断 - 每中断一次需要256个机器周期
void timer1() interrupt 3
{
IRtime++; // _MACHINE_CYCLE*256=277.76 μs
}
// 外部中断0
void int0() interrupt 0
{
static BYTE i; // 32次数据计数
static bit startflag = 0; // 开始储存脉宽标志位
static BYTE IRdata[4]; // 数据接收缓冲区
BYTE j;
if (startflag) {
if (IRtime >= 32 && IRtime < 53) { // 起始码判定 8.8ms~14ms
i = 0;
IRtime = 0;
return;
}
j = (i++) >> 3;
IRdata[j] >>= 1;
if (IRtime > 5) // 数据0=高电平560μs+低电平560μs=1120μs
IRdata[j] |= 0x80;
IRtime = 0; // 计数清零
if (i == 32) { // 如果已经存入了32次脉宽
i = 0; // 数据计数清零准备下次存入
if (IRdata[0] == ~IRdata[1] && IRdata[2] == ~IRdata[3]) {
IRdone = 1; // 32位数据接收完成
IRcord[0] = IRdata[0];
IRcord[1] = IRdata[2];
}
}
} else {
IRtime = 0;
startflag = 1;
}
}
7.开机初始化
/* 开机初始化 */
void init()
{
// 初始化时钟模块
DS1302_write_byte(0x8e, 0x80); // 开写保护
// 初始化LCD1802液晶
delay_ms(15);
LCD_write_cmd(0x38);
delay_ms(5);
LCD_write_cmd(0x38);
delay_ms(5);
LCD_write_cmd(0x38);
LCD_wait_cmd(0x38); // 显示模式设置
LCD_wait_cmd(0x0c); // 开显示 不显示光标 光标不闪烁
LCD_wait_cmd(_LCD_CLS); // 显示清屏
/* 红外通讯初始化 - 使用定时器1 */
TMOD = (TMOD & 0x0f) | 0x20;
TH1 = 0;
TL1 = 0;
TR1 = 1;
EA = 1; // 开总中断
ET1 = 1; // 开定时器1中断
EX0 = 1; // 开外部中断0
IT0 = 1; // 设置外部中断0边沿触发
TR1 = 1; // 启动定时器0
}
8.特殊功能函数
/* 转换函数 */
// 组合BCD码转换函数
BYTE to_BCD(BYTE _Dat)
{
return ((_Dat / 10) << 4) | _Dat % 10;
}
// 非组合BCD码 ---> 可显示字符ASCII
BYTE to_hex(BYTE _Dat)
{
_Dat += _Dat < 10 ? '0' : '7';
return _Dat;
}
// 返回是否是闰年
bit is_leap(WORD _Year)
{
return _Year % 4 == 0 && _Year % 100 != 0 || _Year % 400 == 0;
}
/* 延时函数 */
// 低精度毫秒级延时
void delay_ms(WORD _Ms)
{
BYTE x;
while (_Ms--)
for (x = 144; x > 0; x--)
;
}
// 定时器0延时
void timer0_delay(WORD _Th)
{
TMOD = (TMOD & 0xf0) | 0x01;
TH0 = _Th >> 8;
TL0 = _Th & 0xff;
TR0 = 1;
while (TF0 == 0)
;
TF0 = 0;
}
9.代码段常量
// 星期的英文缩写
char code weekday[7][3] = {
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
// 一个月有几天(平年)
BYTE code monthday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
10.完整代码
#include <reg52.h>
#include <intrins.h>
/* typedef */
typedef unsigned char BYTE;
typedef unsigned short WORD;
/* cast */
BYTE to_BCD(BYTE _Dat)
{
return ((_Dat / 10) << 4) | _Dat % 10;
}
BYTE to_hex(BYTE _Dat)
{
_Dat += _Dat < 10 ? '0' : '7';
return _Dat;
}
char code weekday[7][3] = {
"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
BYTE code monthday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bit is_leap(WORD _Year)
{
return _Year % 4 == 0 && _Year % 100 != 0 || _Year % 400 == 0;
}
/* 时钟模块 */
sbit TSCLK = P1 ^ 0;
sbit TIO = P1 ^ 1;
sbit TEN = P1 ^ 2;
// 读一字节
BYTE DS1302_read_byte(BYTE _Cmd)
{
BYTE i;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Cmd & 0x01;
TSCLK = 1;
_Cmd >>= 1;
}
for (i = 0; i < 8; i++) {
TSCLK = 0;
_Cmd >>= 1;
if (TIO)
_Cmd |= 0x80;
TSCLK = 1;
}
return _Cmd;
}
// 写一字节
void DS1302_write_byte(BYTE _Cmd, BYTE _Dat)
{
BYTE i;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Cmd & 0x01;
TSCLK = 1;
_Cmd >>= 1;
}
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = _Dat & 0x01;
TSCLK = 1;
_Dat >>= 1;
}
}
// 时钟突发突发模式读
void clock_brust_read(BYTE *_Buf)
{
BYTE i, j = 0xbf;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = j & 0x01;
TSCLK = 1;
j >>= 1;
}
for (i = 0; i < 7; i++)
for (j = 0; j < 8; j++) {
TSCLK = 0;
_Buf[i] >>= 1;
if (TIO)
_Buf[i] |= 0x80;
TSCLK = 1;
}
}
// 时钟突发突发模式写
void clock_brust_write(const BYTE *_Buf)
{
BYTE i, j = 0xbe, k;
TEN = 0;
TSCLK = 0;
TEN = 1;
for (i = 0; i < 8; i++) {
TSCLK = 0;
TIO = j & 0x01;
TSCLK = 1;
j >>= 1;
}
for (i = 0; i < 7; i++) {
k = _Buf[i];
for (j = 0; j < 8; j++) {
TSCLK = 0;
TIO = k & 0x01;
TSCLK = 1;
k >>= 1;
}
}
}
/* 延时 */
// 低精度毫秒级延时
void delay_ms(WORD _Ms)
{
BYTE x;
while (_Ms--)
for (x = 144; x > 0; x--)
;
}
// 定时器0延时
void timer0_delay(WORD _Th)
{
TMOD = (TMOD & 0xf0) | 0x01;
TH0 = _Th >> 8;
TL0 = _Th & 0xff;
TR0 = 1;
while (TF0 == 0)
;
TF0 = 0;
}
/* LCD1802液晶 */
#define LCD_DATA P0
sbit LCD_RS = P3 ^ 5; // 数据/命令选择端
sbit LCD_WR = P3 ^ 6; // 读/写选择端
sbit LCD_EN = P3 ^ 4; // 使能端
// 读状态
BYTE LCD_read_state()
{
BYTE state;
LCD_RS = 0;
LCD_WR = 1;
LCD_EN = 1;
state = LCD_DATA;
LCD_EN = 0;
return state;
}
// 写指令
void LCD_write_cmd(BYTE _Cmd)
{
LCD_EN = 0;
LCD_EN = 1;
LCD_RS = 0;
LCD_WR = 0;
LCD_DATA = _Cmd;
LCD_EN = 0;
}
// 读数据
BYTE LCD_read_data()
{
BYTE i;
LCD_RS = 1;
LCD_WR = 1;
LCD_EN = 1;
i = LCD_DATA;
LCD_EN = 0;
return i;
}
// 写数据
void LCD_write_data(BYTE _Dat)
{
LCD_EN = 0;
LCD_EN = 1;
LCD_RS = 1;
LCD_WR = 0;
LCD_DATA = _Dat;
LCD_EN = 0;
}
// 等待写指令
void LCD_wait_cmd(BYTE _Cmd)
{
while (LCD_read_state() & 0x80)
;
LCD_write_cmd(_Cmd);
}
// 等待写数据
void LCD_wait_write_data(BYTE _Dat)
{
while (LCD_read_state() & 0x80)
;
LCD_write_data(_Dat);
}
// 等待读数据
BYTE LCD_wait_read_data()
{
while (LCD_read_state() & 0x80)
;
return LCD_read_data();
}
// 写入字符串
void LCD_write_string(const char *_Str)
{
BYTE i = 0;
while (_Str[i])
LCD_wait_write_data(_Str[i++]);
}
#define _LCD_CLS 0x01 // 显示清屏
/* 1-wire总线 */
sbit DS18B20 = P2 ^ 2;
// 1-wire初始化时序
void init_DS18B20()
{
do {
DS18B20 = 1;
_nop_();
DS18B20 = 0;
timer0_delay(65074); // delay 499.45 us
DS18B20 = 1;
timer0_delay(65500); // delay 37.95 us
} while (DS18B20);
timer0_delay(65404); // delay 141.95 us
DS18B20 = 1;
_nop_();
}
// 1-wire写时序
void write_byte_1wire(BYTE _Dat)
{
BYTE i;
for (i = 0; i < 8; i++) {
DS18B20 = 0;
_nop_();
DS18B20 = _Dat & 0x01 ? 1 : 0;
timer0_delay(65464); // delay 76.95 us
DS18B20 = 1;
_nop_();
_Dat >>= 1;
}
}
// 1-wire读时序
BYTE read_byte_1wire()
{
BYTE dat = 0, i;
for (i = 0; i < 8; i++) {
dat >>= 1;
DS18B20 = 0;
_nop_(); // 产生读时序
DS18B20 = 1;
_nop_(); // 释放总线
if (DS18B20)
dat |= 0x80;
timer0_delay(65464); // delay 76.95 us
}
return dat;
}
// ROM指令
#define _SEARCH_ROM 0xf0 // 搜索 ROM 指令
#define _READ_ROM 0x33 // 读取 ROM 指令
#define _MATH_ROM 0x55 // 匹配 ROM 指令
#define _SIKP_ROM 0xcc // 忽略 ROM 指令
#define _ALARM_ROM 0xec // 报警搜索指令
// DS18B20功能指令
#define _CONVERT_T 0x44 // 温度转换指令
#define _WRITE_SCRATCHPAD 0x4e // 写暂存器指令
#define _READ_SCRATCHPAD 0xbe // 读暂存器指令
#define _COPY_SCRATCHPAD 0x48 // 拷贝暂存器指令
#define _RECALL_E2 0xb8 // 召回 EEPROM 指令
#define _READ_POWER_SUPPLY 0xb4 // 读电源模式指令
/* 红外通讯 */
BYTE IRtime; // 红外高低电平持续时间
BYTE IRcord[2]; // 8位地址+8位数据
bit IRdone = 0; // 数据接收完成标志位
// 定时器1中断 - 每中断一次需要256个机器周期
void timer1() interrupt 3
{
IRtime++; // _MACHINE_CYCLE*256=277.76 μs
}
// 外部中断0
void int0() interrupt 0
{
static BYTE i; // 32次数据计数
static bit startflag = 0; // 开始储存脉宽标志位
static BYTE IRdata[4]; // 数据接收缓冲区
BYTE j;
if (startflag) {
if (IRtime >= 32 && IRtime < 53) { // 起始码判定 8.8ms~14ms
i = 0;
IRtime = 0;
return;
}
j = (i++) >> 3;
IRdata[j] >>= 1;
if (IRtime > 5) // 数据0=高电平560μs+低电平560μs=1120μs
IRdata[j] |= 0x80;
IRtime = 0; // 计数清零
if (i == 32) { // 如果已经存入了32次脉宽
i = 0; // 数据计数清零准备下次存入
if (IRdata[0] == ~IRdata[1] && IRdata[2] == ~IRdata[3]) {
IRdone = 1; // 32位数据接收完成
IRcord[0] = IRdata[0];
IRcord[1] = IRdata[2];
}
}
} else {
IRtime = 0;
startflag = 1;
}
}
/* 开机初始化 */
void init()
{
/* 初始化数码管 */
NIXIE_TUBE = 0x00;
DU = 1;
DU = 0;
WE = 0;
// 初始化时钟模块
DS1302_write_byte(0x8e, 0x80); // 开写保护
// 初始化LCD1802液晶
delay_ms(15);
LCD_write_cmd(0x38);
delay_ms(5);
LCD_write_cmd(0x38);
delay_ms(5);
LCD_write_cmd(0x38);
LCD_wait_cmd(0x38); // 显示模式设置
LCD_wait_cmd(0x0c); // 开显示 不显示光标 光标不闪烁
LCD_wait_cmd(_LCD_CLS); // 显示清屏
/* 红外通讯初始化 - 使用定时器1 */
TMOD = (TMOD & 0x0f) | 0x20;
TH1 = 0;
TL1 = 0;
TR1 = 1;
EA = 1; // 开总中断
ET1 = 1; // 开定时器1中断
EX0 = 1; // 开外部中断0
IT0 = 1; // 设置外部中断0边沿触发
TR1 = 1; // 启动定时器0
}
void main()
{
BYTE i, j, k;
BYTE buf[7] = {0, 2, 13, 17, 11, 4, 22};
char line1[17] = "2022/03/11 Wed:3";
char line2[17] = "21:40:00 PM 37C";
WORD temp;
bit IRflag = 0;
BYTE cursor = 0x00;
for (i = 0; i < 7; i++)
buf[i] = to_BCD(buf[i]);
init();
DS1302_write_byte(0x8e, 0x00); // 关写保护
clock_brust_write(buf);
DS1302_write_byte(0x8e, 0x80); // 开写保护
while (1) {
clock_brust_read(buf);
/* update line1 */
line1[2] = '0' + (buf[6] >> 4);
line1[3] = '0' + (buf[6] & 0x0f);
line1[5] = '0' + (buf[4] >> 4);
line1[6] = '0' + (buf[4] & 0x0f);
line1[8] = '0' + (buf[3] >> 4);
line1[9] = '0' + (buf[3] & 0x0f);
buf[5]--;
line1[11] = weekday[buf[5]][0];
line1[12] = weekday[buf[5]][1];
line1[13] = weekday[buf[5]][2];
buf[5]++;
line1[15] = '0' + buf[5];
/* update line2 */
line2[0] = '0' + (buf[2] >> 4);
line2[1] = '0' + (buf[2] & 0x0f);
line2[3] = '0' + (buf[1] >> 4);
line2[4] = '0' + (buf[1] & 0x0f);
line2[6] = '0' + (buf[0] >> 4);
line2[7] = '0' + (buf[0] & 0x0f);
line2[9] = buf[2] >= 0x12 ? 'P' : 'A';
/* update temperature */
init_DS18B20();
write_byte_1wire(_SIKP_ROM);
write_byte_1wire(_CONVERT_T);
init_DS18B20();
write_byte_1wire(_SIKP_ROM);
write_byte_1wire(_READ_SCRATCHPAD);
temp = read_byte_1wire();
temp |= read_byte_1wire() << 8;
temp >>= 4;
line2[12] = '0' + temp / 10;
line2[13] = '0' + temp % 10;
/* display */
LCD_wait_cmd(0x80);
LCD_write_string(line1);
LCD_write_cmd(0xc0);
LCD_write_string(line2);
/* IR receive */
if (IRdone) {
if (IRcord[0] == 0x00) {
if (IRflag == 0)
IRflag = 1;
else
switch (IRcord[1]) {
case 0x44: // PREV
switch (cursor) {
case 0x05:
case 0x08:
case 0x43:
case 0x46:
cursor -= 2;
break;
case 0x0f:
cursor = 0x09;
break;
case 0x40:
cursor = 0x0f;
break;
case 0x00:
cursor = 0x47;
break;
default:
cursor--;
}
break;
case 0x40: // NEXT
switch (cursor) {
case 0x03:
case 0x06:
case 0x41:
case 0x44:
cursor += 2;
break;
case 0x09:
cursor = 0x0f;
break;
case 0x0f:
cursor = 0x40;
break;
case 0x47:
cursor = 0x00;
break;
default:
cursor++;
}
break;
case 0x07: // VOL-
case 0x15: // VOL+
j = IRcord[1] == 0x15 ? 0x01 : 0x09;
switch (cursor) {
case 0x00:
case 0x01:
line1[cursor] = (line1[cursor] - '0' + j) % 10 + '0';
LCD_wait_cmd(0x80 | cursor);
LCD_wait_write_data(line1[cursor]);
break;
case 0x02:
case 0x03:
DS1302_write_byte(0x8e, 0x00); // 关写保护
i = DS1302_read_byte(0x8d);
i += j << ((0x03 - cursor) << 2);
i = (((i >> 4) % 10) << 4) | ((i & 0x0f) % 10);
DS1302_write_byte(0x8c, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
case 0x05:
case 0x06:
DS1302_write_byte(0x8e, 0x00); // 关写保护
i = DS1302_read_byte(0x89);
if (cursor == 0x05) {
if (i >> 4)
i &= 0x0f;
else {
i |= 0x10;
if (i > 0x12)
i &= 0x0f;
}
} else {
k = i & 0x0f;
i &= 0xf0;
if (i && j == 0x09)
j = 0x02;
k = (k + j) % (i ? 3 : 10);
i |= k;
}
DS1302_write_byte(0x88, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
case 0x08:
case 0x09:
i = buf[3]; // 日
buf[4] = (buf[4] >> 4) * 10 + (buf[4] & 0x0f);
buf[3] = monthday[buf[4] - 1];
if (buf[4] == 2 && is_leap((WORD)(line1[0] - '0') * 1000 + (WORD)(line1[1] - '0') * 100 + (WORD)buf[6]))
buf[3]++;
if (cursor == 0x08) {
buf[0] = buf[3] / 10; // mod
if ((i & 0x0f) <= buf[3] % 10)
buf[0]++;
if (j == 0x09)
j = buf[0] - 1;
k = i >> 4;
i &= 0x0f;
k = (k + j) % buf[0];
i |= k << 4;
} else {
buf[0] = 10; // mod;
if ((i >> 4) == buf[3] / 10)
buf[0] = buf[3] % 10;
if (buf[0]) {
if (j == 0x09)
j = buf[0] - 1;
k = i & 0x0f;
i &= 0xf0;
k = (k + j) % buf[0];
i |= k;
}
}
DS1302_write_byte(0x8e, 0x00); // 关写保护
DS1302_write_byte(0x86, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
case 0x0f:
i = buf[5];
if (j == 0x09)
j = 0x06;
i = (i - 1 + j) % 7 + 1;
DS1302_write_byte(0x8e, 0x00); // 关写保护
DS1302_write_byte(0x8a, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
case 0x40:
case 0x41:
i = buf[2];
if (cursor == 0x40) {
buf[0] = 2; // mod
if ((i & 0x0f) < 4)
buf[0]++;
if (j == 0x09)
j = buf[0] - 1;
k = i >> 4;
i &= 0x0f;
k = (k + j) % buf[0];
i |= k << 4;
} else {
buf[0] = i >> 4 < 2 ? 10 : 4; // mod
if (j == 0x09)
j = buf[0] - 1;
k = i & 0x0f;
i &= 0xf0;
k = (k + j) % buf[0];
i |= k;
}
DS1302_write_byte(0x8e, 0x00); // 关写保护
DS1302_write_byte(0x84, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
case 0x43:
case 0x44:
case 0x46:
case 0x47:
i = buf[cursor <= 0x44 ? 1 : 0];
if (cursor == 0x43 || cursor == 0x46) {
if (j == 0x09)
j = 0x05;
k = i >> 4;
i &= 0x0f;
k = (k + j) % 0x06;
i |= k << 4;
} else {
k = i & 0x0f;
i &= 0xf0;
k = (k + j) % 10;
i |= k;
}
DS1302_write_byte(0x8e, 0x00); // 关写保护
DS1302_write_byte(cursor <= 0x44 ? 0x82 : 0x80, i);
DS1302_write_byte(0x8e, 0x80); // 开写保护
break;
}
break;
case 0x09: // EQ
IRflag = 0;
LCD_wait_cmd(0x0c);
break;
}
}
IRdone = 0;
}
/* IR display */
if (IRflag) {
LCD_wait_cmd(0x80 | cursor);
LCD_wait_cmd(0x0e);
}
}
}