我写了大半天的程序,从像素位置显示字符串函数开始一点点调试改来的,我这里只做了32*32的字体实现,可以参考本程序,实现12,16,24等字体的这个功能,先看一下使用说明:
我封装出来的函数:
// x:0-14,y:0-24,单位是每个字32像素的个数,改造成LCD1525这样的屏幕,我的屏幕是480*800,总共显示15x25个汉字(类似带字库的LCD12864屏幕那样的显示方式),支持自动换行,屏幕上下自动循环,字母串自动补充空格实现对齐显示,不然汉字的一半刚好显示在屏幕结尾时候,是会乱码的
void myShow_String_15x25LCD(u8 x,u8 y,u8*str,u32 color)
主函数中这样调用后
显示效果:
可以看到当字符串中字母串是奇数个的时候,我是把它添加了空格的,这样每个汉字始终是在正确的位置上,其次屏幕底部自动换行到屏幕顶部了,实现了我们需要的功能。
所以只要我们给这个函数一个很长很长的字符串,比如在做记事本这类软件时候,从sd卡文本文件里面读取到任意长(里面用的是u16的类型,那么最大读取文本长度可能不能太大,一般而言几千字符没问题,那就一部分一部分的读呗就可以了)的字符串,然后给这个函数就能自动换行,自动上下屏幕循环显示了,不需要我们自己手动去费尽心思考虑显示位置,何时换行,对齐等等问题
核心.c代码我直接贴出来,免得去csdn下载
我是在正点原子的教程汉字显示实验改的,如果需要完整工程可以找我要,也可以自己去原子那儿下载,然后把这个.C和.h文件替换掉即可:
text.h
#ifndef __TEXT_H__
#define __TEXT_H__
#include "fontupd.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32H7开发板
//汉字显示 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2018/8/2
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//
void Get_HzMat(unsigned char *code,unsigned char *mat,u8 size); //得到汉字的点阵码
void Show_Font(u16 x,u16 y,u8 *font,u8 size,u8 mode); //在指定位置显示一个汉字
void Show_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode); //在指定位置显示一个字符串
void Show_Str_Mid(u16 x,u16 y,u8*str,u8 size,u8 len);
// x:0-14,y:0-24,单位是每个字32像素的个数,改造成LCD12864这样的屏幕,总共显示15x25个汉字
void myShow_String_15x25LCD(u8 x,u8 y,u8*str,u32 color);
#endif
text.c
#include "sys.h"
#include "fontupd.h"
#include "w25qxx.h"
#include "lcd.h"
#include "text.h"
#include "string.h"
#include "usart.h"
#include "malloc.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32H7开发板
//汉字显示 驱动代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2018/8/2
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//
//code 字符指针开始
//从字库中查找出字模
//code 字符串的开始地址,GBK码
//mat 数据存放地址 (size/8+((size%8)?1:0))*(size) bytes大小
//size:字体大小
void Get_HzMat(unsigned char *code,unsigned char *mat,u8 size)
{
unsigned char qh,ql;
unsigned char i;
unsigned long foffset;
u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数
qh=*code;
ql=*(++code);
if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用汉字
{
for(i=0;i0x80) // 是汉字
{
str=str+2;
if(n%2==1) // 如果n是奇数个英文字符
{
cntSpace++;
}
n=0;
}
else
{
str++;
n++;
}
}
return cntSpace;
}
// 函数作用:把一个字符串里面连续的英文字符变成偶数个,且存放在新的空间,方便后面的液晶显示函数
// 比如"你abc好a它b"->"你abc 好a 它b ",如果本来就是偶数个,那就不需要填充空格了
u8*myStr2StrHaveSpace(u8*str)
{
u16 nStr=myGetNumSpaceInsetFromStr(str);
u8* p=mymalloc(SRAMEX,myGetLengthOfStr(str)+nStr+1);// 最后一个填'\0'
u8* pTmp=p;
u16 n=0;
while(*str!=0)//数据未结束
{
if(*str>0x80) // 是汉字
{
if(n%2==1) // 如果n是奇数个英文字符
{
*p=' ';
p=p+1;
}
n=0;
*p=*str; // 拷贝字符过去
*(p+1)=*(str+1);
str=str+2;
p=p+2;
}
else
{
*p=*str; // 拷贝字符过去
str++;
p++;
n++;
}
}
*p='\0';
return pTmp;
}
// 这个函数是我自己写的工具函数,不对外开放,下面的函数自己调用的,用来解决每一行的片段显示功能
void myShow_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode)
{
u16 a=0;
u8 b;
a=width/16;
b=*(str+a);
*(str+a)='\0';
Show_Str(x,y,width,height,str,32,0);
*(str+a)=b;
}
// x:0-14,y:0-24,单位是每个字32像素的个数,改造成LCD12864这样的屏幕,总共显示15x25个汉字,支持自动换行
void myShow_String_15x25LCD(u8 x,u8 y,u8*str,u32 color)
{
u16 cnt = 0;
u16 nRow = 0;
u16 nC = 0; // 当前行已经显示了多少个字符
u16 nC1 = 0; // 最后一行应该显示多少个字符
u16 i;
POINT_COLOR=color;
str=myStr2StrHaveSpace(str);
cnt=myGetLengthOfStr(str);
if((480-32*x) >= (16*cnt)) // 说明当前行就够显示了
{
myShow_Str(x*32,y*32,cnt*16,32,str,32,0);
}
else // 说明需要多行才能显示
{
nC = (480-32*x)/16; // 第一行已经显示了多少个字符
nRow = (16*cnt - (480-32*x))/480 + 1; // 计算还需要多少行,加上第一行,总的行数是nRow+1行
nRow=nRow+1;
nC1 = cnt-nC-(nRow-2)*30; // 最后一行显示的字符个数,是减去的2(第一行和最后一行),不是1
for(i=0;i0x80)bHz=1;//中文
else //字符
{
if(x>(x0+width-size/2))//换行
{
y+=size;
x=x0;
}
if(y>(y0+height-size))break;//越界返回
if(*str==13)//换行符号
{
y+=size;
x=x0;
str++;
}
else LCD_ShowChar(x,y,*str,size,mode);//有效部分写入
str++;
x+=size/2; //字符,为全字的一半
}
}else//中文
{
bHz=0;//有汉字库
if(x>(x0+width-size))//换行
{
y+=size;
x=x0;
}
if(y>(y0+height-size))break;//越界返回
Show_Font(x,y,str,size,mode); //显示这个汉字,空心显示
str+=2;
x+=size;//下一个汉字偏移
}
}
}
//在指定宽度的中间显示字符串
//如果字符长度超过了len,则用Show_Str显示
//len:指定要显示的宽度
void Show_Str_Mid(u16 x,u16 y,u8*str,u8 size,u8 len)
{
u16 strlenth=0;
strlenth=strlen((const char*)str);
strlenth*=size/2;
if(strlenth>len)Show_Str(x,y,lcddev.width,lcddev.height,str,size,1);
else
{
strlenth=(len-strlenth)/2;
Show_Str(strlenth+x,y,lcddev.width,lcddev.height,str,size,1);
}
}
主函数中这样使用即可:main.c
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "usart.h"
#include "mpu.h"
#include "lcd.h"
#include "sdram.h"
#include "key.h"
#include "malloc.h"
#include "nand.h"
#include "ftl.h"
#include "w25qxx.h"
#include "sdmmc_sdcard.h"
#include "ff.h"
#include "exfuns.h"
#include "text.h"
//ALIENTEK 阿波罗STM32H7开发板 实验43
//汉字显示 实验
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司
int main(void)
{
Stm32_Clock_Init(160,5,2,4); //设置时钟,400Mhz
delay_init(400); //延时初始化
uart_init(100,115200); //串口初始化为115200
LED_Init(); //初始化与LED连接的硬件接口
MPU_Memory_Protection(); //保护相关存储区域
SDRAM_Init(); //初始化SDRAM
LCD_Init(); //初始化LCD
KEY_Init(); //初始化按键
W25QXX_Init(); //初始化W25Q256
my_mem_init(SRAMIN); //初始化内部内存池(AXI)
my_mem_init(SRAMEX); //初始化外部内存池(SDRAM)
my_mem_init(SRAM12); //初始化SRAM12内存池(SRAM1+SRAM2)
my_mem_init(SRAM4); //初始化SRAM4内存池(SRAM4)
my_mem_init(SRAMDTCM); //初始化DTCM内存池(DTCM)
my_mem_init(SRAMITCM); //初始化ITCM内存池(ITCM)
exfuns_init(); //为fatfs相关变量申请内存
f_mount(fs[0],"0:",1); //挂载SD卡
f_mount(fs[1],"1:",1); //挂载FLASH.
font_init();
POINT_COLOR=BLACK;
// Show_Str(0,0,200,32,"hello World",32,0);
// Show_Str(0,790,100,32,"S你好",32,0);
// myShow_String_15x25LCD(0,25,"H你好",BLUE);
myShow_String_15x25LCD(0,23," 你好挂载FLASH挂载FLASH为fatfs相关变量申请内存初始化DTCM内存池(DTCM)",BLACK);
// LCD_ShowChar(0,785,'A',32,0);
// LCD_ShowChar(0,773,'S',32,0);
while(1)
{
}
}