OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 12984|回复: 12

能不能直接读取SD卡中的字库的字模来显示汉字?

[复制链接]

4

主题

13

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2011-10-21
在线时间
0 小时
发表于 2011-10-21 15:58:36 | 显示全部楼层 |阅读模式
我知道Alientek的板子是把字库从SD卡中写如SPIflash中,再从flash中调用,但是我们这回参加嵌入式竞赛的开发板是不带SPIflash的,所以我想能不能直接从SD卡中调用字模来实现汉字显示,不知有没有这样的程序?
小弟对FAT不是很熟悉,不太会改读SD卡的程序。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-10-21 19:14:08 | 显示全部楼层
回复【楼主位】WLwind:
---------------------------------
肯定可以的.这个代码要参考我很久以前的程序.最早的时候,我就是这样做的.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

46

主题

284

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
494
金钱
494
注册时间
2011-6-20
在线时间
0 小时
发表于 2011-10-22 01:01:17 | 显示全部楼层
回复【楼主位】WLwind:

---------------------------------
我做过这个,但是这个速度不是一般的蛮!建议把用到的字取模直接放在内部了算了
回复 支持 反对

使用道具 举报

4

主题

13

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2011-10-21
在线时间
0 小时
 楼主| 发表于 2011-10-23 04:44:06 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
能否给个例程看看?我对fat实在是不太熟。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-10-23 09:24:24 | 显示全部楼层
#include "TXT.H"
#include "lcd.h"
//电子书操作函数
//还没有加入向前翻页的操作,等搞完毕业论文再弄了。。。         
//正点原子@SCUT
//V1.2

//字体大小选择
u8 FSIZE=FONTSIZE16;//汉字大小,默认为16*16的   
u32 FONT16CLUSTER=0;//16字体的首簇
u32 FONT12CLUSTER=0;//12字体的首簇
                  
//Cluster 簇的序号 返回为该簇号所对应的扇区地址
//得到Cluster
unsigned long GetSysFileSector(u8 uoh,unsigned int Cluster)
{
unsigned long foffset=0;
unsigned int i; 

if(uoh==16)foffset=FONT16CLUSTER;//得到unicode码的首簇  
    else if(uoh==12)foffset=FONT12CLUSTER; 
i=Cluster;
while(i)
{
    //printf("foffset:%d\n",foffset);
    foffset=FAT_NextCluster(foffset);
    i--;
}
//printf("final foffset:%d\n",foffset);
return fatClustToSect(foffset); 
}                       
//code 字符指针开始
//从字库中查找出字模
//code 字符串的开始地址,ascii码
//mat  数据存放地址 FSIZE*2 bytes大小
void Get_HzMat(unsigned char *code,unsigned char *mat)
{
unsigned char qh,wh;
unsigned char i;
unsigned int  sector,cluster,secoff;
unsigned long foffset; 
if(*code<0xa1)if(*code++<0xa1)//非常用汉字
{   
    code--;
    for(i=0;i<(FSIZE*2);i++)*mat++=0x00;//填充满格
    return; //结束访问
}          
qh=(*code++)-0xa1;
wh=(*code)-0xa1;   
foffset=((unsigned long)94*qh+wh)*(FSIZE*2);//得到字库中的字节偏移量   
sector=foffset/BytesPerSector;              //得到总的完整的扇区数(不要写成(unsigned int ) 
  secoff= (unsigned int) foffset%BytesPerSector;//扇区内的字节数偏移
wh=(unsigned char)sector%SectorsPerClust; 
cluster=(unsigned int)sector/SectorsPerClust;//得到总的簇数

foffset=GetSysFileSector(FSIZE,cluster); //取汉字库的clusor簇数的扇区地址 
 
if(BytesPerSector-secoff>=(FSIZE*2))//确定是否跨扇区?
{          
SD_Read_Bytes(foffset+wh,mat,secoff,(FSIZE*2));  //读取(FSIZE*2)字节
}else
{
i=BytesPerSector-secoff; //读取的数据已跨扇区
SD_Read_Bytes(foffset+wh,mat,secoff,i);
if(++wh>SectorsPerClust)
{  
wh=0; 
foffset=GetSysFileSector(0,++cluster);//读取的数据已经跨簇

SD_Read_Bytes(foffset+wh,mat+i,0,(FSIZE*2)-i); //读取剩余的数据

}  
   
//显示一个指定大小的汉字
//x,y:汉字的坐标
//font:汉字ASCII码
//mode:0,全填充写入.1,有效部分写入(适合在图片上叠加汉字)
void show_font(u8 x,u16 y,u8 *font,u8 mode)
{
u8 t1,t2;
u8 temp=0;
//扫描方式控制
    LCD_WriteReg(0x0003,(1<<12)|(3<<4)|(1<<3) );//上至下,左至右  
//面板大小设置   开辟1个FSIZE*FSIZE的空间
LCD_WriteReg(R80,x);           //水平方向GRAM起始地址
LCD_WriteReg(R81,x+FSIZE-1);   //水平方向GRAM结束地址
LCD_WriteReg(R82,y);           //垂直方向GRAM起始地址
LCD_WriteReg(R83,y+FSIZE-1);   //垂直方向GRAM结束地址
LCD_SetCursor(x,y);            //设置光标位置 
LCD_WriteRAM_Prepare();        //开始写入GRAM  
if(!mode)//非叠加模式
{
for(t1=0;t1<FSIZE;t1++)//共FSIZE个字节,每次读两个
{
temp=font[t1];
for(t2=0;t2<8;t2++)
{
if(temp&0x01)LCD->LCD_RAM=POINT_COLOR;
else LCD->LCD_RAM=BACK_COLOR;
temp>>=1;
}
temp=font[t1+FSIZE];
for(t2=0;t2<(FSIZE-8);t2++)//这里对16*16和其以下的字体合适
{
if(temp&0x01)LCD->LCD_RAM=POINT_COLOR;
else LCD->LCD_RAM=BACK_COLOR;
temp>>=1;
}  
}
}else//叠加模式
{
for(t1=0;t1<FSIZE;t1++)//共FSIZE个字节,每次读两个
{
temp=font[t1];
for(t2=0;t2<8;t2++)
{
if(temp&0x01)TFT_DrawPoint(x+t1,y+t2);//画一个点  
temp>>=1;
}
temp=font[t1+FSIZE];
for(t2=0;t2<(FSIZE-8);t2++)//这里对16*16和其以下的字体合适
{
if(temp&0x01)TFT_DrawPoint(x+t1,y+t2+8);//画一个点    
temp>>=1;
}  
}
}
//恢复原来的设置.
    LCD_WriteReg(0x0003,(1<<12)|(3<<4)|(0<<3) );//左至右,上至下  
//TFT_WR_CMD(0,0x00,0x04); //上至下,左至右 型扫描                  
LCD_WriteReg(R80, 0x0000); //水平方向GRAM起始地址
LCD_WriteReg(R81, 0x00EF); //水平方向GRAM结束地址
LCD_WriteReg(R82, 0x0000); //垂直方向GRAM起始地址
LCD_WriteReg(R83, 0x013F); //垂直方向GRAM结束地址   
}
//在指定位置开始显示一个字符串
//非叠加方式显示
//支持自动换行
//(x,y):起始坐标
//str:字符串
//mode:模式:
//bit 0:1,叠加模式;0,覆盖模式
//bit 1:1,自动换行;0,不自动换行;
void Show_Str(u8 x,u16 y,u8*str,u8 mode)
{      
    u8 bHz=0;         //字符或者中文     
unsigned char *mat; //保存点陈内容        
mat=jpg_buffer+512;//指向jpg_buffer的后半部分.前半部分用来存放文本文件了.  
    while(*str!=0)//数据未结束
    { 
        if(!bHz)
        {
        if(*str>0x80)bHz=1;//中文 
        else             //字符
        {      
                if(x>(239-FSIZE/2))//换行
{
if(mode&0x02)//判断是不是要自动换行?
{
y+=FSIZE;
x=0;
}else return;
}
        if(y>(319-FSIZE))break;//越界返回      
        if(*str==13)//换行符号
        {         
            y+=FSIZE;
x=0;
            str++; 
        }  
        else TFT_ShowChar(x,y,*str,FSIZE,mode&0x01);//有效部分写入 
str++; 
        x+=FSIZE/2; //字符,为全字的一半 
        }
        }else//中文 
        {     
            bHz=0;//有汉字库    
            if(x>(239-FSIZE))//换行
{
if(mode&0x02)//判断是不是要自动换行?
{
y+=FSIZE;
x=0;
}else return;
}
        if(y>(319-FSIZE))break;//越界返回  
Get_HzMat(str,mat);//得到点阵数据 (无字库不起动系统)   
        show_font(x,y,mat,mode&0x01); //显示这个汉字,空心显示 
        str+=2; 
        x+=FSIZE;    //下一个汉字偏移
        }  
    }   
}
//在指定宽度的中间显示字符串
//如果字符长度超过了len,则用Show_Str显示
//len:指定要显示的宽度
//针对1616字体!!!
void Show_Str_Mid(u8 x,u16 y,u8*str,u8 mode,u8 len)
{
u16 strlenth=0;
    strlenth=strlen((const char *)str);
strlenth*=8;
if(strlenth>len)Show_Str(x,y,str,mode);
else
{
strlenth=(len-strlenth)/2;
    Show_Str(strlenth+x,y,str,mode);
}
}    

typedef struct 
{
u32* Lentable;         
}LAST_TEXT;
LAST_TEXT txtprev;
 
//文本文件读取程序  
//实现功能:把文件 FileName 打开.在液晶上显示出来 
//打开txt/lrc文件    
void Read_Book(FileInfoStruct *FileName)
{         
    u16 pointpos=0;   //指针位置   
    unsigned long offlenth=0;//文件读取的大小 
//unsigned long marklenth=0;//文件上一页的标记位 
    u16 x=0,y=0;
    u8 *p=0;            //指向txt文件
    u8 temp[2]={0,0};   //换扇区使用 
    u8 bHz=0;           //字符或者中文     
unsigned char *mat; //保存点陈内容
  
u8 key;
u8 enout=0;//能否退出的标志 
u8 keycnt=0;

u8 preven=0;//向上翻页的标志
u16 age_Cnt=0;//页码计数  
        
txtprev.Lentable=(u32*)iclip;      

mat=jpg_buffer+512; //指向jpg_buffer的后半部分.前半部分用来存放文本文件了.  
if((FileName->F_Type&0xF0)==0)return;//不是TXT类型的文件
F_Open(FileName);//打开文件            
   
txtprev.Lentable[0]=0;//读取了0个字节    

LCD_Clear(WHITE);//清屏
POINT_COLOR=BLUE;//蓝色笔头     
    while(1)
    {      
//PRVIEW: 
F_Read(FileName,jpg_buffer);//读取数据    
if(preven)
{
pointpos=txtprev.Lentable[Page_Cnt]%BytesPerSector;
p=jpg_buffer+pointpos;//偏移后的了 
printf("preven pointpos:%d\n",pointpos);
}
else p=jpg_buffer; //指向txt数据首地址       
preven=0;  
do
        {   
//printf("pointpos:%d\n",pointpos);
//printf("*p:%d\n\n",*p);
 
        while(*p!=0)//数据未结束
        {    
        if(!bHz)
        {
        if(*p>0x80)bHz=1;//中文字符 
        else             //ASCII字符
        {      
                        if(x>(240-FSIZE/2)){y+=FSIZE;x=0;}//一行已满,换行  
        if(y>(320-FSIZE))break;//越界返回      
        if(*p==13)//换行符号
        {         
            y+=FSIZE;
x=0;
            p++;pointpos++;//跳过 
        }  
        else TFT_ShowChar(x,y,*p,FSIZE,1); 
p++;pointpos++; 
        x+=FSIZE/2; //字符,为全字的一半 
        }
        }else
        {     
            bHz=0;//清除汉字标志 
            if(x>(240-FSIZE)){y+=FSIZE;x=0;}//换行
        if(y>(320-FSIZE))break;//越界返回  
        //临界处理   
        if(pointpos==511)//保存上一扇区的最后一个字节,退出        
        {
            temp[0]=*p; //记录最后的字节                
            break;      //此扇区数据已经读完
        }
        if(temp[0])//上一次没有显示完
        {                         
            temp[1]=*p;//取第二扇区的第一个字节
            Get_HzMat(temp,mat);//显示上一次的最后一个字 (无字库不起动系统)
            p++;pointpos++;//偏移一个字节
            temp[0]=0;     //清除标记
        }
        else Get_HzMat(p,mat);//得到点阵数据 (无字库不起动系统)   
        show_font(x,y,mat,1); //显示这个汉字,空心显示 
        p+=2;pointpos+=2;     //指针偏移 
        x+=FSIZE;    //下一个汉字偏移
        }
        if(pointpos>511)break;
        }  
            if(pointpos>=511)break;//一个扇区读取完毕,直接跳出,读下一个扇区,防止停顿    
Pen_Point.Key_Sta=Key_Up;//释放显示期间的触发 
enout=0; //退出使能标志不使能
key=0;  
while(1) //是否显示下一屏数据
            {     
                if((Pen_Point.Key_Sta==Key_Down||NPEN)&&Pen_Point.Key_LSta)key=Touch_To_Num(7);//扩展按键扫描
  if(PEN)//按键松开了,状态改变(状态机)
{
Pen_Point.Key_LSta=1;   
Pen_Point.Key_Sta=Key_Up;
}   
/*if(key==KEY_PREV)//向上翻页
{
Pen_Point.Key_LSta=Key_Up;     
if(Page_Cnt)
{
Page_Cnt--; 
offlenth=txtprev.Lentable[Page_Cnt]/BytesPerSector;//得到现在已经读取了的扇区数     
printf("dec offlenth:%d\n",offlenth);
printf("p offlenth:%d\n\n",txtprev.Lentable[Page_Cnt]);
F_Open(FileName);          
while(offlenth)    
{
F_Read(FileName,jpg_buffer);
offlenth--;//增加一个扇区
}    
offlenth=txtprev.Lentable[Page_Cnt];//指向下一个扇    
temp[0]=0;
bHz=0;    
x=0;y=0;
preven=1;
LCD_Clear(WHITE);//清屏   
goto RVIEW;

}*/             
if(key==KEY_NEXT)//向下翻页
                {         
Pen_Point.Key_LSta=Key_Up;  
keycnt=0;   
if(enout){if(Is_In_Area(200,300,239,319))return;}//退出文件阅读       
                    if(offlenth+pointpos+1>=FileName->F_Size)return;//文件读取结束(长度结束)      
                    if(y>(320-FSIZE)){x=0;y=0;}//非结尾返回,屏幕已满,清屏     
LCD_Clear(WHITE);//清屏    
                    //Page_Cnt++;
//txtprev.Lentable[Page_Cnt]=offlenth+pointpos+1;//得到当前所读取的字节数
//printf("n offlenth:%d\n\n",txtprev.Lentable[Page_Cnt]);  
break;
                }else if(key==KEY_FUNC)//按中中间区域了    
{    
Pen_Point.Key_LSta=Key_Down;//使能下次进入    
keycnt++;
if(keycnt>=20)

keycnt=0;
enout=1;//使能退出     
POINT_COLOR=RED;
TFT_Fill(0,298,239,319,0X81BF);//填充底部颜色
Show_Str(203,300,"返回",0x01); //叠加模式,非自动换行
POINT_COLOR=BLUE; 
}  
}
key=0;//清除此次按键          
                delay_ms(5); 
            }   
        }while(pointpos<511);  
        offlenth+=pointpos+1;//文件长度累加     
pointpos=0;//清除指针计数器           
    } 
}  




我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-10-23 09:25:27 | 显示全部楼层
重点在:void Get_HzMat(unsigned char *code,unsigned char *mat) 这个函数.
其实我那个毕业设计,就是用的这种方法.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

4

主题

13

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2011-10-21
在线时间
0 小时
 楼主| 发表于 2011-10-24 12:17:22 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
感谢,我会慢慢消化
回复 支持 反对

使用道具 举报

10

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
110
金钱
110
注册时间
2012-1-27
在线时间
0 小时
发表于 2012-6-12 22:03:44 | 显示全部楼层
将字库放在SD卡中,是不是显示时要变慢
回复 支持 反对

使用道具 举报

14

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
112
金钱
112
注册时间
2012-5-18
在线时间
3 小时
发表于 2012-6-13 17:37:52 | 显示全部楼层
正在研究同样的问题呢,就看到了这么好的贴子,顶一个~~
回复 支持 反对

使用道具 举报

31

主题

161

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
328
金钱
328
注册时间
2013-4-22
在线时间
7 小时
发表于 2014-10-23 20:01:16 | 显示全部楼层
回复【6楼】正点原子:
---------------------------------
额,原子大哥果然牛叉啊,当时stm32还是刚出吧,就能搞这么复杂的东西,记得我读书的时候,还只能用51做做万年历啊、多点温度什么的小玩意,stm32当时都不知道是什么
http://www.tudou.com/programs/view/h5G_H9Kpk04/?bid=03&pid=1&resourceId=375113802_03_05_01
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
27
金钱
27
注册时间
2014-12-4
在线时间
1 小时
发表于 2014-12-5 10:43:46 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
  怎样获得 字体FON16文件所在的簇号啊 上面贴的代码是用宏定义了为0  实际上不是这样啊    还有  GetSysFileSector(u8 uoh,unsigned int Cluster)   函数中调用的       FAT_NextCluster(foffset);   函数  和  fatClustToSect(foffset);函数 在哪里啊    是自己写 的 还是 Fatfs里面的  ????
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-12-5 22:55:31 | 显示全部楼层
回复【11楼】三哥:
---------------------------------
建议看我们最新的教程,都是用fatfs了,比较好理解。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
25
金钱
25
注册时间
2016-1-7
在线时间
3 小时
发表于 2016-1-7 21:22:23 | 显示全部楼层
楼主,请问你这个最后做出来了吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-22 06:28

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表