📄 lcd.c
字号:
/********************************************************************************************************
* 文 件 名 : LCD.c
* 日 期 : 2006-03-02
* 说 明 : 这一版本的软件是针对 深圳市松山电子科技有限公司 的CA12864K 系列LCM 模块的驱动
* 可以兼容 OCMJ(奥可拉中文集成模块) C系列液晶显示器 (带汉字库LCD开发的驱动)
* 驱动芯片ST7920 ST7921组成的驱动组 及其兼容芯片
* 适用型号 : OCMJ12864C_1 OCMJ4X8C OCMJ4X10C OCMJ4X8C OCMJ4X16A OCMJ4X16B 等
* 松山公司资料
* 网站 : http://www.sunson.net Email : sunson@sunson.net
* 电话 : 0755-27891155 /0755-27890697 /0755-27890723/10/16/19
* 技术支持 :
* 奥可拉公司资料
* 网站 : http://www.gptlcm.cn Email : syl@gptlcm.cn
* 电话 : 0758-2317153/2317143
* 技术支持 : 0758-2317156
* 程 序 员 : 蔡杰(hnclcj@163.com)
********************************************************************************************************/
#define LCD_GLOBALS
#include "includes.h"
#include "FONT_MACRO.h"
#include "Font.h"
#if LCD_MODULS_EN > 0
OS_EVENT *DispSem; // 显示信号量
/********************************************************************************************************
* 常数 LCM 支持的命令集 常用的命令 共18条
********************************************************************************************************/
/* -----------------ST7920 ST7921 COMMANDS ------------------ */
/* 基本指令集 */
#define DISP_CMD_BSCLS 0x01 /* 清屏 即屏幕用' ' 填充满 */
#define DISP_CMD_BSACR 0x02 /* DDRAM位置计数器 复位到0 并将右边游标移动到00 不改变DDRAM内容 */
#define DISP_CMD_BSRMOVE 0x05 /* 整体显示为右移 */
#define DISP_CMD_BSMOVE 0x06 /* 整体显示不移动 光标右移 */
#define DISP_CMD_BSLMOVE 0x07 /* 整体显示为左移 */
#define DISP_CMD_BSOFF 0x08 /* D=0:整体关闭,DDRAM内容不改变, C=1游标ON, B=1游标位置显示反白 */
#define DISP_CMD_BSON 0x0c /* D=1:整体显示,C=0,B=0 */
#define DISP_CMD_BSIO 0x30 /* DL=0; 4BIT接口 DL=1; 8BIT接口 RE=0:基本指令 */
#define DISP_CMD_BASIC 0x30 /* RE=1; 扩充指令集 */
#define DISP_CMD_EXTEND 0x36 /* RE=1:扩充指令 */
/* 扩充指令集 */
#define DISP_CMD_EXTWAIT 0x01 /* 待命模式 */
#define DISP_CMD_EXTEXSR 0x02 /* 允许输入IRAM 或CGRAM位置 */
#define DISP_CMD_EXTENSR 0x03 /* 允许输入垂直卷动位置 */
#define DISP_CMD_EXLINE1 0x04 /* 第一行反白显示 */
#define DISP_CMD_EXLINE2 0x05 /* 第二行反白显示 */
#define DISP_CMD_EXLINE3 0x06 /* 第三行反白显示 */
#define DISP_CMD_EXLINE4 0x07 /* 第四行反白显示 */
#define DISP_CMD_EXTENIDLE 0x08 /* 进入睡眠模式 */
#define DISP_CMD_EXTEXIDLE 0x0c /* 退出睡眠模式 */
#define DISP_CMD_EXTIRAMADD 0x40 /* 起始IRAM位置或卷动位置 看SR命令SR=1卷动位置 SR=0ICOM RAM 地址*/
/********************************************************************************************************
* 本地函数
********************************************************************************************************/
#if DISP_GRH_EN > 0 /* LCM 图形方式驱动的本地函数 */
static void DispGrhInit (void);
static void DispGrhDataWrExt (INT8U x0, INT8U y0, INT16U dat);
static void DispGrhPosSetCur (INT8U x, INT8U y);
#endif
#if DISP_TXT_EN > 0 /* TXT 文本方式驱动的本地函数 */
static void DispTxtCharExt (INT8U row, INT8U col, char c);
static void DispTxtInit (void);
static void DispTxtPosSetCur (INT8U row, INT8U col);
static void DispTxtPosSetFront (INT8U row, INT8U col);
static void DispTxtStrExt (INT8U row, INT8U col, const char *s, BOOL constsel);//AVR扩展
#endif
/* 以下的函数与硬件有关 需要根据硬件来更改 是公用部分 */
#if DISP_TXT_EN > 0 || DISP_GRH_EN > 0
static void DispCtrlCmdWr (INT8U cmd);
static void DispCtrlDataWr (INT8U dat);
static INT8U DispCtrlDataRd (BOOL par);
static void DispInitHard (void);
static void DispLock (void);
static void DispUnLock (void);
#endif
/********************************************************************************************************
* 功 能 : 向LCM命令寄存器写命令
* 入 口 : 'cmd' 是当前要写入的命令数据
* 返 回 : 无
* 说 明 :1> 如果送到数据端口的数据跟实际需要送出的数据不一样 表示LCM可能出问题或着有共享的I/O被利用了
* 则需要等待其他的释放共享的I/O 来保证数据的正确性
* 2> 这里的时序问题 这里再不能做精简了
* 3> 这里的各种延时是在AVR 4MHz环境下测试得到
********************************************************************************************************/
#if DISP_GRH_EN > 0 || DISP_TXT_EN > 0
static void DispCtrlCmdWr (INT8U cmd)
{
LCDDATA_PORT_LOW = 0xff << LCDDATA; //
LCDDATA_PORT_HIGH = cmd << LCDDATA; //
SETBIT(LCDRS_PORT_LOW, LCDRS); // 选择命令寄存器 Cmd Reg low
SETBIT(LCDRW_PORT_LOW, LCDRW); // 选择写状态
SETBIT(LCDE_PORT_HIGH, LCDE); // 写入命令数据 _|---|_
DelayNUs(83); // 16US*5 的E线脉冲 经过测试必须>=5 85
SETBIT(LCDE_PORT_LOW, LCDE); //
DelayNUs(9); // 命令执行时间>=74uS
}
#endif
/********************************************************************************************************
* 功 能 : 从LCM数据寄存器读一字节数据
* 入 口 : 'bi' 如果是写地址后立即读 就需要虚读一次 连续读不需要 只能为 : 1地址立即读 0为连续读
* 返 回 : 当前读到的数据
* 说 明 : 1> 在调用此函数前需要写入要读数据的地址 如果是当前读 则不需要
* 2> 这里的时序问题 这里再不能做精简了
* 3> 这里的各种延时是在AVR 4MHz环境下测试得到
********************************************************************************************************/
#if DISP_GRH_EN > 0 || DISP_TXT_EN > 0
static INT8U DispCtrlDataRd (BOOL par)
{
INT8U dat;
LCDDATA_DDR &= ~(0xff << LCDDATA); // 输入方式
LCDDATA_PORT_HIGH |= (0xff << LCDDATA); // 处理数据
SETBIT(LCDRS_PORT_HIGH, LCDRS); // 选择数据寄存器
SETBIT(LCDRW_PORT_HIGH, LCDRW); // 选择为读方式
DelayNUs(23); // 等待信号稳定 >=2us
if (par) { //
SETBIT(LCDE_PORT_HIGH, LCDE); //
DelayNUs(16); //
SETBIT(LCDE_PORT_LOW, LCDE); //
DelayNUs(16); //
}
SETBIT(LCDE_PORT_HIGH, LCDE); //
DelayNUs(16); // 等待信号稳定
dat = (INT8U)(LCDDATA_PIN >> LCDDATA);// 读LCM的数据
SETBIT(LCDE_PORT_LOW, LCDE); //
LCDDATA_DDR |= (0xff << LCDDATA); // 恢复为输出方式
return (dat);
}
#endif
/********************************************************************************************************
* 功 能 : 向LCM数据寄存器写一字节数据
* 入 口 : 'dat' 是当前要写入的命令
* 返 回 : 无
* 说 明 :1> 如果送到数据端口的数据跟实际需要送出的数据不一样 表示LCM可能出问题或着有共享的I/O被利用了
* 则需要等待其他的释放共享的I/O 来保证数据的正确性
* 2> 这里的时序问题 这里再不能做精简了
* 3> 这里的各种延时是在AVR 4MHz环境下测试得到
********************************************************************************************************/
#if DISP_GRH_EN > 0 || DISP_TXT_EN > 0
static void DispCtrlDataWr (INT8U dat)
{
LCDDATA_PORT_LOW = 0xff << LCDDATA; //
LCDDATA_PORT_HIGH = dat << LCDDATA; //
SETBIT(LCDRS_PORT_HIGH, LCDRS); // 选择数据寄存器
SETBIT(LCDRW_PORT_LOW, LCDRW); // 选择写方式
SETBIT(LCDE_PORT_HIGH, LCDE); // LCDE __/--
DelayNUs(85); // 16US*5 的E线脉冲 经过测试必须>=5 85
SETBIT(LCDE_PORT_LOW, LCDE); //
DelayNUs(9); // 等待命令执行时间>=74uS
}
#endif
/********************************************************************************************************
* 功 能 : 图形方式全屏填充指定的数据
* 入 口 : 无
* 返 回 : 无
* 说 明 : 1>
********************************************************************************************************/
#if DISP_GRH_EN > 0
void DispGrhAllFill (INT8U dat)
{
BOOL bCS = 0;
INT8U x;
INT8U y;
INT8U ex;
INT8U bx;
DispLock(); //
while (1) {
if (!bCS) { // 根据软片选信号选择上半屏还是下半屏
bx = 0x80; //
ex = 0x80 + 8; //
} else {
bx = 0x88; //
ex = 0x88 + 8; //
}
for (y=0x80; y<(0x80+32); y++) { // 处理上下各半部分
for (x=bx; x<ex; x++) { //
DispGrhDataWrExt(x, y, (dat<<8)+dat);// 写数据
}
}
if (!bCS) { // 上下半部分起始地址选择
bCS = 1; // 切换到下半屏地址
continue; //
}
if (bCS) { // 已经是下半屏 退出
break; //
}
}
DispUnLock(); //
}
#endif
/********************************************************************************************************
* 功 能 : 图形方法显示BCD
* 入 口 : 'x' 显示的X坐标位置 范围0~DispMaxX
* 'y' 显示的Y坐标位置 范围0~DispMaxY
* 'dat' 显示的数据
* 返 回 : 无
* 说 明 : x y 方向大于DISP_GRH_MAX_X 和DISP_GRH_MAX_Y 时 不在显示范围内的部分会自动截掉
********************************************************************************************************/
#if DISP_GRH_EN > 0 && DISP_GRH_BCD_EN > 0
void DispGrhBCD (INT8U x0, INT8U y0, INT8U dat, COLORS colors)
{
DispLock();
dat %= 100;
DispGrhChar57(x0, y0, dat / 10 + '0', colors);
DispGrhChar57(x0+6, y0, dat % 10 + '0', colors);
DispUnLock();
}
#endif
/********************************************************************************************************
* 功 能 : 图形方法显示一个字符标准ASCII码 不包含控制字符
* 入 口 : 'x' 显示的X坐标位置 范围0~DispMaxX
* 'y' 显示的Y坐标位置 范围0~DispMaxY
* 'c' 显示的字符
* 返 回 : 无
* 说 明 : x y 方向大于DISP_GRH_MAX_X 和DISP_GRH_MAX_Y 时 不在显示范围内的部分会自动截掉
********************************************************************************************************/
#if DISP_GRH_EN > 0 && (DISP_GRH_CHAR_EN > 0 || DISP_GRH_STR_EN > 0 || DISP_GRH_BCD_EN > 0)
void DispGrhChar (INT8U x0, INT8U y0, char c, COLORS colors)
{
DispLock();
DispGrhChar57(x0, y0, c, colors);
DispUnLock();
}
#endif
/********************************************************************************************************
* 功 能 : 图形方法显示一个字符标准ASCII码 不包含控制字符
* 入 口 : 'x' 显示的X坐标位置 范围0~DispMaxX
* 'y' 显示的Y坐标位置 范围0~DispMaxY
* 'c' 显示的字符
* 返 回 : 无
* 说 明 : x y 方向大于DISP_GRH_MAX_X 和DISP_GRH_MAX_Y 时 不在显示范围内的部分会自动截掉
********************************************************************************************************/
#if DISP_GRH_EN > 0 && (DISP_GRH_CHAR_EN > 0 || DISP_GRH_STR_EN > 0 || DISP_GRH_BCD_EN > 0)
void DispGrhCharExt (INT8U x0, INT8U y0, char c, COLORS colors)
{
INT8U temph;
INT8U templ;
INT8U y_offset;
INT8U xBak;
if (x0 < DISP_GRH_MAX_X && y0 < DISP_GRH_MAX_Y) {
DispLock();
xBak = x0 >> 3; // 显示字节内位置 高8BIT跟低8BIT选择
c -= 0x20; //
for (y_offset=0; y_offset<8; y_offset++) {//
DispGrhPosSetCur(x0, y0+y_offset); // 显示坐标
DispCtrlCmdWr(DISP_CMD_BASIC); // 基本命令集
temph = DispCtrlDataRd(1); // 数据高字节
templ = DispCtrlDataRd(0); // 数据低字节
if ((xBak % 2) == 0) { // 处理待显示数据
//memcpy(&temph, &FONT5x7ASCII[(INT8U)c][y_offset], 1);// 是高字节写数据 取字库数据
temph = FONT5x7ASCII[(INT8U)c][y_offset];
if (colors) { // 判断颜色
temph = ~temph; //
}
} else {
//memcpy(&templ, &FONT5x7ASCII[(INT8U)c][y_offset], 1);// 是低字节写数据 取字库数据
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -