基于STC12C5A的MINI3216多功能点阵时钟
硬件详解
PCB
硬件原理图

主控模块

max7219模块

ds1302模块

按键模块

源码详解
代码框架

main.c
系统主函数模块,包含各种变量的定义及初始化,系统模块初始化和系统主循环.
系统主循环采用 switch case状态机 模式.状态机默认为主页模式, 在主循环中不断检测按键状态, 在状态机中根据按键状态改变状态机的模式.状态机主要有以下几种模式:
状态机代码 | 含义 |
---|---|
SYS_PAGE_MAIN | 主界面 |
SYS_PAGE_MENU | 菜单界面 |
SYS_PAGE_SET_CLOCK | 时间设置界面 |
SYS_PAGE_SET_ALARM | 闹钟设置界面 |
SYS_PAGE_SET_DATE | 日期设置界面 |
SYS_PAGE_GET_TEMP | 查看温度湿度界面 |
SYS_PAGE_SET_SYSTEM | 设置界面 |
SYS_PAGE_PLAY_SNAKE | 贪吃蛇游戏界面 |
SYS_PAGE_PLY_TETRIS | 俄罗斯方块界面 |
SYS_PAGE_GET_SINFO | 系统信息界面 |
SYS_PAGE_GET_NONLI | 查看农历 |
SYS_PAGE_SET_BRTDY | 生日设置 |
SYS_PAGE_POWER | 关闭显示模式 |
SYS_PAGE_TEST_LED | 屏幕测试模式 |
#include "common.h"
#include "drv_led.h"
#include "game_snake.h"
#include "game_tetris.h"
#include "img_code.h"
#include "drv_1302.h"
#include "drv_irm.h"
#include "drv_dht11.h"
#include "china_nonli.h"
#include "drv_cfgsave.h"
#define SYS_PAGE_MAIN 0xa0//主界面
#define SYS_PAGE_MENU 0xa1//菜单界面
#define SYS_PAGE_SET_CLOCK 0xa2//时间设置界面
#define SYS_PAGE_SET_ALARM 0xa3//闹钟设置界面
#define SYS_PAGE_SET_DATE 0xa4//日期设置界面
#define SYS_PAGE_GET_TEMP 0xa5//查看温度湿度界面
#define SYS_PAGE_PLAY_SNAKE 0xa6//游戏界面
#define SYS_PAGE_SET_SYSTEM 0xa7//设置界面
#define SYS_PAGE_POWER 0xa8
#define SYS_PAGE_TEST_LED 0xa9
#define SYS_PAGE_PLY_TETRIS 0xb0//俄罗斯方块界面
#define SYS_PAGE_GET_SINFO 0xb1//系统信息界面
#define SYS_PAGE_GET_NONLI 0xb2//查看农历
#define SYS_PAGE_SET_BRTDY 0xb3//设置生日
#define SET_OPER_ADD 1//加操作
#define SET_OPER_SUB 2//减操作
//#define MAX_MENU_ENTRY 11
#define MAX_MENU_ENTRY_ID 9
uchar code MENU_ENTRY[/*MAX_MENU_ENTRY*/] =
{
CHN_CODE_CLOCK,// 0
CHN_CODE_ALARM,// 1
CHN_CODE_DATE,// 2
CHN_CODE_NONLI,// 3
CHN_CODE_BIRTHDAY,// 4
CHN_CODE_TEMP,// 5
CHN_CODE_SETTING,// 6
CHN_CODE_SYSINFO,// 7
CHN_CODE_SNAKE,// 8
CHN_CODE_TETRIS,// 9
CHN_CODE_CNHS_BLANK,// 10
};
/*****************************************************************************
函 数 名 : _menu_data_deal_
功能描述 : 根据给定的上下限值来对数据加减,自动处理越界
输入参数 : dat 待处理的数据的指针
op 对数据的操作方式:+/-
max 待处理的数据的最大值
min 待处理的数据的最小值
输出参数 : dat 处理后的数据的指针
返 回 值 : 无
*****************************************************************************/
void _menu_data_deal_(uchar* dat, uchar op, uchar max, uchar min)
{
char data_t = 0;
data_t = (char)(*dat);
if(op == SET_OPER_ADD)//加
{
data_t++;
if(data_t > max)
{
data_t = min;
}
}
else if(op == SET_OPER_SUB)///减
{
data_t--;
if(data_t < min)
{
data_t = max;
}
}
*dat = (uchar)data_t;
}
/*****************************************************************************
函 数 名 : show_entry_memu
功能描述 : 显示主菜单的函数
输入参数 : muety 主菜单图标集
mnmax 主菜单中的的图标数
etyid 当前选中的图标
输出参数 : 无
返 回 值 : 当前选中的图标
*****************************************************************************/
uchar show_entry_memu(uchar* muety, uchar mnmax, uchar etyid)
{
etyid = ((etyid > mnmax) ¡ mnmax : ((etyid < 0) ¡ 0 : etyid));
if((etyid % 2) == 0)
{//偶数则被选中项在前
led_putc_16x16(0, muety[etyid], 0);//反显,选中
led_putc_16x16(16, muety[etyid + 1], 1);//正显,非选中
}
else
{//奇数则被选中项在后
led_putc_16x16(0, muety[etyid - 1], 1);//正显,非选中
led_putc_16x16(16, muety[etyid], 0);//反显,选中
}
return etyid;
}
typedef enum system_cfg_id_e
{
SYSCFG_ID_LEDPOWER = 0,
SYSCFG_ID_LEDTEST,// 1
SYSCFG_ID_LEDLIGHT,// 2
SYSCFG_ID_MAINMOD,// 3
SYSCFG_ID_TIMEMOD,// 4
SYSCFG_ID_NOWTIME,// 5
SYSCFG_ID_SOUNDVAL,// 6
SYSCFG_ID_WELCOME,// 7
SYSCFG_ID_SAVE,// 8
MAX_SYSCFG_ID = SYSCFG_ID_SAVE,// 6
} system_cfg_id_t;
typedef struct system_cfg_s
{
uchar led_power; //屏幕开关0-1
uchar led_test; //屏幕测试0-1
uchar led_light; //CONFIG_DEFAULT_LED_LIGHT;//屏幕亮度0-10
uchar mainpg_mode; //CONFIG_DEFAULT_MAIN_PG;//主页显示模式0-2
uchar time_mode; //CONFIG_DEFAULT_TIME_MODE;//时间模式,0-1
uchar now_time;//整点报时开关
uchar sound_value;
uchar welcome;
} system_cfg_t;
#define SIZEOF_SYSTEM_CFG_T 8//sizeof(system_cfg_t)
//static system_cfg_t system_config = {0};
/*****************************************************************************
函 数 名 : system_config_init
功能描述 : 初始化系统配置
输入参数 : 无
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
void system_config_init(system_cfg_t* cfg)
{
if(cfg != NULL)
{
cfg->led_power = 1;
cfg->led_test= 0;
cfg->led_light = CONFIG_DEFAULT_LED_LIGHT;
cfg->mainpg_mode = CONFIG_DEFAULT_MAIN_PG;
cfg->time_mode = CONFIG_DEFAULT_TIME_MODE;
cfg->now_time = 0;
cfg->sound_value = 1;
cfg->welcome = 1;
}
}
/*****************************************************************************
函 数 名 : system_config_set
功能描述 : 把系统配置保存到内部eeprom中
输入参数 : cfg 输入的系统配置
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
void system_config_set(system_cfg_t* cfg)
{
if(cfg != NULL)
{
//_memcpy_((uchar*)&system_config, (uchar*)cfg, sizeof(system_cfg_t));
cfgsave_write((uchar*)cfg, /*sizeof(system_cfg_t)*/SIZEOF_SYSTEM_CFG_T);
}
}
/*****************************************************************************
函 数 名 : system_config_get
功能描述 : 从内部eeprom中读取系统配置
输入参数 : cfg 输入的系统配置
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
void system_config_get(system_cfg_t* cfg)
{
if(cfg != NULL)
{
//_memcpy_((uchar*)cfg, (uchar*)&system_config, sizeof(system_cfg_t));
cfgsave_read((uchar*)cfg, /*sizeof(system_cfg_t)*/SIZEOF_SYSTEM_CFG_T);
}
}
/*****************************************************************************
函 数 名 : system_config_apply
功能描述 : 把软件中的系统配置同步到硬件中
输入参数 : cfg 输入的系统配置
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
void system_config_apply(system_cfg_t* cfg)
{
if(cfg != NULL)
{
led_set_light(cfg->led_light);//设置亮度
sound_value(cfg->sound_value);//设置静音
}
}
/*****************************************************************************
函 数 名 : system_config_get_byid
功能描述 : 根据配置ID获取对应配置
输入参数 : cfg_id 输入的系统配置ID
输出参数 : 无
返 回 值 : 系统配置参数
*****************************************************************************/
#if 0
uchar system_config_get_byid(uchar cfg_id)
{
uchar config = 0;
switch(cfg_id)
{
case SYSCFG_ID_LEDPOWER:
config = system_config.led_power;
break;
case SYSCFG_ID_LEDTEST:
config = system_config.led_test;
break;
case SYSCFG_ID_LEDLIGHT:
config = system_config.led_light;
break;
case SYSCFG_ID_MAINMOD:
config = system_config.mainpg_mode;
break;
case SYSCFG_ID_TIMEMOD:
config = system_config.time_mode;
break;
case SYSCFG_ID_NOWTIME:
config = system_config.now_time;
break;
case SYSCFG_ID_SOUNDVAL:
config = system_config.sound_value;
break;
default:
break;
}
return config;
}
#endif
/*****************************************************************************
函 数 名 : show_system_config
功能描述 : 显示系统配置菜单
输入参数 : cfg_id 当前选择的菜单ID
syscfg 系统配置
op 数组处理方式+/-
save 是否保存配置
输出参数 : syscfg 系统配置
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_system_config(uchar cfg_id, system_cfg_t* syscfg, uchar op, uchar* save)
{
uchar* syscfg_name_str = NULL;
uchar syscfg_num_str[7] = {0};
uchar config = 0;
cfg_id = ((cfg_id > MAX_SYSCFG_ID) ¡ MAX_SYSCFG_ID : ((cfg_id < 0) ¡ 0 : cfg_id));
//*save = FALSE;
switch(cfg_id)
{
case SYSCFG_ID_LEDPOWER:
_menu_data_deal_(&(syscfg->led_power), op, 1, 0);
syscfg_name_str = "POWER ";
config = syscfg->led_power;
break;
case SYSCFG_ID_LEDTEST:
_menu_data_deal_(&(syscfg->led_test), op, 1, 0);
syscfg_name_str = "TEST ";
config = syscfg->led_test;
break;
case SYSCFG_ID_LEDLIGHT:
_menu_data_deal_(&(syscfg->led_light), op, 10, 0);//0-10级亮度
syscfg_name_str = "LIGHT ";
config = syscfg->led_light;
break;
case SYSCFG_ID_MAINMOD:
_menu_data_deal_(&(syscfg->mainpg_mode), op, 3, 1);//1-3三种模式
syscfg_name_str = "MODE ";
config = syscfg->mainpg_mode;
break;
case SYSCFG_ID_TIMEMOD:
_menu_data_deal_(&(syscfg->time_mode), op, 1, 0);//12/24小时制
syscfg_name_str = "24HOUR";
config = syscfg->time_mode;
break;
case SYSCFG_ID_NOWTIME:
_menu_data_deal_(&(syscfg->now_time), op, 1, 0);//整点报时
syscfg_name_str = "NOW-T ";
config = syscfg->now_time;
break;
case SYSCFG_ID_SOUNDVAL:
_menu_data_deal_(&(syscfg->sound_value), op, 1, 0);//静音开关
syscfg_name_str = "SOUND ";
config = syscfg->sound_value;
break;
case SYSCFG_ID_WELCOME:
_menu_data_deal_(&(syscfg->welcome), op, 1, 0);//欢迎界面
syscfg_name_str = "WELCOM";
config = syscfg->welcome;
break;
case SYSCFG_ID_SAVE:
_menu_data_deal_(save, op, 1, 0);
syscfg_name_str = "SAVE ";
config = *save;
break;
default:
break;
}
_memcpy_(syscfg_num_str, "Set: ", 6);
if((SYSCFG_ID_SAVE == cfg_id) ||
(SYSCFG_ID_LEDPOWER == cfg_id) ||
(SYSCFG_ID_LEDTEST == cfg_id) ||
(SYSCFG_ID_TIMEMOD == cfg_id) ||
(SYSCFG_ID_NOWTIME == cfg_id) ||
(SYSCFG_ID_SOUNDVAL == cfg_id) ||
(SYSCFG_ID_WELCOME == cfg_id))
{
syscfg_num_str[5] = ((config == 1) ¡ 'Y':'N');
}
/*else if(SYSCFG_ID_TIMEMOD == cfg_id)
{
syscfg_num_str[4] = ((config == 1) ¡ '2' : '1');
syscfg_num_str[5] = ((config == 1) ¡ '4' : '2');
}*/
else
{
syscfg_num_str[4] = (config / 10) + '0';
syscfg_num_str[5] = (config % 10) + '0';
}
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, syscfg_name_str, 1, 0);
led_puts_5x7_undline(0, 1, syscfg_num_str, 1, 0);
return cfg_id;
}
typedef enum setdate_id_e
{
SETDATE_ID_YEAR = 0,
SETDATE_ID_WEEK,// 1
SETDATE_ID_MONTH,// 2
SETDATE_ID_DAY,// 3
SETDATE_ID_SAVE,// 4
MAX_SETDATE_ID = SETDATE_ID_SAVE,//4,年周月日
} setdate_id_t;
uchar code DATE_WEEK_STR[7][2] =
{
"Mo",//Monday,一
"Tu",//Tuesday,二
"We",//Wednesday,三
"Th",//Thurday,四
"Fr",//Friday,五
"Sa",//Saturday,六
"Su",//Sunday,日
};
/*****************************************************************************
函 数 名 : show_date_config
功能描述 : 显示系统配置菜单
输入参数 : date_id 当前选择的菜单ID
setdate 日期配置
op 数组处理方式+/-
save 是否保存
输出参数 : setdate 日期配置
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_date_config(uchar date_id, rtc_time_t* setdate, uchar op, uchar* save)
{
uchar* date_name_str = NULL;
uchar date_num_str[7] = {0};
uchar date_t = 0;
date_id = ((date_id > MAX_SETDATE_ID) ¡ MAX_SETDATE_ID : ((date_id < 0) ¡ 0 : date_id));
//*save = FALSE;
switch(date_id)
{
case SETDATE_ID_YEAR:
_menu_data_deal_(&(setdate->year), op, 99, 0);
date_name_str = "YEAR ";
date_t = setdate->year;
break;
case SETDATE_ID_WEEK:
_menu_data_deal_(&(setdate->week), op, 7, 1);
date_name_str = "WEEK ";
date_t = setdate->week;
break;
case SETDATE_ID_MONTH:
_menu_data_deal_(&(setdate->month), op, 12, 1);
date_name_str = "MONTH ";
date_t = setdate->month;
break;
case SETDATE_ID_DAY:
_menu_data_deal_(&(setdate->day), op, 31, 1);
date_name_str = "DAY ";
date_t = setdate->day;
break;
case SETDATE_ID_SAVE:
_menu_data_deal_(save, op, 1, 0);
date_name_str = "SAVE ";
date_t = *save;
break;
default:
break;
}
_memcpy_(date_num_str, "Set: ", 6);
if(SETDATE_ID_SAVE == date_id)
{
date_num_str[5] = ((date_t == 1)¡ 'Y':'N');
}
else if(SETDATE_ID_WEEK == date_id)
{
date_num_str[4] = DATE_WEEK_STR[date_t - 1][0];
date_num_str[5] = DATE_WEEK_STR[date_t - 1][1];
}
else
{
date_num_str[4] = (date_t / 10) + '0';
date_num_str[5] = (date_t % 10) + '0';
}
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, date_name_str, 1, 0);
led_puts_5x7_undline(0, 1, date_num_str, 1, 0);
return date_id;
}
/*****************************************************************************
函 数 名 : get_date_string
功能描述 : 获取当前日期字符串
输入参数 : date 当前日期
输出参数 : 无
返 回 值 : 当前日期字符串
*****************************************************************************/
char* get_date_string(rtc_time_t* date)
{
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
//| 2 | 0 | 1 | 8 | - | 0 | 3 | - | 0 | 9 | | F | r | \0 |
static char date_str[14] = {"2018-03-09 Fr"};//日期字符串
//static char date_str[14] = {" 2018-03-09 Fr "};//日期字符串
if(date == NULL)
{
return NULL;
}
date_str[2] = (date->year / 10) + '0';
date_str[3] = (date->year % 10) + '0';
date_str[5] = (date->month / 10) + '0';
date_str[6] = (date->month % 10) + '0';
date_str[8] = (date->day / 10) + '0';
date_str[9] = (date->day % 10) + '0';
date_str[11] = DATE_WEEK_STR[date->week - 1][0];
date_str[12] = DATE_WEEK_STR[date->week - 1][1];
return date_str;
}
typedef enum getnonli_id_e
{
GETNONLI_ID_INTCAL,// 0
GETNONLI_ID_MONTH,// 1
GETNONLI_ID_DAY,// 2
MAX_GETNONLI_ID = GETNONLI_ID_DAY,//2,闰月,月,日
} getnonli_id_t;
/*****************************************************************************
函 数 名 : show_nonli_config
功能描述 : 显示当前农历日期菜单
输入参数 : date_id 当前选择的菜单ID
time_t 当前RTC时间
输出参数 : 无
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_nonli_config(uchar date_id, rtc_time_t* time_t)
{
uchar* date_name_str = NULL;
uchar date_num_str[7] = {0};
uchar date_t = 0;
china_nonli_t nonli;
date_id = ((date_id > GETNONLI_ID_DAY) ¡ GETNONLI_ID_DAY : ((date_id < 0) ¡ 0 : date_id));
if(time_t == NULL)
{
return NULL;
}
rtc_read_time(time_t);
china_nonli_get(time_t, &nonli);
switch(date_id)
{
case GETNONLI_ID_INTCAL:
date_name_str = "LEAP ";
date_t = nonli.intcal;//闰月
break;
case GETNONLI_ID_MONTH:
date_name_str = "MONTH ";
date_t = nonli.month;//月
break;
case GETNONLI_ID_DAY:
date_name_str = "DAY ";
date_t = nonli.day;//日
break;
default:
break;
}
_memcpy_(date_num_str, "Get: ", 6);
if(GETNONLI_ID_INTCAL == date_id)
{
date_num_str[5] = ((date_t != 0)¡ 'Y':'N');
}
else
{
date_num_str[4] = (date_t / 10) + '0';
date_num_str[5] = (date_t % 10) + '0';
}
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, date_name_str, 1, 0);
led_puts_5x7_undline(0, 1, date_num_str, 1, 0);
return date_id;
}
uchar code CHN_CODE_NONLI_YUE[12] =
{
/*00*/CHN_CODE_CNHS_ZHENG, //正月
/*01*/CHN_CODE_CNHS_ER21, //二月
/*02*/CHN_CODE_CNHS_SAN, //三月
/*03*/CHN_CODE_CNHS_SI, //四月
/*04*/CHN_CODE_CNHS_WU, //五月
/*05*/CHN_CODE_CNHS_LIU, //六月
/*06*/CHN_CODE_CNHS_QI, //七月
/*07*/CHN_CODE_CNHS_BA, //八月
/*08*/CHN_CODE_CNHS_JIU, //九月
/*09*/CHN_CODE_CNHS_SHI20, //十月
/*10*/CHN_CODE_CNHS_DONG, //冬月
/*11*/CHN_CODE_CNHS_LA //腊月
};
uchar code CHN_CODE_NONLI_RI[30*2] =
{
/*00*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_YI11, //初一
/*02*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_ER21, //初二
/*04*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_SAN, //初三
/*06*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_SI, //初四
/*08*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_WU, //初五
/*10*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_LIU, //初六
/*12*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_QI, //初七
/*14*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_BA, //初八
/*16*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_JIU, //初九
/*18*/CHN_CODE_CNHS_CHU,CHN_CODE_CNHS_SHI20, //初十
/*20*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_YI11,//十一
/*22*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_ER21,//十二
/*24*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_SAN, //十三
/*26*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_SI, //十四
/*28*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_WU, //十五
/*30*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_LIU, //十六
/*32*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_QI, //十七
/*34*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_BA, //十八
/*36*/CHN_CODE_CNHS_SHI20,CHN_CODE_CNHS_JIU, //十九
///*38*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_BLANK,//廿
/*38*/CHN_CODE_CNHS_ER21,CHN_CODE_CNHS_SHI20,//二十
/*40*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_YI11, //廿一
/*42*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_ER21, //廿二
/*44*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_SAN, //廿三
/*46*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_SI, //廿四
/*48*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_WU, //廿五
/*50*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_LIU, //廿六
/*52*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_QI, //廿七
/*54*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_BA, //廿八
/*56*/CHN_CODE_CNHS_NIAN,CHN_CODE_CNHS_JIU, //廿九
/*58*/CHN_CODE_CNHS_SAN,CHN_CODE_CNHS_SHI20 //三十
};
uchar code CHN_CODE_NONLI_RUN[2] =
{
/*00*/CHN_CODE_CNHS_BLANK, //非闰月
///*00*/CHN_CODE_CLOCK, //非闰月
/*01*/CHN_CODE_CNHS_RUN //闰月
};
#define NONLI_STRING_LEN 5
/*****************************************************************************
函 数 名 : get_nonli_string
功能描述 : 获取当前日期的农历字符串
输入参数 : date 当前日期
输出参数 : 无
返 回 值 : 当前日期的农历字符串
*****************************************************************************/
uchar* get_nonli_string(rtc_time_t* date_t)
{
china_nonli_t nonli = {0};
static uchar nonli_str[NONLI_STRING_LEN] =
{
/*00*/CHN_CODE_CNHS_RUN,
/*01*/CHN_CODE_CNHS_ER21,
/*02*/CHN_CODE_CNHS_YUE11,
/*03*/CHN_CODE_CNHS_NIAN,
/*04*/CHN_CODE_CNHS_SAN,
};//日期字符串
if(china_nonli_get(date_t, &nonli) != RTN_OK)
{
return NULL;
}
nonli_str[0] = CHN_CODE_NONLI_RUN[(nonli.intcal != 0) ¡ 1 : 0];
nonli_str[1] = CHN_CODE_NONLI_YUE[nonli.month-1];
//nonli_str[2] = CHN_CODE_CNHS_YUE11;
nonli_str[3] = CHN_CODE_NONLI_RI[(nonli.day-1)*2];
nonli_str[4] = CHN_CODE_NONLI_RI[(nonli.day-1)*2 + 1];
return nonli_str;
}
typedef enum settime_id_e
{
SETTIME_ID_HOUR = 0,// 0
SETTIME_ID_MINUTE,// 1
SETTIME_ID_SECOND,// 2
SETTIME_ID_SAVE,// 3
MAX_SETTIME_ID = SETTIME_ID_SAVE,//3,时分秒
} settime_id_t;
/*****************************************************************************
函 数 名 : show_time_config
功能描述 : 显示时间配置菜单
输入参数 : time_id 当前选择的菜单ID
settime 时间配置
op 数组处理方式+/-
save 是否保存
输出参数 : settime 时间配置
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_time_config(uchar time_id, rtc_time_t* settime, uchar op, uchar* save)
{
uchar* time_name_str = NULL;
uchar time_num_str[7] = {0};
uchar time = 0;
time_id = ((time_id > MAX_SETTIME_ID) ¡ MAX_SETTIME_ID : ((time_id < 0) ¡ 0 : time_id));
//*save = FALSE;
switch(time_id)
{
case SETTIME_ID_HOUR:
_menu_data_deal_(&(settime->hour), op, 23, 0);
time_name_str = "HOUR ";
time = settime->hour;
break;
case SETTIME_ID_MINUTE:
_menu_data_deal_(&(settime->minute), op, 59, 0);
time_name_str = "MINUTE";
time = (char)settime->minute;
break;
case SETTIME_ID_SECOND:
_menu_data_deal_(&(settime->second), op, 59, 0);
time_name_str = "SECOND";
time = settime->second;
break;
case SETTIME_ID_SAVE:
_menu_data_deal_(save, op, 1, 0);
time_name_str = "SAVE ";
time = *save;
break;
default:
break;
}
_memcpy_(time_num_str, "Set: ", 6);
if(time_id == SETTIME_ID_SAVE)
{
time_num_str[5] = ((time == 1) ¡ 'Y':'N');
}
else
{
time_num_str[4] = (time / 10) + '0';
time_num_str[5] = (time % 10) + '0';
}
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, time_name_str, 1, 0);
led_puts_5x7_undline(0, 1, time_num_str, 1, 0);
return time_id;
}
typedef enum gettemp_id_e
{
GET_TEMP_ID = 0,// 0
GET_HUMI_ID,// 1
MAX_GETTEMP_ID = GET_HUMI_ID,
} gettemp_id_t;
/*****************************************************************************
函 数 名 : show_temp_config
功能描述 : 显示环境温湿度菜单
输入参数 : temp_id 当前选择的菜单ID
dht_temp 当前温度
dht_humi 当前湿度
save 是否保存
输出参数 : dht_temp 当前温度
dht_humi 当前湿度
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_temp_config(uchar temp_id, uchar* dht_temp, uchar* dht_humi)
{
uchar _temp = 0, _humi = 0;
uchar* dht_name_str = NULL;
uchar dht_temp_str[7] = {0};
uchar tempdate = 0;
if(dht11_get_value(&_temp, &_humi) == 0)
{
*dht_temp = _temp;
*dht_humi = _humi;
}
*dht_temp = ((*dht_temp > 99) ¡ 99 : *dht_temp);
*dht_humi = ((*dht_humi > 99) ¡ 99 : *dht_humi);
if(temp_id == GET_TEMP_ID)
{
dht_name_str = "TEMP C";//温度(C)
tempdate = *dht_temp;
}
else
{
dht_name_str = "HUMI %";//湿度(%)
tempdate = *dht_humi;
}
_memcpy_(dht_temp_str, "Get: ", 6);
dht_temp_str[4] = (tempdate / 10) + '0';
dht_temp_str[5] = (tempdate % 10) + '0';
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, dht_name_str, 1, 0);
led_puts_5x7_undline(0, 1, dht_temp_str, 1, 0);
return temp_id;
}
/*****************************************************************************
函 数 名 : get_temp_string
功能描述 : 获取环境温湿度字符串
输入参数 : dht_temp 当前温度
dht_humi 当前湿度
输出参数 : 无
返 回 值 : 环境温湿度字符串
*****************************************************************************/
char* get_temp_string(uchar* dht_temp, uchar* dht_humi)
{
//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
//| T | : | 2 | 5 | C | | H | : | 6 | 5 | % | \0 |
uchar _temp = 0, _humi = 0;
static char temp_str[12] = {"T:25C H:65%"};//温湿度字符串
if((dht_temp == NULL) || (dht_humi == NULL))
{
return NULL;
}
if(dht11_get_value(&_temp, &_humi) == 0)
{
*dht_temp = _temp;
*dht_humi = _humi;
}
*dht_temp = ((*dht_temp > 99) ¡ 99 : *dht_temp);
*dht_humi = ((*dht_humi > 99) ¡ 99 : *dht_humi);
temp_str[2] = ((*dht_temp) / 10) + '0';
temp_str[3] = ((*dht_temp) % 10) + '0';
temp_str[8] = ((*dht_humi) / 10) + '0';
temp_str[9] = ((*dht_humi) % 10) + '0';
return temp_str;
}
typedef enum getsinfo_id_e
{
GET_SYS_SWVER_ID = 0,// 0
GET_SYS_HWVER_ID,// 1
GET_SYS_VERTIME_ID,// 2
GET_SYS_VERCUST_ID,// 3
MAX_GETSINFO_ID = GET_SYS_VERCUST_ID,
} getsinfo_id_t;
/*****************************************************************************
函 数 名 : show_sinfo_config
功能描述 : 显示环境温湿度菜单
输入参数 : info_id 当前选择的菜单ID
输出参数 : dht_temp 当前温度
dht_humi 当前湿度
返 回 值 : 当前选择的菜单ID
*****************************************************************************/
uchar show_sinfo_config(uchar info_id)
{
uchar* info_name_str = NULL;
uchar* info_temp_str = NULL;
switch(info_id)
{
case GET_SYS_SWVER_ID:
info_name_str = "SW-VER";//软件版本
info_temp_str = SYSTEM_SOFTWARE_VERSION;
break;
case GET_SYS_HWVER_ID:
info_name_str = "HW-VER";//硬件版本
info_temp_str = SYSTEM_HARDWARE_VERSION;
break;
case GET_SYS_VERTIME_ID:
info_name_str = "V-DATE";//发布时间
info_temp_str = SYSTEM_RELVERSION_TIME;
break;
case GET_SYS_VERCUST_ID:
info_name_str = "V-CUST";//客户ID
info_temp_str = SYSTEM_RELVERSION_CUST;
break;
default:
break;
}
led_clear(0);//清屏
led_puts_5x7_undline(0, 0, info_name_str, 1, 0);
led_puts_5x7_undline(0, 1, info_temp_str, 1, 0);
return info_id;
}
void main(void)
{
uchar keycode = 0;//按键和红外的键值
char setting_id = 0;//主菜单中被选中的项目
uchar set_id = 0;//当前选中的设置项
uchar set_op = 0;//设置操作:加或减
uchar set_save = 0;//是否保存配置,1(Y)保存,0(N)不保存
rtc_time_t time_t = {0};//用于保存获取到的当前时间
rtc_time_t stime_t = {0};//用于保存获取到的当前时间
rtc_time_t sdate_t = {0};//用于保存获取到的当前时间
rtc_time_t alarm_t = {18, 6, 2, 24, 9, 0, 0};//用于保存闹钟时间和生日
//char date_string[14] = {"2018-03-09 Fr"};//日期字符串
system_cfg_t system_config_tmp = {0};//临时系统配置
uchar dht_temp = 0, dht_humi = 0;//温湿度数据
uchar main_page_temputer = 0;//用于模式2中的温度显示
uchar system_page = SYS_PAGE_MAIN;//用于指示当前系统界面
uchar snake_life = 0;
uchar snake_dir = 0;
uchar tetris_life = 0;
//uchar tetris_dir = 0;
led_init();//点阵屏初始化
led_clear(0);//清屏
irm_init();//红外初始化
alarm_init(&alarm_t);//闹钟初始化
system_config_init(&system_config_tmp);//初始化当前配置(默认值)
system_config_get(&system_config_tmp);//从EEPROM中获取保存的配置
system_config_apply(&system_config_tmp);//应用当前配置(配置到硬件中)
//显示欢迎界面
if(system_config_tmp.welcome)
{
led_scroll_puts_16x16(WELLCOME_LUNYU, WELLCOME_LUNYU_LEN, 0, 1);
led_scroll_puts_16x16(WELLCOME_STRING, WELLCOME_STRING_LEN, 0, 1);
}
while(1)
{
keycode = key_get_code();
if(keycode != 0)
{
//总共需延时300ms但是为了不让按键音太长,分两次
//sound_beep(1);//按键音
//delay_xms(50);
//sound_beep(0);
sound_open(50);
delay_xms(250);
}
switch(system_page)
{
case SYS_PAGE_MENU://系统主菜单(图形界面)
setting_id = show_entry_memu(MENU_ENTRY, MAX_MENU_ENTRY_ID, (uchar)setting_id);
if(keycode != 0)
{
if(keycode == KEY_CODE_SUB)//向左翻页
{
setting_id--;//向左翻到第一页,继续翻会回到最后一页
if(setting_id < 0)
{
setting_id = MAX_MENU_ENTRY_ID;
}
}
else if(keycode == KEY_CODE_ADD)//向右翻页
{
setting_id++;//向右翻到最后一下,继续翻会回到第一页
if(setting_id > MAX_MENU_ENTRY_ID)
{
setting_id = 0;
}
}
else if((keycode == KEY_CODE_ENTER) ||
(keycode == KEY_CODE_OK))
{//按Enter(DOWN)键或OK键进入子菜单
set_id = 0;
set_op = 0;
set_save = 0;
switch(MENU_ENTRY[setting_id])
{
case CHN_CODE_CLOCK:
system_page = SYS_PAGE_SET_CLOCK;
break;
case CHN_CODE_ALARM:
system_page = SYS_PAGE_SET_ALARM;
break;
case CHN_CODE_DATE:
system_page = SYS_PAGE_SET_DATE;
break;
case CHN_CODE_BIRTHDAY:
set_id = SETDATE_ID_MONTH;//生日只需要设置月和日
system_page = SYS_PAGE_SET_BRTDY;
break;
case CHN_CODE_NONLI:
system_page = SYS_PAGE_GET_NONLI;
break;
case CHN_CODE_TEMP:
system_page = SYS_PAGE_GET_TEMP;
break;
case CHN_CODE_SNAKE:
//只有使用红外键盘的时候才能玩游戏
//只有红外键盘上有OK键
if(keycode == KEY_CODE_OK)
{
snake_life = 0;
system_page = SYS_PAGE_PLAY_SNAKE;
}
break;
case CHN_CODE_SETTING:
system_page = SYS_PAGE_SET_SYSTEM;
break;
case CHN_CODE_TETRIS:
tetris_life = 0;
system_page = SYS_PAGE_PLY_TETRIS;
break;
case CHN_CODE_SYSINFO:
system_page = SYS_PAGE_GET_SINFO;
break;
default:
//system_page = SYS_PAGE_MAIN;
break;
}
}
else if((keycode == KEY_CODE_EXIT)/*||
(keycode == KEY_CODE_ASTRSK) ||
(keycode == KEY_CODE_HSHTG)*/)
{
system_page = SYS_PAGE_MAIN;
}
}
break;
case SYS_PAGE_SET_SYSTEM://系统设置菜单(文字界面)
set_id = show_system_config(set_id, &system_config_tmp, set_op, &set_save);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_SYSCFG_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_SUB)
{
set_op = SET_OPER_SUB;
}
else if(keycode == KEY_CODE_ADD)
{
set_op = SET_OPER_ADD;
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
if(set_save == TRUE)
{//保存系统配置
system_config_set(&system_config_tmp);//保存配置信息
system_config_apply(&system_config_tmp);
// 电源和测试模式不能同时设置
if(system_config_tmp.led_power == 0)
{
system_page = SYS_PAGE_POWER;
}
else
{//测试模式必须在电源打开的情况下开启
if(system_config_tmp.led_test == 1)
{
system_page = SYS_PAGE_TEST_LED;
}
}
}
else
{//未保存的时候,重新获取当前配置
system_config_get(&system_config_tmp);
}
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_GET_SINFO://系统信息查看页面(文字界面)
set_id = show_sinfo_config(set_id);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环查看温度和湿度,按Enter(Down)键查看下一项
set_id++;
if(set_id > MAX_GETSINFO_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_SET_CLOCK://时间设置页面(文字界面)
set_id = show_time_config(set_id, &stime_t, set_op, &set_save);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_SETTIME_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_SUB)
{
set_op = SET_OPER_SUB;
}
else if(keycode == KEY_CODE_ADD)
{
set_op = SET_OPER_ADD;
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
if(set_save == TRUE)
{//保存时间配置
set_save = FALSE;
//因为设置时间和日期是同时的,所以为了避免
//设置时间的时候误修改了日期,要先读取当前日期
rtc_read_time(&time_t);
stime_t.year = time_t.year;
stime_t.month = time_t.month;
stime_t.day = time_t.day;
stime_t.week = time_t.week;
rtc_set_time(&stime_t);
}
else
{
rtc_read_time(&stime_t);//恢复
}
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_SET_ALARM://闹钟设置页面(文字界面)
set_id = show_time_config(set_id, &alarm_t, set_op, &set_save);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_SETTIME_ID)
{//闹钟只需要设置时分秒
set_id = 0;
}
}
else if(keycode == KEY_CODE_SUB)
{
set_op = SET_OPER_SUB;
}
else if(keycode == KEY_CODE_ADD)
{
set_op = SET_OPER_ADD;
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
if(set_save == TRUE)
{//保存闹钟配置
set_save = FALSE;
alarm_set_time(&alarm_t);
}
else
{
alarm_read_time(&alarm_t);
}
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_SET_DATE://日期设置页面(文字界面)
set_id = show_date_config(set_id, &sdate_t, set_op, &set_save);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_SETDATE_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_SUB)
{
set_op = SET_OPER_SUB;
}
else if(keycode == KEY_CODE_ADD)
{
set_op = SET_OPER_ADD;
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
if(set_save == TRUE)
{//保存日期配置
set_save = FALSE;
//因为设置时间和日期是同时的,所以为了避免
//设置日期的时候误修改了时间,要先读取当前时间
rtc_read_time(&time_t);
sdate_t.hour = time_t.hour;
sdate_t.minute = time_t.minute;
sdate_t.second = time_t.second;
rtc_set_time(&sdate_t);
}
else
{
rtc_read_time(&sdate_t);//恢复
}
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_SET_BRTDY://生日设置页面(文字界面)
set_id = show_date_config(set_id, &alarm_t, set_op, &set_save);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_SETDATE_ID)
{
set_id = SETDATE_ID_MONTH;
}
}
else if(keycode == KEY_CODE_SUB)
{
set_op = SET_OPER_SUB;
}
else if(keycode == KEY_CODE_ADD)
{
set_op = SET_OPER_ADD;
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
if(set_save == TRUE)
{//保存生日配置
set_save = FALSE;
alarm_set_time(&alarm_t);//保存
}
else
{
alarm_read_time(&alarm_t);//恢复
}
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_GET_NONLI://查看农历页面(文字界面)
set_id = show_nonli_config(set_id, &time_t);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环设置各项,按Enter(Down)键进入下一项设置
set_id++;
if(set_id > MAX_GETNONLI_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_GET_TEMP://温度查看页面(文字界面)
set_id = show_temp_config(set_id, &dht_temp, &dht_humi);
if(keycode != 0)
{
if(keycode == KEY_CODE_ENTER)
{//循环查看温度和湿度,按Enter(Down)键查看下一项
set_id++;
if(set_id > MAX_GETTEMP_ID)
{
set_id = 0;
}
}
else if(keycode == KEY_CODE_EXIT)
{//按Exit(UP)键返回上一级菜单
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{
set_op = 0;
}
}
else
{
set_op = 0;
}
break;
case SYS_PAGE_PLAY_SNAKE://贪吃蛇游戏页面
//物理按键太少,只有使用红外键盘的时候才能玩游戏
if(snake_life == 0)//进入游戏,初始化游戏
{
led_scroll_puts_8x16(" Start Game ", 0, 1);
led_clear(0);
snake_game_init(3, DR_DOWN, 10, 1);
snake_life = LF_LIVE;
}
else if(snake_life == LF_DIE)//游戏结束,退出游戏
{
led_scroll_puts_8x16(" Game Over ", 0, 1);
led_clear(0);
snake_life = 0;
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else if(snake_life == LF_WIN)//游戏通关,退出游戏
{
led_scroll_puts_8x16(" You Are Win ", 0, 1);
led_clear(0);
snake_life = 0;
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
else
{//响应按键,控制贪吃蛇移动
if(keycode != 0)
{
if(keycode == KEY_CODE_UP)
{
snake_dir = DR_UP;
}
else if(keycode == KEY_CODE_DWN)
{
snake_dir = DR_DOWN;
}
else if(keycode == KEY_CODE_LFT)
{
snake_dir = DR_LEFT;
}
else if(keycode == KEY_CODE_RHT)
{
snake_dir = DR_RIGHT;
}
else if(keycode == KEY_CODE_NUM4)//允许穿墙
{
snake_set_crosswall(TRUE);
}
else if(keycode == KEY_CODE_NUM5)//禁止穿墙
{
snake_set_crosswall(FALSE);
}
else if(keycode == KEY_CODE_NUM1)//加速
{
snake_add_speed();
}
else if(keycode == KEY_CODE_NUM2)//减速
{
snake_sub_speed();
}
else if(keycode == KEY_CODE_OK)//暂停
{
while(TRUE)
{
keycode = key_get_code();
if(keycode != 0)
{
//sound_beep(1);
//delay_xms(50);
//sound_beep(0);
sound_open(50);
if(keycode == KEY_CODE_OK)
{
keycode = 0;
break;
}
}
}
}
else if(keycode == KEY_CODE_NUM0)//退出
{
snake_life = 0;
system_page = SYS_PAGE_MENU;
}
}
snake_life = snake_move_control(snake_dir);//贪吃蛇移动
delay_xms(1000-(snake_get_speed()*100));//控制贪吃蛇移动速度(延时长短)
}
break;
case SYS_PAGE_PLY_TETRIS://俄罗斯方块游戏页面
if(tetris_life == 0)//进入游戏,初始化游戏
{
led_scroll_puts_8x16(" Start Game ", 0, 1);
led_clear(0);
tetris_game_init();
tetris_life = LF_LIVE;
}
else if(tetris_life == LF_DIE)//游戏结束,退出游戏
{
led_scroll_puts_8x16(" Game Over ", 0, 1);
led_clear(0);
tetris_life = 0;
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
#if 0
else if(tetris_life == LF_WIN)//游戏通关,退出游戏
{
led_scroll_puts_8x16(" You Are Win ", 0, 1);
led_clear(0);
tetris_life = 0;
system_page = /*SYS_PAGE_MAIN*/SYS_PAGE_MENU;
}
#endif
else
{//响应按键,控制俄罗斯方块移动
tetris_life = tetris_game_run();//俄罗斯方块运行
if(keycode != 0)
{
if(keycode == KEY_CODE_DWN)//变形
{
//tetris_dir = DR_DOWN;
tetris_shape_deform();
}
else if(keycode == KEY_CODE_LFT)//左移动
{
//tetris_dir = DR_LEFT;
tetris_shape_move(DR_LEFT);
}
else if(keycode == KEY_CODE_RHT)//右移动
{
//tetris_dir = DR_RIGHT;
tetris_shape_move(DR_RIGHT);
}
else if(keycode == KEY_CODE_NUM1)//加速
{
tetris_add_speed();
}
else if(keycode == KEY_CODE_NUM2)//减速
{
tetris_sub_speed();
}
else if(keycode == KEY_CODE_OK)//暂停
{
while(TRUE)
{
keycode = key_get_code();
if(keycode != 0)
{
//sound_beep(1);
//delay_xms(50);
//sound_beep(0);
sound_open(50);
if(keycode == KEY_CODE_OK)
{
keycode = 0;
break;
}
}
}
}
else if(keycode == KEY_CODE_UP)//退出
{
tetris_life = 0;
system_page = SYS_PAGE_MENU;
}
}
delay_xms(1000-(tetris_get_speed()*100));//俄罗斯方块运行速度(延时长短)
}
break;
case SYS_PAGE_POWER://待机模式页面,关闭屏幕显示
led_clear(0);
led_close();
if(keycode != 0)
{//按任意键退出
if((keycode <= KEY_MAX_CODE) &&
(keycode >= KEY_MIN_CODE))
{
system_page = SYS_PAGE_MAIN;
led_open();
}
}
break;
case SYS_PAGE_TEST_LED://屏幕测试页面,LED全亮用于查看坏点
led_clear(1);
if(keycode != 0)
{//按任意键退出,但是因为LD全亮的时候功耗较高,会导致供电
//不足,红外按键这时不起作用,只能通过背后的物理按键退出
if((keycode <= KEY_MAX_CODE) &&
(keycode >= KEY_MIN_CODE))
{
system_page = SYS_PAGE_MAIN;
}
}
break;
case SYS_PAGE_MAIN://系统主界面,显示时间日期
rtc_read_time(&time_t);//读取当前时间
rtc_read_time(&stime_t);//读取当前时间
rtc_read_time(&sdate_t);//读取当前日期
alarm_read_time(&alarm_t);//读取闹钟设置
if(system_config_tmp.mainpg_mode
== CONFIG_MAIN_PG_WITH_TEMP)//主界面带温度模式
{
if(dht11_get_value(&dht_temp, &dht_humi) == 0)
{
main_page_temputer = dht_temp;
}
}
led_put_main_page(&time_t, system_config_tmp.time_mode,
main_page_temputer, 1, system_config_tmp.mainpg_mode);
if(system_config_tmp.now_time != 0)//整点报时
{
if((time_t.minute == 0) && (time_t.second == 0))//整点
{
sound_open(200);
}
}
if((time_t.hour == alarm_t.hour) &&
(time_t.minute == alarm_t.minute) &&
(time_t.second == alarm_t.second))
{
sound_beep(1);//闹钟时间到
}
if(time_t.minute != alarm_t.minute)
{
sound_beep(0);//一分钟之后自动结束闹钟
}
if((time_t.month == alarm_t.month) &&
(time_t.day == alarm_t.day) &&
(time_t.second == 0))//每隔一分钟显示一次生日快乐
{
led_scroll_puts_8x16(" Happy Birthday ", 0, 1);
}
if(keycode != 0)
{
sound_beep(0);//任意键结束闹钟
if((keycode == KEY_CODE_ENTER) ||
(keycode == KEY_CODE_OK))//进入菜单
{
system_page = SYS_PAGE_MENU;
setting_id = 0;
}
#if 1
else if(keycode == KEY_CODE_HSHTG)// #键关闭显示,用于快速待机
{
system_page = SYS_PAGE_POWER;
}
#endif
#if 0
else if(keycode == KEY_CODE_ASTRSK)// *键测进入测试模式
{
system_page = SYS_PAGE_TEST_LED;
}
#endif
else if(keycode == KEY_CODE_UP)//按UP键滚动显示日期
{
led_scroll_puts_8x16(get_date_string(&time_t), 5, 1);
}
else if(keycode == KEY_CODE_LFT)//按LIFT键滚动显示农历
{
led_scroll_puts_16x16(get_nonli_string(&time_t), NONLI_STRING_LEN, 5, 1);
}
else if(keycode == KEY_CODE_RHT)//按RIGHT键滚动显示温湿度
{
if(system_config_tmp.mainpg_mode
== CONFIG_MAIN_PG_WITH_TEMP)//主界面带温度模式
{
delay_xms(400);//两次读取dht11之间应该要有一定间隔,否则会出错(数据为0)
}
led_scroll_puts_8x16(get_temp_string(&dht_temp, &dht_humi), 5, 1);
}
}
break;
default:
break;
}
led_update();
delay_xms(200);
}
}
common
系统通用模块, 包含基础头文件, 基本数据类型的定义, 以及以及基本通用函数的定义, 系统功能定义等
#ifndef __COMMON_H__
#define __COMMON_H__
//#include <reg52.h>
#include <stc12c5a60s2.h>
#include <intrins.h>
#include <stdio.h>
#include <stdlib.h>
/*==========Typedef==========*/
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
#ifndef int32
#define int32 long int
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef OK
#define OK 0
#endif
#ifndef ERROR
#define ERROR 1
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef RTN_ERR
#define RTN_ERR (uchar)1//返回1
#endif
#ifndef RTN_OK
#define RTN_OK (uchar)0//返回0
#endif
#ifndef RTN_NULL
#define RTN_NULL (void*)0//返回NULL
#endif
#if 0
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned int uint16;
typedef signed int int16;
typedef unsigned long uint32;
typedef signed long int32;
#endif
typedef struct rtc_time_s
{
uchar year;
uchar week;
uchar month;
uchar day;
uchar hour;//force 24 hour mode
uchar minute;
uchar second;
} rtc_time_t;
//方向
#define DR_UP (uchar)0x10//0上
#define DR_DOWN (uchar)0x11//1下
#define DR_LEFT (uchar)0x12//2左
#define DR_RIGHT (uchar)0x13//3右
//生命
#define LF_LIVE (uchar)0x20//0活着
#define LF_DIE (uchar)0x21//1死亡
#define LF_WIN (uchar)0x22//2胜利
/*==========Function Extern==========*/
/*****************************************************************************
函 数 名 : delay_xms
功能描述 : 毫秒延时
输入参数 : x 延时时间,毫秒
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void delay_xms(uint x);
/*****************************************************************************
函 数 名 : delay_xus
功能描述 : 微秒延时
输入参数 : x 延时时间,微秒
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void delay_xus(uint x);
/*****************************************************************************
函 数 名 : _memset_
功能描述 : 内存填充函数
输入参数 : mem 要清除的内存首地址
val 要填充的值
sz 填充的长度
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void _memset_(uchar *mem, uchar val, uint sz);
/*****************************************************************************
函 数 名 : _memcpy_
功能描述 : 内存拷贝函数
输入参数 : dst 目的内存地址
src 源内存地址
sz 拷贝的长度
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void _memcpy_(uchar *dst, uchar *src, uint sz);
/*****************************************************************************
函 数 名 : _memcmp_
功能描述 : 内存比较函数
输入参数 : m1 源内存1
m2 源内存2
sz 要比较的长度
输出参数 : 无
返 回 值 : 0-相同, 非0-不同
*****************************************************************************/
extern char _memcmp_(uchar *m1, uchar *m2, uint sz);
/*****************************************************************************
函 数 名 : _strlen_
功能描述 : 计算字符串长度函数
输入参数 : str 待计算的字符串
输出参数 : 无
返 回 值 : 字符串长度
*****************************************************************************/
extern uchar _strlen_(char *str);
//extern char _strcmp_(char *str0, char* str1);
/*****************************************************************************
函 数 名 : sound_beep
功能描述 : 蜂鸣器发声
输入参数 : b TRUE:声音开,FALSE:声音关
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void sound_beep(uchar b);
/*****************************************************************************
函 数 名 : sound_beep
功能描述 : 系统声音总开关
输入参数 : b TRUE:声音开,FALSE:声音关
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void sound_value(uchar v);
/*****************************************************************************
函 数 名 : sound_open
功能描述 : 游戏声音
输入参数 : x 响铃时间,毫秒
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void sound_open(uint xms);
/*==========System Config==========*/
#define CONFIG_INCLUDE_FONT_EN_8X16 1//支持8x16英文字符
#define CONFIG_INCLUDE_FONT_EN_5X7 1//支持8x16英文字符
#define CONFIG_INCLUDE_FONT_CN_16X16 1//支持16x16图片(包括汉字)
#define CONFIG_INCLUDE_SCROLL_DISPLAY 1//支持滚动显示
#define CONFIG_INCLUDE_GAME_SNAKE 1//支持贪吃蛇游戏
#define CONFIG_INCLUDE_GAME_TETRIS 1//支持俄罗斯方块游戏
#define CONFIG_INCLUDE_IRM_HS0038 1//支持红外遥控
#define CONFIG_INCLUDE_RTC_DS1302 1//支持DS1302时钟芯片
#define CONFIG_INCLUDE_TEMP_DHT11 1//支持DHT11温湿度传感器
#define CONFIG_INCLUDE_CHNIA_NONLI 1//支持农历
#define CONFIG_MAIN_PG_WITH_SECOND (uchar)0x01//主页模式:右下角显示秒
#define CONFIG_MAIN_PG_WITH_WEEK (uchar)0x02//主页模式:右下角显示星期(1-7)
#define CONFIG_MAIN_PG_WITH_TEMP (uchar)0x03//主页模式:右下角显示温度
#define CONFIG_DEFAULT_MAIN_PG CONFIG_MAIN_PG_WITH_SECOND//正常模式
#define CONFIG_DEFAULT_LED_LIGHT (uchar)0x00//默认亮度,0,最低
#define CONFIG_DEFAULT_TIME_MODE (uchar)0x00//默认小时制,12小时制
//#define CONFIG_PRODUCT_XIUBAOBAO 1
//#define CONFIG_PRODUCT_WEIXIN 1
//#define CONFIG_PRODUCT_YUHONGQIANG 1
#define SYSTEM_SOFTWARE_VERSION "V:v9r3"//软件版本, versiong 9, release 3
#define SYSTEM_HARDWARE_VERSION "V:v1r5"//硬件版本, versiong 1, release 5
#define SYSTEM_RELVERSION_TIME "180310"//发布时间
#if defined CONFIG_PRODUCT_XIUBAOBAO
#define SYSTEM_RELVERSION_CUST "BAOBAO"//客户
#elif defined CONFIG_PRODUCT_WEIXIN
#define SYSTEM_RELVERSION_CUST "WEIXIN"//客户
#elif defined CONFIG_PRODUCT_YUHONGQIANG
#define SYSTEM_RELVERSION_CUST " YUHQ "//客户
#else
#define SYSTEM_RELVERSION_CUST " WNAVY"//客户
#endif
#endif
drv_led
点阵屏驱动模块,本系统有八块8×8点阵组成, 分辨率为32×16,采用8片max7219驱动芯片驱动. 本系统并没有采用8片max7219级联的方式, 而是8片max7219的CLK和LOAD引脚共用, 分别接在STC122C5A单片机的P1.0和P1.1引脚上. 8个DIN引脚分别接在STC122C5A单片机的P2.0 – P2.7引脚上.
#ifndef __DRV_LED_H__
#define __DRV_LED_H__
#include "common.h"
#define LED_MAX_X 32
#define LED_MAX_Y 16
#define LED_PUT_BLOCK_2X2(x, y, col) \
do \
{ \
led_set_point((x), (y), (col));\
led_set_point((x+1), (y), (col));\
led_set_point((x), (y+1), (col));\
led_set_point((x+1), (y+1), (col));\
}while(0)
/*****************************************************************************
函 数 名 : led_init
功能描述 : max7219初始化
输入参数 : void
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_init(void);
/*****************************************************************************
函 数 名 : led_open
功能描述 : max7219打开显示(硬件)
输入参数 : void
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_open(void);
/*****************************************************************************
函 数 名 : led_close
功能描述 : max7219关闭显示(硬件)
输入参数 : void
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_close(void);
/*****************************************************************************
函 数 名 : led_set_light
功能描述 : 设置显示亮度
输入参数 : uchar n 亮度值(0-15)
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_set_light(uchar n);
/*****************************************************************************
函 数 名 : led_update
功能描述 : 把显存中的数据写入硬件(max7219)中
输入参数 : void
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_update(void);
/*****************************************************************************
函 数 名 : led_clear
功能描述 : 用制定颜色填充(刷新)显存
输入参数 : uchar dat 指定颜色,0:不显示(黑色),非0:显示(白色)
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_clear(uchar dat);
/*****************************************************************************
函 数 名 : led_set_point
功能描述 : 设置显存中指定坐标点的颜色
输入参数 : uchar x 显存中指定点的x坐标[0-32)
uchar y 显存中指定点的y坐标[0-16)
uchar dat 坐标点的颜色,0:不显示(黑色),非0:显示(白色)
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void led_set_point(uchar x, uchar y, uchar dat);
/*****************************************************************************
函 数 名 : led_get_point
功能描述 : 获取显存中指定坐标点的颜色
输入参数 : uchar x 显存中指定点的x坐标[0-32)
uchar y 显存中指定点的y坐标[0-16)
输出参数 : 无
返 回 值 : 坐标点的颜色,0:不显示(黑色),非0:显示(白色)
*****************************************************************************/
extern uchar led_get_point(uchar x, uchar y);
#if 0
extern void open_door(void);
extern void closed_door(void);
#endif
#ifdef CONFIG_INCLUDE_FONT_EN_8X16
/*****************************************************************************
函 数 名 : led_putc_8x16
功能描述 : 显示一个8x16的字符图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符图像的x坐标(y坐标为0)
char chr 需要显示的字符的ascii码
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_putc_8x16(uchar x_pos, char chr, uchar color);
/*****************************************************************************
函 数 名 : led_puts_8x16
功能描述 : 显示一个8x16的字符串图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符串的x坐标(y坐标为0)
char chr 需要显示的字符的指针
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_puts_8x16(uchar x_pos, char *str, uchar color);
//extern void led_put_8x16_with_02x(uchar x, uchar hex, uchar col);
#ifdef CONFIG_INCLUDE_SCROLL_DISPLAY
/*****************************************************************************
函 数 名 : led_scroll_puts_8x16
功能描述 : 滚动(向左)显示一个8x16的字符串
输入参数 : char *str 要显示的字符串的指针
uint delay 滚动延时时间(ms)
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_scroll_puts_8x16(char *str, uint delay, uchar color);
#endif
#endif
#ifdef CONFIG_INCLUDE_FONT_CN_16X16
/*****************************************************************************
函 数 名 : led_putc_16x16
功能描述 : 显示一个8x16的字符图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符图像的x坐标(y坐标为0)
char chr 要显示的字符的图形码
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_putc_16x16(uchar x_pos, uchar chr, uchar color);
/*****************************************************************************
函 数 名 : led_puts_16x16
功能描述 : 显示一个16x16的字符串图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符串的x坐标(y坐标为0)
char* chr 要显示的图形的图形数组指针
uchar len 要显示的图形码数组的长度
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_puts_16x16(uchar x_pos, uchar *chr, uchar len, uchar color);
#ifdef CONFIG_INCLUDE_SCROLL_DISPLAY
/*****************************************************************************
函 数 名 : led_scroll_puts_16x16
功能描述 : 滚动(向左)显示一个8x16的字符串
输入参数 : char *chr 要显示的图形码数组的指针
uchar len 要显示的图形码数组的长度
uint delay 滚动延时时间(ms)
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_scroll_puts_16x16(uchar *chr, uchar len, uint delay, uchar color);
#endif
#endif
/*****************************************************************************
函 数 名 : led_put_small_num
功能描述 : 显示一个7x11或4x5的数字
输入参数 : uchar x 显示位置
uchar y 显示位置
uchar num 要现实的数字(只能显示一位,所以必须<10)
uchar color 颜色反转,0-阴文,非0-阳文
uchar fnt_md 0: 4x5字体, 非0: 7x11字体
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_put_small_num(uchar x, uchar y, uchar num, uchar color, uchar fnt_md);
/*****************************************************************************
函 数 名 : led_put_main_page
功能描述 : 全屏显示时间、日期、星期、秒、温度等信息
输入参数 : rtc_time_t *ttime 时间日期(时间采用24小时制)
uchar tmd_24h 是否使用24小时模式, 非0-24小时制, 0-12小时制
uchar temp 温度,当不使用带温度模式的时候,此参数填0
uchar color 颜色反转,0-阴文,非0-阳文
uchar mpg_mod 附加显示:星期(0-7)或温度(0-99)或秒(0-59)
输出参数 : 无
返 回 值 :
*****************************************************************************/
extern uchar led_put_main_page(rtc_time_t *ttime, uchar tmd_24h, uchar temp, uchar color, uchar mpg_mod);
#ifdef CONFIG_INCLUDE_FONT_EN_5X7
/*****************************************************************************
函 数 名 : led_putc_5x7
功能描述 : 显示一个5x7的字符图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符图像的x坐标(y坐标为0)
char chr 需要显示的字符的ascii码
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_putc_5x7(uchar c_pos, uchar r_pos, char chr, uchar color);
extern uchar led_putc_5x7_undline(uchar c_pos, uchar r_pos, char chr, uchar color, uchar undline);
/*****************************************************************************
函 数 名 : led_puts_5x7
功能描述 : 显示一个5x7的字符串图像(只写入显存,不更新硬件)
输入参数 : uchar x_pos 要显示的字符串的x坐标(y坐标为0)
char chr 需要显示的字符的指针
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_puts_5x7(uchar c_pos, uchar r_pos, char *str, uchar color);
extern uchar led_puts_5x7_undline(uchar c_pos, uchar r_pos, char *str, uchar color, uchar undline);
#ifdef CONFIG_INCLUDE_SCROLL_DISPLAY
/*****************************************************************************
函 数 名 : led_scroll_puts_5x7
功能描述 : 滚动(向左)显示一个5x7的字符串
输入参数 : char *str 要显示的字符串的指针
uint delay 滚动延时时间(ms)
uchar color 颜色反转,0-阴文,非0-阳文
输出参数 : 无
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar led_scroll_puts_5x7(char *str, uint delay, uchar color, uchar r_pos);
#endif
#endif
#endif
drv_cfgsave
系统参数保存模块, 用于保存系统设置参数,以防掉电丢失. 数据保存在STC12C5A的内部EEPROM上.
STC12C5A内部EEPROM共有两个bank, 每个bank512字节, 系统参数保存在第一个bank(bank0)上, 起始地址为0x0000.
因为eeprom只能按bank擦除, 所以当每次参数发生改变重新保存的时候, 都会擦除整个bank0, 然后把新的数据(全部)重新写入到eeprom中.
系统参数从bank0的0x0005地址开始保存, 前五个字节用于保存参数标志"WNAVY".
每次开机的时候总是会从eeprom中读取保存的参数, 并根据保存的系统配置参数设置系统.
#ifndef __DRV_CFGSAVE_H__
#define __DRV_CFGSAVE_H__
#include "common.h"
/*****************************************************************************
函 数 名 : cfgsave_read
功能描述 : 从内部eeprom中读取配置
输入参数 : len 要读区的配置区的长度(字节)
输出参数 : config 指向保存配置的指针
返 回 值 : RTN_OK-成功,RTN_ERR-失败
*****************************************************************************/
uchar cfgsave_read(uchar* config, uint len);
/*****************************************************************************
函 数 名 : cfgsave_write
功能描述 : 把配置保存到内部eeprom中
输入参数 : config 指向保存配置的指针
len 要读区的配置区的长度(字节)
输出参数 : 无
返 回 值 : RTN_OK-成功,RTN_ERR-失败
*****************************************************************************/
uchar cfgsave_write(uchar* config, uint len);
#endif
drv_1302
DS1302实时时钟驱动模块, DS1302采用IIC接口读写数据, 本机采用GPIO模拟IIC时序的方式来读写DS1302, DS1302的CLK, IO, CE引脚分别STC122C5A单片机的P1.7, P1.6, P1.5引脚上. 为了简化DS1302驱动模块, DS1302驱动默认只采用24小时模式来读取和配置, 关于12小时和24小时的转换由软件完成.
#ifndef __DRV_1302_H__
#define __DRV_1302_H__
#include "common.h"
#ifdef CONFIG_INCLUDE_RTC_DS1302
/*****************************************************************************
函 数 名 : rtc_set_time
功能描述 : 设置当前时间
输入参数 : time 要设置的时间
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void rtc_set_time(rtc_time_t* time);
/*****************************************************************************
函 数 名 : rtc_read_time
功能描述 : 获取当前时间
输入参数 : void
输出参数 : time 读取到的闹钟时间
返 回 值 : 无
*****************************************************************************/
extern void rtc_read_time(rtc_time_t* time);
/*****************************************************************************
函 数 名 : alarm_set_time
功能描述 : 设置闹钟时间
输入参数 : time 要设置的闹钟时间
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void alarm_set_time(rtc_time_t* time);
/*****************************************************************************
函 数 名 : alarm_read_time
功能描述 : 获取闹钟时间
输入参数 : 无
输出参数 : time 要设置的闹钟时间
返 回 值 : 无
*****************************************************************************/
extern void alarm_read_time(rtc_time_t* time);
/*****************************************************************************
函 数 名 : alarm_set_flag
功能描述 : 设置闹钟开关
输入参数 : b 闹钟开启标志
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void alarm_set_flag(uchar b);
/*****************************************************************************
函 数 名 : alarm_get_flag
功能描述 : 获取闹钟开关
输入参数 : 无
输出参数 : 无
返 回 值 : 闹钟开启标志
*****************************************************************************/
extern uchar alarm_get_flag(void);
/*****************************************************************************
函 数 名 : alarm_beep
功能描述 : 控制闹钟响铃
输入参数 : b 闹钟开始响铃
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void alarm_init(rtc_time_t* alarm);
/*****************************************************************************
函 数 名 : alarm_init
功能描述 : 闹钟初始化
输入参数 : alarm 初始化时读取保存的闹钟时间
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
//extern void alarm_beep(uchar b);
//#define alarm_beep(b) sound_beep(b)
#endif
#endif
drv_irm
红外按键驱动模块, 一体化红外接收头的DATA引脚接在STC122C5A单片机的P3.2引脚上.
红外键盘发送数据时将数据调制在38KHZ的载波上, 红外接收头接收到载波数据后会自动解调出载波中的数据.
P3.2引脚具有外部中断功能, 当红外接收到数据后接收头的输出脚开始输出电平,进而出发外部中断(中断号0), 在外部中断0中配合红外定时器(timer0)可以测量红外高低电平持续时间,从而转化成数字0或1,追后解码出红外按键码.
本机带有四个物理按键(UP, DOWN, LEFT, RIGHT), 物理按键通过定时器中断(timer1)轮询检测, 为了简化按键处理程序, 物理按键和红外按键公用四个键值码.
详见 红外遥控器工作原理
#ifndef __DRV_IRM_H__
#define __DRV_IRM_H__
#include "common.h"
#ifdef CONFIG_INCLUDE_IRM_HS0038
#define KEY_USR_CODE0 0x00
#define KEY_USR_CODE1 0xFF
//红外键值码
#define KEY_CODE_NUM1 0x45
#define KEY_CODE_NUM2 0x46
#define KEY_CODE_NUM3 0x47
#define KEY_CODE_NUM4 0x44
#define KEY_CODE_NUM5 0x40
#define KEY_CODE_NUM6 0x43
#define KEY_CODE_NUM7 0x07
#define KEY_CODE_NUM8 0x15
#define KEY_CODE_NUM9 0x09
#define KEY_CODE_NUM0 0x19
#define KEY_CODE_ASTRSK 0x16//星号
#define KEY_CODE_HSHTG 0x0D//井号
#define KEY_CODE_OK 0x1C//上
//物理按键和红外按键公用键值码
#define KEY_CODE_UP 0x18//上
#define KEY_CODE_DWN 0x52//下
#define KEY_CODE_LFT 0x08//左
#define KEY_CODE_RHT 0x5A//右
#define KEY_CODE_ADD KEY_CODE_RHT//+
#define KEY_CODE_SUB KEY_CODE_LFT//-
#define KEY_CODE_ENTER KEY_CODE_DWN//Enter
#define KEY_CODE_EXIT KEY_CODE_UP//Enter
#define KEY_MAX_CODE KEY_CODE_RHT
#define KEY_MIN_CODE KEY_CODE_NUM7
/*****************************************************************************
函 数 名 : irm_init
功能描述 : 红外接收初始化,初始化定时器,中断
输入参数 : 无
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern void irm_init(void);
/*****************************************************************************
函 数 名 : key_get_code
功能描述 : 获取按键值,获取完之后立即置0,按键一次,软件中重复多次获取到键值
输入参数 : 无
输出参数 : 无
返 回 值 : 无
*****************************************************************************/
extern uchar key_get_code(void);
#endif
#endif
drv_dht11
DHT11温湿度传感器驱动模块, DHT11的数据引脚接在STC122C5A单片机的P1.3引脚上. 两次读取数据之间的间隔不能小于2秒,否则读取数据会出错.
#ifndef __DRV_DHT11_H__
#define __DRV_DHT11_H__
#include "common.h"
#ifdef CONFIG_INCLUDE_TEMP_DHT11
#if 0
/*****************************************************************************
函 数 名 : dht11_get_temp
功能描述 : 获取温度并返回,读取模块数据周期不易小于 2S
输入参数 : void
输出参数 : 无
返 回 值 : 温度
*****************************************************************************/
extern uchar dht11_get_temp(void);
/*****************************************************************************
函 数 名 : dht11_get_humi
功能描述 : 获取湿度并返回,读取模块数据周期不易小于 2S
输入参数 : void
输出参数 : 无
返 回 值 : 湿度
*****************************************************************************/
extern uchar dht11_get_humi(void);//获取湿度
#endif
/*****************************************************************************
函 数 名 : dht11_get_value
功能描述 : 从dht11模块获取温度和湿度
输入参数 : 无
无
输出参数 : uchar* temp 温度
uchar* humi 湿度
返 回 值 : 0-成功,1-失败
*****************************************************************************/
extern uchar dht11_get_value(uchar *temp, uchar *humi);
#endif
#endif
china_nonli
公历转农历模块, 由网络上的开源代码修改而来.
#ifndef __CHNIA_NONLI_H__
#define __CHNIA_NONLI_H__
#include "common.h"
#ifdef CONFIG_INCLUDE_CHNIA_NONLI
typedef struct china_nonli_s
{
uchar month;//农历月
uchar intcal;//农历闰月
uchar day;//农历日
} china_nonli_t;
/*****************************************************************************
函 数 名 : china_nonli_get
功能描述 : 根据输入的RTC时间获取农历时间
输入参数 : tm 当前RTC时间
输出参数 : nonli 当前农历时间
返 回 值 : 成功-RTN_OK, 失败-RTN_ERR
*****************************************************************************/
extern uchar china_nonli_get(rtc_time_t* tm, china_nonli_t* nonli);
#endif
#endif
game_snake
贪吃蛇游戏模块, 原创, 具体原理可见代码, 都有详细注释.
#ifndef __GAME_SNAKE_H_
#define __GAME_SNAKE_H_
#include "common.h"
#ifdef CONFIG_INCLUDE_GAME_SNAKE
#if 0
//方向
#if 0
typedef enum snake_dir
{
DR_UP = 0, //0上
DR_DOWN, //1下
DR_LEFT, //2左
DR_RIGHT //3右
} SNAKE_DIR;
#else
#define DR_UP (uchar)0x10//0上
#define DR_DOWN (uchar)0x11//1下
#define DR_LEFT (uchar)0x12//2左
#define DR_RIGHT (uchar)0x13//3右
#endif
//生命
#if 0
typedef enum snake_life
{
LF_LIVE = 0, //0活着
LF_DIE, //1死亡
LF_WIN, //2胜利
} SNAKE_LIFE;
#else
#define LF_LIVE (uchar)0x20//0活着
#define LF_DIE (uchar)0x21//1死亡
#define LF_WIN (uchar)0x22//2胜利
#endif
#endif
//函数声明
/*****************************************************************************
函 数 名 : snake_game_init
功能描述 : 贪吃蛇游戏初始化
输入参数 : uchar scnt:初始的蛇身长度
SNAKE_DIR sdir:初始的蛇头方向
uchar sstep:得分速度
uchar speed:速度
输出参数 : 无
返 回 值 :
函数说明 :
*****************************************************************************/
extern uchar snake_game_init(uchar scnt, /*SNAKE_DIR*/uchar sdir, uchar sstep, uchar cwall);
/*****************************************************************************
函 数 名 : snake_move_control
功能描述 : 根据按键值控制蛇移动
输入参数 : SNAKE_DIR KEY
输出参数 : 无
返 回 值 : 返回玩家当前的生命状态
函数说明 : 没有单独的游戏状态处理函数,使用者必须在自己的主函数中根据
该函数返回的生命状态来处理游戏进度(比如说当SnakeLife为LF_DIE的
时候该做什么事,这些需要有使用本函数的人自己完成)
*****************************************************************************/
extern /*SNAKE_LIFE*/uchar snake_move_control(/*SNAKE_DIR*/uchar KEY);
/*****************************************************************************
函 数 名 : snake_get_score
功能描述 : 获取当前游戏得分
输入参数 : 无
输出参数 : 无
返 回 值 : 游戏得分
函数说明 :
*****************************************************************************/
extern uchar snake_get_score(void);
/*****************************************************************************
函 数 名 : snake_get_speed
功能描述 : 获取当前速度
输入参数 : 无
输出参数 : 无
返 回 值 : 速度
函数说明 :
*****************************************************************************/
extern uchar snake_get_speed(void);
/*****************************************************************************
函 数 名 : snake_set_speed
功能描述 : 设置当前速度
输入参数 : uchar speed
输出参数 : 无
返 回 值 : 速度
函数说明 :
*****************************************************************************/
extern uchar snake_set_speed(uchar speed);
/*****************************************************************************
函 数 名 : snake_add_speed
功能描述 : 让速度增大
输入参数 : 无
输出参数 : 无
返 回 值 : 速度
函数说明 : 通过snake_set_scstep函数设置一个步进值SCORE_STEP,速度每次增加
SCORE_STEP个单位。
*****************************************************************************/
extern uchar snake_add_speed(void);
/*****************************************************************************
函 数 名 : snake_sub_speed
功能描述 : 让速度减小
输入参数 : 无
输出参数 : 无
返 回 值 : 速度
函数说明 : 通过snake_set_scstep函数设置一个步进值SCORE_STEP,速度每次减小
SCORE_STEP个单位。
*****************************************************************************/
extern uchar snake_sub_speed(void);
/*****************************************************************************
函 数 名 : snake_get_life
功能描述 : 获取当前游戏生命值
输入参数 : 无
输出参数 : 无
返 回 值 : 当前游戏生命值
函数说明 :
*****************************************************************************/
extern /*SNAKE_LIFE*/uchar snake_get_life(void);
/*****************************************************************************
函 数 名 : snake_set_scstep
功能描述 : 设置游戏得分步进
输入参数 : uchar scstep
输出参数 : 无
返 回 值 : 游戏得分步进
函数说明 : 该值是速度增加的步进值(每吃到一个食物得1分,分数增加到scstep的整数
倍之后速度加快scstep个单位)。
*****************************************************************************/
extern uchar snake_set_scstep(uchar scstep);
/*****************************************************************************
函 数 名 : snake_get_dir
功能描述 : 获取当前蛇头方向
输入参数 : 无
输出参数 : 无
返 回 值 : 当前蛇头方向
函数说明 :
*****************************************************************************/
extern /*SNAKE_DIR*/uchar snake_get_dir(void);
/*****************************************************************************
函 数 名 : snake_set_dir
功能描述 : 设置当前蛇头方向
输入参数 : SNAKE_DIR sdir
输出参数 : 无
返 回 值 : 当前蛇头方向
函数说明 :
*****************************************************************************/
extern /*SNAKE_DIR*/uchar snake_set_dir(/*SNAKE_DIR*/uchar sdir);
/*****************************************************************************
函 数 名 : snake_set_crosswall
功能描述 : 设置是否允许越界
输入参数 : uchar crosswall
输出参数 : 无
返 回 值 : 无
函数说明 : 非零表示允许越界
*****************************************************************************/
extern void snake_set_crosswall(uchar crosswall);
#endif
#endif
game_tetris
俄罗斯方块游戏模块, 原创, 具体原理可见代码, 都有详细注释.
#ifndef __LCD_SNAKE_H_
#define __LCD_SNAKE_H_
#include "common.h"
#ifdef CONFIG_INCLUDE_GAME_TETRIS
/*****************************************************************************
函 数 名 : tetris_game_init
功能描述 : 游戏初始化
输入参数 : void
输出参数 : 无
返 回 值 : RTN_OK:成功
*****************************************************************************/
extern uchar tetris_game_init(void);
/*****************************************************************************
函 数 名 : tetris_game_run
功能描述 : 游戏开始运行,并处理满行,消行,分数
输入参数 : void
输出参数 : 无
返 回 值 : RTN_OK:成功
*****************************************************************************/
extern uchar tetris_game_run(void);
/*****************************************************************************
函 数 名 : tetris_shape_deform
功能描述 : 全局shape变形
输入参数 : void
输出参数 : 无
返 回 值 : RTN_OK:成功
*****************************************************************************/
extern uchar tetris_shape_deform(void);
/*****************************************************************************
函 数 名 : tetris_shape_move
功能描述 : 使全局shape按指定方向移动
输入参数 : game_dir_t dir 全局shape移动的方向
输出参数 : 无
返 回 值 : RTN_OK:成功
*****************************************************************************/
extern uchar tetris_shape_move(uchar dir);
/*****************************************************************************
函 数 名 : tetris_get_life
功能描述 : 获取游戏生命值
输入参数 : void
输出参数 : 无
返 回 值 : 游戏生命值
*****************************************************************************/
extern uchar tetris_get_life(void);
/*****************************************************************************
函 数 名 : tetris_get_score
功能描述 : 获得游戏得分
输入参数 : void
输出参数 : 无
返 回 值 : 游戏得分
*****************************************************************************/
extern uchar tetris_get_score(void);
/*****************************************************************************
函 数 名 : tetris_get_speed
功能描述 : 获得游戏速度
输入参数 : void
输出参数 : 无
返 回 值 : 游戏速度
*****************************************************************************/
extern uchar tetris_get_speed(void);
/*****************************************************************************
函 数 名 : tetris_add_speed
功能描述 : 游戏速度加快
输入参数 : void
输出参数 : 无
返 回 值 : 游戏速度
*****************************************************************************/
extern uchar tetris_add_speed(void);
/*****************************************************************************
函 数 名 : tetris_sub_speed
功能描述 : 游戏速度减慢
输入参数 : void
输出参数 : 无
返 回 值 : 游戏速度
*****************************************************************************/
extern uchar tetris_sub_speed(void);
#endif
#endif
联系作者
功能说明
- 全自动日历
- 温湿度显示
- 红外遥控按键
- 自动循环闹钟
- 农历查看
- 时间设置
- 日期设置
- 闹钟设置
- 24小时制设置
- 勿扰模式设置
- 亮度设置
- 显示模式设置
- 软硬件版本查看
- 贪吃蛇小游戏
- 俄罗斯方块小游戏
- 所有设置掉电不丢失
- 主界面下按 [UP] 键滚动显示日历
- 主界面下按 [LEFT] 键滚动显示农历
- 主界面下按 [RIGHT] 键滚动显示温湿度
演示视频
按键说明

按键功能
按键名 | 功能1 | 功能2 |
---|---|---|
UP | 上方向键 | 退出 |
DOWN | 下方向键 | 确定 |
LEFT | 左方向键 | 减 |
RIGHT | 右方向键 | 加 |
注意: 为了方便正面操作,主板背面的左右键被调换了位置
供电接口

本机使用普通 microUSB 接口供电,只要用一条microUSB线把本机与PC的USB口或者手机的电源适配器相连,即可自动开机.
注意: 请不要使用带有快充功能的电源适配器为本机供电!否则有可能会烧毁本机!只能使用5V供电!
系统主界面
主界面一共有三种模式,分别如下:
模式一(默认模式)

模式二

模式三

菜单界面
操作说明
在系统主界面下按 [Enter/Down] 键即可进入菜单界面,按 [Exit/Up] 键可以退回到主界面.
按 [Left/Sub] 和 [Right/Add] 键可以滚动选择相应功能.
选中之后按 [Enter/Down] 键即可进入对应的设置界面.
图标说明
功能 | 图标 |
---|---|
时间 | ![]() |
闹钟 | ![]() |
日历 | ![]() |
生日 | ![]() |
农历 | ![]() |
温湿度 | ![]() |
系统设置 | ![]() |
系统信息 | ![]() |
贪吃蛇游戏 | ![]() |
俄罗斯方块 | ![]() |
时间设置
小时调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整小时,只能在 [0-23] 之间调整.调整完之后按 [Enter/Down] 键进入分钟调整.
注意: 小时调整必须使用24小时制时间,与主界面显示模式无关!在所有设置项中按 [Exit/Up] 键会放弃调整并退出.
分钟调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整分钟,只能在 [0-59] 之间调整.调整完之后按 [Enter/Down] 键进入秒调整.
秒调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整分钟,只能在 [0-59] 之间调整.调整完之后按 [Enter/Down] 键进入保存配置界面.
保存设置

按 [Left/Sub] 和 [Right/Add] 键可选择是否保存刚才的调整.
如果要保存,选择Y之后按 [Exit/Up] 键即可退出并保存刚才所有的配置.
如果要放弃保存,选择N并按 [Exit/Up] 键退出.
注意: 所有设置项中的保存界面操作方式都一样!在保存界面中按 [Enter/Down] 键会转回到小时调整界面.
日历设置
年调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整年,只能在 [0-99] 之间调整.调整完之后按 [Enter/Down] 键进入星期调整.
周调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整星期,只能在 [1-7] 之间调整.调整完之后按 [Enter/Down] 键进入月调整.
注意: 1代表星期一,7代表星期日,以此类推.(新版已更新,使用英文简写表示)
月调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整月,只能在 [1-12] 之间调整.调整完之后按 [Enter/Down] 键进入日调整.
日调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整日,只能在 [1-31] 之间调整.调整完之后按 [Enter/Down] 键进入保存配置界面.
保存设置

操作方式同上.
生日设置
月调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整月,只能在 [1-12] 之间调整.调整完之后按 [Enter/Down] 键进入日调整.
日调整

按 [Left/Sub] 和 [Right/Add] 键可上下调整日,只能在 [1-31] 之间调整.调整完之后按 [Enter/Down] 键进入保存配置界面.
保存设置

操作方式同上.
查看农历
查看闰月

Y 表示当月是闰月, N 表示当月不是闰月,按 [Enter/Down] 键查看农历月.
查看农历月

1-12 分别表示农历正月到腊月, 按 [Enter/Down] 键查看农历日.
查看农历日

1-30 分别表示农历初一到三十,按 [Exit/Up] 键退出.
查看温湿度
查看温度

按 [Enter/Down] 键可以继续查看湿度.按 [Exit/Up] 键即可退出.
查看湿度

按 [Enter/Down] 键可以继续查看湿度.按 [Exit/Up] 键即可退出.
系统设置
电源(待机)设置

按 [Left/Sub] 和 [Right/Add] 键可上下调整电源选项,只能在 [Y-N] 之间调整.
选择N并保存之后可以关闭显示,进入待机模式.继续按 [Enter/Down] 键进入测试模式设置.
测试模式

按 [Left/Sub] 和 [Right/Add] 键可上下调整测试模式开关,只能在 [Y-N] 之间调整.
选择Y并保存之后可以开启点阵坏点检测模式.继续按 [Enter/Down] 键进入亮度设置.
注意: 测试模式下点亮屏幕的所有LED会导致功耗增加,此时红外按键会不起作用,必须使用主板背面的任意按键退出测试模式.请勿长时间处于测试模式下!
亮度设置

按 [Left/Sub] 和 [Right/Add] 键可上下调整亮度,只能在 [0-10] 之间调整.本机默认亮度为0.
继续按 [Enter/Down] 键进入主页模式设置.
注意: 高亮度会增加功耗,缩短LED寿命,请勿长时间使用较高亮度!
主界面模式设置

按 [Left/Sub] 和 [Right/Add] 键可上下调主界面模式,只能在 [1-3] 之间调整.本机默认模式为1.
继续按 [Enter/Down] 键进入24小时制设置.
24小时制设置

按 [Left/Sub] 和 [Right/Add] 键可上下调24小时制模式,只能在 [Y-N] 之间调整.本机默认模式为N,即不使用24小时制.
继续按 [Enter/Down] 键进入系统静音设置界面.
静音(勿扰)模式设置

按 [Left/Sub] 和 [Right/Add] 键可开启/关闭静音模式,只能在 [Y-N] 之间调整.本机默认为不静音.
继续按 [Enter/Down] 键进入欢迎界面设置界面.
欢迎界面设置

按 [Left/Sub] 和 [Right/Add] 键可开启/关闭欢迎界面,只能在 [Y-N] 之间调整.本机默认为显示欢迎界面.
继续按 [Enter/Down] 键进入保存配置界面.
保存设置

操作方式同上.
系统信息
软件版本

按 [Enter/Down] 键可以继续查看硬件版本.按 [Exit/Up] 键即可退出.
硬件版本

按 [Enter/Down] 键可以继续查看版本发布时间.按 [Exit/Up] 键即可退出.
发布时间

按 [Enter/Down] 键可以继续查看客户ID.按 [Exit/Up] 键即可退出.
客户ID

按 [Enter/Down] 键可以继续查看软件版本.按 [Exit/Up] 键即可退出.
贪吃蛇游戏

在贪吃蛇游戏过程中,使用上下左右方向键控制贪吃蛇移动方向.
使用红外键盘中的数字0键退出游戏, OK键暂停/继续游戏,
数字1键加速,数字2键减速, 数字4键开启无界模式(默认),数字5键关闭无界模式.
注意: 由于物理按键太少,无法完全操作游戏,所以已锁定只能通过红外键盘玩贪吃蛇游戏!
俄罗斯方块游戏

在俄罗斯方块游戏过程中,使用左右方向键控制方块左右移动,
使用下方向键改变方块形状,使用上方向键退出游戏.
使用红外键盘中的OK键暂停/继续游戏, 数字1键加速,数字2键减速.
软件升级方法
本机预留有ISP软件升级接口,可以通过USB转串口线和STC单片机烧录工具对本机系统软件进行升级.
升级接口引脚如下:

升级方法如下:

点击下载之后,把本机的GND,RXD,TXD月USB转串口板的GND,RXD,TXD一一相连,
之后便会自动开始下载程序到单片机,如果遇到无法检测到单片机可以把RXD和TXD连线交换后再试.
更新记录
- MINI3216_code_rev03_20171024:贪吃蛇已经能够成功运行
- MINI3216_code_rev04_20171030:已经支持8×16和16×16两种字体,并且支持滚动显示
- MINI3216_code_rev04_20171031:已经支持反色显示
- MINI3216_code_rev05_20171031:移植dht11、ds1302、红外接收模块
- MINI3216_code_rev05_20171101:小修改
- MINI3216_code_rev05_20171102:DS1302测试,红外解码测试
- MINI3216_code_rev05_20171103:优化红外解码定时器,增加产品宏,增加欢迎页面
- MINI3216_code_rev06_20171104:完成基本功能,第一版
- MINI3216_code_rev06_20171108:添加5×7字库
- MINI3216_code_rev06_20171109:对于任务逻辑做了小改动
- MINI3216_code_rev06_20180202:修改错误
- MINI3216_code_rev07_20180203:第一个正式版本
- MINI3216_code_rev07_20180205:小的改动,把日期设置从时间设置中独立出来,优化了显示
- MINI3216_code_rev07_20180205:小的改动,优化代码格式、注释,更改了日历和温度图标,优化了几处显示
- MINI3216_code_rev08_20180208:增加了俄罗斯方块游戏,增加了系统信息查看
- MINI3216_code_rev08_20180208:替换了5×7字库,增加了游戏声音,修复了俄罗斯方块的部分bug
- MINI3216_code_rev09_20180224:优化了日期设置页面,增加了静音设置,增加了生日提醒,增加了农历显示
- MINI3216_code_rev09_20180226:增加了保存配置功能,把配置保存到内部EEPROM中,修改了农历图标,优化了主页显示界面
- MINI3216_code_rev09_20180310:增加了按左键滚动显示日期,按右键滚动显示温湿度的功能,修改了设置界面中不保存退出再进入的时候设置的值没有恢复的bug
转载请注明:胡椒小兄弟 » 基于STC12C5A60S2的mini3216多功能点阵时钟