本程序采用的是STM32F103VE单片机,外部晶振的大小为8MHz,使用HAL库编写程序。

程序下载地址:https://pan.baidu.com/s/1-Q4LX3DkMjDcLod1m3r1oQ(提取码:mcji)
(程序里面注释FSMC_D16=>RS写错了,应该是A16才对,D没有16)

去ST官网下载STM32F1的Cube包,文件名称为en.stm32cubef1.zip,STemWin图形库就位于STM32Cube_FW_F1_V1.8.0/Middlewares/ST/STemWin文件夹中。

将整个inc文件夹复制到工程中,然后复制Config文件夹下的GUIConf.c、GUIConf.h、LCDConf_FlexColor.c和LCDConf_FlexColor.h文件(去掉了文件名中的_Template)。再复制GUI_X.c和STemWin_CM3_wc16.a就可以了。

STemWin库本身是支持ILI9341的,因此移植过程非常简单。

在GUIConf.c中,我们只需要将GUI_NUMBYTES宏的值调小就行了。因为默认的值太大了,单片机根本没有这么多内存可分配,可以改成32768,也就是只分配32KB的内存给STemWin:

//
// Define the available number of bytes available for the GUI
//
#define GUI_NUMBYTES  32768

对于LCDConf_FlexColor.c,我们只需要实现读写液晶屏命令和数据的函数就行了。先包含STM32头文件:

#include <stm32f1xx.h>
#include "../ILI9341.h"

实现命令和数据读写函数:

/********************************************************************
*
*       LcdWriteReg
*
* Function description:
*   Sets display register
*/
static void LcdWriteReg(U16 Data) {// ... TBD by userILI9341_CMD = Data; // 写命令
}/********************************************************************
*
*       LcdWriteData
*
* Function description:
*   Writes a value to a display register
*/
static void LcdWriteData(U16 Data) {// ... TBD by userILI9341_DATA = Data; // 写数据
}/********************************************************************
*
*       LcdWriteDataMultiple
*
* Function description:
*   Writes multiple values to a display register.
*/
static void LcdWriteDataMultiple(U16 * pData, int NumItems) {while (NumItems--) {// ... TBD by userILI9341_DATA = *pData++; // 写多个数据}
}/********************************************************************
*
*       LcdReadDataMultiple
*
* Function description:
*   Reads multiple values from a display register.
*/
static void LcdReadDataMultiple(U16 * pData, int NumItems) {while (NumItems--) {// ... TBD by user*pData++ = ILI9341_DATA; // 读多个数据}
}

其中ILI9341_CMD和ILI9341_DATA是两个FSMC内存地址,是定义在我们的ILI9341.h中的。

#define ILI9341_CMD (*(volatile uint16_t *)0x60000000)
#define ILI9341_DATA (*(volatile uint16_t *)0x60020000)

接下来在LCD_X_Config中,我们需要调用STemWin中内置的ILI9341的驱动程序,把第三个参数改成F66709:

GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B16);
// 根据StemWin手册, 驱动Ilitek ILI9335的屏幕, 第三个参数应该选择66708
// Ilitek ILI9338, ILI9340, ILI9341, ILI9342应该选择66709
// Samsung S6E63D6应该选择66719

可以在STemWin的手册里面看到ILI9341对应的是F66709:

在本程序中,我们不需要颠倒X和Y坐标轴,也不需要翻转Y轴,于是注释掉:

//Config.Orientation = GUI_SWAP_XY | GUI_MIRROR_Y; // 是否交换XY方向

这样的话,X轴就是短边,Y轴就是长边了。

接下来,将STemWin的头文件目录添加到工程属性里面去:

STemWin_CM3_wc16.a的文件类型要修改为Library file:

OK,就这么简单,移植完成了,现在可以编写主程序运行一下试试看了!

注意:调用GUI_Init函数初始化STemWin图形库前必须要在RCC中打开STM32的CRC外设的时钟!!!

很奇怪今天晚上液晶屏触摸突然好了,X坐标和Y坐标都能读了。触控程序没有改过,之前测的时候按下去X坐标(0xd0寄存器)一直是0,Y坐标(0x90寄存器)的范围是2950~3050(从屏幕上方滑到下方)。松开时X和Y都是4095。也就是说只能读Y坐标不能读X坐标。而且,触摸中断一直为高电平,按下屏幕没有任何反应。
今天晚上弄着弄着就X和Y都能读了,触摸中断(PC4低电平)也好使了。感觉很可能是屏幕本身的问题,同样程序在其他屏幕上运行就没有问题,之前偏偏在这块屏幕上有问题。

#include <stdio.h>
#include <stm32f1xx.h>
#include <GUI.h>
#include "common.h"
#include "images.h"
#include "Keyboard.h"
#include "ILI9341.h"
#include "XPT2046.h"// 矩阵键盘按键处理
static void key_handler(int key, void *arg)
{char str[30];GUI_RECT rect;GUI_SetBkColor(GUI_LIGHTBLUE);rect.x0 = 0;rect.y0 = 0;rect.x1 = 239;rect.y1 = 99;GUI_ClearRectEx(&rect);if (key != -1){snprintf(str, sizeof(str), "You pressed KEY%d!", key);GUI_SetColor(GUI_RED);}else{snprintf(str, sizeof(str), "You released the key!");GUI_SetColor(GUI_GREEN);}GUI_DispStringInRectWrap(str, &rect, GUI_TA_HCENTER | GUI_TA_VCENTER, GUI_WRAPMODE_WORD);//GUI_InvertRect(rect.x0, rect.y0, rect.x1, rect.y1); // 反色
}// 截取一部分位图并显示
static void copy_part_of_bitmap(int x, int y, const GUI_BITMAP *bmp, int x0, int y0, int width, int height)
{GUI_RECT rect;rect.x0 = x;rect.y0 = y;rect.x1 = x + width - 1;rect.y1 = y + height - 1;GUI_SetClipRect(&rect);GUI_DrawBitmap(bmp, x - x0, y - y0);GUI_SetClipRect(NULL);
}static void display_images(void)
{GUI_BITMAP bmp;bmp.BitsPerPixel = 16;bmp.BytesPerLine = sizeof(image1[0]);bmp.pData = (const uint8_t *)image1;bmp.pMethods = GUI_DRAW_BMPM565;bmp.pPal = NULL;bmp.XSize = GUI_COUNTOF(image1[0]);bmp.YSize = GUI_COUNTOF(image1);//GUI_DrawBitmap(&bmp, 0, 36); // 显示完整的图片// 截取图片的一部分并显示copy_part_of_bitmap(20, 120, &bmp, 60, 125, 131, 123);//GUI_Delay(1000);copy_part_of_bitmap(180, 120, &bmp, 127, 32, 16, 64);
}// 显示触控坐标
void display_touch(int x, int y)
{char str[30];GUI_RECT rect;GUI_SetBkColor(GUI_LIGHTGREEN);rect.x0 = 0;rect.y0 = 263;rect.x1 = 239;rect.y1 = 319;GUI_ClearRectEx(&rect);snprintf(str, sizeof(str), "(%d,%d)\n", x, y);GUI_SetColor(GUI_ORANGE);GUI_DispStringInRectWrap(str, &rect, GUI_TA_HCENTER | GUI_TA_VCENTER, GUI_WRAPMODE_WORD);
}int main(void)
{int x, y;HAL_Init();clock_init();usart_init(115200);printf("STM32F103VE FSMC ILI9341\n");printf("SystemCoreClock=%u\n", SystemCoreClock);Keyboard_Init();ILI9341_Init();XPT2046_Init();__HAL_RCC_CRC_CLK_ENABLE();GUI_Init();GUI_SetBkColor(GUI_LIGHTRED);GUI_Clear(); // 清屏ILI9341_Enable(1); // 开显示GUI_SetFont(GUI_FONT_32B_1);GUI_SetTextMode(GUI_TM_TRANS); // 绘制文字时无背景颜色display_images();while (1){if (XPT2046_GetITStatus()){XPT2046_ReadPosition(&x, &y);printf("(%d,%d)\n", x, y);display_touch(x, y);}Keyboard_Process(key_handler, NULL);}
}

程序运行效果:

可以发现已经可以正常绘制图片,矩形,以及显示文字了。
但是现在GUI_Delay无法延时,一调用就会陷入死循环。而且GUI_InvertRect函数也无法正常工作,原因是因为我们还没有正确配置好STemWin读取屏幕像素点的功能,凡是需要读取像素点的(例如GUI_DM_XOR方式绘制)函数都无法正常工作。

首先解决GUI_Delay的问题,只需要将GUI_X.c里面GUI_X_GetTime和GUI_X_Delay分别与HAL库中的HAL_GetTick和HAL_Delay函数绑定就可以了:

GUI_TIMER_TIME GUI_X_GetTime(void) { return HAL_GetTick();
}void GUI_X_Delay(int ms) { HAL_Delay(ms);
}

实现读取屏幕像素点需要修改LCD_X_Config函数。查阅手册可知,STemWin自带了三种读取屏幕像素点的方式,一一测试:

GUIDRV_FlexColor_SetReadFunc66709_B16(pDevice, GUIDRV_FLEXCOLOR_READ_FUNC_I);
GUIDRV_FlexColor_SetReadFunc66709_B16(pDevice, GUIDRV_FLEXCOLOR_READ_FUNC_II);
GUIDRV_FlexColor_SetReadFunc66709_B16(pDevice, GUIDRV_FLEXCOLOR_READ_FUNC_III);

发现前两个都不行,第三个会导致HardFault错误,所以用StemWin自带的没有希望了。我们可以自己编写函数来实现读取像素点,然后和STemWin绑定:

LCD_SetDevFunc(0, LCD_DEVFUNC_READPIXEL, (void (*)(void))LcdReadPixel);
LCD_SetDevFunc(0, LCD_DEVFUNC_READMPIXELS, (void (*)(void))LcdReadMPixels);

第一个函数是读单个点,第二个函数是读多个点,函数的实现如下:

static U16 LcdReadPixel(int LayerIndex)
{U16 color;ILI9341_GetPixels(&color, 1);return color;
}static void LcdReadMPixels(int LayerIndex, U16 *pBuffer, U32 NumPixels)
{ILI9341_GetPixels(pBuffer, NumPixels);
}

注意这两个函数都只传入了LayerIndex(图层号)参数,没有传入X坐标和Y坐标,这是因为STemWin已经帮我们设置好了坐标了,我们只需要去读取颜色值就行了:

/* 读取屏幕显示内容 */
void ILI9341_GetPixels(uint16_t *pixels, int count)
{int i = 0;uint16_t data[3];uint16_t rgb565[2];uint32_t rgb888[2];ILI9341_CMD = 0x2e;ILI9341_DATA; // dummy readwhile (i < count){// 读两个像素, 每个像素3字节// 每字节表示一个分量, 分量在字节中是左对齐的data[0] = ILI9341_DATA; // 0xr1g1 (高字节为第一个像素的红色分量, 低字节为第一个像素的绿色分量)data[1] = ILI9341_DATA; // 0xb1r2 (高字节为第一个像素的蓝色分量, 低字节为第二个像素的红色分量)data[2] = ILI9341_DATA; // 0xg2b2 (高字节为第二个像素的绿色分量, 低字节为第二个像素的蓝色分量)// 转换成RGB888rgb888[0] = (data[0] << 8) | (data[1] >> 8);rgb888[1] = ((data[1] & 0xff) << 16) | data[2];//printf("#%06X #%06X => ", rgb888[0], rgb888[1]);// 再转换成RGB565rgb565[0] = ILI9341_RGB888TO565(rgb888[0]);rgb565[1] = ILI9341_RGB888TO565(rgb888[1]);//printf("0x%04x 0x%04x\n", rgb565[0], rgb565[1]);// 保存颜色值pixels[i++] = rgb565[0];if (i < count)pixels[i++] = rgb565[1];}
}

下面附上完整的LCDConf_FlexColor.c的文件内容:

/*********************************************************************
*                SEGGER Microcontroller GmbH & Co. KG                *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 1996 - 2017  SEGGER Microcontroller GmbH & Co. KG       *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
************************************************************************ emWin V5.44 - Graphical user interface for embedded applications **
All  Intellectual Property rights  in the Software belongs to  SEGGER.
emWin is protected by  international copyright laws.  Knowledge of the
source code may not be used to write a similar product.  This file may
only be used in accordance with the following terms:The  software has  been licensed  to STMicroelectronics International
N.V. a Dutch company with a Swiss branch and its headquarters in Plan-
les-Ouates, Geneva, 39 Chemin du Champ des Filles, Switzerland for the
purposes of creating libraries for ARM Cortex-M-based 32-bit microcon_
troller products commercialized by Licensee only, sublicensed and dis_
tributed under the terms and conditions of the End User License Agree_
ment supplied by STMicroelectronics International N.V.
Full source code is available at: www.segger.comWe appreciate your understanding and fairness.
----------------------------------------------------------------------
File        : LCDConf_FlexColor_Template.c
Purpose     : Display controller configuration (single layer)
---------------------------END-OF-HEADER------------------------------
*//********************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2018 STMicroelectronics. * All rights reserved.</center></h2>** This software component is licensed by ST under Ultimate Liberty license SLA0044,* the "License"; You may not use this file except in compliance with the License.* You may obtain a copy of the License at:*                      http://www.st.com/SLA0044********************************************************************************/#include "GUI.h"
#include "GUIDRV_FlexColor.h"#include <stm32f1xx.h>
#include "../ILI9341.h"/*********************************************************************
*
*       Layer configuration (to be modified)
*
**********************************************************************
*///
// Physical display size
//
#define XSIZE_PHYS  240 // To be adapted to x-screen size
#define YSIZE_PHYS  320 // To be adapted to y-screen size/*********************************************************************
*
*       Configuration checking
*
**********************************************************************
*/
#ifndef   VXSIZE_PHYS#define VXSIZE_PHYS XSIZE_PHYS
#endif
#ifndef   VYSIZE_PHYS#define VYSIZE_PHYS YSIZE_PHYS
#endif
#ifndef   XSIZE_PHYS#error Physical X size of display is not defined!
#endif
#ifndef   YSIZE_PHYS#error Physical Y size of display is not defined!
#endif
#ifndef   GUICC_565#error Color conversion not defined!
#endif
#ifndef   GUIDRV_FLEXCOLOR#error No display driver defined!
#endif/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/
/********************************************************************
*
*       LcdWriteReg
*
* Function description:
*   Sets display register
*/
static void LcdWriteReg(U16 Data) {// ... TBD by userILI9341_CMD = Data; // 写命令
}/********************************************************************
*
*       LcdWriteData
*
* Function description:
*   Writes a value to a display register
*/
static void LcdWriteData(U16 Data) {// ... TBD by userILI9341_DATA = Data; // 写数据
}/********************************************************************
*
*       LcdWriteDataMultiple
*
* Function description:
*   Writes multiple values to a display register.
*/
static void LcdWriteDataMultiple(U16 * pData, int NumItems) {while (NumItems--) {// ... TBD by userILI9341_DATA = *pData++; // 写多个数据}
}/********************************************************************
*
*       LcdReadDataMultiple
*
* Function description:
*   Reads multiple values from a display register.
*/
static void LcdReadDataMultiple(U16 * pData, int NumItems) {while (NumItems--) {// ... TBD by user*pData++ = ILI9341_DATA; // 读多个数据}
}static U16 LcdReadPixel(int LayerIndex)
{U16 color;ILI9341_GetPixels(&color, 1);return color;
}static void LcdReadMPixels(int LayerIndex, U16 *pBuffer, U32 NumPixels)
{ILI9341_GetPixels(pBuffer, NumPixels);
}/*********************************************************************
*
*       Public functions
*
**********************************************************************
*/
/*********************************************************************
*
*       LCD_X_Config
*
* Function description:
*   Called during the initialization process in order to set up the
*   display driver configuration.
*
*/
void LCD_X_Config(void) {GUI_DEVICE * pDevice;CONFIG_FLEXCOLOR Config = {0};GUI_PORT_API PortAPI = {0};//// Set display driver and color conversion//pDevice = GUI_DEVICE_CreateAndLink(GUIDRV_FLEXCOLOR, GUICC_565, 0, 0);//// Display driver configuration, required for Lin-driver//LCD_SetSizeEx (0, XSIZE_PHYS , YSIZE_PHYS);LCD_SetVSizeEx(0, VXSIZE_PHYS, VYSIZE_PHYS);//// Orientation////Config.Orientation = GUI_SWAP_XY | GUI_MIRROR_Y; // 是否交换XY方向GUIDRV_FlexColor_Config(pDevice, &Config);//// Set controller and operation mode//PortAPI.pfWrite16_A0  = LcdWriteReg;PortAPI.pfWrite16_A1  = LcdWriteData;PortAPI.pfWriteM16_A1 = LcdWriteDataMultiple;PortAPI.pfReadM16_A1  = LcdReadDataMultiple;GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B16);// 根据StemWin手册, 驱动Ilitek ILI9335的屏幕, 第三个参数应该选择66708// Ilitek ILI9338, ILI9340, ILI9341, ILI9342应该选择66709// Samsung S6E63D6应该选择66719LCD_SetDevFunc(0, LCD_DEVFUNC_READPIXEL, (void (*)(void))LcdReadPixel);LCD_SetDevFunc(0, LCD_DEVFUNC_READMPIXELS, (void (*)(void))LcdReadMPixels);//GUIDRV_FlexColor_SetReadFunc66709_B16(pDevice, GUIDRV_FLEXCOLOR_READ_FUNC_III);
}/*********************************************************************
*
*       LCD_X_DisplayDriver
*
* Function description:
*   This function is called by the display driver for several purposes.
*   To support the according task the routine needs to be adapted to
*   the display controller. Please note that the commands marked with
*   'optional' are not cogently required and should only be adapted if
*   the display controller supports these features.
*
* Parameter:
*   LayerIndex - Index of layer to be configured
*   Cmd        - Please refer to the details in the switch statement below
*   pData      - Pointer to a LCD_X_DATA structure
*
* Return Value:
*   < -1 - Error
*     -1 - Command not handled
*      0 - Ok
*/
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) {int r;(void) LayerIndex;(void) pData;switch (Cmd) {case LCD_X_INITCONTROLLER: {//// Called during the initialization process in order to set up the// display controller and put it into operation. If the display// controller is not initialized by any external routine this needs// to be adapted by the customer...//// ...return 0;}default:r = -1;}return r;
}/*************************** End of file ****************************/

以及4x4矩阵键盘和彩屏排座的电路图:

连续运行了一天触控一直都好使。晚上关机,第二天中午再开,屏幕触控就没有任何反应了,触控中断无信号。通电大概二十分钟过后,触控又好使了(屏幕透明膜之前已经揭下来了),PC4触控中断有反应。看来这个屏幕真的有问题。。。

【STemWin】STM32F103VE单片机用FSMC驱动ILI9341彩色触摸屏(触控芯片XPT2046),并裸机移植STemWin图形库(采用LCDConf_FlexColor.c模板)相关推荐

  1. 【STemWin】STM32F429IG单片机用LTDC驱动正点原子7寸RGB彩色触摸屏,并裸机移植STemWin图形库

    [器件型号] 单片机采用STM32F429IG,运行频率为180MHz,外部晶振HSE的频率为25MHz. 开发板采用外部32MB的SDRAM内存作显存.显示屏分辨率为800×480,颜色格式为RGB ...

  2. 【程序】STM32F407VE单片机通过FSMC驱动Ilitek ILI9325液晶屏以及XPT2046触控芯片

    本程序使用的单片机为STM32F407VE,晶振大小为8MHz,用10厘米长的杜邦线和彩屏相连,彩屏为微雪(Waveshare)的3.2inch 320x240 ILI9325 Touch LCD ( ...

  3. ST7701芯片820*320屏幕移植stemwin

    简要说明 如题,公司最近更换820*320屏幕,移植stemwin,使用3线spi通讯+16RGB,这屏幕工作流程为:首先通过3线spi发送初始化指令,之后通过16bitRGB发送像素点. 移植过程参 ...

  4. 100脚的STM32F103VE单片机通过FSMC接口读写DS12C887时钟芯片中的寄存器

    STM32F1系列的单片机本身自带的RTC实时时钟外设只是一个单纯的32位计数器,没有分立为年月日.小时.分钟.秒等寄存器,使用起来不是很方便.这时可以考虑使用外部RTC芯片,比如使用SPI接口的双向 ...

  5. 联想小新触摸板驱动_如何下载并安装触控板驱动

    操作步骤: 一.Lenovo系列电脑 1.点击这里打开联想官方网站,在示例的位置输入主机编号后,点击"搜索"按钮,查找本机所带的驱动: 2.在操作系统列表中选择对应的操作系统: 3 ...

  6. 五、TDDI 触控、显示驱动一体化技术

    TDDI(触控.显示驱动一体化技术)即触控与显示驱动器集成(Touch and Display Driver Integration ).目前智能手机的触控和显示功能都由两块芯片独立控制,而TDDI最 ...

  7. GC9A01-TFT屏幕驱动(整理有stm32/51单片机/arduino等驱动代码)

    GC9A01-TFT屏幕驱动 & 整理有stm32/51单片机/arduino等驱动代码 前言 关于GC9A01 stm32驱动 引脚接线 代码移植 文件复制 端口修改 显示函数 中文汉字数组 ...

  8. FSMC驱动TFTLCD原理,时序和寄存器介绍

    一,FSMC简介 FSMC:灵活的静态存储控制器 能够与同步或异步存储器和16位PC存储器卡连接 STM32的FSMC接口支持包括SRAM.NAND FLASH.NOR FLASH和PSRAM等存储器 ...

  9. ST7735-TFT屏幕驱动(整理有stm32/51单片机/arduino等驱动代码)

    ST7735-TFT屏幕驱动 & 整理有stm32/51单片机/arduino等驱动代码 前言 关于ST7735 stm32驱动 引脚接线 代码移植 文件复制 端口修改 显示函数 中文汉字数组 ...

最新文章

  1. QuartusII和NiosII,FPGA板之间的关系
  2. 通过JConsole查看本地远程虚拟机
  3. 数学图形之SineSurface与粽子曲面
  4. BaseAdapter的抽取
  5. 深度学习-吴恩达-笔记-1-深度学习引言
  6. [转]MSSQL CURSOR (游标) 笔记
  7. 用servlet编写下载程序
  8. Debug JDK源码没变量值怎么办?
  9. 计算机二级与c语言有什么关系,计算机二级c和c++区别?
  10. java.lang.NoClassDefFoundError: org/springframework/core/metrics/ApplicationStartup
  11. ruby 之watir
  12. 少男杀手dodolook签约酷6网原创红人阵营
  13. index+match函数/一对多查找匹配,可以代替Vlookup函数的使用。
  14. 宁可编译和链接时出错,也不要运行时出错
  15. Tracert与Traceroute[转]
  16. 谷歌浏览器播放h.265_Google删除H.264
  17. inductive bias:归纳偏置
  18. 福布斯:区块链科技从边缘到主流的…
  19. 用C++封装一个简单的英汉词典
  20. (保姆级)利用ffmpeg将flv批量转mp4

热门文章

  1. 学习yade的日常犯错2019.4.7
  2. PCL 库的安装与应用
  3. 视频教程-机器学习数学基础--概率论与数理统计视频教学-机器学习
  4. Linux source 命令的作用
  5. ubuntu 搜狗输入法只能打出繁体字
  6. 让错的程序看得出错(简体中文)(Making Wrong Code Look Wrong)--让错误代码显得错误
  7. 优维科技王津银:SaaS模式是中小企业实现数字化转型的“利器”
  8. 初识机器学习-理论篇
  9. 深度学习+心脏医学图像分割——自动心脏诊断挑战赛(ACDC)项目的代码学习记录
  10. 电脑商情报LUCENE.CN中文搜索CLUB聚会