stm32驱动液晶屏如何实现字符串自动换行和翻页循环显示源码

我写了大半天的程序,从像素位置显示字符串函数开始一点点调试改来的,我这里只做了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;i<csize;i++)*mat++=0x00;//填充满格
	    return; //结束访问
	}          
	if(ql<0x7f)ql-=0x40;//注意!
	else ql-=0x41;
	qh-=0x81;   
	foffset=((unsigned long)190*qh+ql)*csize;	//得到字库中的字节偏移量  		  
	switch(size)
	{
		case 12:
			W25QXX_Read(mat,foffset+ftinfo.f12addr,csize);
			break;
		case 16:
			W25QXX_Read(mat,foffset+ftinfo.f16addr,csize);
			break;
		case 24:
			W25QXX_Read(mat,foffset+ftinfo.f24addr,csize);
			break;
		case 32:
			W25QXX_Read(mat,foffset+ftinfo.f32addr,csize);
			break;
			
	}     												    
}  
//显示一个指定大小的汉字
//x,y :汉字的坐标
//font:汉字GBK码
//size:字体大小
//mode:0,正常显示,1,叠加显示	   
void Show_Font(u16 x,u16 y,u8 *font,u8 size,u8 mode)
{
	u8 temp,t,t1;
	u16 y0=y;
	u8 dzk[128];   
	u8 csize=(size/8+((size%8)?1:0))*(size);			//得到字体一个字符对应点阵集所占的字节数	 
	if(size!=12&&size!=16&&size!=24&&size!=32)return;	//不支持的size
	Get_HzMat(font,dzk,size);	//得到相应大小的点阵数据 
	for(t=0;t<csize;t++)
	{   												   
		temp=dzk[t];			//得到点阵数据                          
		for(t1=0;t1<8;t1++)
		{
			if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
			else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR); 
			temp<<=1;
			y++;
			if((y-y0)==size)
			{
				y=y0;
				x++;
				break;
			}
		}  	 
	}  
}
u16 myGetLengthOfStr(u8*str)
{
	u16 n=0;
	while(*str!=0)//数据未结束
	{
		++str;
		++n;
	}
	return n;
}
u16 myGetNumSpaceInsetFromStr(u8*str)
{
	u16 n=0;
	u16 cntSpace=0;
	while(*str!=0)//数据未结束
    { 
		if(*str>0x80)	// 是汉字
		{
			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;i<nRow;++i)
		{
			if(i==0)	// 如果是第一行,肯定不可能超过屏幕底部
			{
				myShow_Str(x*32,y*32,nC*16,32,str,32,0);
			}
			else if(i==(nRow-1))	// 如果是最后一行了
			{
				// 这样就实现字符串上下循环屏幕显示效果
				// 即(y+i)%25的方式实现y坐标循环
				myShow_Str(0,((y+i)%25)*32,nC1*16,32,str+nC+30*(i-1),32,0);
			}
			else		
			{
				myShow_Str(0,((y+i)%25)*32,480,32,str+nC+30*(i-1),32,0);	// 30是指每行能显示30个字符
			}
		}
	}
}
//在指定位置开始显示一个字符串	    
//支持自动换行
//(x,y):起始坐标
//width,height:区域
//str  :字符串
//size :字体大小
//mode:0,非叠加方式;1,叠加方式    	   		   
void Show_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode)
{					
	u16 x0=x;
	u16 y0=y;							  	  
    u8 bHz=0;     //字符或者中文  	    				    				  	  
    while(*str!=0)//数据未结束
    { 
        if(!bHz)
        {
	        if(*str>0x80)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)
	{
			
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值