32、嵌入式设备显示技术:从七段显示器到自定义LCD字符

嵌入式设备显示技术:从七段显示器到自定义LCD字符

1. 七段显示器与TM1637控制

在电子显示的应用中,七段显示器是一种常见且实用的设备。例如,数组中包含二进制数 0b01001111 ,这是在七段显示器上显示数字 3 所需的数据。如果将变量加载为显示数字 [3] ,则该变量将被赋值为 0b0101111 ,这正是在七段显示器上显示数字 3 的二进制表示。

TM1637 驱动芯片通过创建伪 I2C 协议来进行控制。有人认为这样做可能是为了避免向 Phillips 支付使用标准 I2C 协议的许可费用。不过,其数据手册需要进一步完善,以更好地解释该协议。

在实际应用中,还会使用多重 if 测试来确保显示器上分钟和小时的个位与十位能够正确递增。同时,通过位测试做出重要决策,比如控制显示器上两个点的闪烁,以及每秒在时间和温度显示之间进行切换。

相关技术的学习涉及到多个方面,包括使用 timer1 及其中断结合外部晶体振荡器创建实时时钟(RTC),使用 DS1307 RTC 模块,以及使用 TM1637 驱动 IC 来控制带有四个七段显示器的实用且低成本模块。

2. LCD 自定义字符显示基础

LCD 不仅可以显示 ASCII 字符,还能实现自定义字符的显示。LCD 内部有两种重要的内存区域:DDRAM 和 CGRAM。
|内存区域|地址范围|用途|
| ---- | ---- | ---- |
|CGRAM|0b00000000 到 0b00001111|用于存储自定义字符的像素映射|
|DDRAM|0b00100000 到 0b11111111|存储标准 ASCII 字符的像素映射|

DDRAM 的地址对应着标准字符集的 ASCII 值,因此只需向 LCD 发送所需字符的 ASCII 码,就能访问 DDRAM 中的正确内存位置。而访问 CGRAM 时,需要发送相应的二进制地址值,因为其中的像素映射代表的字符需要我们自己设计。

3. 像素映射的创建

像素映射的大小取决于 LCD 显示器的分辨率。在本次实践中,LCD 的分辨率设置为 8x5 网格。要创建一个字符,需要控制网格中特定单元格的开关状态,逻辑 ‘1’ 表示打开,逻辑 ‘0’ 表示关闭。

例如,若要在地图中间显示一条竖线,对应的八个字节如下:
- Row 1: 0b00000100
- Row 2: 0b00000100
- Row 3: 0b00000100
- Row 4: 0b00000100
- Row 5: 0b00000100
- Row 6: 0b00000100
- Row 7: 0b00000100
- Row 8: 0b00000100

创建像素映射的代码实现过程是为每一行编写一个字节,共八个字节,以控制地图中所有行的单元格。不过,每个字节只有位 0 到 4 用于控制像素映射。

graph TD;
    A[开始] --> B[设置 RS 引脚为逻辑 '0'];
    B --> C[发送指令 0X40 到 LCD];
    C --> D[设置 RS 引脚为逻辑 '1'];
    D --> E[循环 8 次发送第一个字符的像素映射字节];
    E --> F[循环 8 次发送第二个字符的像素映射字节];
    F --> G[循环 8 次发送第三个字符的像素映射字节];
    G --> H[循环 8 次发送第四个字符的像素映射字节];
    H --> I[设置 RS 引脚为逻辑 '0'];
    I --> J[发送指令 0X80 到 LCD];
    J --> K[结束];
4. 存储像素映射到 CGRAM 的程序实现

以下是一个用于将像素映射存储到 CGRAM 并在 LCD 上显示自定义字符的程序示例:

/*This is a basic program to control the LCD using the 
PIC 18F4525
Written by H H Ward dated 22/05/21.
It writes to the CGRAM in the LCD
The display the four characters we have saved in the CGRAM*/
//some includes
#include <xc.h>
#include <conFigInternalOscNoWDTNoLVP.h>
#include <4bitLCDPortb.h>
char firstCharacter [8] =
{
    0b00000100,
    0b00000100,
    0b00011111,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
    0b00000100,
};
char secondCharacter [8] =
{
    0b00000100,
    0b00011111,
    0b00000100,
    0b00001110,
    0b00011111,
    0b00011111,
    0b00001110,
    0b00000100,
};
char thirdCharacter [8] =
{
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010001,
    0b00010011,
    0b00010111,
    0b00011111,
    0b00011111,
};
char fourthCharacter [8] =
{
    0b00001110,
    0b00010001,
    0b00000100,
    0b00000100,
    0b00011011,
    0b00011111,
    0b00011011,
    0b00001110,
};
void writeToCGram ()
{
    rsLine = 0x00;
    lcdData = 0x40;
    lcdOut ();
    rsLine = 0x10;
    n = 0;
    while (n < 8)
    {
        lcdData = firstCharacter [n];
        lcdOut ();
        n ++;
    }
    n = 0;
    while (n < 8)
    {
        lcdData = secondCharacter [n];
        lcdOut ();
        n ++;
    }
    n = 0;
    while (n < 8)
    {
        lcdData = thirdCharacter [n];
        lcdOut ();
        n ++;
    }
    n = 0;
    while (n < 8)
    {
        lcdData = fourthCharacter [n];
        lcdOut ();
        n ++;
    }
    rsLine = 0x00;
    lcdData = 0x80;
    lcdOut ();
    rsLine = 0x10;
}
void main ()
{
    PORTA = 0;
    PORTB = 0;
    PORTC = 0;
    PORTD = 0;
    TRISA = 0Xff;
    TRISB = 0x00;
    TRISC = 0x00;
    TRISD = 0x00;
    ADCON0 = 0x00;
    ADCON1 = 0x0F;
    OSCTUNE = 0b10000000;
    OSCCON = 0b01110100;
    T0CON = 0b11000111;
    TMR0 = 0;
    while (TMR0 < 255);
    setUpTheLCD ();
    clearTheScreen ();
    writeToCGram ();
    while (1)
    {
        writeString ("Using the CGRAM");
        line2 ();
        lcdData = 0x00;
        lcdOut ();
        lcdData = 0x20;
        lcdOut ();
        lcdData = 0x01;
        lcdOut ();
        lcdData = 0x20;
        lcdOut ();
        lcdData = 0x02;
        lcdOut ();
        lcdData = 0x20;
        lcdOut ();
        lcdData = 0x03;
        lcdOut ();
        lcdData = 0x20;
        lcdOut ();
        lcdData = 0x48;
        lcdOut ();
        lcdData = 0x2E;
        lcdOut ();
        lcdData = 0x57;
        lcdOut ();
        lcdData = 0x2E;
        lcdOut ();
        lcdData = 0x31;
        lcdOut ();
        lcdData = 0x32;
        lcdOut ();
        lcdData = 0x33;
        lcdOut ();
        rsLine = 0x00;
        lcdData = returnHome;
        lcdOut ();
        rsLine = 0x10;
    }
}
5. 程序分析
  • writeToCGRAM 子函数 :该子函数用于向 CGRAM 写入数据。首先,将 rsline 变量赋值为 0 ,确保 RS 引脚为逻辑 ‘0’ ,表示发送指令。然后,将 lcdData 赋值为 0X40 ,并调用 lcdOut() 函数发送该指令,告知 LCD 准备写入 CGRAM 。接着,将 rsline 赋值为 0x10 ,使 RS 引脚为逻辑 ‘1’ ,表示发送数据。之后,通过四个 while 循环分别将四个字符的像素映射字节发送到 CGRAM 。最后,再次将 rsline 赋值为 0 ,发送指令 0X80 ,告知 LCD 已完成 CGRAM 写入。
  • main 函数 :对各个端口进行初始化设置,包括将端口值清零、设置输入输出方向、配置 ADC 和振荡器等。调用 setUpTheLCD() 函数进行 LCD 初始化,清除屏幕。调用 writeToCGram() 函数将像素映射写入 CGRAM 。在无限循环中,先显示一条简单消息,然后依次显示四个自定义字符和一些 ASCII 字符,最后将光标返回起始位置。

通过以上步骤和代码,我们可以在 LCD 上实现自定义字符的显示。虽然创建的图像不如矩阵显示器那样详细,但在特定场景下仍具有一定的实用性。

嵌入式设备显示技术:从七段显示器到自定义LCD字符

6. 程序各部分详细操作分析

在上述程序中,各个部分的操作都有其特定的目的和意义,下面为你详细介绍每个关键步骤的操作过程:
|操作步骤|具体操作|说明|
| ---- | ---- | ---- |
|设置 RS 引脚为逻辑 ‘0’| rsLine = 0x00; |确保向 LCD 发送的是指令,因为 RS 引脚连接到 PORTB 的位 4,逻辑 ‘0’ 表示发送指令|
|发送指令 0X40 到 LCD| lcdData = 0x40; lcdOut (); |告知 LCD 准备写入 CGRAM,此时 LCD 会将指针指向 CGRAM 的第一个地址|
|设置 RS 引脚为逻辑 ‘1’| rsLine = 0x10; |表示接下来要发送的数据是用于显示的|
|发送第一个字符的像素映射字节|通过 while (n < 8) 循环 8 次,每次执行 lcdData = firstCharacter [n]; lcdOut (); n ++; |将第一个字符的 8 个字节像素映射依次发送到 CGRAM|
|发送第二个字符的像素映射字节|同样使用 while (n < 8) 循环 8 次,操作与第一个字符类似|将第二个字符的像素映射发送到 CGRAM 的下一个地址|
|发送第三个字符的像素映射字节|重复上述循环操作|将第三个字符的像素映射写入 CGRAM|
|发送第四个字符的像素映射字节|再次使用循环|将第四个字符的像素映射存入 CGRAM|
|设置 RS 引脚为逻辑 ‘0’| rsLine = 0x00; |为发送结束指令做准备|
|发送指令 0X80 到 LCD| lcdData = 0x80; lcdOut (); |告知 LCD 已完成 CGRAM 写入|
|设置 RS 引脚为逻辑 ‘1’| rsLine = 0x10; |恢复为数据显示模式|

7. 显示自定义字符及 ASCII 字符

在主函数的无限循环中,会进行自定义字符和 ASCII 字符的显示操作,具体步骤如下:
1. 显示简单消息: writeString ("Using the CGRAM"); ,在 LCD 上显示一条提示信息。
2. 移动光标到第二行: line2 (); ,将光标移动到 LCD 的第二行起始位置。
3. 显示自定义字符:
- lcdData = 0x00; lcdOut (); :显示第一个自定义字符,0x00 是 CGRAM 中第一个自定义字符的地址。
- lcdData = 0x20; lcdOut (); :显示一个空格,0x20 既是 DDRAM 中表示空格的地址,也是空格字符的 ASCII 码。
- 按照类似的方式依次显示其他自定义字符和空格。
4. 显示 ASCII 字符:
- lcdData = 0x48; lcdOut (); :显示字符 ‘H’,0x48 是字符 ‘H’ 的 ASCII 码。
- 继续显示其他 ASCII 字符。
5. 光标返回起始位置:
- rsLine = 0x00; lcdData = returnHome; lcdOut (); :将 RS 引脚设置为逻辑 ‘0’,发送 “returnHome” 指令,使光标返回起始位置。
- rsLine = 0x10; :恢复为数据显示模式。

8. 总结与展望

通过上述的程序和操作步骤,我们可以在 LCD 上实现自定义字符的显示。整个过程涉及到对 LCD 内存区域(CGRAM 和 DDRAM)的操作、像素映射的创建和存储,以及字符的显示控制。虽然这种方式创建的图像不如矩阵显示器那样详细,但在一些特定的应用场景中,如显示简单的图标、符号等,具有一定的实用性。

未来,我们可以进一步优化程序,例如将写入 CGRAM 的操作封装成更灵活的函数,允许动态修改要显示的自定义字符;或者结合其他传感器和功能模块,实现更加丰富的显示效果。同时,也可以探索不同分辨率的 LCD 显示器,以创建更复杂、更精美的自定义字符。

graph LR;
    A[开始显示] --> B[显示提示消息];
    B --> C[移动光标到第二行];
    C --> D[显示自定义字符];
    D --> E[显示 ASCII 字符];
    E --> F[光标返回起始位置];
    F --> G{是否继续显示};
    G -- 是 --> A;
    G -- 否 --> H[结束显示];

总之,掌握在 LCD 上显示自定义字符的技术,为我们在嵌入式设备开发中提供了更多的创意和可能性。希望本文的内容能对你有所帮助,让你在实际应用中能够灵活运用这些知识,实现自己的创意和想法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值