正点原子优化代码系列1——字符串排版

正点原子优化代码系列1——字符串排版

  • 刚刚开始学习嵌入式开发,现在使用的是 正点原子@ALIENTEK 的stm32的板子。
    本系列主要记录博主在学习过程中,一些针对正点原子原生代码的优化和一些脑洞想法以及其实现。

在学习正点原子的lcd章节中,正点原子可以提供了一部分可以作为工具使用的原生函数,但是在些代码很多带有小瑕疵。
比如 输出字符串:

void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
               //起始的x,y位置   单行长度   单行高度   字号  字符串指针
{         
	u8 x0=x;
	width+=x;
	//计算单行结束位置
	height+=y;
	//计算结束高度
	//输出是从左到右,从上到下进行的,所以结束高度也是输出结束的标志
    while((*p<='~')&&(*p>=' '))//判断非法字符
    {       
        if(x>=width){x=x0;y+=size;}
        //当输出光标超过单行结束位置时,光标打回同时换行
        if(y>=height)break;
        //当光标超过结束高度时,结束输出
        LCD_ShowChar(x,y,*p,size,0);
        //执行输出单个字符
        x+=size/2;
        //英文字母的字号佔标准字号的一般,所以这里只用增加一般的size
        p++;
    }  
}
  • 注释由博主添加

其中LCD_ShowChar也是原生代码中自带的函数,这个函数的主要功能显而易见,在指定的x,y位置输出size大小的一个字符。
接下来看看实际效果:
(图片截录来自正点原子的开发教程,lcd开发实验)

在这里插入图片描述

乍看之下除了背景色和字符串底色不同,其实并没有什么问题。(这个问题后面也会解决。)
但是来看一下展示的代码:

        LCD_ShowString(30,40,200,24,24,"Mini STM32 ^_^");	
        LCD_ShowString(30,70,100,80,16,"TFTLCD TEST");
		LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
 		LCD_ShowString(30,110,200,16,16,lcd_id);	      					 
		LCD_ShowString(30,130,200,12,12,"2014/3/7");	 

所有的换行都是由代码实现,但是就之前那showstring的源码来看,这个函数是具备换行功能的。
那么实际的效果呢???
(图片截录来自正点原子的开发教程,触摸屏开发实验)

在这里插入图片描述

图中可以发现,cross、styluts、until等单词都出现“断词“的迹象。

  • 那么我们就来思考一下怎么解决这一问题!

首先,要解决这一个问题我们要做的第一件事就是确保单词的连通性,也就说每次输出的都是一个单词,而非一个字母。那么思考一下文本中单词和单词之间的共性是什么?

答案是空格!

两个相邻的单词之间必然存在空格,也就是说空格可以成为我们保障读取单词的标志。

                                                  (ps.寻找共性也是NS规划执行中最重要的手段之一)

接下来实现代码:

void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
{         
	u8 x0=x;
    u8 *char_end;
    //在原生代码基础上增加了扫描单词结束的标志指针
	width+=x;
	height+=y;
    char_end=p;
    //定位到字符串
    while((*p<='~')&&(*p>=' '))//判断非法字符
    {       
        if(y>height)break;
        while((*char_end<='~')&&(*char_end>' ')){char_end++;} 
        //开始读取单词,判断是否为非法字符,并当读到空格时结束。
        if((char_end-p)*(size>>1)<(width-x)){ 
        //第一次执行时,字符串指针p还在原始位置,char_end指针指向了字符串第一个单词后的空格
        //判断剩余的空格是不是足够存放这个单词
        //*(size>>1)说明:char_end-p是多少个单词,在屏幕上具体佔多少位还要*(size>>1)
        //是的话
          while(p<char_end){
          //开始输出单词
            LCD_ShowChar(x,y,*p,size,0);
            p++;
            x+=(size>>1);
          }
          char_end++;
          //输出结束,char_end指针移向下一个单词的开头
        }else{
        //不是的话,换行
          x=x0;y+=size;
        }    
    }
}

OK!代码完成,但是实际效果会有问题!

  - 由于没有照相,博主只能口述实际效果;解决了“断词”现象,但是每次换行的首位会出现一个空格。

重新过一遍代码我们发现源代码逻辑有这样的问题。

 while(p<char_end){
          //开始输出单词
            LCD_ShowChar(x,y,*p,size,0);
            p++;
            x+=(size>>1);
          }
          char_end++;
          //输出结束,char_end指针移向下一个单词的开头

这段代码在结束后,p指在空格,char_end指在新单词的首字。接下来char_end继续读取单词,对比,当发现单词不能填入本行后换行时,p依旧指在空格,char_end指在单词结尾,输出。
逻辑清楚了,改很简单。

        else{
          x=x0;y+=size;
          p++;//换行时p后移,去除空格
        }

好了,代码完成了。
这时候想想有没可能出现极端报错,比如第一个单词就超出设定的行宽,单词之间有不法字符,单词之间有多个空格。
好吧,经过测试,这些极端情况都没有错误。
那么最后有一个问题,由于单词无法填入每行的空余量时就会换行,这就导致了每一行其实都很难填满,除非凑巧字数刚刚好。这就导致了在屏幕上的展示效果极差。应该如何修正?

 if((char_end-p)<(width-x))

原先在判断时,我们仅考虑能不能填满,现在需要给出一个修正量,也就说允许超过几个字母。
最后代码修正如下:

{         
	u8 x0=x;
  u8 *char_end; 
	width+=x;
	height+=y;
  char_end=p;
    while((*p<='~')&&(*p>=' ')){       
        if(y>height)break;
        while((*char_end<='~')&&(*char_end>' ')){char_end++;} 
        if(((char_end-p)*(size>>1)-(size<<1))<(width-x)){ 
                                ///size<<1 2倍的size即4个字母的长度
          while(p<char_end){
            LCD_ShowChar(x,y,*p,size,0);
            p++;
            x+=(size>>1);
          }
          char_end++;
        }else{
          x=x0;y+=size;
          p++;
        }    
    }
}

最后跑了一个莎翁的《as you like it》节选确认了效果。

- ps.小知识:莎士比亚一生创造了超过1700个英语词汇,使用的手段包括名词活用为动词,动词活用为形容词,把从不在一起用的两个词组合成一个词,添加前缀和后缀,以及创造全新的词汇。现在大量公司默认选用其作品作为英语展示的测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值