使用NUCLEO-L412开发板驱动SPI接口的2.2" TFT液晶屏,显示一些简单的信息。掌握硬件SPI操作,简单图形点阵绘制。
2.硬件连接
2.1.硬件连接示意图
说明:
液晶屏工作电压为3.3V,LCD_CS为液晶屏的选通引脚,LCD_RESET为液晶屏的复位引脚,LCD_DC为液晶屏用来区分命令或数据的控制引脚,LCD_BL为液晶屏的背光控制引脚,LCD_SCK & LCD_MISO & LCD_MOSI为液晶屏的SPI通讯接口。
2.2.实物连接图
3.STM32CubeMX配置
3.1.GPIO口及SPI GPIO口配置如下图所示:
3.2.SPI1配置如下图所示:
4.编写驱动程序
4.1.ILI9341驱动程序
/** ****************************************************************************** * @file ILI9341.c * @version V1.00 * @author xld0932 * @brief ****************************************************************************** * @attention * * Copyright (c) 2019. All rights reserved. * ****************************************************************************** */ /* Define to prevent recursive inclusion ------------------------------------*/ #define __ILI9341_C__ /* Includes -----------------------------------------------------------------*/ #include "ILI9341.h" /* Private constants --------------------------------------------------------*/ /* Private defines ----------------------------------------------------------*/ /* Private typedef ----------------------------------------------------------*/ /* Private macro ------------------------------------------------------------*/ /* Private variables --------------------------------------------------------*/ /* Private function prototypes ----------------------------------------------*/ /* Exported variables -------------------------------------------------------*/ extern SPI_HandleTypeDef hspi1; /* Exported function prototypes ---------------------------------------------*/ /** * @brief : * @param : * @returns: * @details: */ static void ILI9341_SPI_Transmit(uint8_t data) { if(HAL_SPI_Transmit(&hspi1, &data, 1, 1000) != HAL_OK) { printf("\r\nSPI Transmit Error!"); } } /** * @brief : * @param : * @returns: * @details: */ void ILI9341_WriteCommand(uint8_t cmd) { LCD_DC_CLR; LCD_CS_CLR; ILI9341_SPI_Transmit(cmd); LCD_CS_SET; } /** * @brief : * @param : * @returns: * @details: */ void ILI9341_WriteData(uint8_t dat) { LCD_DC_SET; LCD_CS_CLR; ILI9341_SPI_Transmit(dat); LCD_CS_SET; } /** * @brief : * @param : * @returns: * @details: */ void ILI9341_WriteWord(uint16_t dat) { ILI9341_WriteData((uint8_t)(dat >> 8)); ILI9341_WriteData((uint8_t)(dat >> 0)); } /** * @brief : * @param : * @returns: * @details: */ static void ILI9341_HardwareReset(void) { LCD_RST_CLR; HAL_Delay(100); LCD_RST_SET; HAL_Delay(100); } /** * @brief : * @param : * @returns: * @details: */ void ILI9341_Init(void) { ILI9341_HardwareReset(); //---Sleep Out ILI9341_WriteCommand(0x11); HAL_Delay(150); //---Memory Access Control ILI9341_WriteCommand(0x36); ILI9341_WriteData(0x48); //---COLMOD:Pixel Format Set = 16 bits / pixel ILI9341_WriteCommand(0x3A); ILI9341_WriteData(0x55); //---Display ON ILI9341_WriteCommand(0x29); } /*********************** (C) COPYRIGHT ************************END OF FILE****/
复制代码/** ****************************************************************************** * @file LCD.h * @version V1.00 * @author xld0932 * @brief ****************************************************************************** * @attention * * Copyright (c) 2019. All rights reserved. * ****************************************************************************** */ /* Define to prevent recursive inclusion ------------------------------------*/ #ifndef __LCD_H__ #define __LCD_H__ #undef EXTERN #ifdef __LCD_C__ #define EXTERN #else #define EXTERN extern #endif /* Includes -----------------------------------------------------------------*/ #include "platform.h" /* Exported constants -------------------------------------------------------*/ /* Exported defines ---------------------------------------------------------*/ #define USE_HORIZONTAL 0 #define LCD_X_SIZE 240 #define LCD_Y_SIZE 320 #if USE_HORIZONTAL #define X_MAX_PIXEL LCD_Y_SIZE #define Y_MAX_PIXEL LCD_X_SIZE #else #define X_MAX_PIXEL LCD_X_SIZE #define Y_MAX_PIXEL LCD_Y_SIZE #endif /* Exported typedef ---------------------------------------------------------*/ typedef enum { TopLeft = 0, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight, } eALIGN; typedef struct { uint16_t x; uint16_t y; eALIGN align; char *text; } sTEXT; /* Exported macro -----------------------------------------------------------*/ #define RGB(r,g,b) ((((r) & 0x1F) << 11) | (((g) & 0x3F) << 6) | ((b) & 0x1F)) /* Exported functions prototypes --------------------------------------------*/ EXTERN void LCD_Init(void); #endif /*********************** (C) COPYRIGHT ************************END OF FILE****/
复制代码/** ****************************************************************************** * @file LCD.c * @version V1.00 * @author xld0932 * @brief ****************************************************************************** * @attention * * Copyright (c) 2019. All rights reserved. * ****************************************************************************** */ /* Define to prevent recursive inclusion ------------------------------------*/ #define __LCD_C__ /* Includes -----------------------------------------------------------------*/ #include "font.h" #include "LCD.h" #include "ILI9341.h" /* Private constants --------------------------------------------------------*/ /* Private defines ----------------------------------------------------------*/ #define LCD_DEFAULT_FONT Font08x16 /* Private typedef ----------------------------------------------------------*/ /* Private macro ------------------------------------------------------------*/ /* Private variables --------------------------------------------------------*/ sFONT *TextFont; uint16_t TextColor = 0; uint16_t BackColor = 0; sTEXT title = {0, 10, MiddleCenter, "MianBaoBan"}; /* Private function prototypes ----------------------------------------------*/ /* Exported variables -------------------------------------------------------*/ /* Exported function prototypes ---------------------------------------------*/ /** * @brief : * @param : * @returns: * @details: */ void LCD_SetCursor(uint16_t x, uint16_t y) { ILI9341_WriteCommand(0x2A); ILI9341_WriteWord(x); ILI9341_WriteCommand(0x2B); ILI9341_WriteWord(y); ILI9341_WriteCommand(0x2C); } /** * @brief : * @param : * @returns: * @details: */ void LCD_SetRegion(uint16_t x, uint16_t y, uint16_t width, uint16_t height) { ILI9341_WriteCommand(0x2A); ILI9341_WriteWord(x); ILI9341_WriteWord(x+width); ILI9341_WriteCommand(0x2B); ILI9341_WriteWord(y); ILI9341_WriteWord(y+height); ILI9341_WriteCommand(0x2C); } /** * @brief : * @param : * @returns: * @details: */ void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color) { LCD_SetCursor(x, y); ILI9341_WriteWord(color); } /** * @brief : * @param : * @returns: * @details: */ void LCD_Clear(uint16_t color) { uint32_t i = 0; LCD_SetRegion(0, 0, X_MAX_PIXEL-1, Y_MAX_PIXEL-1); for(i = 0; i < X_MAX_PIXEL * Y_MAX_PIXEL; i++) { ILI9341_WriteWord(color); } } /** * @brief : * @param : * @returns: * @details: */ void LCD_Setup(void) { ILI9341_Init(); LCD_LED_SET; } /** * @brief : * @param : * @returns: * @details: */ void LCD_SetFont(sFONT *font) { TextFont = font; } /** * @brief : * @param : * @returns: * @details: */ sFONT *LCD_GetFont(void) { return TextFont; } /** * @brief : * @param : * @returns: * @details: */ void LCD_SetColor(uint16_t forecolor, uint16_t backcolor) { TextColor = forecolor; BackColor = backcolor; } /** * @brief : * @param : * @returns: * @details: */ void LCD_GetColor(uint16_t *forecolor, uint16_t *backcolor) { *forecolor = TextColor; *backcolor = BackColor; } /** * @brief : * @param : * @returns: * @details: */ void LCD_SetTextColor(uint16_t color) { TextColor = color; } /** * @brief : * @param : * @returns: * @details: */ uint16_t LCD_GetTextColor(void) { return TextColor; } /** * @brief : * @param : * @returns: * @details: */ void LCD_SetBackColor(uint16_t color) { BackColor = color; } /** * @brief : * @param : * @returns: * @details: */ uint16_t LCD_GetBackColor(void) { return BackColor; } /** * @brief : * @param : * @returns: * @details: */ void LCD_DisplayASCII(uint8_t x, uint16_t y, const uint8_t ch) { uint8_t i = 0, j = 0, k = 0, temp = 0; uint16_t forecolor = 0, backcolor = 0; sFONT *font = LCD_GetFont(); LCD_GetColor(&forecolor, &backcolor); for(i = 0; i < font->width; i++) { for(j = 0; j < (font->height / 8); j++) { temp = font->table[(ch - 0x20) * (font->width / 8)][i + j * font->width]; for(k = 0; k < 8; k++) { if((temp << k) & 0x80) LCD_DrawPoint(x + i, y + j * 8 + k, forecolor); else LCD_DrawPoint(x + i, y + j * 8 + k, backcolor); } } } } /** * @brief : * @param : * @returns: * @details: */ void LCD_DisplayString(uint16_t x, uint16_t y, char *str) { sFONT *font = LCD_GetFont(); while (*str != '\0') { if(*str == '\n') { x = 0; y += font->height; } else if(*str == '\r') { // do nothing } else if(*str == '\t') { x += font->width * 4; x %= X_MAX_PIXEL; } else { LCD_DisplayASCII(x, y, *str); x += font->width; } if(x >= X_MAX_PIXEL) { x = 0; y += font->height; } if(y >= Y_MAX_PIXEL) { x = 0; y = 0; } str++; } } /** * @brief : * @param : * @returns: * @details: */ void LCD_DisplayText(sTEXT text) { uint16_t x = 0, width = 0; width = strlen(text.text) * LCD_GetFont()->width; switch(text.align) { case TopLeft: case MiddleLeft: case BottomLeft: break; case TopCenter: case MiddleCenter: case BottomCenter: if((text.x + width) < X_MAX_PIXEL) { x = (X_MAX_PIXEL - width) / 2; } break; case TopRight: case MiddleRight: case BottomRight: if((text.x + width) < X_MAX_PIXEL) { x = X_MAX_PIXEL - width; } break; default: break; } LCD_DisplayString(x, text.y, text.text); } /** * @brief : * @param : * @returns: * @details: */ void LCD_Init(void) { LCD_Setup(); LCD_SetColor(RGB(255,255,0),RGB(255,0,0)); LCD_Clear(LCD_GetBackColor()); LCD_SetFont(&Font16x16); LCD_DisplayText(title); LCD_SetFont(&LCD_DEFAULT_FONT); LCD_DisplayString(0, 50, "\r\nHardware : Nucleo-L412KB"); LCD_DisplayString(0, 100, "\r\nProject : LCD DEMO"); LCD_DisplayString(0, 125, "\r\nAuthor : xld0932"); LCD_DisplayString(0, 150, "\r\nDetails : Hardware SPI Drive LCD (ILI9341) Demo"); } /*********************** (C) COPYRIGHT ************************END OF FILE****/
复制代码6.总结
使用STM32L412KB的硬件SPI接口驱动液晶屏,驱动液晶屏的显示速度较软件模拟实现的SPI操作速度要快很多。但对于有显示需要的项目来说,STM32L412KB肯定不是一个好选择,驱屏的速度还远达不到显示要求,本身这颗芯片也没有对应的总线接口或者内置屏驱。芯片内置的FLASH和SRAM也偏小,外扩SRAM对于芯片引脚数量也是一个限制。所以个人感觉这颗芯片还是适于用对功耗有要求的场合^^。
7.工程代码