这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【Ai8051U】以串行模式驱动带汉字字库的LCD12864

共1条 1/1 1 跳转至

【Ai8051U】以串行模式驱动带汉字字库的LCD12864

专家
2026-08-17 14:06:13     打赏

使用带汉字字库的LCD12864的一个最大优点是,不需要为要显示的汉字提前准备点阵数据。而以串行模式驱动,就不需要太多的消耗IO口。

根据资料,需要使用以下几个IO:

RS(CS)

串行的片选信号

R/W(SID)

串行的数据口

E(CLK)

串行的同步时钟

实际测试中,可以匹配Ai8051U的罗电平。

我手里的这块LCD12864工作电压(VDD)是4.5V~5.5V。

接口时序:

image.png

串行数据传送共分三个字节完成:

第一字节:串口控制—格式 11111ABC

 A 为数据传送方向控制:H 表示数据从 LCD 到 MCU,L 表示数据从 MCU 到 LCD。

 B 为数据类型选择:H 表示数据是显示数据,L 表示数据是控制指令

 C 固定为 0

第二字节:(并行)8 位数据的高 4 位—格式 DDDD0000

第三字节:(并行)8 位数据的低 4 位—格式 0000DDDD

在串行模式下,传输的时钟不能太快,也不能太慢,建议保持在500KHz左右。如果使用IO口模拟方传输,注意单片机的主频以及加必要的延时处理。如果使用SPI外设,注意设置正确的SPI传输速度。

以下是使用STC的Ai8051U的测试代码,使用12MHz的工作主频,用的是擎天柱开发板。

为了方便,我把c文件和h文件合并到h文件中了。

Lcd12864.h

/**
 * 串行模式驱动12864
 * 驱动芯片:ST7920
 * PSB引脚必须接低电平(GND),以选择串行通信模式。你需要将微控制器的三个GPIO引脚分别连接到液晶屏的CS(片选)、SID(串行数据)和SCLK(串行时钟) 引脚。
 */
 
 
#ifndef _LCD12864_S_H_
#define _LCD12864_S_H_
 
 
#include "../comm/AI8051U.h"
#include "stdio.h"
#include "intrins.h"
 
void LCD12864_Init_S(void);
void SetTextPos_S(unsigned char row, unsigned char col);
void ShowString_S(unsigned char row, unsigned char col, unsigned char *str);
void ShowChinese_S(unsigned char row, unsigned char col, unsigned char *ch);
void LCD_Clear_S(void);
void SetGraphicMode_S(void);
void SetTextMode_S(void);
void WriteGDRAM_S(unsigned char x, unsigned char y, unsigned char high_byte, unsigned char low_byte);
void ShowPicture_S(unsigned char *pic);
 
// 定义引脚
sbit LCD_CS_S   = P2^7;   // 片选
sbit LCD_SID_S  = P2^6;   // 串行数据
sbit LCD_SCLK_S = P2^5;   // 串行时钟
 
 
// 延时函数(STC8051U 主频较高,适当调整)
void delay_us(unsigned int t)
{
    while(t--);
}
 
 
// 核心:串行发送一个字节
void SendByte_S(unsigned char dat) {
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
        LCD_SCLK_S = 0;
        if(dat & 0x80)
            LCD_SID_S = 1;
        else
            LCD_SID_S = 0;
        dat <<= 1;
        LCD_SCLK_S = 1;
    }  
}
 
 
// 写指令/数据到 ST7920(串行模式)
// rw: 0=写, 1=读
// rs: 0=指令, 1=数据
// wdata: 要发送的 8 位数据
void Write_ST7920_S(unsigned char rw, unsigned char rs, unsigned char wdata)
{
    unsigned char high, low;
    
    LCD_CS_S = 1;          // 片选有效
    
    // 第一个字节:起始位(5个1) + RW + RS + 0
    SendByte_S(0xF8 | (rw << 2) | (rs << 1));
    
    // 第二个字节:数据高4位 + 4个0
    high = wdata & 0xF0;
    SendByte_S(high);
    
    // 第三个字节:数据低4位左移 + 4个0
    low = (wdata << 4) & 0xF0;
    SendByte_S(low);
    
    LCD_CS_S = 0;          // 片选结束
    delay_us(50);        // 等待指令执行完成
}
 
// 快捷写指令
void WriteCmd_S(unsigned char cmd)
{
    Write_ST7920_S(0, 0, cmd);
}
 
// 快捷写数据
void WriteData_S(unsigned char dat)
{
    Write_ST7920_S(0, 1, dat);
}
 
// 12864 初始化
void LCD12864_Init_S(void)
{
    LCD_CS_S = 0;
    LCD_SID_S = 0;
    LCD_SCLK_S = 0;
    
    delay_us(20000);     // 上电延时等待
    
    WriteCmd_S(0x30);      // 基本指令集,8位数据(串行模式下必须)
    delay_us(100);
    WriteCmd_S(0x0C);      // 显示开,光标关,闪烁关
    delay_us(100);
    WriteCmd_S(0x01);      // 清屏
    delay_us(2000);      // 清屏需要较长延时
    WriteCmd_S(0x06);      // 光标右移,地址自动+1
}
 
// 设置显示地址(基本指令集,文字显示)
// row: 0~3 行
// col: 0~7 列(中文字,每字占16x16,一行8个字)
void SetTextPos_S(unsigned char row, unsigned char col)
{
    unsigned char addr;
    switch(row)
    {
        case 0: addr = 0x80; break;  // 第一行首地址
        case 1: addr = 0x90; break;  // 第二行首地址
        case 2: addr = 0x88; break;  // 第三行首地址
        case 3: addr = 0x98; break;  // 第四行首地址
        default: addr = 0x80;
    }
    addr += col;
    WriteCmd_S(addr);
}
 
// 显示字符串(支持中文和英文)
// 中文占2字节,英文占1字节
// 支持中英文混排,自动处理地址对齐
void ShowString_S(unsigned char row, unsigned char col, unsigned char *str)
{
    unsigned char addr;
    unsigned char *p = str;
    
    // 计算起始地址
    switch(row)
    {
        case 0: addr = 0x80; break;
        case 1: addr = 0x90; break;
        case 2: addr = 0x88; break;
        case 3: addr = 0x98; break;
        default: addr = 0x80;
    }
    addr += col;
    WriteCmd_S(addr);
    
    while(*p != '\0')
    {
        // 判断是否为汉字:GB2312 高字节 >= 0xA1
        if(*p >= 0xA1)
        {
            // 写汉字前,确保地址是偶数(对齐到格子开头)
            if(addr & 0x01)  // 地址为奇数,卡在半格中间
            {
                WriteData_S(' ');  // 补一个半角空格,把地址推到偶数
                addr++;
            }
            // 写汉字(2字节)
            WriteData_S(*p++);
            addr++;
            WriteData_S(*p++);
            addr++;
        }
        else
        {
            // 英文、数字、符号(半角,1字节)
            WriteData_S(*p++);
            addr++;
        }
    }
}
 
 
// 显示单个中文字(16x16,使用内置字库)
void ShowChinese_S(unsigned char row, unsigned char col, unsigned char *ch)
{
    SetTextPos_S(row, col);
    WriteData_S(ch[0]);
    WriteData_S(ch[1]);
}
 
// 清屏
void LCD_Clear_S(void)
{
    WriteCmd_S(0x01);
    delay_us(2000);
}
 
// ==================== 图形显示扩展(可选)====================
 
// 切换到扩充指令集(支持绘图 RAM 访问)
void SetGraphicMode_S(void)
{
    WriteCmd_S(0x36);      // 扩充指令集 + 绘图显示开
}
 
// 切换到基本指令集(文字模式)
void SetTextMode_S(void)
{
    WriteCmd_S(0x30);      // 基本指令集
}
 
// 写图形数据到 GDRAM(绘图 RAM)
// x: 0~15(水平地址,每地址2字节=16像素)
// y: 0~31(垂直地址,共32行,上下半屏各32行)
void WriteGDRAM_S(unsigned char x, unsigned char y, unsigned char high_byte, unsigned char low_byte)
{
    unsigned char row = y;
    unsigned char col = x;
    
    if(y < 32)           // 下半屏
    {
        col += 8;
        row = 31 - y;
    }
    else                 // 上半屏
    {
        row = 63 - y;
    }
    
    WriteCmd_S(0x34);      // 扩充指令集,绘图关
    WriteCmd_S(0x80 + row);    // 设置垂直地址
    WriteCmd_S(0x80 + col);    // 设置水平地址
    
    WriteData_S(high_byte);    // 写入高字节 D15~D8
    WriteData_S(low_byte);     // 写入低字节 D7~D0
    
    WriteCmd_S(0x36);      // 绘图显示开
}
 
// 显示图片(1024字节,128x64 位图)
// pic: 指向 1024 字节图片数据的指针
void ShowPicture_S(unsigned char *pic)
{
    unsigned char i, j, k;
    
    WriteCmd_S(0x34);      // 扩充指令集
    
    for(i = 0; i < 2; i++)      // 上下半屏
    {
        for(j = 0; j < 32; j++) // 每半屏32行
        {
            WriteCmd_S(0x80 + j);         // 行地址
            WriteCmd_S(0x80 + (i ? 0x08 : 0x00)); // 列地址
            
            for(k = 0; k < 16; k++)     // 每行16字节(128点)
            {
                WriteData_S(*pic++);
            }
        }
    }
    
    WriteCmd_S(0x36);      // 绘图显示开
}
#endif   /* _LCD12864_S_H_ */
 

主文件中按照以下顺序添加测试代码即可:

    LCD12864_Init_S();
    
    // 文字显示示例
    ShowString_S(行编号(0-3),列坐标(0-127), "STC8051U 串行");


 





关键词: Ai8051U     LCD12864     串行模式    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]