Linux 下 使用点阵在LCD上显示汉字,字符

举报
糖果罐子 发表于 2023/10/31 21:05:38 2023/10/31
【摘要】 @[TOC](文章目录)---# 前言这篇文章主要讲一下如何在 LCD 上使用点阵显示汉字,字符 ,修改颜色 及效果展示。其中包含了几个核心函数,我们需要了解。# 一、显示字符### 1.获取点阵:各个字符对应的点阵都保存在一个数组里,大家可以打开 ***font_8x16.c*** 中得到点阵。(不同的点阵对应不同的代码,这里我使用的是 **8x16** 的点阵 )```c unsigne...


@[TOC](文章目录)

---

# 前言
这篇文章主要讲一下如何在 LCD 上使用点阵显示汉字,字符 ,修改颜色 及效果展示。其中包含了几个核心函数,我们需要了解。




# 一、显示字符
### 1.获取点阵:
各个字符对应的点阵都保存在一个数组里,大家可以打开 ***font_8x16.c*** 中得到点阵。(不同的点阵对应不同的代码,这里我使用的是 **8x16** 的点阵 )

```c
unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];

```
### 2.描点(显示字符函数):
找到点阵,将里面**需要的点上色**,**就可以在 LCD 上显示出不同的字符**。
我们使用的是 **8x16** 的点阵 ,点阵有十六行,每一行里有8位。所以首先要有一个循环16次的大循环代表每一行,在每一个大循环里也需要一个循环8次的小循环,代表每一位。

**x ,y** : 代表对应点的**横纵坐标**。
**c** : 表示你要显示的**字符**。
***lcd_put_pixel*** 此函数为描点函数,在 [Linux 应用基础 Framebuffer应用编程]( https://blog.csdn.net/wuyiyu_/article/details/128358009) 中我已详细的写出该函数。(第一二个参数代表x,y 坐标 。第三个参数代表颜色,可任意修改。)
```c
void lcd_put_ascii(int x, int y, unsigned char c)
{
unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
int i, b;
unsigned char byte;

for (i = 0; i < 16; i++)
{
byte = dots[i];
for (b = 7; b >= 0; b--)
{
if (byte & (1<<b))
{
/* show */
lcd_put_pixel(x+7-b, y+i, 0x00ff00); /* 绿色 */
}
else
{
/* hide */
lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
}
}
}
}
```
### 3. 要打开LCD设备:
对于不同的板子,你的 framebuffer **节点可能有所不同**,需注意。
```c
int fd_fb;

fd_fb = open("/dev/fb0", O_RDWR);
```
### 4. 通过ioctl 获取Framebuffer参数:
将得到的数据保存在 **var** 结构体中。这个结构体如果不了解的可以参考 [Linux 应用基础 Framebuffer应用编程](https://blog.csdn.net/wuyiyu_/article/details/128358009),我都已详细的说明。
```c
struct fb_var_screeninfo var;

    if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
```
### 5. 通过mmap映射出Framebuffer的地址:
要映射一块内存,就需要知道它的大小和地址。
**screen_size** : 为该内存的地址。(整个framebuffer 的大小)
```c
line_width  = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

```
### 6.清屏并显示字符:
使用 **memset** 将屏幕变成黑色,再显示字符,便于观察。
```c
memset(fbmem, 0, screen_size);

lcd_put_ascii(var.xres/2, var.yres/2, 'A'); /*在屏幕中间显示8*16的字母A*/
```
注意: 上面我们映射了一块内存,我们使用完后需要释放 **munmap** 。

```c
munmap(fbmem , screen_size);
```
---
# 二、显示汉字
显示汉字,我们可以从网上下载 **HZK16** 这个文件, 它是常用汉字的 **16*16** 点阵字库。HZK16里**每个汉字使用32字节来描述**。
### 1.区位码:
HZK16中**是以 GB2312 编码值**来查找点阵的,这里就要涉及汉字的区位码。区位码把GB2312字符集分为94个区,每区含有94个位。**一个汉字所在的区号和位号简单地组合在一起就构成了该汉字的"区位码**"。

例如:
   以“中”字为例,它的编码值是“0xd6 0xd0”,其中的0xd6表示“区码”,表示在哪一个区。其中的0xd0表示“位码”,表示它是这个区里的哪一个字符。由于***区位码从0xA1开始***,所以 “中” 字在 第“0xd6 - 0xa1”区,第“0xd0 - 0xa1”个。
   

```c
unsigned int area  = str[0] - 0xA1; //区码
unsigned int where = str[1] - 0xA1; //位码
unsigned char *dots = hzkmem + (area * 94 + where)*32;//每一个区有94个汉字每个汉字占了32个字节
```

### 2. 打开汉字库文件:
**struct stat** 这个结构体是用来描述一个linux系统文件系统中的文件属性的结构。通过 **fstat** 函数获得文件状态,保存到 **hzk_stat** 结构体中。

```c
int fd_hzk16;
struct stat hzk_stat;

fd_hzk16 = open("HZK16", O_RDONLY);
if (fd_hzk16 < 0)
{
printf("can't open HZK16\n");
return -1;
}
if(fstat(fd_hzk16, &hzk_stat))
{
printf("can't get fstat\n");
return -1;
}
hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
if (hzkmem == (unsigned char *)-1)
{
printf("can't mmap for hzk16\n");
return -1;
}

```
下面是 struct stat 结构体:

```c
struct stat {
mode_t     st_mode;       //文件对应的模式,文件,目录等
    ino_t      st_ino;       //inode节点号
dev_t      st_dev;        //设备号码
dev_t      st_rdev;       //特殊设备号码
nlink_t    st_nlink;      //文件的连接数
uid_t      st_uid;        //文件所有者
gid_t      st_gid;        //文件所有者对应的组
off_t      st_size;       //普通文件,对应的文件字节数
time_t     st_atime;      //文件最后被访问的时间
time_t     st_mtime;      //文件内容最后被修改的时间
time_t     st_ctime;      //文件状态改变时间
blksize_t st_blksize;    //文件内容对应的块大小
blkcnt_t   st_blocks;     //伟建内容对应的块数量
};
```
### 3.显示汉字函数:

```c
void lcd_put_chinese(int x, int y, unsigned char *str,unsigned int color)
{
unsigned int area  = str[0] - 0xA1; //区码
unsigned int where = str[1] - 0xA1; //位码
unsigned char *dots = hzkmem + (area * 94 + where)*32;//每一个区有94个汉字每个汉字占了32个字节
unsigned char byte;

int i, j, b;
for (i = 0; i < 16; i++)
{
for (j = 0; j < 2; j++)
{
byte = dots[i*2 + j];
for (b = 7; b >=0; b--)
{
if (byte & (1<<b))
{
/* show */
lcd_put_pixel(x+j*8+7-b, y+i, 0x00ff00); /* 绿色 */
}
else
{
/* hide */
lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */
}
}
}
}
}

```
可在主函数里面调用 :

```c
unsigned char str1[] = "你";
unsigned char str2[] = "好";

lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str1);
lcd_put_chinese(var.xres/2 + 8+16,  var.yres/2, str2);

```


---

# 总结
效果: 
![在这里插入图片描述](https://img-blog.csdnimg.cn/e5f05063bc6b42299ff76e7d99ccd0aa.png)

大家可以自行实践一下,有不懂的欢迎留言讨论。
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。