切换到宽版
  • 9556阅读
  • 26回复

[STM]STM8学习之——中文字库 [复制链接]

上一主题 下一主题
离线zeze10000
 

发帖
2858
M币
8559
专家
35
粉丝
112
只看楼主 倒序阅读 我要置顶 楼主  发表于: 2018-10-09
单片机想显示中文一般都不是很容易。
一方面是很多屏幕驱动都不带中文字库,一方面是中文的取模数据大,单片机的flash空间宝贵。
对于不带字库的屏幕,显示中文主要分两种情况处理。
一种是显示少量的有限个数的中文,可以将取模数据放在单片机的flash内,然后建立索引表,通过查表来定位字模数据位置并显示。
另一种是显示多个中文或者显示的文字不定,这就需要全套的中文字模数据,由于数据量大,一般都会放置到外部的储存器中,最常用的就是25系列的SPI Flash,其中又以华邦的w25Qxx最为常见。

今天主要分三部分讲:
一、SPI Flash的读写
二、字库的制作
三、字库的写入与读取

涉及的内容比较多,时间可能比较长,我尽量讲的详细些。

一、SPI Flash的读写

这里以w25Q128FV为例讲解,w25q128fv是16M字节的spi flash,除了容量比较大以外,它的配置状态寄存器也普通的要多。总共三个配置状态寄存器。多出的功能主要是区块的保护更加的灵活,还有一些单次编程的寄存器。这些我们不做过多的了解,简单的看一下就好。
这里主要要讲解的是flash的擦除、编程、读取。

1、flash擦除
flash为什么要擦除,擦除之后的数据是什么?是不是0x00?
flash的编程操作只能将1改成0,不能将0变成1。因此在对flash进行编程写入数据前需要将flash进行擦除,使flash的储存位都变成1,也就是每个字节都是0xff。至于为何flash编程不能将0改成1,想了解的请自己查资料。

flash的擦除如何操作?
flash的擦除方式主要有:扇区擦除、块擦除、芯片擦除
扇区的大小为4k,块的大小可以是32k,也可以是64k,芯片的大小就是整个芯片。
具体操作是先将芯片写使能,然后发送擦除命令,然后发送地址,芯片擦除不需要地址。
关于地址,因为不管是扇区和块,都包含有不止一个字节,所以,发送的地址所属于的那个扇区或者块就会被全部擦除!
比如地址发送0x000000和0x000001的擦除效果是一样的,因为这两个地址属于同一个扇区,同一个区块。

flash不擦除能否写入数据?
flash不擦除可以写入数据,但是只能写入0,不能写入1,如果你想写入0x00则不用擦除,其它情况都会导致数据错误。

2、flash编程
flash写入数据需要以页编程的方式进行写入
每个页包含有256字节,页编程可以从页的任意位置开始写入,也不必将页写满。
需要注意的是,在进行页编程时,在同一个页内,地址指针会自增,到达页尾后地址指针会跳转到页首的位置,继续写入则可能发生数据覆盖,所以在页编程时需要在一页写完后将地址指向下一页的首地址。
具体操作是:
芯片写使能,发送编程指令,发送地址,发送数据

3、flash读取
这个是最简单的操作,只需要发送读取指令,然后发送读取地址,然后就一直读就行,只要时钟还在发送,数据就会传出。读取没有扇区、页这些限制,可以连续读出整片flash的内容。

上图说话



flash的内部框图。flash一般是8个引脚,除掉两个电源脚和spi通讯的引脚还有两个引脚。WP,写保护,拉低时不能写入,保护数据,hold,数据传输暂停。

状态寄存器1,常用的是busy位,芯片在忙时,比如在编程、在擦除,其它指令将忽略,除了读状态指令。(还有暂停指令)

保护引脚的配置

状态寄存器2不常用,除非是要进行数据保护、快速读取


状态寄存器3


数据保护相关,可以了解一下,比如写入字库后将字库保护起来,避免被擦除或者覆盖





指令表
常用的是写使能,读寄存器1,擦除、页编程

其它的不是很常用,像一些双输出、四输出的指令需要单片机支持,输出速率能达到上百兆,我们这里是用不到的。

讲这么多不如来个源码实在
w25qxx.c
  1. #include<w25qxx.h>
  2. void w25q_busy()    //判忙函数,忙则等待
  3. {
  4.   char sta;
  5.   W25Q_CS=0;
  6.   
  7.   SPI_RW(R_SR1);    //读SR1状态寄存器
  8.   while((sta=SPI_RW(DUMMY))&0x01)        //判忙
  9.   {
  10.     if(sta==0xff)       return;         //读取失败
  11.   }
  12.   
  13.   W25Q_CS=1;
  14. }
  15. void w25q_W_EN()        //芯片写使能
  16. {
  17.   w25q_busy();
  18.   
  19.   W25Q_CS=0;
  20.   SPI_RW(W_EN);
  21.   W25Q_CS=1;
  22.   w25q_busy();
  23. }
  24. void w25q_RESET()        //芯片复位
  25. {
  26.   w25q_busy();
  27.   
  28.   W25Q_CS=0;
  29.   SPI_RW(RESET_EN);        //复位使能
  30.   SPI_BUSY();
  31.   W25Q_CS=1;
  32.   
  33.   W25Q_CS=0;
  34.   SPI_RW(RESET);        //执行复位
  35.   W25Q_CS=1;
  36. }
  37. void w25q_CMD(char CMD)    //写单字节命令
  38. {
  39.   w25q_busy();
  40.   
  41.   W25Q_CS=0;
  42.   SPI_RW(CMD);
  43.   W25Q_CS=1;
  44. }
  45. char w25q_R_SR(char SR)    //读状态寄存器
  46. {
  47.   char sta;
  48.   
  49.   W25Q_CS=0;
  50.   SPI_RW(SR);
  51.   sta=SPI_RW(DUMMY);
  52.   W25Q_CS=1;
  53.   
  54.   return sta;
  55. }
  56. void w25q_W_SR(char SR,char dat)    //写状态寄存器
  57. {
  58.   w25q_W_EN();
  59.   
  60.   W25Q_CS=0;
  61.   SPI_RW(SR);
  62.   SPI_RW(dat);
  63.   W25Q_CS=1;
  64. }
  65. void w25q_init()                //W25QXX初始化
  66. {
  67.   W25Q_CS=1;
  68.   PC_DDR_DDR4=1;
  69.   PC_CR1_C14=1;
  70.   PC_CR2_C24=0;
  71.   
  72.   w25q_RESET();                 //软复位
  73.   
  74.   //w25q_W_SR(W_SR1,0x00);
  75.   //w25q_W_SR(W_SR2,0x00);
  76.   //w25q_W_SR(W_SR3,0x40);
  77. }
  78. void w25q_SEC_ERASE(unsigned long addr)         //4k扇区擦除
  79. {
  80.   w25q_W_EN();
  81.   
  82.   W25Q_CS=0;
  83.   SPI_RW(SEC_ERASE);
  84.   SPI_RW((addr>>16)&0xff);
  85.   SPI_RW((addr>>8)&0xff);
  86.   SPI_RW(addr&0xff);
  87.   W25Q_CS=1;
  88. }
  89. void w25q_BLOCK_ERASE32(unsigned long addr)     //32K块擦除
  90. {
  91.   w25q_W_EN();
  92.   
  93.   W25Q_CS=0;
  94.   SPI_RW(BLOCK_ERASE32);
  95.   SPI_RW((addr>>16)&0xff);
  96.   SPI_RW((addr>>8)&0xff);
  97.   SPI_RW(addr&0xff);
  98.   W25Q_CS=1;
  99. }
  100. void w25q_BLOCK_ERASE64(unsigned long addr)     //64K块擦除
  101. {
  102.   w25q_W_EN();
  103.   
  104.   W25Q_CS=0;
  105.   SPI_RW(BLOCK_ERASE64);
  106.   SPI_RW((addr>>16)&0xff);
  107.   SPI_RW((addr>>8)&0xff);
  108.   SPI_RW(addr&0xff);
  109.   W25Q_CS=1;
  110. }
  111. void w25q_CHIP_ERASE()                  //芯片擦除
  112. {
  113.   w25q_W_EN();
  114.   w25q_CMD(CHIP_ERASE);
  115. }
  116. /*
  117. //W25QXX读取
  118. //addr:读取地址,*pBuf:数据存放地址,len:读取长度
  119. */
  120. void w25q_R_DAT(unsigned long addr,unsigned char *pBuf,unsigned int len)        //数据读取
  121. {
  122.   w25q_busy();
  123.   
  124.   W25Q_CS=0;
  125.   SPI_RW(R_DAT);        //读数据
  126.   SPI_RW((addr>>16)&0xff);    //传入地址
  127.   SPI_RW((addr>>8)&0xff);
  128.   SPI_RW(addr&0xff);
  129.   while(len--)        //连续读
  130.   {
  131.     *pBuf++=SPI_RW(DUMMY);
  132.   }
  133.   W25Q_CS=1;
  134. }
  135. /*
  136. //W25QXX写入
  137. //addr:写入地址,*pBuf:写入数据地址,len:写入长度
  138. */
  139. void w25q_PAGE_PROG(unsigned long addr,unsigned char *pBuf,unsigned int len)    //页编程
  140. {
  141.   unsigned char left=0xff;
  142.   
  143.   left-=(addr&0xff);            //当前页剩余字节数
  144.   
  145.   w25q_W_EN();                  //写使能          
  146.   
  147.   W25Q_CS=0;                    //芯片使能
  148.   
  149.   SPI_RW(PAGE_PROG);            //页编程指令
  150.   SPI_RW((addr>>16)&0xff);      //传地址
  151.   SPI_RW((addr>>8)&0xff);
  152.   SPI_RW(addr&0xff);
  153.   
  154.   while(len--)                  //循环写入
  155.   {
  156.     SPI_W(*pBuf++);             //写入
  157.     if(left--==0)               //本页写满,换下一页
  158.     {
  159.       left=0xff;                
  160.       
  161.       W25Q_CS=1;
  162.       w25q_W_EN();
  163.       W25Q_CS=0;
  164.       SPI_RW(PAGE_PROG);
  165.       addr+=0x100;              //地址指向下一页
  166.       addr&=0xffff00;
  167.       SPI_RW((addr>>16)&0xff);
  168.       SPI_RW((addr>>8)&0xff);
  169.       SPI_RW(addr&0xff);  
  170.     }
  171.   }
  172.   SPI_BUSY();                   //等待传输结束
  173.   W25Q_CS=1;                    //取消芯片选择
  174. }


待续。。。

本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共5条打赏M币+58
慕名而来 M币 +9 图文并茂不错的文章,W25Q那点儿事说的非常清楚了,对于诸如OLED这种扫描模式的屏做的对应的字库。 2018-10-11
mousebat04 M币 +8 flash讲解很好。 2018-10-11
wenxueroom M币 +13 優秀文章 2018-10-09
jjbboox M币 +8 優秀文章 2018-10-09
2545889167 M币 +20 我之前发过个做好的字库。偷懒的话,直接吧那个用编程器写进去就能用了,哈哈 2018-10-09
离线zeze10000

发帖
2858
M币
8559
专家
35
粉丝
112
只看该作者 1楼 发表于: 2018-10-09
请登录后查看
[ 此帖被zeze10000在2018-10-09 19:02重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共1条打赏M币+20
wenxueroom M币 +20 好东西,备用备用 2018-10-09
离线zeze10000

发帖
2858
M币
8559
专家
35
粉丝
112
只看该作者 2楼 发表于: 2018-10-09
请登录后查看
[ 此帖被zeze10000在2018-10-09 11:57重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共2条打赏M币+28
guansm M币 +8 優秀文章 2018-10-09
2545889167 M币 +20 - 2018-10-09
离线触景情伤

发帖
3862
M币
28
专家
4
粉丝
70
只看该作者 3楼 发表于: 2018-10-09
离线2545889167

发帖
13268
M币
20754
专家
302
粉丝
4860
只看该作者 4楼 发表于: 2018-10-09
请登录后查看
离线zeze10000

发帖
2858
M币
8559
专家
35
粉丝
112
只看该作者 5楼 发表于: 2018-10-09
回 2545889167 的帖子
请登录后查看
离线wenxueroom

发帖
981
M币
2378
专家
8
粉丝
57
只看该作者 6楼 发表于: 2018-10-09
请登录后查看
离线fsss007

发帖
755
M币
8006
专家
3
粉丝
68
只看该作者 7楼 发表于: 2018-10-09
回 zeze10000 的帖子
请登录后查看
离线fsss007

发帖
755
M币
8006
专家
3
粉丝
68
只看该作者 8楼 发表于: 2018-10-09
回 zeze10000 的帖子
请登录后查看
离线595953427@qq

发帖
610
M币
51
专家
0
粉丝
15
只看该作者 9楼 发表于: 2018-10-09
请登录后查看
快速回复
限80 字节
温馨提示:欢迎交流讨论,请勿发布纯表情、纯引用等灌水帖子;以免被删除
 
上一个 下一个