1. 程式人生 > >微控制器採用RLE演算法實現液晶屏顯示圖片

微控制器採用RLE演算法實現液晶屏顯示圖片

由於需要用到液晶屏(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演算法小工具的使用點選開啟連結

使用:使用也非常簡單 下載下來 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(= 0; i < count; i++)

243             {

244                 outbuf[decSize++] = *src;

245             }

246             src++;

247         }

248         else

249         {

250             for(= 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;
}


}

這個程式還有點小問題 ,不過也可以使用 ,有時間我再改進下