历史上的今天
返回首页

历史上的今天

今天是:2024年09月12日(星期四)

正在发生

2019年09月12日 | 基于STM32的简单电子书的实现

2019-09-12 来源:eefocus

今天玩了会液晶屏,原来显示汉字都是也取模软件区模后在液晶屏上显示,显示内容改变以后还需要重新做字模,比较麻烦。这两天有时间,参考网友资料,实现了读取汉字的内码从SD卡的GB2312点阵字库读取点阵在液晶屏上显示,字库的生成软件用的是易木雨的点阵字库生成器。能生成很多种语言的字库。做完了读取显示后,我自己又琢磨了一下,简单的实现了从SD卡中读取txt文档然后再液晶屏上显示txt内容。


取模过程注意点阵的宽、高和字体大小的关系,宽、高是我们在液晶屏上要显示的像素大小,字体是汉字大小,如果宽、高一定,字体大小太到的话,字在液晶屏上只能显示一部分,可以在左侧的预览区看出来,如果字体在宽高像素点的范围内则可以在液晶上显示完整的字,如果不能显示完整则可以调整宽高或者字体大小。


国标字有GB2312和GBK编码,GBK完全兼容GB2312包括内码的兼容,而且GBK字库增加了很多字。汉字都是用的两个字节表示,第一个字节是区号,第二个字节是在区内的相对偏移位置。通过内码来获取字库内的偏移位置,偏移位置与内码和生成字库的宽高都有关系。我生成的GB2312字库是16*16个像素点显示一个汉字,那在字库内的偏移位置:


offset=32* (  (H-0xa1)*94+(L-0xa1)  )


H 表示内码的高字节,L表示内码的低字节。GB2312高字节是0xa1~0xfe表示区号,每个区有94个字节所以*94得到区的相对位置,L表示内码低字节也是从0xa1~0xfe,L-0xa1 得到的是在当前区内的偏移位置。 因为每个汉字有16*16=32个自己组成,所以最后乘以32得到在点阵字库中的偏移位置,从这个位置开始取出32个字节的点阵数据然后打点显示就可以把一个汉字显示出来了。


获取点阵的代码如下


     FATFS fs1;    // 挂载SD卡的分区用

     FIL f1;            // SD卡中字库的文件描述符  

      FIL ftxt;         // 要读取的txt文档的文件描述符    


    u8 fnGetChinese(u8 *p,u8 *buff)    // 形参是要读取的汉字

    {

        u8 res=0;


u8 H8,L8;

UINT num;


H8=*p; 

L8=*(p+1);


f_mount(&fs1,"",1);                            //  挂载SD卡

res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ);    // 打开SD卡下的点阵字库


if(res!=0)                    // 判断点阵字库是否打开成功

         {

       fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);

printf("res=%x",res);

return 1;

         }

else

{

       fnShowString(10,120,"open ok",16,RED,WHITE,0);

}



        f_lseek(&f1,32*((H8-0xa0-1)*94+(L8-0xa0-1)));                 // 在字库文件中做偏移取出32个字节的点阵数据


res=f_read(&f1,buff,32,&num);


f_close(&f1);                                                   // 读完后关闭点阵字库文件

f_mount(&fs1,"",NULL);                                  // 卸载SD卡


        return 0; 

}


这个是得到汉字点阵的实现过程,得到点阵数据后就可以在液晶上打点实现汉字的显示,具体的底层驱动不再详细介绍。


实现了在单片内显示汉字串以后,能不能读取SD卡中的txt文档中的汉字在液晶屏上显示呢?这块是我自己想的,不知道与别人的一样不一样,反正是实现了。


首先我读取SD卡上txt文档上的一个汉字,然后用串口打印出来,发现,读到的就是汉字的内码,百度了下说windows中txt文档的显示的用GB2312的字库。既然读到直接是内码,那就好办了。汉字内码用的是两个字节,字符用的是一个字节,这个一定要注意,因为在以后显示的过程中要用。


下面直接贴代码:


          //  x,y在液晶屏上的显示位置,我的液晶屏是320*240 ,竖屏显示


          //  color 是画笔的颜色,BkColor 是背景颜色


          u8 fnShowTxt( u16 x, u16 y , u16 color ,u16 BkColor )

          {

              u8 res=0;                      //  SD卡函数的返回值

      u8 buff[100]={0};          //   存储从txt文档中读到的100个字节的内码

      u8 bitbuff[32]={0};         //   存储从点阵字库获得的32个字节的点阵数据

      u8 NeiMaH,NeiMaL;     //   GB2312内码的高位和低位

  

      u8 CntnuF=1;               //   用来 判断是不是读到文档的末尾了,如果读到字节的个数小于100则表示读到末尾了


      u16 offset=0;                //   读txt文档的偏移地址

      u8 i=0;  


      UINT Hznum,bytenum; // 实际读回的内码字节个数、点阵字节个数

      


              u16 x0,y0;                     // 点阵显示的位置


      u8 charCnt=0;               // 读取的100个字节内码中有几个字符,如果字符个数是偶数则下次偏移再偏移100,如果是奇数,


                                                   // 则读取的100个字节中的最后一个字节可能是下一个汉字的内码高位字节,则偏移99,下次再把这个字节读上。


   x0=x;

   y0=y;


  f_mount(&fs1,"",1);            // 挂载SD卡

  res=f_open(&f1,ReadPath,FA_OPEN_EXISTING|FA_READ);    // 打开字库文件

  if(res!=0)

          {

       fnShowString(10,120,"open hzk fail",16,RED,WHITE,0);

printf("res=%x",res);

return 1;

          }


res=f_open(&ftxt,TxtPath,FA_OPEN_EXISTING|FA_READ);        // 打开txt文档

if(res!=0)

        {

     fnShowString(10,120,"open txt fail",16,RED,WHITE,0);

printf("res=%x",res);

return 1;

        }


f_lseek(&ftxt,offset);                                          // 初始化偏移为0从头开始读。

res=f_read(&ftxt,buff,100,&Hznum);                 // 每次读100个内码字节

while(CntnuF)                                                   //  循环判断是不是读到文件末尾了

for(i=0;i

if(x>220)                                            // 显示位置的判断

{

 x=x0;

y+=16;

if((y>300))  

{

fnRefreshscreen(WHITE);

        x=x0;

y=y0;

}


        if(buff[i]>0x80)                                     // 是不是汉字 

{

        f_lseek(&f1,32*((buff[i]-0xa0-1)*94+(buff[i+1]-0xa0-1)));    // 点阵字库内的偏移

res=f_read(&f1,bitbuff,32,&bytenum);

fnShowHzk(x,y,bitbuff,color,BkColor); 

x+=16;

                                 i++;                                                             // 这个i++非常重要,因为一个汉字两个字节,除了判断语句i++,


                                                                                                     // 这里需要还要一个 

                                memset(bitbuff,0,sizeof(bitbuff)); 

else                                                      // 可能是标点也可能是换行符 

{

if(buff[i]==0x0D)                           // 换行标志

y+=16;

else

                                     fnShowChar( x,y,buff[i],16,color,BkColor,0);        // 字符

                                x+=8; 

        charCnt++;                                   // 字符个数计算,用于判断下一次读txt文档的偏移地址

}


       // 计算txt文档的偏移地址


if(Hznum!=100)   //   判断是不是读到文档末尾了

{

 CntnuF=0;

}

else                           // 没有读到末尾继续读 

{

    if(charCnt%2==0)    // 字符个数是偶数,100个字节内码里边正好成对出现,地址偏移+100

offset +=100; 

    else

offset +=99;

memset(buff,0,sizeof(buff));



     f_lseek(&ftxt,offset);                                  //  txt 文档地址偏移

             res=f_read(&ftxt,buff,100,&Hznum);         //  读内码数据

}

}


f_close(&f1);                                //  关闭打开的点阵字库

f_close(&ftxt);                               // 关闭打开的txt文档

f_mount(&fs1,"",NULL);              //  卸载磁盘


         return 0; 

    }


          

以上是简单的电子书的实现。


因为不同的系统有不同的编码这个要注意,比如我再Windows上的汉字拷贝到CSDN网页上就是乱码,这是因为使用的汉字的编码不同,对于不同的编码格式,还需要做内码的对应转换,把其他的格式转换成GB2312或者GBK格式然后调用字库显示。


其他常用编码格式Unicode、utf-8等的具体介绍和转换成GB编码可以百度。


SD卡注意事项:


对一个文件读,必须先打开文件,读完后关闭。


对一个文件写,必须先打开文件,根据情况确定打开的权限,只读,读、写、创建等,先完后最好调用f_sync()函数,这是一个同步函数,类似于linux中的同步函数。SD卡中的写函数应该是带缓冲(猜的),在关闭之前调用这个函数将缓冲区的内容写入SD卡中,然后关闭文件,否则可能写入失败,不能将内容成功写到文件上。


文件的打开路径,Windows中的文档可能是隐藏文件类型的,这个一定要注意,隐藏文件类型的a.txt和不隐藏文件类型的a.txt 不是同一个文件,这个一定要非常注意。


推荐阅读

史海拾趣

ELINA INDEK公司的发展小趣事

因美纳始终将创新与研发作为公司的核心竞争力。随着技术的不断进步,公司不断推出更先进、更便捷的基因测序产品,满足市场的多样化需求。同时,因美纳还积极与全球各大科研机构合作,共同推动基因测序技术的发展和应用。这种持续的创新和研发精神使得因美纳在电子行业中保持领先地位。

CTC [Compact Technology Corp.]公司的发展小趣事

随着业务的发展,CTC公司意识到全球化布局的重要性。公司开始在全球范围内寻找合适的合作伙伴和投资机会,以拓展自身的业务范围和市场影响力。同时,CTC公司还加强了对国际市场的调研和分析,以更好地适应不同地区的市场需求和文化差异。这一全球布局策略使得CTC公司的竞争力得到了进一步提升。

BB公司的发展小趣事

在成立后的几年里,BB公司逐渐在国内市场站稳了脚跟。然而,创始人并没有满足于此,他看到了更广阔的国际市场。1961年,BB公司首次进入国际市场,凭借其高品质的产品和专业的服务,迅速赢得了国际客户的青睐。此后,BB公司不断加快国际化步伐,先后在英国和日本设立子公司,进一步扩大了市场份额。这一系列的国际化举措,不仅提升了BB公司的知名度,也为其带来了丰厚的回报。

Capar Components Corp公司的发展小趣事

在追求经济效益的同时,Capar Components Corp也注重环保和可持续发展。公司积极采用环保材料和生产工艺,减少生产过程中的污染排放。同时,公司还推出了一系列绿色电子产品,满足消费者对环保产品的需求。这些举措不仅提升了公司的社会形象,还为公司赢得了更多客户的青睐。

Gravitech公司的发展小趣事

随着国内市场的饱和,Capar Components Corp开始将目光投向国际市场。公司积极参加国际电子展会,与海外客户建立联系,拓展销售渠道。同时,公司还根据不同国家和地区的市场需求,调整产品结构和营销策略,逐步打开了国际市场的大门。如今,公司的产品已经远销欧美、东南亚等多个国家和地区,成为了国际电子市场上的一支重要力量。

Fractus公司的发展小趣事

1999年,Carles Puente博士和Ruben Bonet联合创立了Fractus公司,致力于将几何结构天线技术商业化。公司成立之初便取得了重大突破,获得了全球首个分形天线和多重分形天线专利。这些专利不仅展示了Fractus在天线设计领域的领先地位,也为公司后续的发展奠定了坚实的技术基础。

问答坊 | AI 解惑

ISD1700录放电路图

ISD1700录放电路图,PDF文件…

查看全部问答>

如何EMC

1、如何选择PCB板材? 选择PCB板材必须在满足设计需求和可量产性及成本中间取得平衡点。设计需求包含电气和机构这两部分。通常在设计非常高速的PCB板子(大于GHz的频率)时这材质问题会比较重要。例如,现在常用的FR-4材质,在几个GHz的频率时的介质 ...…

查看全部问答>

求ADI公司的DSP

请问有没有ADI公司的DSP学习资料啊…

查看全部问答>

全国电子设计竞赛论文写作指导

本帖最后由 paulhyde 于 2014-9-15 09:14 编辑 全国电子设计竞赛论文写作指导——电子竞赛设计与总结报告[书写格式]××××××设计与总结报告摘要一:方案设计与论证方案1:方案2:方案3:方案论证:方案选定:二:电路设计1、×××单元电路设 ...…

查看全部问答>

USB 驱动问题

插入USB设备时,打印出如下调试错误: device not accepting address 2, error -32 请问这是怎么回事啊…

查看全部问答>

EVC里调用小键盘对话框输入值

在EVC里,点编辑框控件调用小键盘对话框输入值,如果m_Fspz,m_Screen都定义为CString下面的程序可以实现,         CSoftKeybd dlg;         if(dlg.DoModal()==IDOK)         { ...…

查看全部问答>

请问有什么办法可以使用wince滚动条两端的箭头

请问有什么办法可以使用wince滚动条两端的箭头…

查看全部问答>

9052芯片驱动设计

简单说,就是做一个板子,pci接口的,在与计算机通信这一块使用了plx的9052芯片来简化设计。我们所需要的功能是,计算机上编一个界面,可以发送指令读和写该设备,将指令写入设备上的芯片中,再将芯片中的存储信息读回来显示一下。 请熟悉该芯片的 ...…

查看全部问答>

12864驱动显示电子钟

12864驱动显示电子钟…

查看全部问答>

315M Hz的信号接收使用何种天线?

315M Hz的信号接收使用何种天线(材质、形状、大小等属性)最好?…

查看全部问答>