在屏幕上显示字符我之前就在做好了,之前只是可以显示。这两天把显示部分做了些修改。
修改如下
1.加了换行
2.字体大小大小的适应,如果以后换了字体简单修改后就可以用了
3.显示内容过多时自动换行
4.字距 行距的控制
5.加入了个显示控制结构体,方便做参数修改,
6.增加了print参数的单独配置函数
字库下载方法跳转
先声明
开发板 德飞莱STM32系列尼莫M3S
1.TFTLCD屏幕的配置是引用开发板的汉字显示程序
2.串口指令是参照“C语言中文网中的51单片机教程”
3.flash SPI也是借鉴开发板程序做了大量修改来符合自己的程序。。
在屏幕上显示字符的前提
1.最重要的当然是要有TFTLCD屏幕啦并且配置好参数,还有有个LCD显存地址设置函数 还有窗口设置函数
2.还有就是字库了,一般使用点阵字库,网上有字库生成工具,
3.把字库写到flash芯片。
4flash 要有个 读取指定个数的函数,
下面看代码
在这里插入代码片
#include "text.h"
extern struct
{ u16 backC; ///底色
u16 pen; ///画笔颜色
}LCD_Colour;
InitLcdPrintTypedef PrintInit;
uint32_t CN_PYL;
uint32_t CH_PYL;
/*--------------------print参数初始化--------------------*/
void InitPrint(){
PrintInit.backC = LCD_Colour.backC; ; //底色
PrintInit.pen = LCD_Colour.pen; //字体颜色颜色
PrintInit.Print_X = 1; //起始打印位置 X方向
PrintInit.Print_Y = 2; //起始打印位置 Y方向
PrintInit.size_H = 32; //字体大小 高度
PrintInit.size_L = 32; //字体大小 宽度
PrintInit.Word_Spacing = 1; //字距
PrintInit.Line_Spacing = 1; //行距
PrintInit.Word_Wrap = 1; //自动换行
//计数中文字符要读取的点阵字节数
CN_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L)/8;
//计数英文字符要读取的点阵字节数
CH_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L)/16;
}
/*--------------------print字体颜色配置--------------------*/
void ConfigPrintColour(uint16_t Print_backC, uint16_t Print_pen) {
PrintInit.backC = Print_backC;
PrintInit.pen = Print_pen;
}
/*--------------------print起始打印位置--------------------*/
void ConfigPrintSite(uint16_t Print_X, uint16_t Print_Y) {
PrintInit.Print_X = Print_X;
PrintInit.Print_Y = Print_Y;
}
/*--------------------print字体大小配置--------------------*/
void ConfigPrintSize(uint8_t size_H, uint8_t size_L) {
PrintInit.size_H = size_H;
PrintInit.size_L = size_L;
CN_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L) / 8;
CH_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L) / 16;
}
/*--------------------print行距字距配置--------------------*/
void ConfigPrintSpacing(uint8_t Word_Spacing, uint8_t Line_Spacing) {
PrintInit.Word_Spacing = Word_Spacing;
PrintInit.Line_Spacing = Line_Spacing;
}
/*--------------------print自动换行配置--------------------*/
void ConfigPrintWord_Wrap(uint8_t Word_Wrap) {
PrintInit.Word_Wrap = Word_Wrap;
}
/*--------------------打印字体点阵--------------------*/
void LCD_CharDot(uint8_t *dot, uint8_t c) {
uint8_t p = 0x01; //像素点控制,
KS_GRAM; //LCD RAM入口
/*汉字打印*/
if (c > 1) {
p = 0x80; //这与点阵字体的存储方式有关
//打印点阵行控制
for (uint8_t i = PrintInit.size_H; i > 0; i--) {
//打印点阵列控制
for(uint8_t j = PrintInit.size_L / 8; j > 0; j--){
while (p) {
if(*dot&p)
W_GRAM = PrintInit.pen; //字体打印
else
W_GRAM = PrintInit.backC; //底色打印
p = p >> 1;
}
p = 0x80;
dot++;
}
}
}
/*英文打印*/
else {
for (uint8_t i = PrintInit.size_H; i > 0; i--) {
for(uint8_t j = PrintInit.size_L / 16; j > 0; j--){
while (p) {
if(*dot&p)
W_GRAM = PrintInit.pen; //字体打印
else
W_GRAM = PrintInit.backC; //底色打印
p = p << 1;
}
p = 0x01;
dot++;
}
}
}
}
/*-----------------在LCD屏上打印字符串-----------------*/
void LCD_print(uint8_t *string) {
uint8_t dot[128]; //临时存储 用来存储从Flash中读出的字符点阵数据
uint8_t GBK_H, GBK_L; //GBK编码 高字节 和低字节
uint32_t GBK; //字符点阵在flash中的地址
uint16_t x = PrintInit.Print_X; //字符打印位置控制 X方向
uint16_t y = PrintInit.Print_Y; //字符打印位置控制 Y方向
while (*string!='\0') {
GBK_H = *string;
if(*string=='\n'){
x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
}
else{
/*汉字*/
if (GBK_H > 0x80) {
GBK_L = *(++string);
GBK_H -= 0x81;
if (GBK_L > 0x7f)
GBK_L -= 0x41;
else
GBK_L -= 0x40;
//计算所打印的字符在Flash字库存储的位置
GBK = ((uint32_t)190 * GBK_H + GBK_L) * CN_PYL+ (uint32_t)CH_PYL * 96 ;
//从Flash字库中读取字符点阵存放到dot数组中
FLASH_Read_Data(dot, GBK, CN_PYL);
//设置打印窗口
LCD_Window(x, x + PrintInit.size_L - 1, y, y + PrintInit.size_H - 1);
LCD_X_Y(x, y); //设置打印起始地址
LCD_CharDot(dot, 2); //打印字符
//调整字距字距
x = x + (PrintInit.size_L - 1 + PrintInit.Word_Spacing);
//检测本行是否无法显示所有内容,判断是否要自动换
if ((239 - x < PrintInit.size_L || x >= 239) && PrintInit.Word_Wrap) { 行
x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
}
}
/*英文*/
else {
/*---------ASCII码一共有128个可以显示出来的只有96个字库里也只有这96个--------*/
GBK = (GBK_H-0x20)* CH_PYL; //计算所打印的字符在Flash字库存储的位置
FLASH_Read_Data(dot, GBK, CH_PYL);
//ASCII码一共有128个可以显示出来的只有96个字库里也只有这96个
LCD_Window(x, x + PrintInit.size_L / 2 - 1, y, y + PrintInit.size_H -1);
LCD_X_Y(x, y);
LCD_CharDot(dot, 1);
x = x + (PrintInit.size_L / 2 + PrintInit.Word_Spacing)-1;
if ((239 - x < (PrintInit.size_L/2) || x >= 239) && PrintInit.Word_Wrap) {
x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
}
}
}
string++;
}
}
}
}
下面是头文件
#ifndef __TEXT_H
#define __TEXT_H
#include "stm32f10x.h"
#include "tft.h"
#include "usart.h"
typedef struct
{
uint16_t backC; //底色
uint16_t pen; //字体颜色颜色
uint16_t Print_X; //起始打印位置 X方向
uint16_t Print_Y; //起始打印位置 Y方向
uint8_t size_H; //字体大小 高度
uint8_t size_L; //字体大小 宽度
uint8_t Word_Spacing; //字距
uint8_t Line_Spacing; //行距
uint8_t Word_Wrap; //自动换行
}InitLcdPrintTypedef;
void InitPrint(); //print参数初始化
void ConfigPrintColour(uint16_t backC, uint16_t pen); //print字体颜色配置
void ConfigPrintSite(uint16_t Print_X, uint16_t Print_Y); //print起始打印位置
void ConfigPrintSize(uint8_t size_H, uint8_t size_L); //print字体大小配置
void ConfigPrintSpacing(uint8_t Word_Spacing, uint8_t Line_Spacing); //print行距字距配置
void ConfigPrintWord_Wrap(uint8_t Word_Wrap); //print自动换行配置 1:自动换行 0:不自动换行
void LCD_CharDot(uint8_t *dot, uint8_t c); //打印字体点阵
void LCD_print(uint8_t *string); //在LCD屏上打印字符串
#endif
下面开始代码讲解
为了以后方便使用我写了5个print配置函数,因为有的时候不一定全部参数都会配置,所以做了单独配置的函数。
GBK字库地址的计算:
GBK汉字的编码方式
第一个字节为 0x81~0xFE 称为汉字的区码
第二字节为两部分 1:0x40~0x7E 2:0x80~0xFE 称为汉字的位码 这就是汉字的区位码
接下来就是怎么把区位码转换成我们下载到Flash中字库的地址,首先我们要弄清楚几个问题
1.一个汉字的点阵集是多少个字节,如 3232的汉字 3232/8=128字节 英文的话 16*32/8=64字节
2.字库的点阵集是连续下载到Flash里的(我的字库ASCII和GBK是连着的,我先下载的ASCII接着下载GBK)
3.ASCII可以在屏幕上显示的只有96个字符
先判断第一个字节 若小于等于0x80,则编码为ASCII,说明是英文字符 英文字符因为前面32个是控制字符所以 ASCII字库的起始编码为0x20
uint32_t CH_PYL; //英文字符要读取的点阵字节数
uint32_t GBK; //字符点阵在flash中的地址
uint8_t GBK_H, GBK_L; //GBK编码 高字节 和低字节
uint8_t *string //要显示的字符
GBK_H = *string;
if (GBK_H <=0x80)
GBK = (GBK_H-0x20)* CH_PYL;
若第一个字节大于0x80说明编码为GBK第一个字节和第二个字节组成区位码
第一个字节减去0x81就是我们字库的正确区码
然后判断第二个字节 如果小于0x7f则减去0x40,如大于0x7f则减去0x41。
uint32_t CH_PYL; //英文字符要读取的点阵字节数
uint32_t GBK; //字符点阵在flash中的地址
uint8_t GBK_H, GBK_L; //GBK编码 高字节 和低字节
uint8_t *string //要显示的字符
GBK_H = *string; //第一个字节
if (GBK_H > 0x80) {
GBK_L = *(++string); //第二个字节
GBK_H -= 0x81;
if (GBK_L > 0x7f)
GBK_L -= 0x41;
else
GBK_L -= 0x40;
GBK = ((uint32_t)190 * GBK_H + GBK_L) * CN_PYL+ (uint32_t)CH_PYL * 96 ; //计算所打印的字符在Flash字库存储的位置
为什么高位要*190:因为GBK一个区有190个位,为什么减去0x41:因为0x400x7E与0x800xFE空了个0x7f,+ (uint32_t)CH_PYL * 96是为什么:因为GBK字库紧随ASCII其后,ascii在flash的起始地址为0x00
最后
我认为这次汉字显示中有难度的是:
1.怎么把字库下载到flash中 下载ASCII时没问题 但下GBK时非常容易中断,32*32的GBK字库文件有3MB大
2.字库区位码转换成flash中的地址,我在网上看了好多资料。
3.这只是我的笔记
本文由博客群发一文多发等运营工具平台 OpenWrite 发布