3 Star 15 Fork 4

建伟F4nniu / FN1895E-MCU101

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
MCU080.md 11.02 KB
一键复制 编辑 原始数据 按行查看 历史
建伟F4nniu 提交于 2016-12-24 10:44 . 整理完 70-90节。

#第八十节:调用液晶屏内部字库来显示汉字或字符的坐标体系和本质。

开场白:

前面章节讲的内容全部都是用自构字库的,相当于使用液晶屏的图像模式。其实这个款12864液晶屏的驱动芯片是st7920,它内部是自带16x16字库的,可以显示16x16的汉字或者8x16的字符。这一节开始就跟大家讲讲这方面的内容。要教会大家四个知识点:

  • 第一个:内部字库的真实坐标体系的本质。当我们用内部字库的时候,它的坐标体系跟前面讲的自造字库坐标不一样,不再是256x32的液晶屏。它还原成为128x64的液晶屏,横坐标x轴坐标没办法精确到每个点,只能以16个点(2个字节)为一个单位,因此128个点的x轴坐标范围是0至8。而y轴的坐标也是以16个点(2个字节)为一个单位,因此64个点的x轴坐标范围是0至3。把12864液晶屏分成4行8列,每个数代表一个坐标点。

  • 第二个:在使用内部字库时,C51编译器暗地里干了啥?如果使用液晶屏内部自带字库,编程的时候只要在源代码里直接写入所需要的汉字或者字符,就可以自动调用相对应的字库了。但是细心的网友一定会问,为什么在源代码上直接写入某个汉字就可以调用到这个汉字的字库?其实,表面上我们写下具体的某个汉字或者字符,但是C51编译器会自动对数组内的汉字翻译成 机内码(2字节),会自动对数组内的字符翻译成 ASCII码(1字节)。

  • 第三个:12864的控制芯片st7920内部有两套驱动显示指令方式,一种是前面章节讲的自构字库模式,也是图像模式。另外一种就是本节讲的用内部字库模式。在切换模式的时候,发送命令字0x0c表示用内部字库模式,发送命令字0x36表示用自构字库模式。

  • 第四个:12864整屏有4行8列,一共32个坐标点,每个坐标点可以显示一个16x16的汉字,但是在显示8x16字符时候,必须一次显示2个字符筹够16x16的点阵。例如,只想达到显示一个字符的时候,应该在另外一个空位置上显示空字符来填充。

具体内容,请看源代码讲解。

  • (1)硬件平台:基于朱兆祺51单片机学习板。

  • (2)实现功能:

  • 开机上电后,液晶屏第一行调用直接汉字书写方式的数组来显示(馒头V5)的内容。第四行调用机内码和ASCII码的数组来显示(馒头V5)的内容。

(3)源代码讲解如下:

#include "REG52.H"

sbit  LCDCS_dr  = P1 ^ 6; //片选线
sbit  LCDSID_dr = P1 ^ 7; //串行数据线
sbit  LCDCLK_dr = P3 ^ 2; //串行时钟线
sbit  LCDRST_dr = P3 ^ 4; //复位线

void SendByteToLcd(unsigned char ucData);  //发送一个字节数据到液晶模块
void SPIWrite(unsigned char ucWData, unsigned char ucWRS); //模拟SPI发送一个字节的命令或者数据给液晶模块的底层驱动
void WriteCommand(unsigned char ucCommand); //发送一个字节的命令给液晶模块
void LCDWriteData(unsigned char ucData);   //发送一个字节的数据给液晶模块
void LCDInit(void);  //初始化  函数内部包括液晶模块的复位
void display_clear(void); // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。

void display_hz1616(unsigned int x, unsigned int y, const unsigned char  *ucArray);
void display_double_zf816(unsigned int x, unsigned int y, const unsigned char  *ucArray1, const unsigned char  *ucArray2);

void delay_short(unsigned int uiDelayshort); //延时

/* 注释一:内部字库的真实坐标体系的本质。
* 当我们用内部字库的时候,它的坐标体系跟前面讲的自造字库坐标不一样,不再是256x32的液晶屏。
* 它还原成为128x64的液晶屏,横坐标x轴坐标没办法精确到每个点,只能以16个点(2个字节)为一个单位,
* 因此128个点的x轴坐标范围是0至8。而y轴的坐标也是以16个点(2个字节)为一个单位,因此64个点的x轴
* 坐标范围是0至3。以下是坐标地址的位置编码。把12864液晶屏分成4行8列,每个数代表一个坐标点,
* 用深究具体含义,液晶驱动芯片ST7920的手册上有提到。
*/
code unsigned char  ucAddrTable[] = //调用内部字库时,液晶屏的坐标体系,位置编码,是驱动内容,读者可以不用深究它的含义。
{
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
};


/* 注释二:在使用内部字库时,C51编译器暗地里干了啥?
* 如果使用液晶屏内部自带字库,以下编程的时候只要在源代码里直接写入所需要的汉字或者字符,
* 就可以自动调用相对应的字库了。但是细心的网友一定会问,为什么在源代码上直接写入某个汉字
* 就可以调用到这个汉字的字库?其实,表面上我们写下具体的某个汉字或者字符,但是C51编译器
* 会自动对数组内的汉字翻译成 机内码(2字节),会自动对数组内的字符翻译成 ASCII码(1字节)。
* 本节程序会做这个实验来验证它。以下两种书写方式不一样,但本质是一样的。
*/

code unsigned char Hz1616_man[] = "馒"; //对于数组内的汉字,编译会自动翻译成 机内码(2字节)
code unsigned char JN1616_man[] = //机内码  馒  网上有很多把汉字或者字符转换成相关编码的工具软件
{
    0xC2,
    0xF8,
};

code unsigned char Hz1616_tou[] = "头"; //对于数组内的汉字,编译会自动翻译成 机内码(2字节)
code unsigned char JN1616_tou[] = //机内码  头  网上有很多把汉字或者字符转换成相关编码的工具软件
{
    0xCD,
    0xB7,
};

code unsigned char Zf816_V[] = "V";   //对于数组内的字符,编译会自动翻译成 ASCII码(1字节)
code unsigned char ASCII816_V[] = //ASCII码  V  网上有很多把汉字或者字符转换成相关编码的工具软件
{
    0x56,
};

code unsigned char Zf816_5[] = "5";   //对于数组内的字符,编译会自动翻译成 ASCII码(1字节)
code unsigned char ASCII816_5[] = //ASCII码  5  网上有很多把汉字或者字符转换成相关编码的工具软件
{
    0x35,
};


code unsigned char Zf816_nc[] = " ";   //对于数组内的字符,编译会自动翻译成 ASCII码(1字节)
code unsigned char ASCII816_nc[] = //ASCII码  空字符  网上有很多把汉字或者字符转换成相关编码的工具软件
{
    0x20,
};


void main()
{
    LCDInit(); //初始化12864 内部包含液晶模块的复位

    /* 注释三:
    * 12864的控制芯片st7920内部有两套驱动显示指令方式,一种是前面章节讲的自构字库模式,也是图像模式。
    * 另外一种就是本节讲的用内部字库模式。以下是切换模式的命令,命令字0x0c表示用内部字库模式。
    * 命令字0x36表示用自构字库模式。
    */
    WriteCommand(0x0C); //命令字0x0c表示用内部字库模式。命令字0x36表示用自构字库模式。

    display_clear(); // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。


    display_hz1616(0, 0, Hz1616_man); //第一行,调用直接汉字书写方式的数组来显示(馒头V5),
    display_hz1616(1, 0, Hz1616_tou);
    display_double_zf816(2, 0, Zf816_V, Zf816_5);

    display_hz1616(0, 3, JN1616_man); //第四行,调用机内码和ASCII码的数组来显示(馒头V5),
    display_hz1616(1, 3, JN1616_tou);
    display_double_zf816(2, 3, ASCII816_V, Zf816_5);


    while(1)
    {
        ;
    }

}


/* 注释四:在一个坐标点显示1个内部字库汉字的函数
* 第1,2个参数x,y是坐标体系。x的范围是0至8,y的范围是0至3.
* 第3个参数*ucArray是汉字机内码,是有2个字节的数组。
*/
void display_hz1616(unsigned int x, unsigned int y, const unsigned char  *ucArray)
{
    WriteCommand(0x30);   //基本指令集
    WriteCommand(ucAddrTable[8 * y + x]);    //起始位置
    LCDWriteData(ucArray[0]);
    LCDWriteData(ucArray[1]);
}

/* 注释五:在一个坐标点显示2个内部字库字符的函数
* 注意,由于一个坐标点是16x16点阵,而一个字符是8x16点阵的,所以务必要显示2个字符筹够1个坐标点。
* 第1,2个参数x,y是坐标体系。x的范围是0至8,y的范围是0至3.
* 第3个参数*ucArray1是左边第1个字符ASCII码,是有1个字节的数组。
* 第4个参数*ucArray2是右边第2个字符ASCII码,是有1个字节的数组。
*/
void display_double_zf816(unsigned int x, unsigned int y, const unsigned char *ucArray1, const unsigned char  *ucArray2)
{
    WriteCommand(0x30);   //基本指令集
    WriteCommand(ucAddrTable[8 * y + x]);    //起始位置
    LCDWriteData(ucArray1[0]);
    LCDWriteData(ucArray2[0]);
}


void display_clear(void) // 清屏。4行8列的坐标点全部显示2个空字符相当于清屏了。
{

    unsigned int i, j;
    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 8; j++)
        {
            display_double_zf816(j, i, Zf816_nc, ASCII816_nc); //Zf816_nc与ASCII816_nc本质是一样的,只是书写方式不一样。
        }
    }
}

void SendByteToLcd(unsigned char ucData)  //发送一个字节数据到液晶模块
{
    unsigned char i;
    for ( i = 0; i < 8; i++ )
    {
        if ( (ucData << i) & 0x80 )
        {
            LCDSID_dr = 1;
        }
        else
        {
            LCDSID_dr = 0;
        }
        LCDCLK_dr = 0;
        LCDCLK_dr = 1;
    }
}

void SPIWrite(unsigned char ucWData, unsigned char ucWRS) //模拟SPI发送一个字节的命令或者数据给液晶模块的底层驱动
{
    SendByteToLcd( 0xf8 + (ucWRS << 1) );
    SendByteToLcd( ucWData & 0xf0 );
    SendByteToLcd( (ucWData << 4) & 0xf0);
}


void WriteCommand(unsigned char ucCommand) //发送一个字节的命令给液晶模块
{

    LCDCS_dr = 0;
    LCDCS_dr = 1;
    SPIWrite(ucCommand, 0);
    delay_short(90);
}

void LCDWriteData(unsigned char ucData)  //发送一个字节的数据给液晶模块
{
    LCDCS_dr = 0;
    LCDCS_dr = 1;
    SPIWrite(ucData, 1);
}

void LCDInit(void) //初始化  函数内部包括液晶模块的复位
{
    LCDRST_dr = 1;  //复位
    LCDRST_dr = 0;
    LCDRST_dr = 1;
}

void delay_short(unsigned int uiDelayShort) //延时函数
{
    unsigned int i;
    for(i = 0; i < uiDelayShort; i++)
    {
        ;
    }
}

总结陈词:

通过本节的实验,我们发现汉字的识别本质是机内码,字符的识别本质是ASCII码。不管是机内码还是ASCII码,这些都是16进制的数字,也就是我们手机平时接收和发送的信息本质都是这些数字编码,但是机内码是2个字节,ASCII码是1个字节,如果在一串随机的信息中,同时包含汉字和字符两种数字信息,我们的程序又该如何能筛选和识别它们,会不会把机内码和ASCII码搞混乱了?不会的。其实这两种编码都是有规律可以筛选识别的,欲知详情,请听下回分解-----液晶屏显示串口发送过来的任意汉字和字符。

(未完待续,下节更精彩,不要走开哦)

C
1
https://gitee.com/F4NNIU/FN1895E-MCU101.git
git@gitee.com:F4NNIU/FN1895E-MCU101.git
F4NNIU
FN1895E-MCU101
FN1895E-MCU101
Development

搜索帮助