嵌入式设备显示技术:从七段显示器到自定义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 上显示自定义字符的技术,为我们在嵌入式设备开发中提供了更多的创意和可能性。希望本文的内容能对你有所帮助,让你在实际应用中能够灵活运用这些知识,实现自己的创意和想法。
超级会员免费看
351

被折叠的 条评论
为什么被折叠?



