extern _pic_phy pic_phy; //图像信息 typedef struct { u32 ImgWidth; //图像的实际宽度和高度 u32 ImgHeight; u32 Div_Fac; //缩放系数 (扩大了8192倍的) u32 S_Height; //设定的高度和宽度 u32 S_Width; u32 S_XOFF; //x轴和y轴的偏移量 u32 S_YOFF; u32 staticx; //当前显示到的xy坐标 u32 staticy; }_pic_info; extern _pic_info picinfo;//图像信息 void piclib_init(void); //初始化画图 u16 piclib_alpha_blend(u16 src,u16 dst,u8 alpha); //alphablend处理 void ai_draw_init(void); //初始化智能画图 u8 is_element_ok(u16 x,u16 y,u8 chg); //判断像素是否有效 u8 ai_load_picfile(const u8 *filename,u16 x,u16 y,u16 width,u16 height);//智能画图 #endif 这里基本就是我们前面提到的两个结构体的定义以及一些函数的申明,保存piclib.h。最后我们在test.c文件里面修改代码如下: //得到path路径下,目标文件的总个数 //path:路径 //返回值:总有效文件数 u16 pic_get_tnum(u8 *path) { u8 res; u16 rval=0; DIR tdir; //临时目录 FILINFO tfileinfo; //临时文件信息 u8 *fn; res=f_opendir(&tdir,(const TCHAR*)path); //打开目录 tfileinfo.lfsize=_MAX_LFN*2+1; //长文件名最大长度 tfileinfo.lfname=mymalloc(SRAMIN,tfileinfo.lfsize); //为长文件缓存区分配内存 if(res==FR_OK&&tfileinfo.lfname!=NULL) { while(1)//查询总的有效文件数 { res=f_readdir(&tdir,&tfileinfo); //读取目录下的一个文件 if(res!=FR_OK||tfileinfo.fname[0]==0)break; //错误了/到末尾了,退出 fn=(u8*)(*tfileinfo.lfname?tfileinfo.lfname:tfileinfo.fname); res=f_typetell(fn); if((res&0XF0)==0X50) rval++;//图片文件?则有效文件加1 } } return rval; } int main(void) { u8 res; DIR picdir; //图片目录 FILINFO picfileinfo; //文件信息 u8 *fn; //长文件名 u8 *pname; //带路径的文件名 u16 totpicnum; //图片文件总数 u16 curindex; //图片当前索引 u8 key; //键值 u8 pause=0; //暂停标记 u8 t; u16 temp; u16 *picindextbl; //图片索引表 Stm32_Clock_Init(9); //系统时钟设置 delay_init(72); //延时初始化 uart_init(72,9600); //串口1初始化 LCD_Init(); //初始化液晶 LED_Init(); //LED初始化 KEY_Init(); //按键初始化 usmart_dev.init(72) ; //usmart初始化 mem_init(SRAMIN); //初始化内部内存池 exfuns_init(); //为fatfs相关变量申请内存 f_mount(0,fs[0]); //挂载SD卡 f_mount(1,fs[1]); //挂载FLASH. POINT_COLOR=RED; while(font_init()) //检查字库 { LCD_ShowString(60,50,200,16,16,"Font Error!");delay_ms(200); LCD_Fill(60,50,240,66,WHITE);//清除显示 } Show_Str(60,50,200,16,"战舰 STM32开发板",16,0); Show_Str(60,70,200,16,"图片显示程序",16,0); Show_Str(60,90,200,16,"KEY0:NEXT KEY2:PREV",16,0); Show_Str(60,110,200,16,"正点原子@ALIENTEK",16,0); Show_Str(60,130,200,16,"2012年9月19日",16,0); while(f_opendir(&picdir,"0:/PICTURE"))//打开图片文件夹 { Show_Str(60,150,240,16,"PICTURE文件夹错误!",16,0); delay_ms(200); LCD_Fill(60,150,240,156,WHITE); delay_ms(200);//清除显示 } totpicnum=pic_get_tnum("0:/PICTURE"); //得到总有效文件数 while(totpicnum==NULL)//图片文件为0 { Show_Str(60,150,240,16,"没有图片文件!",16,0); delay_ms(200); LCD_Fill(60,150,240,156,WHITE); delay_ms(200);//清除显示 } printf("图片总数为:%d\r\n",totpicnum); picfileinfo.lfsize=_MAX_LFN*2+1; //长文件名最大长度 picfileinfo.lfname=mymalloc(SRAMIN,picfileinfo.lfsize);//为长文件缓存区分配内存 pname=mymalloc(SRAMIN,picfileinfo.lfsize);//为带路径的文件名分配内存 picindextbl=mymalloc(SRAMIN,2*totpicnum); //申请2*totpicnum个字节的内存,用于存放图片索引 while(picfileinfo.lfname==NULL||pname==NULL||picindextbl==NULL) //内存分配出错 { Show_Str(60,150,240,16,"内存分配失败!",16,0); delay_ms(200); LCD_Fill(60,150,240,146,WHITE); delay_ms(200);//清除显示 } //记录索引 res=f_opendir(&picdir,"0:/PICTURE"); //打开目录 if(res==FR_OK) { curindex=0;//当前索引为0 while(1)//全部查询一遍 { temp=picdir.index; //记录当前index res=f_readdir(&picdir,&picfileinfo); //读取目录下的一个文件 if(res!=FR_OK||picfileinfo.fname[0]==0)break; //错误了/到末尾了,退出 fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname); res=f_typetell(fn); if((res&0XF0)==0X50)//取高四位,看看是不是图片文件 { picindextbl[curindex]=temp; curindex++;//记录索引 } } } Show_Str(60,150,240,16,"开始显示...",16,0); delay_ms(1500); piclib_init(); //初始化画图 curindex=0; //从0开始显示 res=f_opendir(&picdir,(const TCHAR*)"0:/PICTURE"); //打开目录 while(res==FR_OK)//打开成功 { dir_sdi(&picdir,picindextbl[curindex]); //改变当前目录索引 res=f_readdir(&picdir,&picfileinfo); //读取目录下的一个文件 if(res!=FR_OK||picfileinfo.fname[0]==0)break; //错误了/到末尾了,退出 fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname); strcpy((char*)pname,"0:/PICTURE/"); //复制路径(目录) strcat((char*)pname,(const char*)fn); //将文件名接在后面 LCD_Clear(BLACK); ai_load_picfile(pname,0,0,lcddev.width,lcddev.height);//显示图片 Show_Str(2,2,240,16,pname,16,1); //显示图片名字 t=0; while(1) { key=KEY_Scan(0); //扫描按键 if(t>250)key=KEY_RIGHT; //模拟一次按下右键 if(key==KEY_LEFT) //上一张 { if(curindex)curindex--; else curindex=totpicnum-1; break; }else if(key==KEY_RIGHT)//下一张 { curindex++; if(curindex>=totpicnum)curindex=0;//到末尾的时候,自动从头开始 break; }else if(key==KEY_UP) {pause=!pause; LED1=!pause;} //暂停的时候LED1亮. if(pause==0)t++; delay_ms(10); } res=0; } myfree(SRAMIN,picfileinfo.lfname); //释放内存 myfree(SRAMIN,pname); //释放内存 myfree(SRAMIN,picindextbl); //释放内存 } 此部分除了mian函数,还有一个pic_get_tnum的函数,用来得到path路径下,所有有效文件(图片文件)的个数。在mian函数里面我们通过索引(图片文件在PICTURE文件夹下的编号),来查找上一个/下一个图片文件,这里我们需要用到fatfs自带的一个函数:dir_sdi,来设置当前目录的索引(因为f_readdir只能沿着索引一直往下找,不能往上找),方便定位到任何一个文件。dir_sdi在FATFS下面被定义为static函数,所以我们必须在ff.c里面将该函数的static修饰词去掉,然后在ff.h里面添加该函数的申明,以便main函数使用。 其他部分就比较简单了,至此,整个图片显示实验的软件设计部分就结束了。该程序将实现浏览PICTURE文件夹下的所有图片,并显示其名字,每隔3s左右切换一幅图片。 47.4 下载验证 在代码编译成功之后,我们下载代码到ALIENTEK战舰STM32开发板上,可以看到LCD开始显示图片(假设SD卡及文件都准备好了),如图47.4.1所示:
图47.4.1 图片显示实验显示效果 按KEY0和KEY2可以快速切换到下一张或上一张,WK_UP按键可以暂停自动播放,同时DS1亮,指示处于暂停状态,再按一次WK_UP则继续播放。同时,由于我们的代码支持gif格式的图片显示(注意尺寸不能超过LCD屏幕尺寸),所以可以放一些gif图片到PICTURE文件夹,来看动画了。 另外需要注意,不是所有的jpg格式图片都可以正常显示,只有JFIF格式的jpg文件才能正常显示,对于EXIF格式的jpg文件,则不能直接显示,大家可以将EXIF格式的jpg文件用XP的画图打开,然后再保存一下,就将EXIF格式转为JFIF格式了,这样就可以正常解码显示了。 本章,同样可以通过USMART来测试该实验,将ai_load_picfile函数加入USMART控制(方法前面已经讲了很多次了),就可以通过串口调用该函数,在屏幕上任何区域显示任何你想要显示的图片了! |