您的位置:首页 > 其它

单片机采用RLE算法实现液晶屏显示图片

2016-11-29 00:10 627 查看
由于需要用到液晶屏(320*240)显示图片,而且图片的数量比较多(好几百张),并且图片要求保存到16M的SPI FLASH里面,显然如果不处理 16M的FLASH明显是放不下去。后来同事说可以用压缩算法RLE,并且用C#给我做了个小的软件,压缩图片得到RLE压缩后的数据。

点击打开链接 ---------- 详细的RLE算法可以参考次连接http://blog.csdn.net/orbit/article/details/7062218

这个算法的缺点是 如果图片颜色复杂就不好,所以颜色尽量单调些。

1、RLE算法小工具的使用

2、我使用的RLE和上面连接的区别(改进)

3、单片机里面实现的方法

1、RLE算法小工具的使用点击打开链接

这里是小工具的下载地址 http://download.csdn.net/detail/chen244798611/9696253

使用:使用也非常简单 下载下来 RLETest.exe,点击打开 --》界面就一个按钮 “压缩”---》点击选择图片 自动压缩

提示完成可以看见生成



第一个里面有压缩前和压缩后的文件大小对比

最后一个.c文件压缩后得到一个数据,可以保存到spi flash里面

2、我使用的RLE和上面连接的区别(改进)

由于采用的液晶屏是16位的数据,那么比较可定应该是按照2字节 一个数据的比较,不能采用上面那种1个字节的比较。所以这里做了改进,其他都和上面那篇文章介绍一样。并且采用的是上面文章介绍的最后一个改进算法,如下

详细介绍 还是去看看那个文章。

225 int Rle_Decode_O(unsigned char *inbuf, int inSize, unsigned char *outbuf, intonuBufSize)

226 {

227 unsigned char *src = inbuf;

228 int i;

229 int decSize = 0;

230 int count = 0;

231

232 while(src < (inbuf + inSize))

233 {

234 unsigned char sign = *src++;

235 int count = sign & 0x3F;

236 if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/

237 {

238 return -1;

239 }

240 if((sign & 0x80) == 0x80) /*连续重复数据标志*/

241 {

242 for(i = 0; i < count; i++)

243 {

244 outbuf[decSize++] = *src;

245 }

246 src++;

247 }

248 else

249 {

250 for(i = 0; i < count; i++)

251 {

252 outbuf[decSize++] = *src++;

253 }

254 }

255 }

256

257 return decSize;

258 }

3、单片机里面实现的方法

下面是在单片机里面实现的代码,不过这里一个问题频繁读取 刷屏速度比较慢 测试发现要100多MS,后面改进了算法 ,并且采用FATFS管理SPI FLASH 测试发现28ms可以显示一张图片(不过颜色不是很复杂 复杂时间会更长)

void lcd_display_image(uint32_t epromoffset)//保存在flsah中的地址

{

uint8_t buf[1024] = {0};//定义缓冲区大小

uint32_t totlelen = 0;//用于保存数据总长度

uint32_t index = 0;//索引

uint8_t temp = 0;//临时存放数据

uint8_t count = 0;//连续数据个数

uint16_t colour = 0;//保存颜色用如液晶显示

uint8_t i = 0;

SPI_FLASH_ReadBuffer(buf,epromoffset, 3);//前3个字节保存数据的总长度

epromoffset = epromoffset + 3;//flash 地址偏移3

totlelen = buf[0] << 16 | buf[1] << 8 | buf[2];//计算得到总长度

LCD_SetWindows(0,319,0,239);//320 240 设置LCD显示区域

while(index < totlelen)//判断 索引和文件总长度 退出的条件

{

SPI_FLASH_ReadBuffer(buf,epromoffset, 1);//读数据

epromoffset++;//flash 地址自加

temp = buf[0];//得到读取的数据

index++;//索引自加

count = temp & 0x7f;//得到连续的个数

if((temp & 0x80) == 0x80)//判断是否是相同 还是不同的 连续

{

SPI_FLASH_ReadBuffer(buf,epromoffset, 2);//相同连续 读取两个字节

epromoffset = epromoffset + 2;

index = index + 2;

colour = buf[0] << 8 | buf[1];//组合成颜色 RGB 565

for(i = 0;i < count;i++)

{

LCD_RAM = colour;//显示 FSMC

}

}

else//不相同 连续

{

//SPI_FLASH_ReadBuffer(buf,epromoffset, count *2);

//读取 count*2个数据 2个数据组成一个颜色数据 count 个颜色数据 所以要*2

SPI_DMA_FLASH_ReadBuffer_1(epromoffset,buf,count *2);

epromoffset = epromoffset + count * 2;//地址偏移

index = index + count * 2;

for(i = 0; i < count * 2;i= i+2)

{

LCD_RAM = buf[i] << 8 | buf[i+1];//显示

}

}

}

index = 0;

}

改进后的单片机程序

void SPI_Flash_lcd_Fatfs_image(const char *filename)//文件名

{

uint8_t buf[piece_size] = {0};//开辟一个大的缓冲区

uint32_t epromoffset = 0;

uint32_t totlelen = 0;

uint32_t index = 0;

uint8_t temp = 0;

uint32_t num = 0;

uint8_t count = 0;

uint16_t colour = 0;

uint8_t i = 0,j = 0;

uint16_t write_buf = 0;

uint16_t read_buf = 0;

SPI_Flash_ReadFileData_add(filename,buf,epromoffset,3,&num);//读取总长度 采用FATFA

epromoffset = epromoffset + 3;

totlelen = buf[0] << 16 | buf[1] << 8 | buf[2];

LCD_SetWindows(0,319,0,239);//320 240

while(index < totlelen)

{

if(totlelen - index > piece_size)

{

SPI_Flash_ReadFileData_add(filename,buf,epromoffset,piece_size,&num);//读取数据保存到缓冲区

epromoffset = epromoffset + piece_size;

read_buf = piece_size;

index = index + piece_size;

}

else

{

SPI_Flash_ReadFileData_add(filename,buf,epromoffset,totlelen - index,&num);

epromoffset = epromoffset + totlelen - index;

read_buf = totlelen - index;

index = totlelen;

}

while(write_buf < read_buf)

{

temp = buf[write_buf];

write_buf++;

count = temp & 0x7f;

if((temp & 0x80) == 0x80)

{

if((read_buf- write_buf) > 2)

{

colour = buf[write_buf] << 8 | buf[write_buf+1];

write_buf = write_buf + 2;

}

else

{

write_buf = write_buf + 2;

}

for(i = 0;i < count;i++)

{

LCD_RAM = colour;

}

}

else

{

count = count *2;

j = 0;

for(i = 0; i < count ;i= i+2)

{

if((read_buf - write_buf) > 2)

{

colour = buf[write_buf] << 8 | buf[write_buf+1];

LCD_RAM = colour;

write_buf = write_buf +2;

}

else

{

SPI_Flash_ReadFileData_add(filename,buf,epromoffset + j,2,&num);//这里有点问题 需要改进 假如缓冲区数据读完 就会出现点问题

j = j + 2;

LCD_RAM =buf[0] << 8 | buf[1];

write_buf = write_buf +2;

}

}

}

}

write_buf= write_buf %piece_size;

}

}

这个程序还有点小问题 ,不过也可以使用 ,有时间我再改进下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RLE