这几天一直在搞电子书和数码相框。取得了一点小小成绩。在这分享一下。
txt文档和图片存在sd卡里,翻阅的时候通过 文件系统访问sd卡,从里边读出数据。先前的sd卡读写函数用的是sdio模式,速度是很快的,这次我尝试了spi模式(考虑到可以用到8位机上),参考了一些前人的程序,做了很多地方的修改,{zh1}的效果很稳定,速度测试: 读达到了120kbyte per sec
写 23kbyte per sec。
做电子书 当然要上 文件系统,我上次移植了fatfs0.07e这次刚好能用上,再根据上次的方式做了移植,然后在ffconfg.h里选择codepage 为 936 #define _CODE_PAGE 936 接下来 在disk io.c 里#i nclude "cc936.c" 这样就支持中文文件名了。网上很多人都以为fatfs0.07e不支持中文文件名,其实这样做 就能让它支持了。只不过cc936.c"占用很大的程序空间 有将近200k的 flash 都会被占用。当然对于小容量的片子这就是致命伤,这时我们可以考虑把这个文件放到外扩的eeprm里然后修改下 文件系统里查表的函数,不光是这个表 想中文字库 这样耗程序空间的东东 都可以放到外部存储器里。
电子书要用到滚屏,我在写lcd底层驱动的时候就开始研究ili9325如何能实现滚屏,可惜ili9325的0x6a这个寄存器和0x61寄存器所描述的滚屏 只能实现一次滚,第2次滚的的时候就失效了,再把滚屏禁止 原来的数据又回来了,弄了好久 滚屏这块我还是没弄懂。{zh1}我只能每次翻一页,每次重新刷数据。还有一个问题是这样的,翻页问题。因为一个文档里可以有英文、汉字、特殊符号(ascii里 小于32的那些)这样一屏显示多少数据是不固定的,有可能是540 也有可能是530 或者更少,所以每次翻页文件指针移动的多少都不固定。向下翻页的时候很简单,只要记录上一屏给lcd上显示了几个数据,然后下翻的时候只要把文件指针向后移动多少就行了。但向上翻页时怎么办?必须要知道 上上一屏的数据是从哪个文件指针开始读的,这就要做记录。我开了一个20 长度的int型数据来存储当然这只能支持向上翻18页,其实这块xx可以根据要读的txt文档的大小来计算出最坏情况下需要的数据长度,然后用malloc动态分配出这么长的内存单元来做记录(这要保证 启动代码里分配了足够大的heap,因为malloc申请的内存来源于堆)。{zh1}我加上了按键动作,我的这个电子书就这么完成了。
做完了电子书,我本来是想玩玩mp3 播放的,vs1003的驱动都写好了,焊好硬件 兴冲冲的去做 vs1003的正弦测试,发现 DREQ这个脚一直为低,程序根本走不下去。一阵排查,硬件没有问题啊,再goole 百度 了大半天,{zh1}只能怀疑我的vs1003 挂了,因为我用的烙铁很破,可能焊接的时候vs1003 被静电整挂了。无奈 mp3 暂时是玩不了了。
数码相框这块 bmp的显示速度还可以,但是jpg的解码速度很慢,除了很慢之外,还有别的问题,到现在 我还没xx搞定。
下面附上 电子书的 那段程序:
/*-------------------------------------------------------------------------*/
#define FN_BuffLen 541
#define Per_Len 20
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
功能:
down键长按 下一个文件
down键短按 下一屏
up键短按 上一屏
---------------------------------------------------------------------------*/
FRESULT Ebook_View(char* path)
{ // 路径 格式 此格式的有多少个
FRESULT res;
FILINFO fno;
FIL F ;
FATFS fs;
DIR dir;
u32 i, j, z;
vu8 fs_type_copy = 0;
UINT bytesWritten = 0;//从这个可看出文件读完了没 或从 FIL.fsize
char *fn;
u8 *pdata;
u8 databuf[FN_BuffLen]= {0};//存储读出来的数据
u8 Point = 0;
u16 File_Dptr[Per_Len] = {0};//存储上一屏数据指针值,向上翻页时用到
//Per_Len-2值决定可以向上翻多少页
#if _USE_LFN //为 长文件名区指针赋初值
static char lfn[_MAX_LFN * (_DF1S ? 2 : 1) + 1];
fno.lfname = lfn;
fno.lfsize = sizeof(lfn);
#endif
//每次 open一个对象时都先要注册一个缓冲区
res =f_mount(0, &fs);
// 打开指定的目录
res = f_opendir(&dir, path);
if (res == FR_OK) {
for (;;)
{
repet:
//{dy}次执行读一个文件,第二次执行读第二个文件………………
res = f_readdir(&dir, &fno);//读出目录里的 文件信息 存入 fno
fs_type_copy = dir.fs->fs_type;
if (res != FR_OK || fno.fname[0] == 0) break;
#if _USE_LFN
{
fn = *fno.lfname ? fno.lfname : fno.fname;
j = *fno.lfname ? (fno.lfsize-1): (8+1+3 -1);
}
#else
{
fn = fno.fname; j=8+1+3 -1;
}
#endif
for(i = j; i >= 3; i--) //文件名 从右到左判断 当文件扩展名为 XXX时成立
{
if ((*(fn+i-2) == 't')&&(*(fn+i-1) == 'x')&&(*(fn+i) == 't'))
{
//成功检测到相符的文件了
//lcd开个矩形框显示文件名 xxxx…………txt
lcd_fill_rect(2, 2, 32, 236, yellow);
lcd_text_color(black);
lcd_back_color(yellow);
lcd_display(8, 5, (u8 *)fn);
memcpy(databuf, "ebook/", 6);
memcpy(&databuf[6], fn, j+1);
fn = databuf;
*(fn+i+1+6)='\0';//为文件名添加字符串结束符
lcd_text_color(red);
lcd_back_color(cyan);
//开始显示 文件内容
z = 0;//文件定位
res = f_open (&F, fn, FA_OPEN_EXISTING | FA_WRITE | FA_READ);
memset(databuf, 0, FN_BuffLen);
Point = 0;
/*--------------------------------------------*/
for (;;)
{
next:
if (Point > Per_Len)
{ //数组被写满了
for (j = 0; j < Per_Len-1; j++)
{
//数据向左移,新数据放到数组{zh1}一个元素
File_Dptr[j] = File_Dptr[j+1];
}
File_Dptr[Per_Len-1] = z;
}
else
{
File_Dptr[Point] = z;//每一屏数据的起始地址进行存储
Point += 1;
}
i = 32; j = 0;//记行列
res = f_lseek (&F, z);
res = f_read(&F, databuf, FN_BuffLen, &bytesWritten);//读出541个数据
if (bytesWritten == FN_BuffLen)
{
pdata = databuf;
while(*pdata)
{
if (*pdata < 128)
{
if (*pdata < 32)//回车
{
*pdata = ' ';
}
lcd_display_char(i, j, *pdata);
j += 8;
pdata += 1;
z += 1;
}
else
{
lcd_display_hzchar(i, j, pdata);
j += 16;
pdata += 2;
z +=2;
}
if ((j > 224)&&(*pdata > 128)&& (j!=240))//防止一行的{zh1}半字
{
lcd_display_char(i, j, ' ');//清边界残留
j = 240 ;
}
if (j >= 240)
{
j = 0;
i += 16; //一行写满了,换行
if (i >= 320)
{
i = 0; //整屏写满了
//动态停机 等待按键
while (1)
{
event = read_fifo();
switch (event)
{
case key_up_s:
if (Point >=2) //
{
Point -= 2;
z = File_Dptr[Point];
memset(databuf, 0, FN_BuffLen);
goto next;//显示上一屏数据
}
else
{
break;
}
case key_down_s:
memset(databuf, 0, FN_BuffLen);
goto next; //显示下一屏数据
case key_down_l://浏览下一个文件
//memset(databuf, 0, FN_BuffLen);
goto repet;
}
}
}
}
}
}
else //文件快结束了这是一个文件的{zh1}
{
pdata = databuf;
//后面补空格,以清掉上页留下的数据
memset(&databuf[bytesWritten], ' ', FN_BuffLen-bytesWritten-1 );
while(*pdata)
{
if (*pdata < 128)
{
if (*pdata < 32)//回车
{
*pdata = ' ';
}
lcd_display_char(i, j, *pdata);
j += 8;
pdata += 1;
z += 1;
}
else
{
lcd_display_hzchar(i, j, pdata);
j += 16;
pdata += 2;
z +=2;
}
if ((j > 224) && (*pdata > 128))//防止一行的{zh1}半字
{
lcd_display_char(i, j, ' ');//清边界残留
j = 240 ;
}
if (j >= 240)
{
j = 0;
i += 16; //一行写满了,换行
}
}
//动态停机 等待按键
while (1)
{
event = read_fifo();
switch (event)
{
case key_up_s:
if (Point >=2) //
{
Point -= 2;
z = File_Dptr[Point];
memset(databuf, 0, FN_BuffLen);
goto next;
}
else
{
break;
}
case key_down_l:
//memset(databuf, 0, FN_BuffLen);
goto repet;
}
}
}
}
/*--------------------------------------------*/
dir.fs->fs_type=fs_type_copy;
//打开文件时,dir.fs->fs_type被改动了,所以下一次打开目录时要恢复dir.fs->fs_type
goto repet;
}
}
goto repet;
}
}
return res;
}