前言
- 本博文基於emWin V5.50和MDK環境下編寫和調試;
- 本博客內容介紹STM32利用STemWIn庫從搭載了文件系統(FATFS V13c)的SD卡上獲取到一個位圖流,並顯示在LCD的指定位置上的小實驗;看本博文需要有一些GUI的基礎和位圖基礎;
- 如有不足,還請多多指教;
獲取流程
對於一個大的GUI項目來說,如果所有的圖標數據都保存在單片機內部ROM中,所佔用的內存空間是非常大的,尤其是像單片機這種小容量CPU,內存尤爲珍貴。如果把這些圖標都保存在外部函數中,雖說在一定程度上增加了響應時間,但是很省內存,在一定程度上降低了成本。爲此emWin專門提供了功能函數可以將位於外部存儲設備上的流位圖文件顯示在LCD上,其數據轉移流程如下:
在我的這個實驗中這並不是一個簡單的從存儲器讀取數據顯示在LCD上,他要經過幾個結構層,如下圖:
所以這個實驗需要:
- 硬件:SD卡,LCD顯示器;
- 軟件:FATFS,SD卡驅動,STemWin,LCD底層驅動(描點函數);
但是 本實驗並不介紹上面這些驅動和移植過程,而是着重介紹STemWin提供的相應繪圖函數GUI_DrawStreamedBitmapExAuto()
外部存儲器流位圖獲取函數
int GUI_DrawStreamedBitmapExAuto(GUI_GET_DATA_FUNC * pfGetData, const void * p, int x, int y);
描述: 自動識別從外部獲取到的不同格式的位圖流數據,從而將其顯示在以(x,y)爲起點的LCD屏幕上;
參數:
pfGetData:外部數據獲取函數。GUI_DrawStreamedBitmapExAuto()本身並不能從外部存儲器獲取位圖數據,而是通過一個用戶自定義的GetData函數將要顯示的位圖數據從外部存儲器讀出來,指針就指向這個GetData函數;GUI_DrawStreamedBitmapExAuto()會多次調用這個函數;
p:用戶自定義指針。這個指針很重要,從外部存儲器獲取數據的方式有很多種。比如不需要FATFS的是直接訪問,那麼這裏的P所指向的變量或結構體,用來將需要讀取數據的起始地址,讀取數據的大小等這些重要信息傳遞給pfGetData所指向的函數;同理,外部存儲器如果搭載了FATFS,那麼這裏可以傳遞文件類型結構體變量,從而獲取相應數據;
x,y:這兩個參數很好理解,就是LCD屏幕點座標;
返回值: 0 on success, 1 on error.
注意:這裏有一個問題,在數據獲取的過程中是要佔用單片機的RAM的,如果一個位圖的大小大於了單片機本身的RAM大小,這很棘手。所以GUI_DrawStreamedBitmapExAuto()提供了分批獲取數據的方法。但是每一批獲取的數據量必須大於或等於LCD屏幕上一行數據的像素點數據所佔用的內存空間; 這一點需要怎麼自己設定;
指定位圖格式的獲取函數: 功能上和Auto沒有太大區別,如下
數據獲取函數GetData (兩種)
在官方手冊的204頁,給出了獲取函數的要求:
下面這是我自己編寫的帶FATFS的SD卡數據獲取函數:
第一種: 分兩批獲取數據函數
int APP_GetData_Stream(void * p,const U8 ** ppData,unsigned NumBytesReq,U32 offset )
{
FRESULT res_SD = FR_OK;
FIL * phFile = (FIL *)p;
U8 * pData = (U8 *)*ppData;
DWORD NumBytesRead;
//將數據讀入緩衝區(至少一行像素點數據大小的緩衝區)
res_SD = f_mount(&FATFS_DEV_SDHC,"1:",1);
if(res_SD == FR_OK)
{
//1.打開文件;
res_SD = f_open(phFile,"1:AliPay.dta",FA_READ|FA_OPEN_EXISTING);
if( res_SD == FR_OK )
{
printf( "文件打開成功!\r\n");
//2.根據偏移量設置文件讀寫指針位置
f_lseek(phFile,offset);
//3.獲取文件頭信息/單行字節數據;
res_SD = f_read(phFile,pData,NumBytesReq,&NumBytesRead);
if((res_SD == FR_OK) && (NumBytesReq == NumBytesRead))
{
printf("數據獲取成功!\r\n");
}
else
printf("數據獲取失敗!錯誤代碼:%d\r\n",res_SD);
}
else
printf("文件打開失敗!錯誤代碼:%d\r\n",res_SD);
f_close(phFile);
}
else
printf("文件系統掛載失敗!錯誤代碼:%d\r\n",res_SD);
f_mount(NULL,"1:",0);
return NumBytesRead;
}
效果圖:
第二種: 多批獲取數據函數 (這個函數的功能我並沒有實現,測試了很多遍,以後再修補把,這裏先把代碼寫下來)
int APP_GetData(void * p,const U8 ** ppData,unsigned NumBytes,U32 offset )
{
FRESULT res_SD = FR_OK;
static U8 acBuffer[480];
FIL * phFile = NULL;
DWORD NumBytesRead;
phFile = (FIL *)p;
if( NumBytes > sizeof(acBuffer) ) NumBytes = sizeof( acBuffer );
res_SD = f_mount(&FATFS_DEV_SDHC,"1:",1);
if(res_SD == FR_OK)
{
//1.打開文件;
res_SD = f_open(phFile,"1:AliPay.dta",FA_READ|FA_OPEN_EXISTING);
if( res_SD == FR_OK )
{
printf( "文件打開成功!\r\n");
//2.根據偏移量設置文件讀寫指針位置
f_lseek(phFile,offset);
//3.獲取文件頭信息/單行字節數據;
res_SD = f_read(phFile,acBuffer,NumBytes,&NumBytesRead);
if((res_SD == FR_OK) && (NumBytes == NumBytesRead))
*ppData = acBuffer; //返回緩存區的起始地址;
else
printf("數據獲取失敗!錯誤代碼:%d\r\n",res_SD);
}
else
printf("文件打開失敗!錯誤代碼:%d\r\n",res_SD);
f_close(phFile);
}
else
printf("文件系統掛載失敗!錯誤代碼:%d\r\n",res_SD);
f_mount(NULL,"1:",0);
return NumBytesRead;
}