本實驗使用STM32F407VE(開發版STM32_F4VE)連接2.8inch 16BIT parallel-port Module(含 ILI9341、XPT2046與SPI SD card)。開發環境使用STM32CubeIDE與HAL library。
實驗目標:
- 顯示儲存在SD卡上JPEG image file, image width 無須小於TFT顯示寬度。
- Screenshot: 將TFT顯示內容儲存在SD卡上(RGB565 bitmap format)。
- TFT顯示方向改變時,修正Touch screen座標與TFT座標一致。
- pop-up message window。
- XPT2046與SPI SD Card使用同一個SPI介面,run time改變baud rate以適應慢速XPT2046與高速需求SD read/write。
模組圖片
- 2.8 ' LCD Module:
- 開發版STM32_F4VE
- 線路連接:
使用FSMC、SPI2介面與LCD module連接。開發版TFT pin腳位如下:
TFT LCD header pins
# | Name | Function | Connected to |
---|---|---|---|
1 | - | GND | Ground plane |
2 | - | RST | Reset button |
3 | - | FSMC D15 | PD10 |
4 | - | FSMC D14 | PD9 |
5 | - | FSMC D13 | PD8 |
6 | - | FSMC D12 | PE15 |
7 | - | FSMC D11 | PE14 |
8 | - | FSMC D10 | PE13 |
9 | - | FSMC D9 | PE12 |
10 | - | FSMC D8 | PE11 |
11 | - | FSMC D7 | PE10 |
12 | - | FSMC D6 | PE9 |
13 | - | FSMC D5 | PE8 |
14 | - | FSMC D4 | PE7 |
15 | - | FSMC D3 | PD1 |
16 | - | FSMC D2 | PD0 |
17 | - | FSMC D1 | PD15 |
18 | - | FSMC D0 | PD14 |
19 | - | FSMC NOE | PD4 |
20 | - | FSMC NWE | PD5 |
21 | - | FSMC A18 | PD13 |
22 | - | FSMC NE1 | PD7 |
23 | - | Touch CLK | PB13 |
24 | - | Touch CS | PB12 |
25 | - | Touch MOSI | PB15 |
26 | - | Touch MISO | PB14 |
27 | - | Touch PEN | PC5 |
28 | - | LCD Backlight | PB1 |
29 | - | VBAT | N.C. |
30 | - | GND | Ground plane |
31 | - | 3V3 | +3.3V rail |
32 | - | GND | Ground plane |
接線方式
STM32_F4VE Pin LCD Module pin
31 3V3 VDD
32 GND GND
19 NOE RD
20 NWE WR
21 A18 RS
22 NE1 CS
23 Touch CLK CLK
24 Touch CS T_CS
25 Touch MOSI MOSI
26 Touch MSIO MISO
27 Touch PEN PEN
28 LCD Backlight BL
2 RST RST
D0~D15 D0~D15
PC3 SDCS
完成圖:
介面設定
1.FSMC: LCD Interface 16bit
2. SPI2介面:
- Prescaler :128配合慢速Touch XPT2046,當要做SD IO時再改變baud rate。
- DMA,SPI2 pin與interrupt如下圖選擇。
FATFS與SPI SD存取檔案詳細運作,請參閱前篇
STM32微控制器(STM32F407VET6) SD-4bits、SD-SPI,FLASH等儲存設備管理
使用LIBJPEG library 處理jpeg image,但對於大的影像檔 LIBJPEG僅能縮小的倍數為1/1,1/2,1/4,1/8,所以當超過libjpeg最大縮小倍數時仍可能超過TFT最大寬度,因此需再二次處理。本實驗處理的照片檔如下:
程式碼說明:
- 儲存TFT影像檔於SD卡(Screenshot):
因為LCD module 顯示為16bit RGB565模式,因此選擇儲存檔案的格式為Bitmap,RGB565 header設定,File Information header的bitCount:16 RGB565,Compression:BI_BITFIELDS=3,
RGB565 mask 為0x00f80000e00700001f000000。height為正數,因此從左下至右上依序讀取每個16bits pixel color value轉成low byte first寫入SD中。詳細程式碼請參閱bitmap.h, bitmap.c。
因為SPI SD讀寫需較高baud rate,更改baud rate prescale:
HAL_SPI_DeInit(&hspi2); oldBraudRate = hspi2.Init.BaudRatePrescaler; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; HAL_SPI_Init(&hspi2); . . . HAL_SPI_DeInit(&hspi2); hspi2.Init.BaudRatePrescaler = oldBraudRate; HAL_SPI_Init(&hspi2);
- XPT2046 touch module
參考網址:https://github.com/taburyak/STM32-touchscreen-XPT2046-HAL-SPI。
改寫原來程式碼加入calibration與TFT螢幕轉向時touch point相對座標轉換。詳細程式碼請參閱XPT2046_touch.c, XPT2046_touch.h。
- ILI9341 FSMC driver
參考網址:https://stm32withoutfear.blogspot.com/2019/09/stm32-ili9341-fsmc.html。
將ili9341, fontxx複製到src資料夾。
- Display JPEG image files:
使用Middleware LIBJPEG,因開發板的SRAM只有192KiB,因此對於image width大於TFT display width的檔案先設定
cinfo.scale_num 與cinfo.scale_denom調整縮小倍數,呼叫jpeg_read_scanlines才能使用較小量的memory,因為最大的縮小量為8倍,像本實驗05.jpg為4656X2620,縮小後仍大於TFT display width,為了能整個顯示,需再一次處理調整顯示再TFT display上的pixel。詳細程式碼請參閱jpeg_view.c,jpeg_view.h。
本實驗使用LCD module上的SPI介面SD,讀取速度較慢,因此對於7MB的05.jpg IO時間過長,較不具實用價值,因此在實用上須將SD改為開發版上SDIO介面。
- screenshot demo
- pop-up message window
浮動訊息視窗,設定顯示秒數,關閉視窗後,回存被視窗覆蓋的影像。詳細程式碼參閱showmessage.h,showmessage.c
完成測試影片
程式碼
bitmap.h
#ifndef INC_BITMAP_H_ #define INC_BITMAP_H_ enum compressionMethod { BI_RGB=0, BI_RLE8=1, BI_RLE4=2, BI_BITFIELDS=3, BI_JPEG=4, BI_PNG=5, BI_ALPHABITFIELDS=6 }; typedef struct tagBITMAPFILEHEADER { uint16_t bfType; DWORD bfSize; // file size uint16_t bfReserved1; uint16_t bfReserved2; DWORD bfOffBits; //bitmap data offset } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; // info header size LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; //1, 4, 8, 16, 24 or 32 DWORD biCompression; //0:BI_RGB, 1:BI_RLE8, 2: BI_RLE4, 3:BI_BITFIELDS, 4:BI_JPEG, 5:BI_PNG DWORD biSizeImage; // if BI_RGB, can set be 0 LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; FRESULT saveScreenBigmap(FIL *fp); uint8_t saveScreen(TCHAR* path); FRESULT bitmapHeader(FIL* fp, BITMAPFILEHEADER *fh, BITMAPINFOHEADER *ih); #endif /* INC_BITMAP_H_ */
bitmap.c
#include "fatfs.h" #include "string.h" #include "bitmap.h" #include "ili9341.h" #include "string.h" #include "stdio.h" extern SPI_HandleTypeDef hspi2; FRESULT LSBFirstWrite(FIL *fp, DWORD value, uint8_t len) { UINT bw; char lsb[len]; for (int i = 0; i < len; i++) { lsb[i] = (value>>(i*8))&0xFF; } return f_write(fp, lsb, len, &bw); } FRESULT saveScreenBigmap(FIL *fp) { FRESULT res; uint8_t RGBMask[12] = {0x00,0xf8,0x00,0x00,0xe0,0x07,0x00,0x00,0x1f,0x00,0x00,0x00}; UINT bw; DWORD tempValue; uint16_t w,h; w=lcdGetWidth(); h=lcdGetHeight(); uint16_t pixvalue; char buff[w*2]; //write file header // type: BM res = f_write(fp, "BM", 2, &bw); if (res!=FR_OK) return res; // size: width*height*2(bytes,16bits)+14(file header)+40(info header)+12(RGB mask) tempValue = lcdGetWidth()*lcdGetHeight()*2+66; res = LSBFirstWrite(fp, tempValue, 4); if (res!=FR_OK) return res; // Reserved1, Reserved2: 0,0 memset(buff,0,4); res = f_write(fp, buff, 4, &bw); if (res!=FR_OK) return res; // bitmap offset: 14+40+12=66 res = LSBFirstWrite(fp, 66, 4); if (res!=FR_OK) return res; // File Information Header // info header size:40 res = LSBFirstWrite(fp, 40, 4); if (res!=FR_OK) return res; //width: lcd width res = LSBFirstWrite(fp, (DWORD)w, 4); if (res!=FR_OK) return res; //height: lcd height res = LSBFirstWrite(fp, (DWORD)h, 4); if (res!=FR_OK) return res; //Planes:1 res = LSBFirstWrite(fp, 1, 2); if (res!=FR_OK) return res; //bitCount:16 RGB565 res = LSBFirstWrite(fp, 16, 2); if (res!=FR_OK) return res; //Compression:BI_BITFIELDS=3, res = LSBFirstWrite(fp, 3, 4); if (res!=FR_OK) return res; //sizeImage:0, do not care res = LSBFirstWrite(fp, tempValue, 4); if (res!=FR_OK) return res; //x: 72 dpi=2835 PelsPerMeter res = LSBFirstWrite(fp, 2835, 4); if (res!=FR_OK) return res; //y: 72 dpi=2835 PelsPerMeter res = LSBFirstWrite(fp, 2835, 4); if (res!=FR_OK) return res; //color use:0 res = LSBFirstWrite(fp, 0, 4); if (res!=FR_OK) return res; //color important:0 res = LSBFirstWrite(fp, 0, 4); if (res!=FR_OK) return res; // RGB565 mask res = f_write(fp, RGBMask, 12, &bw); if (res!=FR_OK) return res; //write image pixel from LB to RT for (int y = h-1; y >= 0; y--) { memset(buff,0, w*2); for (int x = 0; x <=w-1; x++) { pixvalue=0; pixvalue = lcdReadPixel((uint16_t)x, (uint16_t)y); buff[x*2+1] = ((pixvalue>>8) & 0xFF); buff[x*2] = (pixvalue & 0xFF); } res = f_write(fp, buff,w*2,&bw); if (res!=FR_OK) return res; } return res; } uint8_t saveScreen(char* path) { FATFS fs; FIL file; FRESULT res; uint32_t oldBraudRate; char fn[256]; HAL_SPI_DeInit(&hspi2); oldBraudRate = hspi2.Init.BaudRatePrescaler; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; HAL_SPI_Init(&hspi2); res = f_mount(&fs, path, 1); if (res==FR_OK) { sprintf(fn,"%sScreen%ld.bmp",path,get_fattime()&0xFFFF); res = f_open(&file, fn, FA_CREATE_ALWAYS|FA_WRITE); if (res==FR_OK) { lcdSetWindow(0, 0, lcdGetWidth()-1, lcdGetHeight()-1); res=saveScreenBigmap(&file); f_close(&file); } f_mount(&fs, "", 0); } HAL_SPI_DeInit(&hspi2); hspi2.Init.BaudRatePrescaler = oldBraudRate; HAL_SPI_Init(&hspi2); return res; } FRESULT bitmapHeader(FIL* fp, BITMAPFILEHEADER *fh, BITMAPINFOHEADER *ih) { FRESULT r; uint8_t fbuff[14], ibuff[40],maskbuf[12]; UINT br; if ((r=f_read(fp, fbuff, 14, &br)) != FR_OK) return r; fh->bfType=fbuff[0] << 8 | fbuff[1]; fh->bfSize = fbuff[5] << 24 | fbuff[4] << 16 |fbuff[3] << 8 | fbuff[2]; fh->bfReserved1 =fbuff[7] << 8 |fbuff[6]; fh->bfReserved2 =fbuff[9] << 8 |fbuff[8]; fh->bfOffBits = fbuff[13] << 24 | fbuff[12] << 16 |fbuff[11] << 8 | fbuff[10]; if ((r=f_read(fp, ibuff, 40, &br)) != FR_OK) return r; ih->biSize = ibuff[3] << 24 | ibuff[2] << 16 |ibuff[1] << 8 | ibuff[0]; ih->biWidth = ibuff[7] << 24 | ibuff[6] << 16 |ibuff[5] << 8 | ibuff[4]; ih->biHeight = ibuff[11] << 24 | ibuff[10] << 16 |ibuff[9] << 8 | ibuff[8]; ih->biPlanes = ibuff[13] << 8 | ibuff[12]; ih->biBitCount = ibuff[15] << 8 | ibuff[14]; ih->biCompression = ibuff[19] << 24 | ibuff[18] << 16 |ibuff[17] << 8 | ibuff[16]; ih->biSizeImage =ibuff[23] << 24 | ibuff[22] << 16 |ibuff[21] << 8 | ibuff[20]; ih->biXPelsPerMeter = ibuff[27] << 24 | ibuff[26] << 16 |ibuff[25] << 8 | ibuff[24]; ih->biYPelsPerMeter =ibuff[31] << 24 | ibuff[30] << 16 |ibuff[29] << 8 | ibuff[28]; ih->biClrUsed = ibuff[35] << 24 | ibuff[34] << 16 |ibuff[33] << 8 | ibuff[32]; ih->biClrImportant = ibuff[39] << 24 | ibuff[38] << 16 |ibuff[37] << 8 | ibuff[36]; if ((r=f_read(fp, maskbuf, 12, &br)) != FR_OK) return r; f_close(fp); return FR_OK; }
showmessage.h
#ifndef INC_SHOWMESSAGE_H_ #define INC_SHOWMESSAGE_H_ #include "stm32f4xx_hal.h" #include "integer.h" void showMessage(char* msg, uint8_t sec); #endif /* INC_SHOWMESSAGE_H_ */
showmessage.c
#include "showmessage.h" #include "ili9341.h" #include "string.h" #include "stdlib.h" void showMessage(char* msg, uint8_t sec) { UINT px,py; UINT x,y; uint8_t fw,fh; uint16_t *msgBuff; px = (lcdGetWidth()-210)/2; py = (lcdGetHeight()-110)/2; msgBuff = malloc(sizeof(uint16_t)*(210*110)); lcdSetWindow(0, 0, lcdGetWidth(), lcdGetHeight()); for (x=px; x < 210+px; x++) { for (y=py; y < 110+py;y++) { msgBuff[(x-px)*110+y-py] = lcdReadPixel(x, y); } } lcdFillRect(px, py, 209, 109, COLOR_BLUE); lcdFillRect(px+5, py+5, 199, 99, COLOR_WHITE); lcdSetTextColor(COLOR_BLUE, COLOR_WHITE); lcdSetTextFont(&Font16); fw=Font16.Width; fh = Font16.Height; for (int posx=0, posy=0, i=0; i < strlen(msg);i++,posx++) { if (msg[i] == '\n' || (posx+1)*(fw) > 200-fw) { posy++; posx=0; } if (msg[i] == '\n') i++; lcdDrawChar(px+12+posx*fw, py+12+posy*(fh+2), msg[i], COLOR_BLUE, COLOR_WHITE); } HAL_Delay(sec*1000); lcdSetWindow(0, 0, lcdGetWidth(), lcdGetHeight()); for (x=px; x < 210+px; x++) { for (y=py; y < 110+py; y++) { lcdDrawPixel(x, y, msgBuff[(x-px)*110+y-py]); } } free(msgBuff); HAL_Delay(10); }
XPT2046_touch,h
#ifndef XPT2046_TOUCH_H_ #define XPT2046_TOUCH_H_ #include "main.h" #include <stdbool.h> /*** Redefine if necessary ***/ // Warning! Use SPI bus with < 2.5 Mbit speed, better ~650 Kbit to be save. #define XPT2046_SPI_PORT hspi2 extern SPI_HandleTypeDef XPT2046_SPI_PORT; #define XPT2046_IRQ_Pin T_IRQ_Pin #define XPT2046_IRQ_GPIO_Port T_IRQ_GPIO_Port #define XPT2046_CS_Pin T_CS_Pin #define XPT2046_CS_GPIO_Port T_CS_GPIO_Port // change depending on screen orientation #define XPT2046_SCALE_X 240 #define XPT2046_SCALE_Y 320 // to calibrate uncomment UART_Printf line in ili9341_touch.c //#define XPT2046_MIN_RAW_X 3400 //#define XPT2046_MAX_RAW_X 29000 //#define XPT2046_MIN_RAW_Y 3300 //#define XPT2046_MAX_RAW_Y 30000 #define XPT2046_MIN_RAW_X 2000 #define XPT2046_MAX_RAW_X 30000 #define XPT2046_MIN_RAW_Y 1500 #define XPT2046_MAX_RAW_Y 29000 #define XTP2046_CALI_DIFF 600 // call before initializing any SPI devices void XPT2046_TouchUnselect(void); bool XPT2046_TouchPressed(void); bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y); bool XPT2046_TouchGetRawCoordinates(uint32_t* raw_, uint32_t* raw_y); bool XPT2046_TouchCalibration(void); #endif /* XPT2046_TOUCH_H_ */
XPT2046_touch.c
#include <stdio.h> #include <stdlib.h> #include <XPT2046_touch.h> #include "ili9341.h" #define READ_X 0xD0 #define READ_Y 0x90 uint16_t cRawX_min = XPT2046_MIN_RAW_X; uint16_t cRawX_max = XPT2046_MAX_RAW_X; uint16_t cRawY_min = XPT2046_MIN_RAW_Y; uint16_t cRawY_max = XPT2046_MAX_RAW_Y; static void XPT2046_TouchSelect() { HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_RESET); } void XPT2046_TouchUnselect() { HAL_GPIO_WritePin(XPT2046_CS_GPIO_Port, XPT2046_CS_Pin, GPIO_PIN_SET); } bool XPT2046_TouchPressed() { return HAL_GPIO_ReadPin(XPT2046_IRQ_GPIO_Port, XPT2046_IRQ_Pin) == GPIO_PIN_RESET; } bool XPT2046_TouchGetCoordinates(uint16_t* x, uint16_t* y) { bool ret_value=false; uint16_t tx,ty; uint32_t raw_x; uint32_t raw_y; if (XPT2046_TouchGetRawCoordinates(&raw_x, &raw_y)) { if(raw_x < cRawX_min) raw_x = cRawX_min; if(raw_x > cRawX_max) raw_x = cRawX_max; if(raw_y < cRawY_min) raw_y = cRawY_min; if(raw_y > cRawY_max) raw_y = cRawY_max; tx = (raw_x - cRawX_min) * XPT2046_SCALE_X / (cRawX_max - cRawX_min); ty = (raw_y - cRawY_min) * XPT2046_SCALE_Y / (cRawY_max - cRawY_min); lcdOrientationTypeDef lot = lcdGetOrientation(); switch (lot) { case LCD_ORIENTATION_PORTRAIT: *x=tx; *y=ty; break; case LCD_ORIENTATION_LANDSCAPE: *x=ty; *y=ILI9341_PIXEL_WIDTH-tx; break; case LCD_ORIENTATION_PORTRAIT_MIRROR: *x=ILI9341_PIXEL_WIDTH-tx; *y=ILI9341_PIXEL_HEIGHT-ty; break; case LCD_ORIENTATION_LANDSCAPE_MIRROR: *x=ILI9341_PIXEL_HEIGHT-ty; *y=tx; break; } ret_value =true; } return ret_value; } bool XPT2046_TouchGetRawCoordinates(uint32_t* raw_x, uint32_t* raw_y) { static const uint8_t cmd_read_x[] = { READ_X }; static const uint8_t cmd_read_y[] = { READ_Y }; static const uint8_t zeroes_tx[] = { 0x00, 0x00 }; static const uint8_t SAMPLES=16; XPT2046_TouchSelect(); uint32_t avg_x = 0; uint32_t avg_y = 0; uint8_t nsamples = 0; for(uint8_t i = 0; i < SAMPLES; i++) { if(!XPT2046_TouchPressed()) break; nsamples++; HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_y, sizeof(cmd_read_y), HAL_MAX_DELAY); uint8_t y_raw[2]; HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, y_raw, sizeof(y_raw), HAL_MAX_DELAY); HAL_SPI_Transmit(&XPT2046_SPI_PORT, (uint8_t*)cmd_read_x, sizeof(cmd_read_x), HAL_MAX_DELAY); uint8_t x_raw[2]; HAL_SPI_TransmitReceive(&XPT2046_SPI_PORT, (uint8_t*)zeroes_tx, x_raw, sizeof(x_raw), HAL_MAX_DELAY); avg_x += (((uint16_t)x_raw[0]) << 8) | ((uint16_t)x_raw[1]); avg_y += (((uint16_t)y_raw[0]) << 8) | ((uint16_t)y_raw[1]); } XPT2046_TouchUnselect(); if(nsamples < SAMPLES) return false; *raw_x = (avg_x / SAMPLES); *raw_y = (avg_y / SAMPLES); return true; } bool XPT2046_TouchCalibration() { uint32_t x0=0,y0=0,x1=0,y1=0,x2=0,y2=0,x3=0,y3=0; bool correct=true; lcdOrientationTypeDef lot = lcdGetOrientation(); lcdSetOrientation(LCD_ORIENTATION_PORTRAIT); lcdFillRGB(COLOR_BLACK); lcdDrawRect(0, 0, 6, 6, COLOR_YELLOW); //lcdSetCursor(20, 100); while(!XPT2046_TouchPressed()) ; if (!XPT2046_TouchGetRawCoordinates(&x0, &y0)) { //lcdPrintf("Calibration Error!"); lcdSetOrientation(lot); return false; } //lcdPrintf("Release Pen"); lcdFillRGB(COLOR_BLACK); lcdDrawRect(0, lcdGetHeight()-6, 6, 6, COLOR_YELLOW); while(XPT2046_TouchPressed()); HAL_Delay(1); //lcdSetCursor(20, 100); while(!XPT2046_TouchPressed()); if(!XPT2046_TouchGetRawCoordinates(&x1, &y1)) { //lcdPrintf("Calibration Error!"); lcdSetOrientation(lot); return false; } //lcdPrintf("Release Pen"); lcdFillRGB(COLOR_BLACK); lcdDrawRect(lcdGetWidth()-6, lcdGetHeight()-6, 6, 6, COLOR_YELLOW); while(XPT2046_TouchPressed()); HAL_Delay(1); //lcdSetCursor(20, 100); while(!XPT2046_TouchPressed()); if (!XPT2046_TouchGetRawCoordinates(&x2, &y2)) { //lcdPrintf("Calibration Error!"); lcdSetOrientation(lot); return false; } //lcdPrintf("Release Pen"); lcdFillRGB(COLOR_BLACK); lcdDrawRect(lcdGetWidth()-6, 0, 6, 6, COLOR_YELLOW); while(XPT2046_TouchPressed()); HAL_Delay(1); //lcdSetCursor(20, 100); while(!XPT2046_TouchPressed()); if (!XPT2046_TouchGetRawCoordinates(&x3, &y3)) { //lcdPrintf("Calibration Error!"); lcdSetOrientation(lot); return false; } //lcdPrintf("Release Pen"); while(XPT2046_TouchPressed()); if ( (int)(x0-x1) < -1*XTP2046_CALI_DIFF || (int)(x0-x1) > XTP2046_CALI_DIFF) correct=false; if ( (int)(y1-y2) < -1*XTP2046_CALI_DIFF || (int)(y1-y2) > XTP2046_CALI_DIFF) correct=false; if ( (int)(x2-x3) < -1*XTP2046_CALI_DIFF || (int)(x2-x3) > XTP2046_CALI_DIFF) correct=false; if ( (int)(y0-y3) < -1*XTP2046_CALI_DIFF || (int)(y0-y3) > XTP2046_CALI_DIFF) correct=false; if (correct) { cRawX_min = (x0+x1)/2; cRawX_max = (x2+x3)/2; cRawY_min = (y0+y3)/2; cRawY_max = (y1+y2)/2; } lcdFillRGB(COLOR_BLACK); //lcdSetCursor(20, 100); //lcdPrintf("Calibration OK:\r\nx_min=%04x,\r\ny_min=%04x,\r\nx_max=%04x,\r\ny_max=%04x",cRawX_min,cRawY_min,cRawX_max,cRawY_max); lcdSetOrientation(lot); return correct; }
jpeg_view.h
#ifndef INC_JPEG_VIEW_H_ #define INC_JPEG_VIEW_H_ void jpeg_screen_view(char* path, char* fn, int px, int py, UINT *iw, UINT *ih); #endif /* INC_JPEG_VIEW_H_ */
jpeg_view.c
#define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "ili9341.h" #include "showmessage.h" extern SPI_HandleTypeDef hspi2; struct jpeg_decompress_struct cinfo; typedef struct RGB { uint8_t B; uint8_t G; uint8_t R; }RGB_typedef; struct jpeg_error_mgr jerr; RGB_typedef *RGB_matrix; uint16_t RGB16PixelColor; static uint8_t *rowBuff; static uint8_t jpeg_decode(JFILE *file, uint8_t *rowBuff, int posx, int posy, UINT *iw, UINT *ih) { uint32_t line_counter = 0; uint32_t i = 0, xc=0, ratio; uint8_t offset=1; JSAMPROW buffer[2] = {0}; UINT lcdWidth, lcdHeight; buffer[0] = rowBuff; lcdWidth = lcdGetWidth(); lcdHeight = lcdGetHeight(); cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src (&cinfo, file); jpeg_read_header(&cinfo, TRUE); if (cinfo.image_width > 6000) { showMessage("Image width exceeds 6000!!!", 5); return 0; } if (cinfo.image_width > lcdWidth) { ratio=cinfo.image_width/lcdWidth; cinfo.scale_num=1; if (ratio <= 8) { cinfo.scale_denom=1; for(int s = 0x8; s > 0x01; s /=2) { if (ratio & s) { cinfo.scale_denom=s; break; } } } else { cinfo.scale_denom=8; } } cinfo.dct_method = JDCT_IFAST; jpeg_start_decompress(&cinfo); if (cinfo.output_width > lcdWidth) { offset = cinfo.output_width / lcdWidth; if (cinfo.output_width % lcdWidth > lcdWidth/4) offset++; } if (posx <0 || posy < 0) { posx=(lcdWidth-(cinfo.output_width*(offset-1)/offset))/2; posy=(lcdHeight-(cinfo.output_height*(offset-1)/offset))/2; } *iw = cinfo.image_width; *ih = cinfo.image_height; lcdFillRGB(COLOR_BLACK); if (posx > 0 && cinfo.output_width/offset < lcdWidth) { lcdDrawRect(posx-1, posy-1, cinfo.output_width/offset+2, cinfo.output_height/offset+2, COLOR_WHITE); } while (cinfo.output_scanline < cinfo.output_height && line_counter < lcdHeight-posy) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); RGB_matrix=(RGB_typedef*)buffer[0]; for(i = 0, xc=0; i < cinfo.output_width && xc < (lcdWidth -posx); i+=offset, xc++) { RGB16PixelColor = (uint16_t) ( ((RGB_matrix[i].R & 0x00F8) >> 3)| ((RGB_matrix[i].G & 0x00FC) << 3)| ((RGB_matrix[i].B & 0x00F8) << 8) ); lcdDrawPixel(xc+posx, line_counter+posy, RGB16PixelColor); } for(i=0; i < offset-1 && cinfo.output_scanline < cinfo.output_height; i++) (void) jpeg_read_scanlines(&cinfo, buffer, 1); line_counter++; } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return 1; } void jpeg_screen_view(char* path, char* fn, int px, int py, UINT *iw, UINT *ih) { FIL file; FATFS fs; uint32_t oldBaudRate; char sf[256]; HAL_SPI_DeInit(&hspi2); oldBaudRate = hspi2.Init.BaudRatePrescaler; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; HAL_SPI_Init(&hspi2); rowBuff = JMALLOC(2048); sprintf(sf, "%s%s", path, fn); if (f_mount(&fs, path, 0) != FR_OK) { JFREE(rowBuff); return; } if(f_open(&file, sf, FA_READ) == FR_OK) { jpeg_decode(&file,rowBuff,px,py, iw, ih); f_close(&file); } else { sprintf(sf, "%s\nFile open Error!!", sf); showMessage(sf, 5); } f_mount(&fs, "", 0); JFREE(rowBuff); HAL_SPI_DeInit(&hspi2); hspi2.Init.BaudRatePrescaler = oldBaudRate; HAL_SPI_Init(&hspi2); }
main.c
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2020 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "fatfs.h" #include "libjpeg.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "ili9341.h" #include "XPT2046_touch.h" #include "lcdDemo.h" #include "menu.h" #include "string.h" #include "bitmap.h" #include "jpeg_view.h" #include "showmessage.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ RTC_HandleTypeDef hrtc; SPI_HandleTypeDef hspi2; DMA_HandleTypeDef hdma_spi2_rx; DMA_HandleTypeDef hdma_spi2_tx; SRAM_HandleTypeDef hsram1; /* USER CODE BEGIN PV */ uint8_t isDraw=0; uint8_t penWidth=1; uint8_t tempIgnoralEXTI=0; RTC_TimeTypeDef sTime; RTC_DateTypeDef sDate; uint16_t cx = 0, cy = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_FSMC_Init(void); static void MX_SPI2_Init(void); static void MX_RTC_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ uint8_t isCalbriating,demo; void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin) { if (GPIO_Pin == T_IRQ_Pin) { if (tempIgnoralEXTI || isCalbriating) return; if (activedMenuItem == SAVEITEM || activedMenuItem == JPEGITEM) return; if(XPT2046_TouchPressed()) { tempIgnoralEXTI=1; XPT2046_TouchGetCoordinates(&cx, &cy); if (menuActived) { uint8_t i=getTouchMenItem(cx, cy); if (i > 0) { showMenu(i); switch (i) { case DRAWINGITEM: lcdFillRect(1, 26, lcdGetWidth()-2, lcdGetHeight()-2, COLOR_BLACK); lcdDrawRect(1, 26, lcdGetWidth()-2, lcdGetHeight()-2, COLOR_WHITE); break; case LCDORIITEM: menuActived=0; break; } } } if (activedMenuItem == DRAWINGITEM) { if (cx > 1 && cx < lcdGetWidth()-1 && cy > 26 && cy < lcdGetHeight()-1 ) lcdFillCircle(cx, cy, penWidth, COLOR_GREENYELLOW); } tempIgnoralEXTI=0; } } } void loadJpegFileTest() { uint32_t stick,etick; lcdOrientationTypeDef lcdori; UINT iw, ih; lcdori=lcdGetOrientation(); lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE); lcdSetTextFont(&Font16); lcdSetTextColor(COLOR_WHITE, COLOR_BLACK); stick = HAL_GetTick(); jpeg_screen_view("0:/", "jpg/01.jpg", 0, 0, &iw, &ih); etick = HAL_GetTick(); lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1); lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick); HAL_Delay(5000); jpeg_screen_view("0:/", "jpg/nofile.jpg", 0, 0, &iw, &ih); HAL_Delay(1000); lcdSetTextFont(&Font16); lcdSetTextColor(COLOR_WHITE, COLOR_BLACK); stick = HAL_GetTick(); jpeg_screen_view("0:/", "jpg/02.jpg", 0, 0, &iw, &ih); etick = HAL_GetTick(); lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1); lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick); HAL_Delay(5000); stick = HAL_GetTick(); jpeg_screen_view("0:/", "jpg/03.jpg", -1, 0, &iw, &ih); etick = HAL_GetTick(); lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1); lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick); HAL_Delay(5000); stick = HAL_GetTick(); jpeg_screen_view("0:/", "jpg/04.jpg", -1, 0, &iw, &ih); etick = HAL_GetTick(); lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1); lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick); HAL_Delay(5000); stick = HAL_GetTick(); jpeg_screen_view("0:/", "jpg/05.jpg", -1, 0, &iw, &ih); etick = HAL_GetTick(); lcdSetCursor(0, lcdGetHeight() - 2*lcdGetTextFont()->Height - 1); lcdPrintf("Resolution:%dX%d, \nTime: %4lu ms", iw, ih, etick-stick); HAL_Delay(5000); lcdSetOrientation(lcdori); } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ activedMenuItem=0; menuActived=0; FATFS fs; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_FSMC_Init(); MX_SPI2_Init(); MX_FATFS_Init(); MX_RTC_Init(); MX_LIBJPEG_Init(); /* USER CODE BEGIN 2 */ lcdBacklightOn(); lcdInit(); lcdFillRGB(COLOR_BLACK); //lcdSetOrientation(LCD_ORIENTATION_LANDSCAPE); demo=false; lcdSetOrientation(LCD_ORIENTATION_PORTRAIT); //start Calibrating isCalbriating=true; showMessage("Start Calibration",2); //HAL_Delay(2000); while(!XPT2046_TouchCalibration()) { showMessage("Calibration Error!!!\n Try again", 2); } isCalbriating=false; showMessage("Calibrate\n successfully",2); //HAL_Delay(2000); // end Calibrating menuActived=1; showMenu(0); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { switch(activedMenuItem) { case SAVEITEM: saveScreen(USERPath); showMenu(0); break; case JPEGITEM: loadJpegFileTest(); showMenu(0); break; case DEMOITEM: demoLCD(); showMenu(0); break; case DRAWINGITEM: break; case LCDORIITEM: tempIgnoralEXTI=1; lcdFillRGB(COLOR_BLACK); lcdSetOrientation((lcdGetOrientation()+1)%4); showMenu(0); tempIgnoralEXTI=0; menuActived=1; break; } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } } /** * @brief RTC Initialization Function * @param None * @retval None */ static void MX_RTC_Init(void) { /* USER CODE BEGIN RTC_Init 0 */ /* USER CODE END RTC_Init 0 */ RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; /* USER CODE BEGIN RTC_Init 1 */ /* USER CODE END RTC_Init 1 */ /** Initialize RTC Only */ hrtc.Instance = RTC; hrtc.Init.HourFormat = RTC_HOURFORMAT_24; hrtc.Init.AsynchPrediv = 127; hrtc.Init.SynchPrediv = 255; hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN Check_RTC_BKUP */ /* USER CODE END Check_RTC_BKUP */ /** Initialize RTC and set the Time and Date */ sTime.Hours = 12; sTime.Minutes = 10; sTime.Seconds = 0; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } sDate.WeekDay = RTC_WEEKDAY_MONDAY; sDate.Month = RTC_MONTH_JANUARY; sDate.Date = 1; sDate.Year = 21; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN RTC_Init 2 */ /* USER CODE END RTC_Init 2 */ } /** * @brief SPI2 Initialization Function * @param None * @retval None */ static void MX_SPI2_Init(void) { /* USER CODE BEGIN SPI2_Init 0 */ /* USER CODE END SPI2_Init 0 */ /* USER CODE BEGIN SPI2_Init 1 */ /* USER CODE END SPI2_Init 1 */ /* SPI2 parameter configuration*/ hspi2.Instance = SPI2; hspi2.Init.Mode = SPI_MODE_MASTER; hspi2.Init.Direction = SPI_DIRECTION_2LINES; hspi2.Init.DataSize = SPI_DATASIZE_8BIT; hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; hspi2.Init.NSS = SPI_NSS_SOFT; hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi2.Init.TIMode = SPI_TIMODE_DISABLE; hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi2.Init.CRCPolynomial = 10; if (HAL_SPI_Init(&hspi2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN SPI2_Init 2 */ /* USER CODE END SPI2_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ /* DMA1_Stream3_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); /* DMA1_Stream4_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, LCD_BL_Pin|T_CS_Pin, GPIO_PIN_SET); /*Configure GPIO pin : SD_CS_Pin */ GPIO_InitStruct.Pin = SD_CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(SD_CS_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : T_IRQ_Pin */ GPIO_InitStruct.Pin = T_IRQ_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(T_IRQ_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pins : LCD_BL_Pin T_CS_Pin */ GPIO_InitStruct.Pin = LCD_BL_Pin|T_CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); } /* FSMC initialization function */ static void MX_FSMC_Init(void) { /* USER CODE BEGIN FSMC_Init 0 */ /* USER CODE END FSMC_Init 0 */ FSMC_NORSRAM_TimingTypeDef Timing = {0}; /* USER CODE BEGIN FSMC_Init 1 */ /* USER CODE END FSMC_Init 1 */ /** Perform the SRAM1 memory initialization sequence */ hsram1.Instance = FSMC_NORSRAM_DEVICE; hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; /* hsram1.Init */ hsram1.Init.NSBank = FSMC_NORSRAM_BANK1; hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE; hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE; hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE; /* Timing */ Timing.AddressSetupTime = 1; Timing.AddressHoldTime = 15; Timing.DataSetupTime = 5; Timing.BusTurnAroundDuration = 0; Timing.CLKDivision = 16; Timing.DataLatency = 17; Timing.AccessMode = FSMC_ACCESS_MODE_A; /* ExtTiming */ if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK) { Error_Handler( ); } /* USER CODE BEGIN FSMC_Init 2 */ /* USER CODE END FSMC_Init 2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
menu.h
#include "stm32f4xx_hal.h" #include "ili9341.h" #define MENU_ITEMS 5 #define JPEGITEM 1 #define DEMOITEM 2 #define DRAWINGITEM 3 #define SAVEITEM 5 #define LCDORIITEM 4 uint8_t activedMenuItem; uint8_t menuActived; void showMenu(uint8_t selectedIndex); void hideMenu(void); uint8_t getTouchMenItem(uint16_t x, uint16_t y);
menu.c
#include "menu.h" uint16_t menuColordinate[][4]={{5,5,44,20},{52, 5, 44, 20},{99, 5, 44, 20},{146, 5, 25, 20}, {174,5,44,20}}; char *menuText[]={"JPEG", "DEMO","DRAW", "R", "SAVE"}; uint16_t menuBGColor[]={COLOR_BLUE,COLOR_BLUE,COLOR_BLUE,COLOR_BLUE,COLOR_BLUE}; uint16_t selmenuBGColor=COLOR_GREEN; void hideMenu() { lcdFillRect(0, 0,lcdGetWidth(), 25, COLOR_BLACK); } void showMenu(uint8_t selectedIndex) { lcdSetTextFont(&Font12); if (selectedIndex > 0 && selectedIndex <= MENU_ITEMS) { if (activedMenuItem > 0 && activedMenuItem <= MENU_ITEMS) { int ti=activedMenuItem-1; lcdSetTextColor(COLOR_WHITE, menuBGColor[ti]); lcdFillRect(menuColordinate[ti][0], menuColordinate[ti][1], menuColordinate[ti][2], menuColordinate[ti][3], menuBGColor[ti]); lcdSetCursor(menuColordinate[ti][0]+6, menuColordinate[ti][1]+4); lcdPrintf(menuText[ti]); } activedMenuItem=selectedIndex; selectedIndex--; lcdSetTextColor(COLOR_WHITE, selmenuBGColor); lcdFillRect(menuColordinate[selectedIndex][0], menuColordinate[selectedIndex][1], menuColordinate[selectedIndex][2], menuColordinate[selectedIndex][3], selmenuBGColor); lcdSetCursor(menuColordinate[selectedIndex][0]+6, menuColordinate[selectedIndex][1]+4); lcdPrintf(menuText[selectedIndex]); } else { hideMenu(); activedMenuItem=0; for (int i=0;i<MENU_ITEMS;i++) { lcdSetTextColor(COLOR_WHITE, menuBGColor[i]); lcdFillRect(menuColordinate[i][0], menuColordinate[i][1], menuColordinate[i][2], menuColordinate[i][3], menuBGColor[i]); lcdSetCursor(menuColordinate[i][0]+6, menuColordinate[i][1]+4); lcdPrintf(menuText[i]); } } } uint8_t getTouchMenItem(uint16_t x, uint16_t y) { uint8_t ret = 0; for (int i=0;i<MENU_ITEMS;i++) { if (x > menuColordinate[i][0] && x < menuColordinate[i][0]+menuColordinate[i][2] && y > menuColordinate[i][1] && y < menuColordinate[i][1]+menuColordinate[i][3]) { ret = i+1; break; } } return ret; }