完成了基础的中文和英文字符显示

This commit is contained in:
2026-03-08 21:30:46 +08:00
parent f45b571162
commit 9da748efb8
19 changed files with 5645 additions and 12905 deletions

File diff suppressed because it is too large Load Diff

24
src/Drv/ascii.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef __ASCII_H__
#define __ASCII_H__
#include "../../include/types.h"
/* 8x8 ASCII 点阵表 */
extern const uint8_t g_abyASCII88[][8];
/* 12x6或 12 列宽ASCII 点阵表 */
extern uint8_t g_abyASCII126[][12];
/* 16x8 ASCII 点阵表 */
extern uint8_t g_abyASCII168[][16];
#define UTF8_HZ12_BYTES_PER_CHAR 24
#define UTF8_HZ12_NUM_CHARS 4030
/* 按 Unicode 码点查找点阵,返回 24 字节指针,未找到返回 NULL */
const uint8_t* utf8_hz12_get(uint32_t unicode);
#endif /* ASCII_FONT_TABLES_H */

156
src/Drv/display.c Normal file
View File

@@ -0,0 +1,156 @@
#include "menu.h"
#include "display.h"
//========================================== //
// 字符串代号常量定义
enum _STR_FLAG_ {
EN_STR_FLAG_FUNSET = 0, // 投入,退出
EN_STR_FLAG_OKCANCEL,
EN_VALUE_FLAG_SLOTTYPE, // 板件类型
EN_VALUE_FLAG_YESNO, // 是否
EN_VALUE_FLAG_CHN_NUM, // 中文数字
EN_VALUE_FLAG_YXSET, // 遥信设置
EN_VALUE_FLAG_YKSTEP, // 遥控步骤
EN_VALUE_FLAG_YKACTION, // 遥控操作类型
EN_VALUE_FLAG_CHK, // 自检信息
EN_VALUE_FLAG_BEUSED, // 是否使用
EN_VALUE_FLAG_PORTTYPE, // 端口类型
EN_VALUE_FLAG_MAPNAME, // 转发表名称
EN_VALUE_FLAG_RECTITLE, // 记录类型表
EN_VALUE_FLAG_BHINFO, // 保护动作/复归
EN_VALUE_FLAG_BHSET, // 保护动作/复归
EN_VALUE_FLAG_OKCANCEL, // 确定/取消
EN_VALUE_FLAG_FILETYPE, // 文件类型
EN_VALUE_FLAG_ROLE, // 备份角色
EN_VALUE_FLAG_COMMSTATE, // 通讯状态
EN_VALUE_FLAG_ALARM, // 告警状态
EN_VALUE_FLAG_YXTYPE, // 遥信类型
EN_STR_FLAG_MENUALAUTO,
EN_STR_FLAG_LINKBREAK,
EN_STR_FLAG_DONEUNDONE,
EN_STR_FLAG_ACTBACK,
EN_STR_FLAG_RESUMEBREAK,
EN_STR_FLAG_USESTOP,
EN_STR_FLAG_BAUDRATE,
EN_STR_FLAG_VERIFY,
EN_STR_FLAG_PROTOL,
EN_STR_FLAG_RECORD,
EN_STR_FLAG_MESSAGE,
EN_STR_FLAG_COM,
EN_STR_FLAG_MODE,
EN_STR_FLAG_COMBAUD,
EN_STR_FLAG_DATABIT,
EN_STR_FLAG_STOPBIT,
EN_STR_FLAG_COMTYPE,
EN_STR_FLAG_SAMEV,
EN_STR_FLAG_PT,
EN_STR_FLAG_CT,
EN_STR_FLAG_TRANSTYPE,
EN_STR_FLAG_LINEPHS,
EN_STR_FLAG_RETOUT,
EN_STR_FLAG_YXDI,
EN_STR_FLAG_YKPUL,
EN_STR_FLAG_WAVE,
EN_STR_FLAG_MEMTYPE,
EN_STR_FLAG_CHANNEL,
EN_STR_FLAG_POWERTYPE,
EN_STR_FLAG_ZEROTYPE,
EN_STR_FLAG_YCCOMMTYPE,
EN_STR_FLAG_YXCOMMTYPE,
EN_STR_FLAG_CTRLWORD,
EN_STR_FLAG_BUSNAME,
EN_STR_FLAG_UNITSHOWMODE,
EN_STR_FLAG_BAYMODE,
EN_STR_FLAG_BASEANA,
EN_STR_FLAG_BASEPHASE,
EN_STR_FLAG_BAYCODE,
EN_STR_FLAG_SET_NUM,
EN_STR_FLAG_DCTYPE,
EN_STR_FLAG_DCINTYPE,
EN_STR_FLAG_DWINTYPE,
EN_STR_FLAG_PTCT,
EN_STR_FLAG_HARMOTYPE,
EN_STR_FLAG_YXSIN_DI, //设置双点遥信
EN_STR_FLAG_SHOWANATYPE,
EN_STR_FLAG_ANAPOLARTYPE, // 交流通道极性
EN_STR_FLAG_WIRDIAGRAMTYPE // 增加主接线图类型识别.modified by zhanggl 111010
} enumStrType;
// 主菜单定义
//============================================================
// byMenuClass; 菜单分级标志(最大级数不能超过3级);
// byName[50]; 菜单字符串;
// byTip[36]; 菜单提示文本;
// byAttrib; 菜单属性,设置菜单特殊显示效果;
// wPassword; 访问密码0x0000表示没有密码;
// wPara; 菜单执行函数参数;
// pfnWinProc; 界面执行函数指针;
// 如果CN_HAVE_HIDE_MENU 为 TRUE 0 级菜单的最后一组菜单为隐藏菜单
//===========================================================
const tagMenuModel g_tMenuModelTab[] =
{
{ 0, " ", "", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 1, "装置信息", "查看装置信息", 0, 0x0000, EN_ANA_0, (FUNCPTR)MenuProc_See_AppInfo },
{ 1, "实时数据", "装置实时数据", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "交流量", "查看遥测交流量", EN_MEA_AC, 0x0000, EN_ANA_0, (FUNCPTR)MenuProc_See_YC },
{ 2, "直流量", "查看遥测直流量", EN_MEA_DC, 0x0000, EN_ANA_0, (FUNCPTR)MenuProc_See_YC },
{ 2, "遥信量", "查看遥信开入量", EN_INPUT_RLY_ALL, 0x0000, EN_INPUT_0, (FUNCPTR)MenuProc_See_Input },
{ 1, "参数定值", "保护参数查看与修改", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "整定", "整定装置保护参数", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 3, "参数", "查看设备参数定值", EN_FIGURE_SET, CN_USER_PWD, EN_SIDE_BASIC, (FUNCPTR)MenuProc_Set_Value },
{ 3, "定值", "设置装置数值定值", EN_FIGURE_SET, CN_USER_PWD, EN_SIDE_DEF, (FUNCPTR)MenuProc_Set_Value },
{ 3, "控制字", "设置装置控制字", EN_SOFT_SET, CN_USER_PWD, EN_SIDE_DEF, (FUNCPTR)MenuProc_Set_Value },
{ 3, "软压板", "设置软压板", 0, CN_USER_PWD, EN_SOFT_PRO, (FUNCPTR)MenuProc_Set_Soft },
{ 2, "查看", "查看装置保护参数", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 3, "参数", "设置设备参数定值", EN_FIGURE_SET, 0x0000, EN_SIDE_BASIC, (FUNCPTR)MenuProc_See_Set },
{ 3, "定值", "查看数值型定值", EN_FIGURE_SET, 0x0000, EN_SIDE_DEF, (FUNCPTR)MenuProc_See_Set },
{ 3, "控制字", "查看控制字定值", EN_SOFT_SET, 0x0000, EN_SIDE_DEF, (FUNCPTR)MenuProc_See_Set },
{ 3, "软压板", "查看软压板", 0, 0x0000, EN_SOFT_PRO, (FUNCPTR)MenuProc_See_Soft },
{ 1, "三遥设置", "", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "遥测死区", "设置遥测量死区门槛", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_YC_SetSqValue },
{ 2, "遥测系数", "设置遥测量微调系数", EN_MEA_ADJ, CN_USER_PWD, 0, (FUNCPTR)MenuProc_YC_SetAdjCoe },
{ 2, "遥信类型", "设置遥信类型", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_YX_SetCommType },
{ 2, "遥信防抖", "设置遥信防抖时间", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_YX_SetWidth },
{ 2, "双点遥信", "设置双点遥信虚端子", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_YX_SetTwin },
{ 1, "装置维护", "", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "时钟设置", "设置系统时钟", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_Time },
{ 2, "强制复归", "可复归未返回事件", EN_REV_FORCE, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_RevEvent },
{ 2, "手动录波", "启动手动录波", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_ManualWave },
{ 2, "清除记录", "", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_ClrRec },
{ 1, "通讯参数", "", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "通讯设置", "外部通讯设置", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_ComPara },
{ 2, "网口设置", "", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_EditIP },
{ 2, "SNTP设置", "", 0, CN_USER_PWD, 0, (FUNCPTR)MenuProc_Cfg_EditSntp },
{ 1, "记录查询", "查看各种装置记录", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "SOE记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecSOE },
{ 2, "事故记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecAct },
{ 2, "操作记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecOpt },
{ 2, "保护告警", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecAlm },
{ 2, "保护启动", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecStart },
{ 2, "遥控记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecYK },
{ 2, "自检记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecChk },
{ 2, "运行记录", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecRun },
{ 2, "运行报告", "", 0, 0x0000, 0, (FUNCPTR)MenuProc_See_RecFault },
{ 0, "厂家设置", "设置装置相关参数", 0, CN_COP_PWD, 0, (FUNCPTR)Menu_NonPfunc },
{ 1, "元件配置", "配置元件配置", 0, CN_COP_PWD, EN_FACTORY_PASSWORD,(FUNCPTR)MenuProc_Cfg_CellConf },
{ 1, "恢复默认", "恢复默认元件定值参数", 0, CN_COP_PWD, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "全部恢复", "全部参数恢复默认", 0, CN_COP_PWD, EN_NO_USER_PWD, (FUNCPTR)MenuProc_AllInf_Default },
{ 2, "默认参数", "当前参数恢复默认", 0, CN_COP_PWD, EN_NO_USER_PWD, (FUNCPTR)MenuProc_Para_Default },
{ 2, "默认定值", "当前定值区恢复默认", 0, CN_COP_PWD, EN_NO_USER_PWD, (FUNCPTR)MenuProc_Set_Default },
{ 2, "软压板", "当前软压板恢复默认", 0, CN_COP_PWD, EN_NO_USER_PWD, (FUNCPTR)MenuProc_Resume_Soft },
{ 2, "元件配置", "元件配置恢复默认", 0, CN_COP_PWD, EN_NO_USER_PWD, (FUNCPTR)MenuProc_Cfg_CellDef },
{ 1, "交流显示", "交流显示方式设置", 0, CN_COP_PWD, 0, (FUNCPTR)MenuProc_Cfg_ShowAnaType },
{ 1, "装置调试", "调试装置", 0, 0x0000, 0, (FUNCPTR)Menu_NonPfunc },
{ 2, "虚拟遥信", "设置虚拟遥信值", 0, CN_COP_PWD, 0, (FUNCPTR)MenuProc_Dbg_XuYX },
{ 2, "交流虚遥测", "设置虚拟交流遥测值", EN_MEA_AC, CN_COP_PWD, EN_ANA_0, (FUNCPTR)MenuProc_Dbg_XuYC },
{ 2, "直流虚遥测", "设置虚拟直流遥测值", EN_MEA_DC, CN_COP_PWD, EN_ANA_0, (FUNCPTR)MenuProc_Dbg_XuYC },
{ 2, "电度虚遥测", "设置虚拟电度遥测值", EN_MEA_POWER, CN_COP_PWD, EN_ANA_0, (FUNCPTR)MenuProc_Dbg_XuYC },
{ 2, "动作虚事件", "设置虚拟动作事件", EN_ACT_REC, CN_COP_PWD, 0, (FUNCPTR)MenuProc_Dbg_XuEvent },
{ 2, "告警虚事件", "设置虚拟告警事件", EN_ALM_REC, CN_COP_PWD, 0, (FUNCPTR)MenuProc_Dbg_XuEvent },
{ 2, "动作出口", "进入此菜单保护退出", EN_OUTPUT_TRIP, CN_COP_PWD, EN_INPUT_0, (FUNCPTR)MenuProc_Dbg_Relay },
{ 2, "信号出口", "进入此菜单保护退出", EN_OUTPUT_SIGN, CN_COP_PWD, 0, (FUNCPTR)MenuProc_Dbg_Relay },
{ 1, "版本信息", "查看板件版本信息", 0, CN_COP_PWD, 0, (FUNCPTR)MenuProc_See_VersionBoard },
};

174
src/Drv/display.h Normal file
View File

@@ -0,0 +1,174 @@
#ifndef __DISPLAY__H__
#define __DISPLAY__H__
#include "../../include/types.h"
// 菜单常量表定义
typedef struct
{
uint8_t byClass; // 菜单分级标志;
uint8_t byName[50]; // 菜单字符串;
uint8_t byTip[50]; // 菜单提示文本;
uint8_t byAttrib; // 菜单属性,设置菜单特殊显示效果;
uint16_t wPassword; // 访问密码0x0000表示没有密码;
uint16_t wPara; // 菜单执行函数参数;
FUNCPTR pfnWinProc; // 界面执行函数指针;
}tagMenuModel,*tagPMenuModel;
//菜单密码设置
//==============================================================================
#define CN_COP_PWD (321) // 厂家密码:可修改保护元件配置、查看内存等
#define CN_USER_PWD (700) // 用户超级密码:可用于修改普通密码、定值,预设等
#define CN_SUPER_PWD (620)
enum _REV_TYPE_ // 复归类型
{
EN_REV_FREE, // 非强制复归
EN_REV_FORCE // 强制复归
};
enum _SET_SIDE_TYPE_ // 定值类别
{
EN_SIDE_START = 0, // 备用侧
EN_SIDE_BASIC, // 基本信息
EN_SIDE_DEVINF, // 装置参数
EN_SIDE_COP, // 内部定值
EN_SIDE_MATRIX, // 内部定值 出口矩阵
EN_SIDE_ALL, // 全侧
EN_SIDE_HIGH, // 高压侧
EN_SIDE_MED1, // 中压侧
EN_SIDE_MED2, // 中压侧
EN_SIDE_LOW1, // 低压1侧
EN_SIDE_LOW2, // 低压2侧
EN_SIDE_LK, // 电抗器
EN_SIDE_Z, // Z变
EN_SIDE_DEF, // 自定义
EN_SIDE_NONE = 0xFF // 不存在
};
// ============================================================================
// Const_Soft.h 常量固定部分
// ============================================================================
// 软压板类型
enum _SOFT_TYPE_NUMBER
{
EN_SOFT_PRO = 0, // 保护功能软压板
EN_SOFT_GOOSE, // GOOSE软压板
EN_SOFT_MU, // MU软压板
EN_SOFT_SWITCH, // 刀闸强制软压板
EN_SOFT_BAK, // 备用软压板
//----------------------------------------------//
EN_SOFT_TYPE_END // 软压板类型总数目,不可改动
};
//============================================================================
//实时数据类型标志
//============================================================================
enum _MEA_TYPE_{
//保护交流量
EN_MEA_RLY, // 保护交流量1
EN_MEA_RLY2, // 保护交流量2
EN_MEA_RLY3, // 保护交流量3
EN_MEA_ANA, // 保护测量量1
EN_MEA_ANA2, // 保护测量量2
EN_MEA_ANA3, // 保护测量量3
//遥测
EN_MEA_AC, // 遥测交流量
EN_MEA_DC, // 保护直流量
EN_MEA_SYN, // 保护谐波量
EN_MEA_POWER, // 保护电能量
EN_MEA_DD, // 电度量
EN_MEA_JLYC,
EN_MEA_GEAR, // 保护档位量
EN_MEA_TQ, // 保护同期量
EN_MEA_INPUT1, // 保护交流量1
EN_MEA_INPUT2, // 保护交流量2
EN_MEA_INPUT3, // 保护交流量3
EN_INPUT_RLY_ALL, //开入加遥信
EN_INPUT_RLY_FAULT,
EN_INPUT_RLY_OTHER,
EN_INPUT_BS_ALL,
EN_INPUT_BS_FAULT,
EN_INPUT_BS_OTHER,
EN_MEA_ADJ, // 遥测微调系数
EN_MEA_YX, // 遥信状态
EN_OUTPUT_TRIP, // 保护出口调试
EN_OUTPUT_SIGN, // 信号出口调试
EN_MEA_LS, // 联锁信号.zhanggl
EN_MEA_SCRLY // 顺控配置信号.zhanggl
};
enum _INDEX_VALUE_TYPE_{
EN_SOFT_SET,
EN_FIGURE_SET
};
//==============================================================================
// 菜单常量表相关常量
//============================================================================
//交流量菜单对应wParameter执行菜单参数应用于菜单常量表
//============================================================================
enum _ANA_PARA_ {
EN_ANA_0 = 1,
EN_ANA_1
};
//============================================================================
//开入量菜单对应wParameter执行菜单参数应用于菜单常量表
//============================================================================
enum _INPUT_PARA_ {
EN_INPUT_0 = 1,
EN_INPUT_1
};
enum _ANA_TYPE_
{
EN_TYPE_DIF_CURRENT=0 ,
EN_TYPE_UNIT_CURRENT ,
EN_TYPE_UNIT_VOLTAGE
};
enum _NO_USER_PASSWORD_{
EN_NO_USER_PWD = 0x55
};
enum _FACTORY_PASSWORD_{
EN_FACTORY_PASSWORD = 0x55
};
// 记录类型
enum _REC_TYPE_
{
EN_ACT_REC = 0, // 事件记录
EN_ALM_REC, // 告警记录
EN_CHK_REC, // 自检记录
EN_SOE_REC, // SOE记录
EN_COS_REC, // COS记录
EN_LOCK_REC, // 瞬时闭锁记录
EN_OVER_REC, // 越限记录
EN_START_REC, // 启动记录
EN_RUN_REC, // 运行记录
EN_INPUT_REC, // 开入变位记录
EN_ONOFF_REC, // 保护投退记录
EN_OPT_REC, // 保护操作记录
EN_YK_REC, // 保护遥控记录
EN_SC_REC, // 装置顺控记录
EN_SCSTEPINFO_REC, // 装置顺控单步记录
EN_FAULT_REC, // 事故报告记录
EN_ACTWAVE_REC, // 动作录波信息记录
EN_STARTWAVE_REC, // 启动录波信息记录
EN_HANDWAVE_REC, // 手动录波信息记录
EN_FAULT_NO, // 故障序号
EN_ALL_REC = 0xFF, // 所有记录
EN_NO_REC = 0xFFFF // 无效记录
};
#endif

34
src/Drv/key.c Normal file
View File

@@ -0,0 +1,34 @@
#include "key.h"
typedef struct{ // 按键控制结构
uint8_t byUsrFlg; // 用户标志0x55标志 有显示已刷新,供远程显示用
uint8_t byKeyValid; // 有效标志 <见 _KEY_VALID_FLAG_ 定义>
uint8_t byKeyValue; // 键值
uint8_t bUseRkey; //是否启用远程按键
}tagRKeyCtrl;
tagRKeyCtrl g_tRemoteKey; //远程按键
uint8_t Key_Read()
{
uint8_t byKeyTmp;
byKeyTmp = KEY_NONE;
if(EN_KEY_FLAG_NEW == g_tRemoteKey.byKeyValid )
{
byKeyTmp = g_tRemoteKey.byKeyValue;
g_tRemoteKey.byKeyValid = EN_KEY_FLAG_NULL;
}
return byKeyTmp;
}

31
src/Drv/key.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef __KEY_H__
#define __KEY_H__
#include "../../include/types.h"
#define KEY_U (0x02) // 上 32
#define KEY_D (0x40) // 下 16
#define KEY_L (0x10) // 左 8
#define KEY_R (0x08) // 右 4
#define KEY_ENT (0x20) // 确认 1
#define KEY_ESC (0x01) // 取消 2
#define KEY_F1 (0x04) // F1
#define KEY_F2 (0x80) // F2
#define KEY_ADD (0x82)
#define KEY_SUB (0x84)
#define KEY_NONE (0) // (无)
enum _KEY_VALID_FLAG_ { // 按键是否有效标志
EN_KEY_FLAG_NULL =0, // 无新按键
EN_KEY_FLAG_NEW, // 有新按键
EN_KEY_FLAG_SAM, // 采样过程中(未确定)
};
uint8_t Key_Read();
#endif

336
src/Drv/lcd.c Normal file
View File

@@ -0,0 +1,336 @@
#include "lcd.h"
#include <string.h>
#include "ascii.h"
tagScreenControl g_tCVsr; // 当前界面结构指针
tagDspAttrib g_tDspAttrib; // 显示属性
void Lcd_Init(void)
{
/* 清空显存 */
memset(g_tCVsr.pwbyLCDMemory, 0, sizeof(g_tCVsr.pwbyLCDMemory));
/* 设置默认颜色 */
g_tCVsr.wFontColor = LCD_COLOR_WHITE;
g_tCVsr.wBackColor = LCD_COLOR_BLACK;
/* 设置默认字体 */
//g_tCVsr.pwLibHZ = (uint16_t*)HZK12;
g_tCVsr.wGBFontWidth = 14;
g_tCVsr.wGBFontHeight = 12;
/* 设置默认ASCII字体 */
g_tCVsr.pbyLibAscii = g_abyASCII126[0];
g_tCVsr.wASCIIFontWidth = 8;
g_tCVsr.wASCIIFontHeight = 12;
g_tDspAttrib.rowSpace = 2;
}
/* 填充矩形区域 */
void Lcd_FillRect(uint16_t lx, uint16_t ty, uint16_t rx, uint16_t by, uint32_t dwRGB)
{
uint16_t h, l, err; /* 行/列循环变量CheckPosi 返回值(本函数未使用) */
uint32_t dwRRGB; /* 保存进入前的字体色,用于退出时恢复 */
dwRRGB = g_tCVsr.wFontColor;
g_tCVsr.wFontColor = dwRGB;
/* 按行扫描矩形区域逐点用当前颜色绘制__Lcd_PixelFT 使用当前字体色作为像素色) */
for ( h = ty; h <= by; h++ )
{
for ( l = lx; l <= rx; l++ )
{
Lcd_SetPixel(l, h, g_tCVsr.wFontColor);
}
}
}
void Lcd_SetPixel(uint16_t x, uint16_t y, uint16_t color)
{
if (x >= LCD_SIZE_X || y >= LCD_SIZE_Y)
{
return;
}
/* 一个字节一个像素点 */
g_tCVsr.pwbyLCDMemory[y * LCD_LINE_SIZE + x] = color;
}
uint16_t Lcd_GetPixel(uint16_t x, uint16_t y)
{
if (x >= LCD_SIZE_X || y >= LCD_SIZE_Y)
{
return 0;
}
/* 一个字节一个像素点 */
return g_tCVsr.pwbyLCDMemory[y * LCD_LINE_SIZE + x];
}
//==============================================================================
// 功能说明 : 在指定屏幕坐标处显示一个 ASCII 字符
// 设计说明 : 从 ASCII 字库中取出点阵, 按当前显示属性(正显/反显、旋转 90° 与否)
// 逐点调用画点函数进行显示
// 参数说明 : byScreen - 屏幕号
// x, y - 字符左上角基准坐标(若 Rotate!=0, 实际显示会旋转 90°)
// byAscii - 要显示的 ASCII 码
// bTR - TRUE : 透明显示, 点阵为 0 时保留原背景
// FALSE : 非透明, 点阵为 0 时用背景色重绘
// 返回说明 : 0 - 正常
// -1 - Y 方向越界
// -2 - X 方向越界
//==============================================================================
inline uint16_t Lcd_Pub_Ascii(uint16_t x, uint16_t y, uint8_t byAscii)
{
uint8_t i, j;
uint8_t byLine, *pbyFontLib;
uint16_t on_color, off_color;
/* 从 ASCII 字库中取得当前字符的点阵数据首地址
每个字符占用 wASCIIFontHeight 个字节, 按行存储 */
pbyFontLib = &g_tCVsr.pbyLibAscii[byAscii * g_tCVsr.wASCIIFontHeight];
/* 边界检查:根据旋转与字符宽高判断是否越界 */
if (0 == g_tDspAttrib.Rotate) {
if ((x + g_tCVsr.wASCIIFontWidth) > LCD_SIZE_X) return (uint16_t)-2; /* X 越界 */
if ((y + g_tCVsr.wASCIIFontHeight) > LCD_SIZE_Y) return (uint16_t)-1; /* Y 越界 */
}
else
{
/* 旋转后宽高互换, 重新按宽高做边界检查 */
if ((x + g_tCVsr.wASCIIFontHeight) > LCD_SIZE_X) return (uint16_t)-2; /* X 越界 */
if ((y + 1) < g_tCVsr.wASCIIFontWidth) return (uint16_t)-1; /* Y 越界(向上旋转) */
}
/* 根据正显/反显选择“点阵为 1/0 时用的颜色” */
if (0 == g_tDspAttrib.style) {
/* 正显1 = 前景色0 = 背景色 */
on_color = g_tCVsr.wFontColor;
off_color = g_tCVsr.wBackColor;
} else {
/* 反显1 = 背景色0 = 前景色 */
on_color = g_tCVsr.wBackColor;
off_color = g_tCVsr.wFontColor;
}
for (j = 0; j < g_tCVsr.wASCIIFontHeight; j++)
{
byLine = pbyFontLib[j]; /* 第 j 行的 8bit 点阵 */
for (i = 0; i < g_tCVsr.wASCIIFontWidth; i++)
{
uint8_t bit_on = ((byLine << i) & 0x80) != 0;
uint16_t color;
uint16_t px, py;
if (bit_on)
{
color = on_color;
}
else
{
color = off_color;
}
if (0 == g_tDspAttrib.Rotate)
{
/* 不旋转: (x+i, y+j) */
px = x + i;
py = y + j;
}
else
{
/* 旋转 90°: 将 (i,j) 映射到 (x+j, y-i) */
px = x + j;
py = y - i;
}
Lcd_SetPixel(px, py, color);
}
}
return 0;
}
/**
* 从 UTF-8 字节流中解析下一个字符的 Unicode 码点,并返回该字符占用的字节数。
*
* UTF-8 编码规则简要:
* - 1 字节0xxxxxxxASCII0x00..0x7F
* - 2 字节110xxxxx 10xxxxxxU+0080..U+07FF
* - 3 字节1110xxxx 10xxxxxx 10xxxxxxU+0800..U+FFFF含常用汉字
* - 4 字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxxU+10000..,本函数不处理)
*
* @param utf8 指向当前 UTF-8 字节的指针(可含多字节序列)
* @param out_unicode 输出该字符的 Unicode 码点U+0000..U+FFFF
* @return 该字符占用的字节数 1/2/30 表示结束、无效或无法解析
*/
static int utf8_next(const unsigned char *utf8, uint32_t *out_unicode)
{
unsigned char c = utf8[0];
/* 字符串结束:'\0' 不算一个可解析字符,返回 0 表示“无更多字符” */
if (c == 0) {
*out_unicode = 0;
return 0;
}
/* -----------------------------------------------------------------------
* 1 字节ASCIIU+0000..U+007F
* 格式0xxxxxxx即 c < 0x80。码点等于该字节的数值。
* ----------------------------------------------------------------------- */
if (c < 0x80) {
*out_unicode = c;
return 1;
}
/* -----------------------------------------------------------------------
* 2 字节U+0080..U+07FF如拉丁扩展、希腊文等
* 格式:首字节 110xxxxx0xC0..0xDF),次字节 10xxxxxx0x80..0xBF)。
* 码点 = (首字节低 5 位)<<6 | (次字节低 6 位) = (c&0x1F)<<6 | (utf8[1]&0x3F)。
* ----------------------------------------------------------------------- */
if ((c & 0xE0) == 0xC0) {
if (utf8[1] == 0)
return 0; /* 首字节后无后续字节,非法 UTF-8 序列 */
*out_unicode = (uint32_t)((c & 0x1F) << 6 | (utf8[1] & 0x3F));
return 2;
}
/* -----------------------------------------------------------------------
* 3 字节U+0800..U+FFFF含常用汉字、日韩等
* 格式:首字节 1110xxxx0xE0..0xEF),后两字节均为 10xxxxxx。
* 码点 = (首字节低 4 位)<<12 | (第2字节低6位)<<6 | (第3字节低6位)。
* 例如 “你” 的 UTF-8 为 E4 BD A0 → U+4F60。
* ----------------------------------------------------------------------- */
if ((c & 0xF0) == 0xE0) {
if (utf8[1] == 0 || utf8[2] == 0)
return 0; /* 缺少第二或第三字节,非法序列 */
*out_unicode = (uint32_t)((c & 0x0F) << 12 | (utf8[1] & 0x3F) << 6 | (utf8[2] & 0x3F));
return 3;
}
/* 4 字节U+10000 及以上)或非法首字节(如 10xxxxxx 单独出现):本实现不解析 */
*out_unicode = 0;
return 0;
}
void Lcd_Pub_UTF8(uint16_t x, uint16_t y, uint32_t unicode )
{
const uint8_t *bitmap = utf8_hz12_get(unicode);
uint16_t word = 0;
if (bitmap == NULL)
return;
for (uint8_t j = 0; j < g_tCVsr.wGBFontHeight; j++)
{
word = (uint16_t)((bitmap[j*2] << 8) | bitmap[j*2+1]);
for (uint8_t i = 0; i < g_tCVsr.wGBFontWidth; i++)
{
if ((word >> (15 - i)) & 1)
{
Lcd_SetPixel(x + i, y + j, g_tCVsr.wFontColor);
}
else
{
Lcd_SetPixel(x + i, y + j, g_tCVsr.wBackColor);
}
}
}
}
/**
* 在指定坐标起逐字显示 UTF-8 字符串支持汉字UTF-8 字库、ASCII 与换行。
* 字符串以 \\0 结尾;遇换行符 0x0A 则换到下一行;本行放不下时擦除本行剩余部分。
*
* @param x, y 起始坐标(首个字符左上角)
* @param pcString UTF-8 字符串
* @return 0 成功;-1 起始 X 越界;-2 起始 Y 越界;<0 其它错误(如找不到换行导致换行失败)
*/
int8_t Lcd_ShowStr(uint16_t x, uint16_t y, uint8_t *pcString)
{
uint16_t bakx, baky; /* 当前行行首坐标,换行时 x 回到 bakx */
uint32_t unicode; /* utf8_next 解析出的当前字符码点 */
uint16_t index = 0; /* 当前字符在 pcString 中的字节下标 */
int8_t err;
bakx = x;
baky = y;
/* 起始坐标合法性:至少能放下一个 ASCII 宽、一行汉字高 */
if (x > LCD_SIZE_X - g_tCVsr.wASCIIFontWidth)
return -1;
if (y >= LCD_SIZE_Y - g_tCVsr.wGBFontHeight)
return -2;
while (pcString[index] != 0x0)
{
/* 解析当前字符n = 占用字节数1=ASCII2/3=多字节unicode = 码点 */
int n = utf8_next(pcString + index, &unicode);
if (n <= 0)
break;
/* ---------- 多字节字符如汉字n=2 或 3用 UTF-8 字库绘制 ---------- */
if (n > 1)
{
/* 本行剩余宽度放不下一个汉字:向后查找换行符并换行 */
if (x > LCD_SIZE_X - g_tCVsr.wGBFontWidth)
{
/*擦除本行剩余部分*/
for(uint16_t j = y; j < y + g_tCVsr.wGBFontHeight; j++)
{
for(uint16_t i = x; i < LCD_SIZE_X; i++)
{
Lcd_SetPixel(i, j, g_tCVsr.wBackColor);
}
}
return -1;
}
else
{
Lcd_Pub_UTF8(x, y, unicode);
x += g_tCVsr.wGBFontWidth;
}
}
/* ---------- 单字节字符ASCIIn=1 ---------- */
else
{
if (unicode == 0x0a)
{
/* 换行符x 回到行首y 下移一行高度 + 行距 */
x = bakx;
y += g_tCVsr.wGBFontHeight + g_tDspAttrib.rowSpace;
}
else
{
/* 控制字符0x00..0x0F 且非 0x0A不绘制仅跳过 */
if (unicode >= 0x10)
{
/* 本行放不下一个 ASCII 时,向后查找换行符并换行 */
if (x > LCD_SIZE_X - g_tCVsr.wASCIIFontWidth)
{
/*擦除本行剩余部分*/
for(uint16_t j = y; j < y + g_tCVsr.wASCIIFontHeight; j++)
{
for(uint16_t i = x; i < LCD_SIZE_X; i++)
{
Lcd_SetPixel(i, j, g_tCVsr.wBackColor);
}
}
return -1;
}
else
{
Lcd_Pub_Ascii(x, y, (uint8_t)unicode);
x += g_tCVsr.wASCIIFontWidth;
}
}
}
}
index += n; /* 已处理完当前字符,下标移到下一字符 */
}
return 0;
}
int8_t Lcd_ShowTest(uint16_t x, uint16_t y, uint8_t *pcString)
{
return 0;
}

55
src/Drv/lcd.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef __LCD__H__
#define __LCD__H__
#include "../../include/types.h"
/* 单色液晶屏幕 160*160
一个 byte 代表一个像素点
0xFF 代表白色
0x00 代表黑色
*/
#define LCD_SIZE_X 160
#define LCD_SIZE_Y 160
#define LCD_LINE_SIZE LCD_SIZE_X
#define LCD_DISPLAYMEMORYSIZE (LCD_SIZE_X * LCD_SIZE_Y)
#define LCD_COLOR_WHITE 0xFF
#define LCD_COLOR_BLACK 0x00
typedef struct
{
uint8_t pwbyLCDMemory[LCD_DISPLAYMEMORYSIZE]; //定义显存
uint16_t wFontColor; // 字体颜色
uint16_t wBackColor; // 字符显示背景颜色
uint16_t wGBFontWidth; // 汉字字体宽度
uint16_t wGBFontHeight; // 汉字字体高度
uint16_t wASCIIFontWidth; // 字符字体宽度
uint16_t wASCIIFontHeight; // 字符字体高度
uint16_t *pwLibHZ; // 汉字库地址
uint8_t *pbyLibAscii; // ASCII库地址
} tagScreenControl;
/* 当前界面/显存lcd.c 中定义,供 remoteDisplay 等模块读取显存) */
extern tagScreenControl g_tCVsr;
typedef struct { // 显示属性数据结构
uint16_t style:1; // 显示方式 <0=正常显示; 1=返显>
uint16_t StringDirect:1; // 字符显示方向<0=横向显示, 1=竖向显示>
uint16_t fillZero:1; // 10进制数显示前面是否补0。0=不补0,1=补0;
uint16_t Rotate:1; // 字符是否旋转显示目前只支持逆时针转90度
uint16_t res:6; // 保留
uint16_t rowSpace:4; // 行距
}tagDspAttrib, *tagPDspAttrib;
void Lcd_Init(void);
void Lcd_SetPixel(uint16_t x, uint16_t y, uint16_t color);
uint16_t Lcd_GetPixel(uint16_t x, uint16_t y);
int8_t Lcd_ShowStr(uint16_t x, uint16_t y, uint8_t *pcString);
int8_t Lcd_ShowTest(uint16_t x, uint16_t y, uint8_t *pcString);
#endif

178
src/Drv/menu.c Normal file
View File

@@ -0,0 +1,178 @@
#include "menu.h"
#include <stdio.h>
#include <string.h>
#include "lcd.h"
#include "key.h"
/* 简单的静态菜单树:
*
* 层级 0: [运行界面] [定值设置] [查看数据]
* │ │
* 层级 1: (子菜单...) (子菜单...)
*/
typedef struct _MENU_ITEM_
{
struct _MENU_ITEM_ *ptHigher; // 上级菜单指针
struct _MENU_ITEM_ *ptLower; // 下级菜单指针
struct _MENU_ITEM_ *ptBefore; // 同级上方指针
struct _MENU_ITEM_ *ptBehind; // 同级下方指针
uint8_t byClass; // 菜单分级标志;
uint8_t byName[50]; // 菜单字符串;
uint8_t byTip[50]; // 菜单提示文本;
uint8_t byAttrib; // 菜单属性,设置菜单特殊显示效果;
uint16_t wPassword; // 访问密码0x0000表示没有密码;
uint16_t wPara; // 菜单执行函数参数;
FUNCPTR pfnWinProc; // 界面执行函数指针;
uint16_t wPos; // 当前菜单位置,相对于本级菜单。
uint16_t wNum; // 下级菜单项数
uint16_t wSPosX; // 下级菜单起始坐标
uint16_t wSPosY; // 下级菜单起始坐标
uint16_t wEPosX; // 下级菜单对角坐标
uint16_t wEPosY; // 下级菜单对角坐标
}tagMenuItem,*tagPMenuItem;
// 显示控制结构
typedef struct
{
tagPMenuItem ptMenuCur; // 菜单当前指针
uint8_t byLayer; // 显示层
uint8_t bySide; // 用于显示定值侧别
uint16_t wGroup; // 最大页面数
uint16_t wPage; // 当前页面数
uint16_t wRes; // RES
uint16_t wPassword; // 输入密码
uint16_t wPara; // 菜单参数
uint16_t wItemN; // 当前菜单对应显示项数
uint16_t wPos; // 数据定位
uint16_t wBaseNo; // 相位基准(debug)
uint8_t byNumOfPage; // 每页显示项数
uint8_t byCount; // 通用计数
uint8_t byAdjustX;
uint8_t bGetSet; // 上电召定值标志
uint8_t bLightByNewRec; // 由新记录点亮背光灯.modified by zhanggl.111109
unsigned bPwdOK:1; // 密码状态
unsigned bFirst:1; // 第一次进入界面<是/否>
unsigned bChanged:1; // 数据是否被修改
unsigned bModFlag:1; // 是否处于修改状态
unsigned bEdit:1; // 重入标志
unsigned bFlash:1; // 闪烁标志
unsigned bRunLayer:1; // 运行层标志
unsigned bitOutput:1;
unsigned bShowMode:1; // F1功能键切换同轴显示模式
unsigned bShowCursor:1; // F2功能键切换游标显示模式
unsigned bRes:1;
}tagDspCtrl,*tagPDspCtrl;
tagDspCtrl g_tDspCtrl; // 显示控制全局结构
static MenuItem g_menuRun;
static MenuItem g_menuSet;
static MenuItem g_menuSee;
static MenuItem g_menuSet1;
static MenuItem g_menuSet2;
void Menu_Init()
{
Lcd_Init();
/* 初始化显示控制结构 */
memset(&g_tDspCtrl, 0, sizeof(g_tDspCtrl));
}
void Menu_Show_0Level()
{
tagPMenuItem ptIndex; /* 遍历 0 级菜单链表用的指针(从表头开始依次后移) */
uint16_t wSPosX; /* 当前要显示的 0 级菜单项左上角 X 坐标(屏幕坐标) */
uint16_t wSPosY; /* 0 级菜单“下陷框”左上角 Y 坐标 */
uint16_t wEPosX; /* 0 级菜单“下陷框”右下角 X 坐标 */
uint16_t wEPosY; /* 0 级菜单“下陷框”右下角 Y 坐标 */
uint16_t wLoop; /* 循环计数:第几个 0 级菜单项(从 0 开始) */
uint8_t byName[50]; /* 临时缓冲区:存放当前 0 级菜单项名称 */
uint8_t byInterval; /* 每个 0 级菜单在 X 方向上的间隔宽度(用于平均分布) */
uint8_t byLeftMove; /* 当前 0 级菜单整体向左平移的像素数(超出一屏时产生“滚动”效果) */
uint8_t by0LevelNum; /* 实际参与显示的 0 级菜单个数(是否显示“隐藏/显示”项会影响个数) */
Lcd_ShowStr(16, 20, (uint8_t*)"你好!\nabcsadfasdfasdfsdfasdf"); /* 你好! */
}
void MenuProc_See_AppInfo()
{
printf("MenuProc_See_AppInfo\n");
}
void MenuProc_See_YC()
{
printf("MenuProc_See_YC\n");
}
void MenuProc_Set_Value()
{
printf("MenuProc_Set_Value\n");
}
void MenuProc_Set_Soft()
{
printf("MenuProc_Set_Soft\n");
}
void MenuProc_Cfg_Time()
{
printf("MenuProc_Cfg_Time\n");
}
void MenuProc_Cfg_RevEvent()
{
printf("MenuProc_Cfg_RevEvent\n");
}
void MenuProc_Cfg_ManualWave()
{
printf("MenuProc_Cfg_ManualWave\n");
}
void MenuProc_See_Input()
{
printf("MenuProc_See_Input\n");
}
void MenuProc_See_Set()
{
printf("MenuProc_See_Set\n");
}
void MenuProc_See_Soft()
{
printf("MenuProc_See_Soft\n");
}
void MenuProc_YX_SetCommType()
{
printf("MenuProc_YX_SetCommType\n");
}
void MenuProc_YX_SetWidth()
{
printf("MenuProc_YX_SetWidth\n");
}
void MenuProc_YX_SetTwin()
{
printf("MenuProc_YX_SetTwin\n");
}
int Menu_MapKey(int ch)
{
if (ch == 'w' || ch == 'W') return KEY_U;
if (ch == 's' || ch == 'S') return KEY_D;
if (ch == 'a' || ch == 'A') return KEY_L;
if (ch == 'd' || ch == 'D') return KEY_R;
if (ch == '\r' || ch == '\n') return KEY_ENT;
if (ch == 27) return KEY_ESC; /* ESC */
return KEY_NONE;
}

89
src/Drv/menu.h Normal file
View File

@@ -0,0 +1,89 @@
#ifndef __MENU_H__
#define __MENU_H__
/*
* PC 端菜单模拟环境
*
* 目标:
* - 用纯 C 语言在控制台模拟嵌入式 HMI 的菜单逻辑
* - 键值映射W/S/A/D/Enter/Esc → 上/下/左/右/确认/退出
* - 结构设计尽量贴近原工程的 g_tMenuCtrl / Menu_Route / Menu_Show_Proc
*/
#include <stdint.h>
typedef struct MenuItem MenuItem;
struct MenuItem {
const char *name; /* 菜单名称 */
const char *tip; /* 底部提示信息 */
MenuItem *higher; /* 上级菜单 */
MenuItem *lower; /* 下级第一个菜单 */
MenuItem *before; /* 同级上一个 */
MenuItem *behind; /* 同级下一个 */
uint8_t level; /* 菜单级别0/1/2/... */
uint8_t pos; /* 在同级菜单中的序号(从 0 开始) */
};
typedef struct {
MenuItem *head0; /* 0 级菜单头结点 */
MenuItem *current; /* 当前选中的菜单结点 */
} MenuCtrl;
/* 初始化一棵简单的测试菜单树 */
void Menu_Init();
void Menu_Show_0Level();
/* 非功能键处理 */
void Menu_NonPfunc();
void MenuProc_AllInf_Default();
void MenuProc_Para_Default();
void MenuProc_Set_Default();
void MenuProc_Resume_Soft();
void MenuProc_Cfg_CellDef();
void MenuProc_Cfg_ShowAnaType();
void MenuProc_Dbg_XuYX();
void MenuProc_Dbg_XuYC();
void MenuProc_Dbg_XuEvent();
void MenuProc_Dbg_Relay();
void MenuProc_See_VersionBoard();
void MenuProc_See_AppInfo();
void MenuProc_Set_Value();
void MenuProc_Set_Soft();
void MenuProc_Cfg_Time();
void MenuProc_Cfg_RevEvent();
void MenuProc_Cfg_ManualWave();
void MenuProc_Cfg_ClrRec();
void MenuProc_Cfg_ComPara();
void MenuProc_Cfg_EditIP();
void MenuProc_Cfg_EditSntp();
void MenuProc_Cfg_CellConf();
void MenuProc_See_RecSOE();
void MenuProc_See_RecAct();
void MenuProc_See_RecOpt();
void MenuProc_See_RecAlm();
void MenuProc_See_RecStart();
void MenuProc_See_RecYK();
void MenuProc_See_RecChk();
void MenuProc_See_RecRun();
void MenuProc_See_RecFault();
void MenuProc_See_YC();
void MenuProc_See_Input();
void MenuProc_See_Set();
void MenuProc_See_Soft();
void MenuProc_YC_SetSqValue();
void MenuProc_YC_SetAdjCoe();
void MenuProc_YX_SetCommType();
void MenuProc_YX_SetWidth();
void MenuProc_YX_SetTwin();
#endif