Files
DTU-LCD/Drivers/BSP/160160D/160160D.C

1833 lines
70 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************************************************************
* @file 160160D.C
* @brief UC1698U控制器驱动的 160x160 像素 LCD 显示屏驱动文件
* @details 本文件实现了基于 UC1698U 控制器的 160x160 像素彩色 LCD 显示屏的底层驱动功能,
* 包括初始化、显示控制、字符显示、图形显示等功能。
* @author 阜阳师范大学物电学院
* @version V0.1
* @date 2026.1.19
* @note 控制器: UC1698U
* 显示屏: 160x160像素
* 段地址: SEG112~SEG271
* 外部MPU晶振: 20MHz
******************************************************************************/
#include "160160D.h"
#include "GraphicsLibrary.h"
#include "ChineseLibraryCrossWise12x12.h"
#include "math.h"
#include <string.h>
#include <stdio.h>
/* ============================================================================
* LCD偏置电压配置宏定义
* ============================================================================ */
#define LCD_MTPM_MAX 31 /**< MTP多次可编程最大值 */
#define LCD_PM_NORMAL 190 /**< 正常偏置电压值 */
#define LCD_PM_MAX (LCD_PM_NORMAL + LCD_MTPM_MAX) /**< 最大偏置电压值 */
#define LCD_PM_MIN (LCD_PM_NORMAL - LCD_MTPM_MAX) /**< 最小偏置电压值 */
/* ============================================================================
* 颜色模式配置宏定义
* ============================================================================ */
#define COLOR_64K_565 0x02 /**< 64K色模式RGB565格式 */
#define COLOR_4K_444 0x01 /**< 4K色模式RGB444格式 */
/** @brief 设置颜色模式
* @param n 颜色模式值0x01=4K色0x02=64K色
*/
#define set_color_mode(n) do{WriteCMD(0xD4 | ((n) & 0x03));}while(0)
/* ============================================================================
* 功能宏定义
* ============================================================================ */
/** @brief 设置偏置电压电位器
* @param n 偏置电压值0-255
*/
#define set_vbias_potentiometer(n) do{WriteCMD(0x81); WriteCMD((n));}while(0)
/* ============================================================================
* UC1698U控制器寄存器命令定义
* ============================================================================ */
#define UC1698U_CAL (0x00) /**< 列地址低4位Column Address Low */
#define UC1698U_CAM (0x10) /**< 列地址高3位Column Address Middle */
#define UC1698U_WA /**< 窗口地址Window Address未定义值 */
#define UC1698U_TC (0x24) /**< 温度补偿控制Temp. Compensation低2位有效 */
#define UC1698U_PC (0x28) /**< 电源控制Power Control低2位有效 */
#define UC1698U_SLL (0x40) /**< 滚动行低4位Scroll Line Low */
#define UC1698U_SLM (0x50) /**< 滚动行高4位Scroll Line Middle */
#define UC1698U_RAL (0x60) /**< 行地址低4位Row Address Low */
#define UC1698U_RAM (0x70) /**< 行地址高4位Row Address Middle */
#define UC1698U_PM (0x81) /**< 偏置电压电位器Vbias Potentiometer */
#define UC1698U_LC8 (0x84) /**< 部分显示控制Partial Display Control低1位有效 */
#define UC1698U_AC20 (0x88) /**< RAM地址控制RAM Address Control低3位有效 */
#define CURSOR_R (0x01) /**< 光标方向向右Cursor Right */
#define CURSOR_D (0x03) /**< 光标方向向下Cursor Down */
#define CURSOR_U (0x07) /**< 光标方向向上Cursor Up */
#define UC1698U_FLT_FLB (0x90) /**< 固定行设置Fixed Lines Top/Bottom */
#define UC1698U_LC43 (0xA0) /**< 行速率控制Line Rate低2位有效 */
#define UC1698U_DC1 (0xA4) /**< 全像素开启All-Pixel-ON低1位有效 */
#define UC1698U_DC0 (0xA6) /**< 反色显示控制Inverse Display低1位有效 */
#define UC1698U_DC42 (0xA8) /**< 显示使能控制Display Enable低3位有效 */
#define UC1698U_LC20 (0xC0) /**< LCD映射控制LCD Mapping Control低3位有效 */
#define UC1698U_NIV (0xC8) /**< N线反转N-Line Inversion */
#define UC1698U_LC5 (0xD0) /**< 颜色模式Color Pattern低1位有效 */
#define UC1698U_LC76 (0xD4) /**< 颜色模式选择Color Mode低2位有效 */
#define UC1698U_CSF20 (0xD8) /**< COM扫描功能COM Scan Function低3位有效 */
#define UC1698U_RST (0xE2) /**< 复位命令RESET */
#define UC1698U_NOP (0xE3) /**< 空操作NOP - No Operation */
#define UC1698U_BR10 (0xE8) /**< LCD偏置比率LCD Bias Ratio低2位有效 */
#define UC1698U_CEN60 (0xF1) /**< COM结束地址COM End */
#define UC1698U_DST60 (0xF2) /**< 部分显示起始地址Partial Display Start */
#define UC1698U_DEN60 (0xF3) /**< 部分显示结束地址Partial Display End */
#define UC1698U_WPC0 (0xF4) /**< 窗口程序起始列地址Window Program Starting Column Address */
#define UC1698U_WPP0 (0xF5) /**< 窗口程序起始行地址Window Program Starting Row Address */
#define UC1698U_WPC1 (0xF6) /**< 窗口程序结束列地址Window Program Ending Column Address */
#define UC1698U_WPP1 (0xF7) /**< 窗口程序结束行地址Window Program Ending Row Address */
#define UC1698U_AC3 (0xF8) /**< 窗口程序控制Window Program低1位有效 */
#define UC1698U_MTPC40 (0xB8) /**< MTP操作控制MTP Operation Control */
#define UC1698U_MTPM (0xB9) /**< MTP写掩码MTP Write Mask */
/* ============================================================================
* MTP多次可编程相关寄存器定义
* ============================================================================ */
#define UC1698U_MTP1 (0xF4) /**< MTP1电位器Vmtp1 Potentiometer */
#define UC1698U_MTP2 (0xF5) /**< MTP2电位器Vmtp2 Potentiometer */
#define UC1698U_MTP3 (0xF6) /**< MTP写定时器MTP Write Timer */
#define UC1698U_MTP4 (0xF7) /**< MTP读定时器MTP Read Timer */
/* ============================================================================
* GPIO控制宏定义硬件接口层
* 注意:以下宏定义中部分引脚的高低电平设置可能存在问题,需要根据实际硬件连接进行修正
* ============================================================================ */
/** @brief 设置CDCommand/Data引脚为高电平
* @note CD引脚用于区分命令和数据高电平=数据,低电平=命令
*/
#define UC1698U_CD_H() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_SET);}while(0)
/** @brief 设置CDCommand/Data引脚为低电平 */
#define UC1698U_CD_L() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_PIN_RESET);}while(0)
/** @brief 设置WRWrite写信号引脚为高电平 */
#define UC1698U_WR_H() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);}while(0)
/** @brief 设置WRWrite写信号引脚为低电平 */
#define UC1698U_WR_L() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET);}while(0)
/** @brief 设置RDRead读信号引脚为高电平 */
#define UC1698U_RD_H() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);}while(0)
/** @brief 设置RDRead读信号引脚为低电平 */
#define UC1698U_RD_L() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);}while(0)
/** @brief 设置CSChip Select片选引脚为高电平取消选中 */
#define UC1698U_CS_H() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);}while(0)
/** @brief 设置CSChip Select片选引脚为低电平选中芯片 */
#define UC1698U_CS_L() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);}while(0)
/** @brief 设置RSTReset复位引脚为高电平正常工作 */
#define UC1698U_RST_H() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);}while(0)
/** @brief 设置RSTReset复位引脚为低电平复位状态 */
#define UC1698U_RST_L() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);}while(0)
/** @brief 设置背光引脚为关闭 */
#define LCD_BackLight_OFF() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);}while(0)
/** @brief 设置背光引脚为打开 */
#define LCD_BackLight_ON() do{HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}while(0)
volatile static uint32_t BackLightCount = 0;
#define BackLightTimeMax (20000) /* 100s */
/**
* @brief 背光处理函数
* @note 背光超时,关闭背光
* @retval 无
*/
void BackLight_Close(void)
{
BackLightCount++;
if(BackLightCount >= BackLightTimeMax)
{
BackLightCount = BackLightTimeMax; //防止参数溢出
LCD_BackLight_OFF();
}
}
/**
* @brief 背光处理函数
* @note 开启背光,重置背光计时
* @retval 无
*/
void BackLight_ON(void)
{
LCD_BackLight_ON();
BackLightCount = 0;
}
/* ============================================================================
* 底层硬件接口函数
* ============================================================================ */
/**
* @brief 向LCD屏幕写入8位数据
* @param Data 要写入的8位数据0x00-0xFF
* @note 硬件连接使用了PE8-PE15即GPIOE数据线的高8位
* 此函数直接操作GPIOE的ODR寄存器保留低8位不变更新高8位
* @retval 无
*/
static void UC1698U_Write(uint8_t Data)
{
uint16_t itmp = 0;
/* 读取ODR寄存器的低8位保留原有值 */
itmp = GPIOE->ODR & 0xFF;
/* 将数据写入ODR寄存器的高8位PE8-PE15 */
GPIOE->ODR = (Data<<8) | itmp;
}
/**
* @brief 向LCD控制器写入命令
* @param data 要写入的命令字节
* @note 命令写入时序:
* 1. 设置CD为低电平表示命令
* 2. 设置RD为高电平读禁止
* 3. 写入数据
* 4. 拉低CS片选有效
* 5. 拉低WR写有效
* 6. 拉高WR写完成
* 7. 拉高CS片选无效
* @retval 无
*/
static void WriteCMD(uint8_t data)
{
UC1698U_CD_L(); /* 设置为命令模式 */
UC1698U_RD_H(); /* 禁止读操作 */
UC1698U_Write(data); /* 写入命令数据 */
UC1698U_CS_L(); /* 片选有效 */
UC1698U_WR_L(); /* 写信号有效 */
UC1698U_WR_H(); /* 写信号无效,完成写入 */
UC1698U_CS_H(); /* 片选无效 */
}
/**
* @brief 向 LCD 控制器写入显示数据
* @param data 要写入的数据字节
* @note 数据写入时序与命令写入类似,但 CD 引脚设置为高电平(表示数据)
* @retval 无
*/
static void WriteData(uint8_t data)
{
UC1698U_CD_H(); /* 设置为数据模式 */
UC1698U_RD_H(); /* 禁止读操作 */
UC1698U_Write(data); /* 写入显示数据 */
UC1698U_CS_L(); /* 片选有效 */
UC1698U_WR_L(); /* 写信号有效 */
UC1698U_WR_H(); /* 写信号无效,完成写入 */
UC1698U_CS_H(); /* 片选无效 */
}
/**
* @brief LCD硬件复位函数
* @note 复位时序:
* 1. 拉高RST引脚确保初始状态
* 2. 延时10ms
* 3. 拉低RST引脚复位有效
* 4. 延时2ms复位保持时间
* 5. 拉高RST引脚复位释放
* 6. 延时150ms等待芯片稳定
* @retval 无
*/
void LCD_Reset(void)
{
UC1698U_RST_H(); /* 复位引脚拉高 */
delay_ms(10); /* 延时10ms */
UC1698U_RST_L(); /* 复位引脚拉低,开始复位 */
delay_ms(2); /* 复位保持时间2ms */
UC1698U_RST_H(); /* 复位引脚拉高,复位完成 */
delay_ms(150); /* 等待芯片稳定150ms */
}
/**
* @brief LCD初始化函数XRD版本黑白模式
* @note 本函数按照 UC1698U 控制器的初始化序列进行配置
* 初始化顺序:
* 1. 偏置比率设置
* 2. 电源控制设置
* 3. 温度补偿设置
* 4. 偏置电压设置
* 5. 显示控制设置
* 6. LCD控制设置
* 7. 扫描功能设置
* 8. 窗口显示区域设置
* 9. RAM 地址控制设置
* 10. 显示使能
* 11. 滚动行设置
* 12. 固定行设置
* 13. 部分显示设置
* 14. COM结束地址设置
* @retval 无
*/
void LCD_InitXRD(void)
{
/* ========== 偏置和电源控制 ========== */
WriteCMD(UC1698U_BR10 | 0x01); /* 设置偏置比率为1/10 */
WriteCMD(UC1698U_PC | 0x03); /* 设置电源控制内部Vlcd */
WriteCMD(UC1698U_TC | 0x00); /* 设置温度补偿为0.15% */
WriteCMD(UC1698U_PM); /* 设置电子电位器命令 */
WriteCMD(190); /* 设置偏置电压值为190正常值 */
/* ========== 显示控制 ========== */
WriteCMD(UC1698U_DC1 | 0x00); /* 所有像素关闭 */
WriteCMD(UC1698U_DC0 | 0x00); /* 反色显示关闭 */
/* ========== LCD控制 ========== */
WriteCMD(UC1698U_LC20 | 0x00); /* 部分显示和MX禁用MY使能 */
WriteCMD(UC1698U_LC43 | 0x03); /* 设置行速率为15.2klps */
WriteCMD(UC1698U_LC5 | 0x01); /* 设置颜色模式为RGB-RGB */
WriteCMD(UC1698U_LC76 | 0x01); /* 设置颜色模式为4K色模式 */
/* ========== 扫描功能 ========== */
WriteCMD(UC1698U_CSF20 | 0x02); /* 使能FRC、PWM、LRM序列 */
/* ========== 窗口显示区域设置 ========== */
/* 说明:列和行设置固定显示区域
* 当AC[0]=1, AC[1]=0时自动换行列优先
* 列自动递增将在结束地址后重新开始
*/
WriteCMD(UC1698U_WPC0); /* 窗口程序起始列地址 */
WriteCMD(37); /* 列起始地址37硬件偏移 */
WriteCMD(UC1698U_WPC1); /* 窗口程序结束列地址 */
WriteCMD(90); /* 列结束地址90总长53160*160X寻址以3位为单位 */
WriteCMD(UC1698U_WPP0); /* 窗口程序起始行地址 */
WriteCMD(0x00); /* 行起始地址0 */
WriteCMD(UC1698U_WPP1); /* 窗口程序结束行地址 */
WriteCMD(159); /* 行结束地址159共160行 */
WriteCMD(UC1698U_AC3 | 0x00); /* 窗口程序模式:内部模式 */
WriteCMD(UC1698U_AC20 | CURSOR_R); /* RAM 地址控制X自动加1加满到53则回0同时Y加1 */
WriteCMD(UC1698U_DC42 | 0x05); /* 显示开启,选择开/关模式,绿色增强模式禁用 */
/* ========== 滚动行设置 ========== */
WriteCMD(UC1698U_SLL | 0x00); /* 滚动行低4位 */
WriteCMD(UC1698U_SLM | 0x00); /* 滚动行高4位 */
WriteCMD(UC1698U_LC20 | 0x04); /* 使能FLT和FLB固定行顶部和底部 */
WriteCMD(UC1698U_FLT_FLB); /* 设置FLT和FLB设置屏幕固定区域大小配合图像动态显示的命令 */
WriteCMD(0xFF); /* 固定行数据 */
/* ========== 部分显示设置 ========== */
WriteCMD(UC1698U_LC8 | 0x00); /* 设置部分显示控制关闭DST/DEN不使用 */
WriteCMD(UC1698U_CEN60); /* COM结束地址命令 */
WriteCMD(0x9F); /* COM结束地址1590x9F */
}
/**
* @brief 设置 LCD 显示地址(行列坐标)
* @param x 行地址X坐标0-53实际显示时会加37偏移
* @param y 列地址Y坐标0-159
* @note X 坐标会自动加上 37 的偏移量(可能是硬件布局导致的)
* 地址设置分为低4位和高位两部分分别写入
* @retval 无
*/
static void SetAddress(uint8_t x, uint8_t y)
{
/* X 坐标偏移 37可能是硬件布局要求 */
x += 37;
/* 设置行地址:低 4 位 */
WriteCMD(UC1698U_CAL | (x & 0x0F));
/* 设置行地址:高 3 位(右移 4 位后取低 3 位) */
WriteCMD(UC1698U_CAM | ((x >> 4) & 0x07));
/* 设置列地址低4位 */
WriteCMD(UC1698U_RAL | (y & 0x0F));
/* 设置列地址高4位右移4位后取低4位 */
WriteCMD(UC1698U_RAM | ((y >> 4) & 0x0F));
}
/* ============================================================================
* 像素数据写入函数(支持不同位宽)
* ============================================================================ */
/**
* @brief 写入 6 位数据到指定坐标,也就是写入 6 个像素点
* @param x 列坐标X 坐标)
* @param y 行坐标Y 坐标)
* @param byte 要写入的8位数据只使用高6位
* @note 将 8 位数据的高 6 位转换为 4K 色模式写入
* 写入数据:| D7 D6 D5 D4 | D3 D2 D1 D0 |
* └ 第一个像素 ┘ └ 第二个像素 ┘
* 写入数据:| D7 D6 D5 D4 | D3 D2 D1 D0 |
* └ 第三个像素 ┘ └ 第四个像素 ┘
* 写入数据:| D7 D6 D5 D4 | D3 D2 D1 D0 |
* └ 第五个像素 ┘ └ 第六个像素 ┘
* @retval 无
*/
static void write_6bit(uint8_t x, uint8_t y, uint8_t byte)
{
/* 4K 色模式下的像素值映射表,每个 bytes 需要映射 2 个 bit 的数据*/
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff};
SetAddress(x, y);
/* 写入高2位bit7-6对应的像素值 */
WriteData(disp_point[((byte>>6) & 0x03)]);
/* 写入中间2位bit5-4对应的像素值 */
WriteData(disp_point[((byte>>4) & 0x03)]);
/* 写入低2位bit3-2对应的像素值 */
WriteData(disp_point[((byte>>2) & 0x03)]);
}
/**
* @brief 写入 3 位数据到指定坐标
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param byte 要写入的 8 位数据(只使用高 3 位)
* @note 将 8 位数据的高 3 位转换为 4K 色模式写入
* @retval 无
*/
static void write_3bit(uint8_t x, uint8_t y, uint8_t byte)
{
/* 4K 色模式下的像素值映射表,每个 bytes 需要映射 2 个 bit 的数据*/
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff};
SetAddress(x, y);
/* 写入高 2 位bit7-6对应的像素值 */
WriteData(disp_point[((byte>>6) & 0x03)]);
/* 写入 bit5 对应的像素值左移1位后映射*/
WriteData(disp_point[((byte>>5) & 0x01) << 1]);
/* 写入黑色像素(补齐) */
WriteData(disp_point[0]);
}
/**
* @brief 写入 8 位数据到指定坐标
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param byte 要写入的 8 位数据
* @param Flag 标志位SET=反显补齐0xFFRESET=正常显示补齐0x00
* @note 将 8 位数据转换为 4K 色模式
* 每个字节对应4个像素点最后补齐一个4位数据
* @retval 无
*/
static void writebyte(uint8_t x, uint8_t y, uint8_t byte, FlagStatus Flag)
{
/* 4K色模式下的像素值映射表 */
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff};
SetAddress(x, y);
/* 写入高2位bit7-6对应的像素值 */
WriteData(disp_point[((byte>>6) & 0x03)]);
/* 写入中间高2位bit5-4对应的像素值 */
WriteData(disp_point[((byte>>4) & 0x03)]);
/* 写入中间低2位bit3-2对应的像素值 */
WriteData(disp_point[((byte>>2) & 0x03)]);
/* 写入低2位bit1-0对应的像素值 */
WriteData(disp_point[((byte>>0) & 0x03)]);
/* 根据标志位补齐最后一个4位数据 */
if(Flag)
WriteData(0xFF); /* 反显模式:补齐白色 */
else
WriteData(0x00); /* 正常模式:补齐黑色 */
}
/**
* @brief 写入12位数据到指定坐标
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param bytes 要写入的16位数据只使用高12位
* @note 将16位数据的高12位转换为4K色模式2位/像素)写入
* 每个12位数据对应6个像素点
* @retval 无
*/
static void write_12bit(uint8_t x, uint8_t y, uint16_t bytes)
{
/* 4K色模式下的像素值映射表 */
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff};
SetAddress(x, y);
/* 写入bit15-14对应的像素值 */
WriteData(disp_point[((bytes>>0x0E) & 0x03)]);
/* 写入bit13-12对应的像素值 */
WriteData(disp_point[((bytes>>0x0C) & 0x03)]);
/* 写入bit11-10对应的像素值 */
WriteData(disp_point[((bytes>>0x0A) & 0x03)]);
/* 写入bit9-8对应的像素值 */
WriteData(disp_point[((bytes>>8) & 0x03)]);
/* 写入bit7-6对应的像素值 */
WriteData(disp_point[((bytes>>6) & 0x03)]);
/* 写入bit5-4对应的像素值 */
WriteData(disp_point[((bytes>>4) & 0x03)]);
}
/**
* @brief 显示单个图形(按键图标或连接单元图标)
* @param column 列坐标X坐标
* @param lin 行坐标Y坐标
* @param hzcode 图形代码索引
* @param tb_index 图形类型索引1=按键图标GRAPHICS_TB其他=连接单元图标CONNECT_UNIT
* @note 显示16x16像素的图形每个图形由32字节数据组成
* 图形数据按行扫描每行16位共16行
* @retval 无
*/
void DisplayOneGraphics(uint8_t column, uint8_t lin, uint16_t hzcode, uint8_t tb_index)
{
uint8_t i, t, row, colm;
/* 4K色模式下的像素值映射表注意顺序与writebyte不同 */
uint8_t disp_point[4] = {0x00, 0xf0, 0x0f, 0xff};
/* 循环显示16行像素 */
for(i = 0; i < 16; i++)
{
if(tb_index == 1) /* 显示按键图标GRAPHICS_TB */
{
row = lin + i;
colm = column;
SetAddress(colm, row);
if(i < 8) /* 前8行使用字节0-15 */
{
/* 每次写入 1 行的 16 个像素点 */
WriteData(disp_point[((GRAPHICS_TB[hzcode][ 0]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][ 1]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][ 2]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][ 3]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][ 4]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][ 5]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][ 6]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][ 7]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][ 8]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][ 9]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][10]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][11]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][12]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][13]>>i) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][14]>>i) & 0x01) | (((GRAPHICS_TB[hzcode][15]>>i) & 0x01) << 1)]);
}
else /* 后8行使用字节16-31 */
{
/* 每次写入 1 行的 16 个像素点 */
t = i - 8; /* 计算后8行的相对索引 */
WriteData(disp_point[((GRAPHICS_TB[hzcode][16]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][17]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][18]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][19]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][20]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][21]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][22]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][23]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][24]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][25]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][26]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][27]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][28]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][29]>>t) & 0x01) << 1)]);
WriteData(disp_point[((GRAPHICS_TB[hzcode][30]>>t) & 0x01) | (((GRAPHICS_TB[hzcode][31]>>t) & 0x01) << 1)]);
}
}
else /* 显示连接单元图标CONNECT_UNIT */
{
row = lin + i;
colm = column;
SetAddress(colm, row);
if(i < 8) /* 前8行使用字节0-15 */
{
WriteData(disp_point[((CONNECT_UNIT[hzcode][ 0]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][ 1]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][ 2]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][ 3]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][ 4]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][ 5]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][ 6]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][ 7]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][ 8]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][ 9]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][10]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][11]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][12]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][13]>>i) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][14]>>i) & 0x01) | (((CONNECT_UNIT[hzcode][15]>>i) & 0x01) << 1)]);
}
else /* 后8行使用字节16-31 */
{
t = i - 8; /* 计算后8行的相对索引 */
WriteData(disp_point[((CONNECT_UNIT[hzcode][16]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][17]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][18]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][19]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][20]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][21]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][22]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][23]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][24]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][25]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][26]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][27]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][28]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][29]>>t) & 0x01) << 1)]);
WriteData(disp_point[((CONNECT_UNIT[hzcode][30]>>t) & 0x01) | (((CONNECT_UNIT[hzcode][31]>>t) & 0x01) << 1)]);
}
}
}
}
/* ============================================================================
* 字符显示函数(支持不同字体大小)
* ============================================================================ */
/**
* @brief 显示 6x12 像素的 ASCII 字符
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param CharCode ASCII字符代码0x20-0x7E即可打印字符
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 字符数据存储在ASCII6x12字库中每个字符12字节
* 字符索引 = CharCode - 0x200x20为空格字符
* 0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, *** 1
*1 0 0 0 0 0 0 0x00
*2 0 0 0 0 0 0 0x00
*3 0 0 1 0 0 0 0x20
*4 0 0 1 1 0 0 0x60
*5 0 0 1 0 0 0 0x20
*6 0 0 1 0 0 0 0x20
*7 0 0 1 0 0 0 0x20
*8 0 0 1 0 0 0 0x20
*9 0 0 1 0 0 0 0x20
*10 0 1 1 1 0 0 0x70
*11 0 0 0 0 0 0 0x20
*12 0 0 0 0 0 0 0x20
* @retval 无
*/
void Char6_Write(uint8_t x, uint8_t y, uint8_t CharCode, FlagStatus Flag)
{
uint8_t const *CodePtr;
uint32_t i = 0, index;
/* 计算字符在字库中的索引ASCII码从0x20开始 */
index = CharCode - 0x20;
/* 获取字符数据指针每个字符12字节 */
CodePtr = ASCII6x12 + (index * 12);
/* 循环显示12行像素 */
for(i = 0; i < 12; i++)
{
if(Flag)
write_6bit(x, y + i, ~CodePtr[i]); /* 反显:取反 */
else
write_6bit(x, y + i, CodePtr[i]); /* 正常显示 */
}
}
/**
* @brief 显示8x12像素的ASCII字符
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param CharCode ASCII字符代码0x20-0x7E
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 字符数据存储在ASCII8x12字库中每个字符12字节
* @retval 无
*/
void Char8_Write(uint8_t x, uint8_t y, uint8_t CharCode, FlagStatus Flag)
{
uint8_t const *CodePtr;
uint32_t i = 0, index = 0;
/* 计算字符在字库中的索引 */
index = CharCode - 0x20;
/* 获取字符数据指针每个字符12字节 */
CodePtr = ASCII8x12 + (index * 12);
/* 循环显示12行像素 */
for(i = 0; i < 12; i++)
{
if(Flag)
writebyte(x, y + i, ~CodePtr[i], Flag); /* 反显:取反 */
else
writebyte(x, y + i, CodePtr[i], Flag); /* 正常显示 */
}
}
/**
* @brief 显示12x12像素的ASCII字符
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param CharCode ASCII字符代码0x20-0x7E
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 字符数据存储在ASCII12x12字库中每个字符24字节12行x2字节/行)
* 每行数据由2个字节组成高字节+低字节)
* @retval 无
*/
void Char12_Write(uint8_t x, uint8_t y, uint8_t CharCode, FlagStatus Flag)
{
uint8_t const *CodePtr;
uint32_t i = 0, index = 0;
/* 计算字符在字库中的索引 */
index = CharCode - 0x20;
/* 获取字符数据指针每个字符24字节12行x2字节 */
CodePtr = ASCII12x12 + (index * 24);
/* 循环显示12行像素 */
for(i = 0; i < 12; i++)
{
if(Flag)
/* 反显将2字节组合后取反 */
write_12bit(x, y+i, (uint16_t)(~(((uint16_t)CodePtr[i*2 ])<<8)|((uint16_t)CodePtr[i*2+1 ])));
else
/* 正常显示将2字节组合高字节左移8位+低字节) */
write_12bit(x, y+i, (uint16_t)(((uint16_t)CodePtr[i*2 ])<<8)|((uint16_t)CodePtr[i*2+1 ]));
}
}
/**
* @brief 显示12x12像素的汉字
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param HzCode 汉字 GB2312 编码指针2字节高字节在前
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 支持 GB2312 编码的汉字显示,字库覆盖 16~55 区的常用汉字
* 每个汉字 24 字节12行x2字节/行)
* 特殊字符映射:罗马数字Ⅰ、Ⅱ、Ⅲ、Ⅳ和符号∠等
* @retval 无
*/
void HZ12_Write(uint8_t x, uint8_t y, const uint8_t *HzCode, FlagStatus Flag)
{
uint8_t const *CodePtr;
uint32_t GB2312Code = 0, HZKcode = 0, hzk_area = 0, hzk_index = 0, i = 0;
/* 组合 GB2312 编码高字节左移8位 + 低字节) */
GB2312Code = (*HzCode << 8) | (*(HzCode + 1));
/* 临时增加特殊字符映射(扩展字符集) */
if(GB2312Code == 0xA2F1) /* 罗马数字Ⅰ */
GB2312Code = 0xB0A1 + (39 << 8 | 89);
if(GB2312Code == 0xA2F2) /* 罗马数字Ⅱ */
GB2312Code = 0xB0A1 + (39 << 8 | 90);
if(GB2312Code == 0xA2F3) /* 罗马数字Ⅲ */
GB2312Code = 0xB0A1 + (39 << 8 | 91);
if(GB2312Code == 0xA2F4) /* 罗马数字Ⅳ */
GB2312Code = 0xB0A1 + (39 << 8 | 92);
if(GB2312Code == 0xA1CF) /* 角度符号∠ */
GB2312Code = 0xB0A1 + (39 << 8 | 93);
if(GB2312Code == 0xA6DA) /* 其他特殊字符 */
GB2312Code = 0xB0A1 + (40 << 8 | 0);
/* 计算汉字在字库中的位置GB2312从0xB0A1开始对应16~55区 */
HZKcode = GB2312Code - 0xB0A1; /* 16~55区的常用汉字区域 */
hzk_area = HZKcode >> 8; /* 区号(高字节) */
hzk_index = (HZKcode & 0x00FF); /* 位号(低字节) */
/* 获取汉字数据指针12x12像素一个汉字24字节 */
CodePtr = &HZ12[hzk_area][hzk_index * 24];
/* 循环显示12行像素 */
for(i = 0; i < 12; i++)
{
if(Flag)
/* 反显将2字节组合后取反 */
write_12bit(x, y + i, (uint16_t)~((((uint16_t)CodePtr[i*2]) << 8) | ((uint16_t)CodePtr[i*2+1])));
else
/* 正常显示将2字节组合高字节左移8位+低字节) */
write_12bit(x, y + i, (uint16_t)((((uint16_t)CodePtr[i*2]) << 8) | ((uint16_t)CodePtr[i*2+1])));
}
}
/**
* @brief 混合显示汉字和ASCII字符字符串
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param ptr 字符串指针支持GB2312汉字和ASCII字符混合
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 自动识别汉字GB2312编码首字节>0xA0和ASCII字符
* 支持换行符'\n'换行后X坐标回到起始位置
* 自动换行X坐标超过51时换行Y坐标超过148时停止显示
* 汉字宽度4个像素单位ASCII字符宽度2个像素单位
* @retval 无
*/
void HZ12AndChar_Printf(uint8_t x, uint8_t y, const uint8_t *ptr, FlagStatus Flag)
{
uint8_t x_base = x; /* 保存起始X坐标用于换行后复位 */
while(*ptr != '\0')
{
if(*ptr > 0xA0) /* 汉字GB2312编码首字节>0xA0 */
{
HZ12_Write(x, y, ptr, Flag); /* 显示汉字 */
x += 4; /* 汉字占4个像素单位 */
ptr += 2; /* 汉字占2字节 */
}
else if(*ptr >= 0x20) /* 可显示ASCII字符0x20-0x7E */
{
Char6_Write(x, y, *ptr, Flag); /* 显示ASCII字符 */
x += 2; /* ASCII字符占2个像素单位 */
ptr += 1; /* ASCII字符占1字节 */
}
else if(*ptr == '\n') /* 换行符 */
{
if(ptr[1] < 0x20) /* 如果下一字节是控制字符,作为行间距 */
y += ptr[1];
else
y += 12; /* 默认行间距12像素 */
x = x_base; /* X坐标回到起始位置 */
ptr += 1;
}
else /* 其他控制字符,跳过 */
{
ptr += 1;
}
/* 自动换行处理 */
if(x > 51) /* X坐标超过屏幕宽度 */
{
x = 0;
y += 12; /* 换行行间距12像素 */
}
/* 超出屏幕高度,停止显示 */
if(y > 148) return;
}
}
/**
* @brief 混合显示汉字和ASCII字符字符串支持指定位置反显
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param ptr 字符串指针支持GB2312汉字和ASCII字符混合
* @param SignNUM 需要反显的字符位置索引从0开始
* @note 功能与HZ12AndChar_Printf类似但可以指定某个字符位置反显
* 用于实现光标或选中效果
* 字符位置索引从0开始汉字和ASCII字符都算作一个字符
* @retval 无
*/
void HZ12AndChar_SignPrintf(uint8_t x, uint8_t y, const uint8_t *ptr, uint32_t SignNUM)
{
uint32_t i = 0; /* 字符位置索引 */
while(*ptr != '\0')
{
if(*ptr > 0xA0) /* 汉字 */
{
if(i != SignNUM)
HZ12_Write(x, y, ptr, RESET); /* 正常显示 */
else
HZ12_Write(x, y, ptr, SET); /* 反显 */
ptr += 2;
x += 4;
}
else if(*ptr >= 0x20) /* ASCII字符 */
{
if(i != SignNUM)
Char6_Write(x, y, *ptr, RESET); /* 正常显示 */
else
Char6_Write(x, y, *ptr, SET); /* 反显 */
x += 2;
ptr += 1;
}
else /* 碰到非字符指针继续加1避免死循环 */
{
ptr += 1;
}
i++; /* 字符位置索引递增 */
/* 自动换行处理 */
if(x > 51)
{
x = 0;
y += 12;
}
/* 超出屏幕高度,停止显示 */
if(y > 148) return;
}
}
/**
* @brief 以十六进制格式显示32位数据
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的32位数据
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 格式0xXXXXXXXX8位十六进制数前面加"0x"前缀)
* @retval 无
*/
void ASCII_Printf(uint8_t x, uint32_t y, uint32_t data, FlagStatus Flag)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
sprintf(ptr, "0x%08X", data); /* 格式化为8位十六进制字符串 */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr, Flag);
}
/**
* @brief 以十六进制格式显示32位数据支持指定位置反显
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的32位数据
* @param SignNUM 需要反显的字符位置索引从0开始不包括"0x"前缀)
* @note 格式0xXXXXXXXX
* SignNUM+2是因为字符串以"0x"开头需要跳过前2个字符
* @retval 无
*/
void ASCII_SignPrintf(uint8_t x, uint32_t y, uint32_t data, uint32_t SignNUM)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
sprintf(ptr, "0x%08X", data);
HZ12AndChar_SignPrintf(x, y, (const uint8_t *)ptr, SignNUM + 2); /* +2跳过"0x"前缀 */
}
/**
* @brief 将32位IP地址数据格式化为字符串
* @param buf 输出缓冲区指针至少17字节
* @param IPdata IP地址数据32位格式高字节为最高位IP段
* @note IP地址格式XXX.XXX.XXX.XXX每个段3位数字不足补空格
* IPdata格式高8位=第一段次8位=第二段次8位=第三段低8位=第四段
* @retval 无
*/
void IP_Sprintf(uint8_t *buf, uint32_t IPdata)
{
uint8_t temp = 0;
memset(buf, 0, 17); /* 清空缓冲区IP地址字符串最多16字节+结束符) */
/* 提取并格式化第一段IP地址高8位 */
temp = (uint8_t)(IPdata >> 24);
sprintf((char *)buf, "%3d", temp);
buf[3] = '.';
/* 提取并格式化第二段IP地址次高8位 */
temp = (uint8_t)(IPdata >> 16);
sprintf((char *)buf + 4, "%3d", temp);
buf[7] = '.';
/* 提取并格式化第三段IP地址次低8位 */
temp = (uint8_t)(IPdata >> 8);
sprintf((char *)buf + 8, "%3d", temp);
buf[11] = '.';
/* 提取并格式化第四段IP地址低8位 */
temp = (uint8_t)(IPdata >> 0);
sprintf((char *)buf + 12, "%3d", temp);
}
/**
* @brief 显示IP地址支持光标位置反显
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param IPdata IP地址数据32位
* @param SetFlag 是否启用光标SET=启用光标RESET=正常显示
* @param cursor 光标位置索引当SetFlag=SET时有效
* @note 先调用IP_Sprintf格式化IP地址然后根据SetFlag选择显示方式
* @retval 无
*/
void IP_Printf(uint8_t x, uint32_t y, uint32_t IPdata, FlagStatus SetFlag, uint32_t cursor)
{
uint8_t buf[17];
memset(buf, 0, sizeof(buf));
IP_Sprintf(buf, IPdata); /* 格式化IP地址 */
if(SetFlag)
{
HZ12AndChar_SignPrintf(x, y, buf, cursor); /* 带光标显示 */
}
else
{
HZ12AndChar_Printf(x, y, buf, RESET); /* 正常显示 */
}
}
/**
* @brief 显示整数数值
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的32位有符号整数
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 使用标准格式"%d"格式化整数
* @retval 无
*/
void IntValue_Printf(uint8_t x, uint32_t y, int32_t data, FlagStatus Flag)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
sprintf(ptr, "%d", data); /* 格式化为整数字符串 */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr, Flag);
}
/**
* @brief 显示菜单项编号格式XX.
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 菜单项编号
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 格式2位数字+点号(例如:"01."、"12."
* @retval 无
*/
void MeunItem_Printf(uint8_t x, uint32_t y, int32_t data, FlagStatus Flag)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
sprintf(ptr, "%2d.", data); /* 格式化为2位数字+点号 */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr, Flag);
}
/**
* @brief 显示固定长度的整数右对齐左补0
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的32位有符号整数
* @param len 显示长度1-10位
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 先格式化为10位右对齐字符串左补0然后截取指定长度显示
* 例如data=123, len=5显示为"00123"
* @retval 无
*/
void FixLenIntValue_Printf(uint32_t x, uint32_t y, int32_t data, uint32_t len, FlagStatus Flag)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
if(len > 10) return; /* 长度限制检查 */
sprintf(ptr, "%010d", data); /* 右对齐左不足补0固定长度10 */
/* 从字符串末尾截取len长度显示 */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr + 10 - len, Flag);
}
/**
* @brief 将整数转换为固定长度的小数字符串类似sprintf功能
* @param str 目标字符串缓冲区指针
* @param data 要转换的32位有符号整数
* @param len 整数部分长度1-10位
* @param dot 小数部分位数0-3位
* @note 将整数除以10^dot转换为小数然后格式化为固定长度字符串
* 例如data=12345, len=3, dot=2结果为"123.45"
* 如果dot=0则只显示整数部分
* @retval 无
*/
void FixLenIToF_Sprintf(uint8_t* str, int32_t data, uint32_t len, uint32_t dot)
{
char ptr[15];
uint32_t i = 0, j = 0;
float fvalue = 0;
memset(ptr, 0, sizeof(ptr));
/* 参数有效性检查 */
if(str == NULL)
return;
if((len + dot) > 10)
return;
if(dot > 3)
return;
if(dot == 0) /* 无小数部分,只显示整数 */
{
sprintf(ptr, "%011d", data); /* 格式化为11位整数右对齐左补0 */
/* 截取指定长度 */
while(j < len)
{
*str++ = *(ptr + (11 - len) + j);
j++;
}
}
else /* 有小数部分 */
{
/* 将整数转换为小数除以10^dot */
fvalue = (float)data / pow(10.0, dot);
sprintf(ptr, "%011.3f", fvalue); /* 格式化为11位小数3位小数 */
/* 查找小数点位置 */
for(i = 0; i < 10; i++)
{
if(ptr[i] == '.')
{
ptr[i + dot + 1] = '\0'; /* 截取到指定小数位数 */
break;
}
}
/* 复制指定长度的字符串(整数部分+小数点+小数部分) */
while(j < len + dot + 1)
{
*str++ = *(ptr + (i - len) + j);
j++;
}
}
}
/**
* @brief 显示固定长度的整数转小数字符串(支持光标位置反显)
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的32位有符号整数
* @param len 整数部分长度1-10位
* @param dot 小数部分位数0-3位
* @param Flag 是否启用光标SET=启用光标RESET=正常显示
* @param cursor 光标位置索引当Flag=SET时有效
* @note 先调用FixLenIToF_Sprintf格式化字符串然后根据Flag选择显示方式
* @retval 无
*/
void FixLenIToF_Printf(uint32_t x, uint32_t y, int32_t data, uint32_t len, uint32_t dot, FlagStatus Flag, uint32_t cursor)
{
uint8_t ptr[15];
/* 参数有效性检查 */
if((len + dot) > 10)
return;
if(dot > 3)
return;
FixLenIToF_Sprintf(ptr, data, len, dot); /* 格式化字符串 */
if(!Flag)
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr, RESET); /* 正常显示 */
else
HZ12AndChar_SignPrintf(x, y, (const uint8_t *)ptr, cursor); /* 带光标显示 */
}
/**
* @brief 显示浮点数保留2位小数
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的浮点数
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 使用格式"%.2f"格式化浮点数保留2位小数
* @retval 无
*/
void FloatValue_Printf(uint8_t x, uint32_t y, float data, FlagStatus Flag)
{
char ptr[11];
memset(ptr, 0, sizeof(ptr));
sprintf(ptr, "%.2f", data); /* 格式化为2位小数 */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr, Flag);
}
/**
* @brief 显示固定长度的浮点数
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @param data 要显示的浮点数
* @param len 整数部分长度1-10位
* @param dot 小数部分位数0-3位
* @param Flag 显示标志SET=反显RESET=正常显示
* @note 先格式化为11位小数3位小数然后截取指定长度显示
* @retval 无
*/
void FixLenFloatValue_Printf(uint32_t x, uint32_t y, float data, uint32_t len, uint32_t dot, FlagStatus Flag)
{
char ptr[15];
int i = 0;
memset(ptr, 0, sizeof(ptr));
/* 参数有效性检查 */
if((len + dot) > 10)
return;
if(dot > 3)
return;
sprintf(ptr, "%011.3f", data); /* 格式化为11位小数3位小数 */
/* 查找小数点位置并截取到指定小数位数 */
for(i = 0; i < 10; i++)
{
if(ptr[i] == '.')
{
ptr[i + dot + 1] = '\0'; /* 截取到指定小数位数 */
break;
}
}
/* 从指定位置开始显示(整数部分+小数点+小数部分) */
HZ12AndChar_Printf(x, y, (const uint8_t *)ptr + i - len, Flag);
}
/* ============================================================================
* 状态指示和屏幕操作函数
* ============================================================================ */
/**
* @brief 显示系统故障指示(闪烁效果)
* @note 在屏幕右上角坐标52,0显示故障指示图标
* 通过计数器实现闪烁效果:
* - count < 0x0280 (640):显示故障图标
* - 0x0280 <= count < 0x1FFF (8191):隐藏图标
* - count >= 0x1FFF重置计数器
* @retval 无
*/
void Fault_Disp(void)
{
static uint32_t count = 0; /* 静态计数器,保持状态 */
const uint32_t x = 52, y = 0; /* 故障指示位置 */
count++;
if(count < 0x0280) /* 显示阶段 */
{
write_3bit(x, y, 0xC0); /* 显示故障图标(上半部分) */
write_3bit(x, y + 1, 0xC0); /* 显示故障图标(下半部分) */
}
else if(count < 0x1FFF) /* 隐藏阶段 */
{
write_3bit(x, y, 0x00); /* 清除图标 */
write_3bit(x, y + 1, 0x00);
}
else /* 重置计数器 */
{
count = 0;
}
}
/**
* @brief 显示按键运行状态指示
* @param Flag 状态标志非0=显示运行指示0=清除指示
* @note 在屏幕左上角坐标0,0显示按键运行状态
* 显示3个像素点表示运行状态
* @retval 无
*/
void KeyRun_Disp(uint32_t Flag)
{
const uint32_t x = 0, y = 0; /* 状态指示位置 */
if(Flag != 0) /* 显示运行指示 */
{
write_3bit(x, y, 0x80); /* 显示指示点1 */
write_3bit(x, y + 1, 0x80); /* 显示指示点2 */
write_3bit(x, y + 3, 0x80); /* 显示指示点3 */
}
else /* 清除指示 */
{
write_3bit(x, y, 0x00);
write_3bit(x, y + 1, 0x00);
write_3bit(x, y + 3, 0x00);
}
}
/**
* @brief 全屏显示图像数据
* @param ptr 图像数据指针160x160像素每像素2位共3200字节
* @note 将图像数据按4K色模式2位/像素)写入整个屏幕
* 图像数据格式每字节包含4个像素点bit7-6, bit5-4, bit3-2, bit1-0
* 每行160像素 = 40字节共160行
* @retval 无
*/
void ScreenPrintf(uint8_t* ptr)
{
uint16_t i, j;
set_color_mode(COLOR_4K_444); /* 设置4K色模式RGB444 */
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff}; /* 像素值映射表 */
SetAddress(0, 0); /* 设置起始地址为屏幕左上角 */
/* 循环显示160行 */
for(i = 0; i < 160; i++)
{
/* 每行20个字节每字节4个像素点共80个像素点但实际显示需要更多 */
for(j = 0; j < 20; j++)
{
/* 将每字节的4个2位像素值转换为显示数据 */
WriteData(disp_point[(ptr[i*20 + j] >> 6) & 0x03]); /* bit7-6 */
WriteData(disp_point[(ptr[i*20 + j] >> 4) & 0x03]); /* bit5-4 */
WriteData(disp_point[(ptr[i*20 + j] >> 2) & 0x03]); /* bit3-2 */
WriteData(disp_point[(ptr[i*20 + j] >> 0) & 0x03]); /* bit1-0 */
}
WriteData(0x00); /* 补全每行末尾的数据使总点数能被3整除 */
}
}
/**
* @brief 显示公司LOGO图像
* @note 调用ScreenPrintf函数全屏显示COMPANY_LOGO图像数据
* @retval 无
*/
void DisplayGraphicsScreen(void)
{
ScreenPrintf((uint8_t*)COMPANY_LOGO);
}
/**
* @brief 清屏函数(全屏填充黑色)
* @note 将整个160x160像素屏幕填充为黑色0x00
* 设置4K色模式然后逐行写入0x00数据
* @retval 无
*/
void ClearScreen(void)
{
uint16_t i, j;
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
SetAddress(0, 0); /* 设置起始地址为屏幕左上角 */
/* 循环160行 */
for(i = 0; i < 160; i++)
{
/* 每行写入20个字节的0x00数据 */
for(j = 0; j < 20; j++)
{
WriteData(0x0);
WriteData(0x0);
WriteData(0x0);
WriteData(0x0);
}
WriteData(0x00); /* 补全每行末尾的数据使总点数能被3整除 */
}
}
/**
* @brief 屏幕全显函数(全屏填充白色)
* @note 将整个160x160像素屏幕填充为白色0xFF
* 用于测试屏幕显示功能
* @retval 无
*/
void ReverseScreen(void)
{
uint16_t i, j;
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
SetAddress(0, 0); /* 设置起始地址为屏幕左上角 */
/* 循环160行 */
for(i = 0; i < 160; i++)
{
/* 每行写入20个字节的0xFF数据 */
for(j = 0; j < 20; j++)
{
WriteData(0xFF);
WriteData(0xFF);
WriteData(0xFF);
WriteData(0xFF);
}
WriteData(0x00); /* 补全每行末尾的数据使总点数能被3整除 */
}
}
/**
* @brief 清除菜单内容区域
* @note 清除屏幕中菜单显示区域从第21行开始共139行
* 用于刷新菜单内容而不影响屏幕其他区域
* @retval 无
*/
void ClearMenuScreen(void)
{
uint16_t i, j;
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
SetAddress(0, 21); /* 设置起始地址为第21行 */
/* 循环139行从第21行到第159行 */
for(i = 0; i < 139; i++)
{
/* 每行写入27个字节的0x00数据 */
for(j = 0; j < 27; j++)
{
WriteData(0x0);
WriteData(0x0);
WriteData(0x0);
}
}
}
/**
* @brief 填充指定矩形区域
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 矩形宽度(列数)
* @param high 矩形高度(行数)
* @param byte 填充数据值用于write_3bit函数
* @note 使用3位写入模式填充指定矩形区域
* 设置4K色模式然后逐行填充数据
* @retval 无
*/
void FillBoxScreen(uint8_t x, uint8_t y, uint8_t len, uint8_t high, uint8_t byte)
{
uint16_t i, j;
uint8_t x1 = x; /* 保存起始X坐标 */
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
/* 循环填充每一行 */
for(i = 0; i < high; i++)
{
SetAddress(x, y); /* 设置当前行起始地址 */
/* 循环填充每一列 */
for(j = 0; j < len; j++)
{
write_3bit(x1, y, byte); /* 写入3位数据 */
x1++;
}
x1 = x; /* 重置X坐标到起始位置 */
y++; /* 移动到下一行 */
}
}
void LCD_GPIO_Init(void)
{
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOB_CLK_ENABLE(); // 时钟初始化
__HAL_RCC_GPIOE_CLK_ENABLE(); // 时钟初始化
// 配置 LCD 引脚
gpio_init_struct.Pin = GPIO_PIN_14 | GPIO_PIN_13 | GPIO_PIN_12 | GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_0;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /*推挽输出模式*/
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_HIGH;
// 初始化 LCD 选引脚
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
// 配置 LCD 引脚
gpio_init_struct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /*推挽输出模式*/
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_HIGH;
// 初始化 LCD 选引脚
HAL_GPIO_Init(GPIOE, &gpio_init_struct);
}
/**
* @brief LCD初始化总函数
* @note 执行LCD初始化的完整流程
* 1. 硬件复位
* 2. 初始化配置XRD版本
* 3. 清屏
* @retval 无
*/
void LcdInit(void)
{
LCD_GPIO_Init();
LCD_BackLight_ON();
LCD_Reset(); /* 硬件复位 */
LCD_InitXRD(); /* 初始化配置XRD版本 */
ClearScreen(); /* 清屏 */
}
/**
* @brief 显示能联LOGO图像
* @note 在屏幕指定位置从第40行开始显示能联LOGO
* LOGO尺寸70行x20字节/行共1400字节
* 使用4K色模式显示
* @retval 无
*/
void DisplayNL_LOGO(void)
{
uint8_t i, n;
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff}; /* 4K色模式像素值映射表 */
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
SetAddress(0, 40); /* 设置起始地址列0行40 */
/* 循环显示70行 */
for(i = 0; i < 70; i++)
{
/* 每行20字节 */
for(n = 0; n < 20; n++)
{
/* 将每字节的4个2位像素值转换为显示数据 */
WriteData(disp_point[(NL_LOGO[i*20 + n] >> 6) & 0x03]); /* bit7-6 */
WriteData(disp_point[(NL_LOGO[i*20 + n] >> 4) & 0x03]); /* bit5-4 */
WriteData(disp_point[(NL_LOGO[i*20 + n] >> 2) & 0x03]); /* bit3-2 */
WriteData(disp_point[(NL_LOGO[i*20 + n] >> 0) & 0x03]); /* bit1-0 */
}
WriteData(0x00); /* 补全每行末尾的数据使总点数能被3整除 */
}
}
/**
* @brief 显示南瑞LOGO图像
* @note 在屏幕指定位置坐标8,50显示南瑞LOGO
* LOGO尺寸50行x15字节/行共750字节
* 使用4K色模式显示
* @retval 无
*/
void DisplayNANRUI_LOGO(void)
{
uint8_t i, n;
uint8_t disp_point[4] = {0x00, 0x0f, 0xf0, 0xff}; /* 4K色模式像素值映射表 */
const uint32_t x = 8, y = 50; /* LOGO显示位置 */
set_color_mode(COLOR_4K_444); /* 设置4K色模式 */
/* 循环显示50行 */
for(i = 0; i < 50; i++)
{
SetAddress(x, y + i); /* 设置当前行地址 */
/* 每行15字节 */
for(n = 0; n < 15; n++)
{
/* 将每字节的4个2位像素值转换为显示数据 */
WriteData(disp_point[(NANRUI_LOGO[i*15 + n] >> 6) & 0x03]); /* bit7-6 */
WriteData(disp_point[(NANRUI_LOGO[i*15 + n] >> 4) & 0x03]); /* bit5-4 */
WriteData(disp_point[(NANRUI_LOGO[i*15 + n] >> 2) & 0x03]); /* bit3-2 */
WriteData(disp_point[(NANRUI_LOGO[i*15 + n] >> 0) & 0x03]); /* bit1-0 */
}
WriteData(0x00); /* 补全每行末尾的数据使总点数能被3整除 */
}
}
/*******************************************************************************
* FunctionName : Display_Picture()
* Description : 图片显示程序
* EntryParameter : none
* ReturnValue : none
*******************************************************************************/
void Display_BMP(uint32_t Width, uint32_t Height, const uint8_t* picture)
{
uint8_t i,n;
uint8_t disp_point[4]={0x00,0x0f,0xf0,0xff};
uint8_t x, y;
uint32_t bytesNumOfRow;
set_color_mode(COLOR_4K_444);//设置4.4.4.模式
if(Width>160 || Height>160)
return ; //设置4.4.4.模式
x = ((160-Width)/2)/3; //x坐标为每3个像素点递增
y = (160-Height)/2 + Height; //x坐标为每3个像素点递增
bytesNumOfRow = Width/8;
for(i=0;i<Height;i++)
{
SetAddress(x, y-i);
for(n=0;n<bytesNumOfRow;n++)
{
WriteData(disp_point[(~picture[i*bytesNumOfRow+n]>>6)&0x03]);
WriteData(disp_point[(~picture[i*bytesNumOfRow+n]>>4)&0x03]);
WriteData(disp_point[(~picture[i*bytesNumOfRow+n]>>2)&0x03]);
WriteData(disp_point[(~picture[i*bytesNumOfRow+n]>>0)&0x03]);
}
WriteData(0x00); //补全每行末尾的数据,使总点数能被三整除
}
}
/*******************************************************************************
* FunctionName : DisplayNANRUI_BMP()
* Description : BMP格式显示测试
* EntryParameter : none
* ReturnValue : none
*******************************************************************************/
void DisplayNANRUI_BMP(void)
{
const uint32_t xmax=128, ymax=50;
Display_BMP(xmax, ymax, NANRUI_BMP);
}
/*******************************************************************************
* FunctionName : DisplayNANRUI_BMP()
* Description : BMP格式显示测试
* EntryParameter : none
* ReturnValue : none
*******************************************************************************/
void DisplayQQ_BMP(void)
{
const uint32_t xmax=96, ymax=94;
Display_BMP(xmax, ymax, QQ_BMP);
}
/**
* @brief 绘制单条水平线(内部函数)
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @note 绘制一条3像素宽的水平线
* 使用固定的像素模式0xFF, 0xF0, 0x00
* @retval 无
*/
static void DrawHorizontalLine(uint8_t x, uint8_t y)
{
SetAddress(x, y);
WriteData(0xFF); /* 第一个像素:白色 */
WriteData(0xF0); /* 第二个像素:深色 */
WriteData(0x00); /* 第三个像素:黑色 */
}
/**
* @brief 绘制指定长度的水平线
* @param x 起始列坐标X坐标
* @param y 行坐标Y坐标
* @param len 线条长度(像素单位)
* @note 通过重复调用DrawHorizontalLine绘制多条水平线
* 自动处理换行当X坐标超过54时换到下一行
* 超出屏幕高度160时停止绘制
* @retval 无
*/
void DisplayHorizontalLine(uint8_t x, uint8_t y, uint8_t len)
{
uint8_t i;
for(i = 0; i < len; i++)
{
DrawHorizontalLine(x, y); /* 绘制一条水平线 */
x++;
/* 自动换行处理 */
if(x > 54) /* X坐标超过屏幕宽度 */
{
x = 0; /* X坐标回到起始位置 */
y += 1; /* 换到下一行 */
}
/* 超出屏幕高度,停止绘制 */
if(y >= 160) return;
}
}
/**
* @brief 绘制纵向线条
* @param x 列坐标X坐标
* @param y 起始行坐标Y坐标
* @param high 线条高度(行数)
* @param value 线条类型值用于write_3bit函数
* 0x80=单边线0xC0=双线0xA0=间隔线,以此类推
* @note 使用write_3bit函数逐行绘制纵向线条
* 超出屏幕高度160时停止绘制
* @retval 无
*/
void DisplayVerticalLine(uint8_t x, uint8_t y, uint8_t high, uint8_t value)
{
uint8_t i;
for(i = 0; i < high; i++)
{
write_3bit(x, y++, value); /* 写入3位数据Y坐标递增 */
/* 超出屏幕高度,停止绘制 */
if(y >= 160) return;
}
}
/**
* @brief 显示矩形光标
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 光标宽度(像素单位)
* @param high 光标高度(行数)
* @note 通过绘制多条水平线形成矩形光标
* 用于指示当前选中位置
* @retval 无
*/
void CursorPrintf(uint8_t x, uint8_t y, uint8_t len, uint8_t high)
{
int i;
for(i = 0; i < high; i++)
DisplayHorizontalLine(x, y + i, len); /* 逐行绘制水平线 */
}
/**
* @brief 显示屏幕头部装饰图形
* @note 绘制屏幕顶部的装饰边框和分隔线
* 包括:
* - 左右两侧的垂直边框线16行高
* - 顶部的水平分隔线
* - 底部的水平分隔线
* - 左侧的垂直边框线142行高
* @retval 无
*/
void DiaplayHeadGraph(void)
{
/* 绘制左侧垂直边框从第0行开始高度16 */
DisplayVerticalLine(20, 0, 16, 0x80);
/* 绘制右侧垂直边框从第0行开始高度16 */
DisplayVerticalLine(53, 0, 16, 0x80);
/* 绘制顶部水平分隔线第15行长度20 */
DisplayHorizontalLine(0, 15, 20);
/* 绘制顶部水平分隔线第15行从第34列开始长度20 */
DisplayHorizontalLine(34, 15, 20);
/* 绘制底部水平分隔线第17行长度54 */
DisplayHorizontalLine(0, 17, 54);
/* 绘制左侧垂直边框从第18行开始高度142 */
DisplayVerticalLine(0, 18, 142, 0x80);
}
/**
* @brief 绘制带阴影效果的方框(内部函数)
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 方框宽度(像素单位)
* @param high 方框高度(行数)
* @note 绘制一个带3D阴影效果的方框
* 包括:左边框、上边框、下边框(带阴影)、右边框(带渐变阴影效果)
* @retval 无
*/
static void DrawBox(uint8_t x, uint8_t y, uint8_t len, uint8_t high)
{
/* 绘制左边框 */
DisplayVerticalLine(x, y, high, 0x80);
/* 绘制上边框 */
DisplayHorizontalLine(x, y, len);
/* 绘制下边框 */
DisplayHorizontalLine(x, y + high, len);
/* 绘制第一层阴影 */
writebyte(x, y + high + 1, 0x7F, RESET);
DisplayHorizontalLine(x + 1, y + high + 1, len);
/* 绘制第二层阴影 */
writebyte(x, y + high + 2, 0x3F, RESET);
DisplayHorizontalLine(x + 1, y + high + 2, len);
/* 绘制右边框(带渐变阴影效果) */
DisplayVerticalLine(x + len, y, high + 3, 0x80); /* 主边框 */
DisplayVerticalLine(x + len, y + 1, high + 2, 0xC0); /* 第一层阴影 */
DisplayVerticalLine(x + len, y + 2, high + 1, 0xE0); /* 第二层阴影 */
}
/**
* @brief 绘制无阴影效果的方框(内部函数)
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 方框宽度(像素单位)
* @param high 方框高度(行数)
* @note 绘制一个简单的方框,无阴影效果
* 包括:左边框、上边框、下边框、右边框
* @retval 无
*/
static void DrawBox_NoShadow(uint8_t x, uint8_t y, uint8_t len, uint8_t high)
{
DisplayVerticalLine(x, y, high, 0x80); /* 左边框 */
DisplayHorizontalLine(x, y, len); /* 上边框 */
DisplayHorizontalLine(x, y + high, len); /* 下边框 */
DisplayVerticalLine(x + len - 1, y, high, 0x20); /* 右边框 */
}
/**
* @brief 绘制一个像素点(带渐变效果)
* @param x 列坐标X坐标
* @param y 行坐标Y坐标
* @note 绘制一个2x6像素的点带有渐变效果
* 用于显示特殊标记或装饰
* @retval 无
*/
void DrawPoint(uint8_t x, uint8_t y)
{
/* 左列像素 */
DisplayVerticalLine(x, y + 1, 1, 0x60);
DisplayVerticalLine(x, y + 2, 1, 0x60);
DisplayVerticalLine(x, y + 3, 1, 0x40); /* 中间最亮 */
DisplayVerticalLine(x, y + 4, 1, 0x60);
DisplayVerticalLine(x, y + 5, 1, 0x60);
/* 右列像素 */
DisplayHorizontalLine(x + 1, y + 1, 1);
DisplayVerticalLine(x + 1, y + 2, 1, 0x60);
DisplayVerticalLine(x + 1, y + 3, 1, 0x20); /* 中间较暗 */
DisplayVerticalLine(x + 1, y + 4, 1, 0x60);
DisplayHorizontalLine(x + 1, y + 5, 1);
}
/**
* @brief 显示消息提示框(静态模式)
* @note 在屏幕指定位置显示一个带阴影的消息提示框
* 位置:坐标(10,40)尺寸33x50像素
* 先清除背景区域,然后绘制方框
* 动态框模式代码已注释需要定义DYNAMIC_BOX
* @retval 无
*/
void MessageBox(void)
{
/* 静态框模式 */
FillBoxScreen(9, 37, 35, 59, 0x00); /* 清除背景区域 */
DrawBox(10, 40, 33, 50); /* 绘制带阴影的方框 */
}
/**
* @brief 清除消息提示框
* @note 清除消息提示框的整个显示区域
* 位置和尺寸与MessageBox函数对应
* @retval 无
*/
void ClrMessageBox(void)
{
FillBoxScreen(9, 37, 35, 59, 0x00); /* 清除消息框区域 */
}
/**
* @brief 清除消息提示框内容区域
* @note 只清除消息框内部的内容区域,保留边框
* 用于刷新消息内容而不重新绘制边框
* @retval 无
*/
void ClrMessageBoxContent(void)
{
FillBoxScreen(11, 41, 31, 48, 0x00); /* 清除内容区域(保留边框) */
}
/**
* @brief 显示可编程消息提示框(支持静态和动态模式)
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param size 方框大小参数(影响方框尺寸)
* @note 根据编译选项显示静态或动态消息框
* 静态模式:直接绘制完整方框
* 动态模式:逐步绘制方框,产生动画效果
* 方框尺寸:宽度=size高度=size*3/2+9
* @retval 无
*/
void ProgramableMessageBox(uint8_t x, uint8_t y, uint8_t size)
{
#ifdef STATIC_BOX /* 静态框模式 */
FillBoxScreen(x - 1, y - 3, size + 2, size * 3 / 2 + 9, 0x00); /* 清除背景 */
DrawBox(x, y, size, size * 3 / 2 + 9); /* 绘制方框 */
#endif //#ifdef STATIC_BOX
#ifdef DYNAMIC_BOX /* 动态框模式 */
FillBoxScreen(x - 1, y - 3, size * 2 + 2, size * 3 + 9, 0x00); /* 清除背景 */
/* 逐步绘制方框,产生动画效果 */
for(int i = 0; i < size; i++)
{
EraseLine(x, y, i * 2, i * 3); /* 擦除旧线条 */
DrawBox(x, y, (i + 1) * 2, (i + 1) * 3); /* 绘制新方框 */
delay_ms(5); /* 延时,产生动画效果 */
}
#endif //#ifdef DYNAMIC_BOX
}
/**
* @brief 绘制下拉菜单组合框
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 菜单框宽度(像素单位)
* @param items 菜单项数量
* @note 根据编译选项显示静态或动态菜单框
* 静态模式:直接绘制完整菜单框
* 动态模式:逐步绘制菜单框,产生下拉动画效果
* 每个菜单项高度20像素
* @retval 无
*/
void DrawMenuComboBox(uint8_t x, uint8_t y, uint8_t len, uint8_t items)
{
#ifdef STATIC_BOX /* 静态框模式 */
FillBoxScreen(x - 1, y - 6, len + 3, items * 20 + 9, 0x00); /* 清除背景 */
DrawBox(x - 1, y - 3, len + 2, items * 20); /* 绘制菜单框 */
#endif //#ifdef STATIC_BOX
#ifdef DYNAMIC_BOX /* 动态框模式 */
FillBoxScreen(x - 2, y - 6, len + 3, items * 20 + 9, 0x00); /* 清除背景 */
/* 逐步绘制菜单框,产生下拉动画效果 */
for(int i = 0; i < items; i++)
{
EraseLine(x - 1, y - 6, len + 2, i * 20 + 3); /* 擦除旧线条 */
DrawBox(x - 1, y - 3, len + 2, (i + 1) * 20); /* 绘制新菜单框 */
delay_ms(15); /* 延时,产生动画效果 */
}
#endif //#ifdef DYNAMIC_BOX
}
/**
* @brief 显示消息设置提示框(带标题栏,清除背景)
* @param title 标题字符串指针GB2312编码
* @note 显示一个带标题栏的消息设置框
* 先清除背景区域,然后绘制无阴影方框
* 标题栏区域填充白色,标题文字反显
* 位置:坐标(8,40)尺寸37x70像素
* @retval 无
*/
void MessageSetBox(const uint8_t *title)
{
FillBoxScreen(7, 37, 39, 79, 0x00); /* 清除背景区域 */
DrawBox_NoShadow(8, 40, 37, 70); /* 绘制无阴影方框 */
FillBoxScreen(8, 40, 37, 20, 0xFF); /* 填充标题栏区域(白色) */
HZ12AndChar_Printf(18, 43, title, SET); /* 显示标题(反显) */
}
/**
* @brief 显示消息设置提示框(带标题栏,不清除背景)
* @param title 标题字符串指针GB2312编码
* @note 功能与MessageSetBox类似但不清除背景区域
* 用于在已有内容上叠加显示消息框
* @retval 无
*/
void MessageSetBox_NoClear(const uint8_t *title)
{
DrawBox_NoShadow(8, 40, 37, 70); /* 绘制无阴影方框 */
FillBoxScreen(8, 40, 37, 20, 0xFF); /* 填充标题栏区域(白色) */
HZ12AndChar_Printf(18, 43, title, SET); /* 显示标题(反显) */
}
/**
* @brief 清除消息设置框的内容显示区域
* @note 只清除消息框内部的内容区域,保留标题栏和边框
* 用于刷新消息内容而不重新绘制整个框
* @retval 无
*/
void ClrMessageSetBox(void)
{
FillBoxScreen(9, 61, 34, 48, 0x00); /* 清除内容区域(保留标题栏和边框) */
}
/**
* @brief 删除消息设置提示框
* @note 清除整个消息设置框的显示区域
* 包括标题栏、边框和内容区域
* @retval 无
*/
void DeleteMessageSetBox(void)
{
FillBoxScreen(7, 37, 39, 79, 0x00); /* 清除整个消息框区域 */
}
/**
* @brief 绘制记录框(用于显示记录列表)
* @param x 起始列坐标X坐标
* @param y 起始行坐标Y坐标
* @param len 框宽度(像素单位)
* @param items 记录项数量
* @note 绘制一个带阴影的记录列表框
* 每个记录项高度16像素显示区域19像素包括间距
* 先清除背景,然后绘制方框
* @retval 无
*/
void DrawRecordBox(uint8_t x, uint8_t y, uint8_t len, uint8_t items)
{
FillBoxScreen(x - 1, y - 3, len + 2, items * 16 + 6, 0x00); /* 清除背景 */
DrawBox(x - 1, y - 3, len + 2, items * 19); /* 绘制记录框 */
}