STM32嵌入式开发教程:触摸屏制作指南
嵌入式开发——制作一个触摸屏
前言
要制作一个STM32触摸屏,需要以下步骤:
-
准备硬件:需要一个STM32微控制器(如STM32F407VGT6),一个触摸屏模块(如ILI9341)和一个LCD显示屏。
-
连接硬件:将触摸屏模块和LCD显示屏连接到STM32微控制器上。通常,触摸屏模块需要5个引脚(CS、RS、WR、RD、RST)连接到STM32的GPIO引脚,而LCD显示屏则需要更多的引脚(如数据、时钟、背光等)。
-
编写代码:使用STM32CubeMX或其他开发工具创建一个新项目,并配置好硬件连接。然后,编写代码来初始化触摸屏和LCD显示屏,并在屏幕上绘制图形或显示文本。
一、触摸屏是什么?
触摸屏是一种人机交互设备,允许用户通过直接触摸屏幕上的图符或文字来向计算机输入指令或信息。触摸屏的功能主要包括:
- 简化操作:触摸屏使得用户能够通过简单的触摸动作进行复杂的操作,提高了使用效率。
- 直观交互:触摸屏提供了直观的人机交互方式,用户可以直接与屏幕上的内容进行互动,增强了用户体验。
- 节省空间:触摸屏整合了输入和输出设备,减少了额外硬件的空间需求。
- 广泛应用:触摸屏在工业控制、医疗、通信、信息查询等多个领域都有广泛的应用。
- 多样类型:触摸屏有多种类型,包括电阻式、电容式、红外线式、声波式等,各有特点和适用场景。
- 耐用设计:现代触摸屏设计坚固耐用,能够承受长时间的使用和各种环境条件。
- 技术发展:触摸屏技术不断发展,如投射式电容屏已成为主流触控技术,提供了更高的精度和多点触控功能。
- 易于维护:触摸屏通常易于清洁和维护,有助于保持设备的长期运行。
此外,在选择触摸屏时,需要考虑的因素包括:
- 应用环境:根据使用环境选择适合的触摸屏类型,如电阻式或电容式。
- 性能要求:考虑所需的精度、反应速度和多点触控支持。
- 耐用性和可靠性:选择适合长时间使用的高耐用性触摸屏。
- 成本预算:根据预算选择性价比高的触摸屏解决方案。
二、源代码
1.基础代码
代码如下(示例):
#include "stm32f4xx_hal.h"
#include "ili9341.h"
SPI_HandleTypeDef hspi5;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI5_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI5_Init();
ILI9341_Init();
ILI9341_FillScreen(ILI9341_BLACK);
ILI9341_DrawString(10, 10, "Hello, World!", ILI9341_WHITE, ILI9341_BLACK, 2);
while (1)
{
}
}
void SystemClock_Config(void)
{
// ...系统时钟配置代码...
}
static void MX_GPIO_Init(void)
{
// ...GPIO初始化代码...
}
static void MX_SPI5_Init(void)
{
// ...SPI5初始化代码...
}
2.主代码
代码如下(示例):
#include "stm32F4xx.h"
#include "stm32f4xx_conf.h"
#include "stdio.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "uart.h"
#include "adc.h"
#include "bsp_lcd.h"
#include "lcd_show_zn.h"
#include "lcd_show_zn_font.h"
#include "bsp_i2c_touch.h"
#include "gt9xx.h"
uint16_t select_index = 0; //表明当前选中哪一个菜单项
uint8_t beep_state = 0; //表示蜂鸣器的开关状态 0表示关闭
uint8_t led_state = 0; //表示LED的开关状态 0表示关闭
#define USER_NEW_METHOD 1 //1表示使用新方法 0 表示使用旧方法
#define USER_KEY_EXIT 1 //1表示按键外部中断 0 表示使用按键轮训检测
#if USER_NEW_METHOD == 1
//mode 0:字体颜色和背景颜色正常显示 1 字体颜色和背景颜色对调
void MyLCD_DisplayStringLine(uint16_t Line, uint8_t *ptr,uint8_t mode)
{
if(mode ==1)
{
//将字体颜色和背景颜色对调
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
//显示文字
LCD_DisplayStringLine(Line,ptr);
//还原字体颜色和背景颜色
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
else if(mode == 0)
{
//显示文字
LCD_DisplayStringLine(Line,ptr);
}
}
#endif
uint8_t press_flag = 0;
//触摸屏被按下时该函数被调用,x,y是按下时的坐标值
void GTP_Press_Event(int32_t x,int32_t y)
{
uint8_t buf[100] = {0};
sprintf((char*)buf,"Press point:%d %d ",x,y); //构造字符串,显示按下时的坐标
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf);
//按键1
if(x>100 && x<300 && y>100 && y<200)
{
LCD_SetColors(LCD_COLOR_YELLOW,LCD_COLOR_BLACK);
LCD_DrawFullRect(100,100,200,100);
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_YELLOW);
LCD_DispString_EN_CH(120,120,"BEEP");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
else
{
// LCD_DrawFullRect(100,100,200,100);
// press_flag = 0;
}
//按键2
if(x>400 && x<600 && y>100 && y<200)
{
LCD_SetColors(LCD_COLOR_RED,LCD_COLOR_BLACK);
LCD_DrawFullRect(400,100,200,100);
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_RED);
LCD_DispString_EN_CH(420,120,"RED");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
else
{
// LCD_DrawFullRect(400,100,200,100);
// press_flag = 0;
}
//按键3
if(x>100 && x<300 && y>300 && y<400)
{
LCD_SetColors(LCD_COLOR_GREEN,LCD_COLOR_BLACK);
LCD_DrawFullRect(100,300,200,100);
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_GREEN);
LCD_DispString_EN_CH(120,320,"GREEN");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
else
{
// LCD_DrawFullRect(400,100,200,100);
// press_flag = 0;
}
//按键4
if(x>400 && x<600 && y>200 && y<300)
{
LCD_SetColors(LCD_COLOR_BLUE,LCD_COLOR_BLACK);
LCD_DrawFullRect(400,300,200,100);
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_BLUE);
LCD_DispString_EN_CH(420,320,"BLUE");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
else
{
// LCD_DrawFullRect(400,100,200,100);
// press_flag = 0;
}
}
//触摸屏松开时该函数被调用,x,y是松开时的坐标值
//按键1
void GTP_Release_Event(int32_t x,int32_t y)
{
uint8_t buf[100] = {0};
sprintf((char*)buf,"Release point:%d %d ",x,y);//构造字符串,显示松开时的坐标
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf);
if(x>100 && x<300 && y>100 && y<200)
{
if(beep_state == 0)
{
GPIO_SetBits(GPIOI,GPIO_Pin_11);
beep_state = 1;
}
else
{
GPIO_ResetBits(GPIOI,GPIO_Pin_11);
beep_state = 0;
}
LCD_DrawFullRect(100,100,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(120,120,"BEEP");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
//按键2
if(x>400 && x<600 && y>100 && y<200)
{
if(led_state == 0) //1表示开灯
{
GPIO_ResetBits(GPIOH,LED_RED);//点亮红灯
led_state = 1;
}
else //其他表示关闭红灯
{
GPIO_SetBits(GPIOH,LED_RED);//关闭红灯
led_state = 0;
}
LCD_DrawFullRect(400,100,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(420,120,"RED");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
//按键3
if(x>100 && x<300 && y>300 && y<400)
{
if(led_state == 0) //1表示开灯
{
GPIO_ResetBits(GPIOH,LED_GREEN);//点亮红灯
led_state = 1;
}
else //其他表示关闭红灯
{
GPIO_SetBits(GPIOH,LED_GREEN);//关闭红灯
led_state = 0;
}
LCD_DrawFullRect(100,300,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(120,320,"GREEN");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
//按键4
if(x>400 && x<600 && y>300 && y<400)
{
if(led_state == 0) //1表示开灯
{
GPIO_ResetBits(GPIOH,LED_BLUE);//点亮红灯
led_state = 1;
}
else //其他表示关闭红灯
{
GPIO_SetBits(GPIOH,LED_BLUE);//关闭红灯
led_state = 0;
}
LCD_DrawFullRect(400,300,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(420,320,"BLUE");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
}
}
int main(void)
{
GPIO_InitTypeDef gpio_info;
Delay_init();
UART_init(115200);
Adc_init();
key1_init();
key2_init();
LED_init();
//屏幕初始化
LCD_Init();
//屏幕显示层初始化
LCD_LayerInit();
//LTCD外设初始化
LTDC_Cmd(ENABLE);
//PI11 蜂鸣器
//初始化GPIO-I时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE);
gpio_info.GPIO_Mode = GPIO_Mode_OUT;
gpio_info.GPIO_OType = GPIO_OType_PP;
gpio_info.GPIO_Pin = GPIO_Pin_11;
gpio_info.GPIO_PuPd = GPIO_PuPd_UP;
gpio_info.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(GPIOI,&gpio_info);
//初始化GPIOH时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,ENABLE);
gpio_info.GPIO_Mode = GPIO_Mode_OUT;
gpio_info.GPIO_OType = GPIO_OType_PP;
gpio_info.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
gpio_info.GPIO_PuPd = GPIO_PuPd_UP;
gpio_info.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(GPIOH,&gpio_info);
GPIO_SetBits(GPIOH,LED_RED);
GPIO_SetBits(GPIOH,LED_GREEN);
GPIO_SetBits(GPIOH,LED_BLUE);
/*把背景层刷黑色*/
//选定控制背景层
LCD_SetLayer(LCD_BACKGROUND_LAYER);
//清除屏幕并用黑色填充
LCD_Clear(LCD_COLOR_BLACK);
/*初始化后默认使用前景层*/
LCD_SetLayer(LCD_FOREGROUND_LAYER);
/*默认设置不透明 ,该函数参数为不透明度,范围 0-0xff ,0为全透明,0xff为不透明*/
LCD_SetTransparency(0xFF);
//清除屏幕并用黑色填充
LCD_Clear(LCD_COLOR_BLACK);
/*设置字体颜色及字体的背景颜色(此处的背景不是指LCD的背景层!注意区分)*/
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
/*选择字体*/
LCD_SetFont(&Font16x24);
LCD_SetZNFont(&ZN_Font24x24);
GTP_Init_Panel(); //触摸屏初始化
LCD_DrawFullRect(100,100,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(120,120,"BEEP");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_DrawFullRect(400,100,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(420,120,"RED");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_DrawFullRect(100,200,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(120,220,"GREEN");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
LCD_DrawFullRect(400,200,200,100);
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
LCD_DispString_EN_CH(420,220,"BLUE");
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK);
while(1)
{
}
}
代码需要模块化分区,方便查看且美观整洁(如下图)
三、项目总结
总的来说,触摸屏是一种重要的人机交互界面,它通过简化操作、提供直观交互和节省空间等优点,极大地改善了用户的体验和效率。它的多样化类型和技术发展使其能够适应不同的应用场景和需求。在选择触摸屏时,应综合考虑应用环境、性能要求、耐用性、可靠性和成本预算等因素。
STM32制作触摸屏涉及硬件选择、接口配置、软件编程和功能实现等多个方面。下面将从几个方面详细介绍STM32制作触摸屏的过程:
- 硬件选择:电阻式触摸屏通过压力感应进行触点检测,需要直接应力接触,通过检测电阻来定位触摸位置。它的精度较高且成本较低,但容易被划伤且不支持多点触摸。电容式触摸屏利用人体感应进行触点检测控制,支持轻微接触甚至非接触操作,通过检测感应电流来定位触摸坐标。它提供了更好的手感体验和透光性,支持多点触摸,但成本较高且抗干扰能力较弱。
- 接口配置:STM32微控制器需要与触摸屏模块连接,常用的接口有SPI和I2C。例如,使用XPT2046作为电阻触摸屏的控制芯片时,会涉及到CS(片选)、DOUT(数据输出)、TDIN(数据输入)、TCLK(时钟信号)和IRQ(中断请求)等引脚的配置。
- 软件编程:在软件开发方面,可以使用Keil等IDE编写代码,利用HAL库简化外设的初始化和配置过程。对于电阻式触摸屏,需要处理AD转换结果以获取触点坐标;而对于电容式触摸屏,则要处理电容变化数据来确定触摸位置。在编程过程中,还需考虑触摸屏的校准、滤波处理以及与用户界面的交互逻辑。
- 功能实现:STM32制作的触摸屏可以应用于多种场合,如工业控制系统的人机界面、医疗设备的操作面板、消费电子产品的控制面板等。根据不同的应用场景,可以设计相应的用户界面和交互功能,如按钮、滑块、绘图板等。
此外,在选择触摸屏类型时,需要考虑应用环境、性能要求、耐用性和成本预算。例如,在户外或工业环境中,可能更倾向于使用电阻式触摸屏,因为它的稳定性和抗干扰能力更强;而在消费电子产品中,电容式触摸屏则因其良好的用户体验和美观性更受欢迎。
综上所述,STM32制作触摸屏是一个涉及硬件选择、接口配置、软件编程和功能实现的综合工程。通过对电阻式和电容式触摸屏的原理和特性的了解,结合实际应用场景的需求,可以设计并实现高效、稳定且用户友好的触摸屏系统。
作者:Amber-z