用户工具

站点工具


icore4t_62

这是本文档旧的修订版!


银杏科技有限公司旗下技术文档发布平台
技术支持电话0379-69926675-801
技术支持邮件Gingko@vip.163.com
技术论坛http://www.eeschool.org
版本 日期 作者 修改内容
V1.0 2020-11-09 gingko 初次建立









STM32CubeMX教程六十二——TOUCH实验

1.在主界面选择File–>New Project 或者直接点击ACCEE TO MCU SELECTOR 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置 在搜索栏的下面,提供的各种查找方式,可以选择芯片内核、型号等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 3.配置RCC,使用外部时钟源 4.时基源选择SysTick 5.将PA10,PB7,PB8,PI1,PI2,PI3设置为GPIO_Output 6.引脚模式配置 7.配置定时器 定时器分配引脚如下所示 8.配置FMC 9.配置SDMMC 10.配置LTDC 11.配置CRC 12.配置FATFS 13.时钟源设置,选择外部高速时钟源,配置为最大主频。 14.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK V5.27 15.点击Code Generator,进行进一步配置

  • Copy all used libraries into the project folder
  • 将HAL库的所有.C和.H都复制到所建工程中
    • 优点:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便
    • 缺点:体积大,编译时间很长
  • Copy only the necessary library files
  • 只复制所需要的.C和.H(推荐)
    • 优点:体积相对小,编译时间短,并且工程可复制拷贝
    • 缺点:新增外设时需要重新用STM32CubeMX导入
  • Add necessary library files as reference in the toolchain project configuration file
  • 不复制文件,直接从软件包存放位置导入.C和.H
    • 优点:体积小,比较节约硬盘空间
    • 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径
  • 自行选择方式即可

16.然后点击GENERATE CODE 创建工程

创建成功,打开工程。


实验六十二:TOUCH实验——电阻触摸

一、 实验目的与意义

  1. 了解STM32 LTDC结构
  2. 了解STM32 LTDC特征
  3. 掌握LTDC液晶屏的使用方法
  4. 掌握LTDC应用之LCD电容触摸芯片NS2009的使用方法
  5. 掌握KEIL MDK 集成开发环境使用方法

二、 实验设备及平台

  1. iCore4T 双核心板
  2. 转接板和40P的FPC连接线。
  3. iCore4T 扩展底板
  4. iCore 4.3寸液晶屏底板
  5. Blaster(或相同功能)仿真器
  6. Micro USB线缆
  7. Keil MDK 开发平台
  8. STM32CubeMX开发平台
  9. 装有WIN XP(及更高版本)系统的计算机

三、 实验原理

电阻式触摸屏检测原理

  • 电阻式的触摸屏结构见下图。它主要由表面硬涂层、两个ITO层、间隔点以及玻璃底层构成,这些结构层都是透明的,整个触摸屏覆盖在液晶面板上,透过触摸屏可看到液晶面板。表面涂层起到保护作用,玻璃底层起承载的作用,而两个ITO层是触摸屏的关键结构,它们是涂有铟锡金属氧化物的导电层。两个ITO层之间使用间隔点使两层分开,当触摸屏表面受到压力时,表面弯曲使得上层ITO与下层ITO接触,在触点处连通电路。

  • 两个ITO涂层的两端分别引出X-、X+、Y-、Y+四个电极,见下图,这是电阻屏最常见的四线结构,通过这些电极,外部电路向这两个涂层可以施加匀强电场或检测电压。

  • 当触摸屏被按下时,两个ITO层相互接触,从触点处把ITO层分为两个电阻,且由于ITO层均匀导电,两个电阻的大小与触点离两电极的距离成比例关系,利用这个特性,可通过以下过程来检测坐标,这也正是电阻触摸屏名称的由来,如下图。

  1. 计算X坐标时,在X+电极施加驱动电压Vref,X-极接地,所以X+与X-处形成了匀强电场,而触点处的电压通过Y+电极采集得到,由于ITO层均匀导电,触点电压与Vref之比等于触点X坐标与屏宽度之比,从而:

  1. 算Y坐标时,在Y+电极施加驱动电压Vref,Y-极接地,所以Y+与Y-处形成了匀强电场,而触点处的电压通过X+电极采集得到,由于ITO层均匀导电,触点电压与Vref之比等于触点Y坐标与屏高度之比,从而:

  • 为了方便检测触摸的坐标,一些芯片厂商制作了电阻屏专用的控制芯片,控制上述采集过程、采集电压,外部微控制器直接与触摸控制芯片通讯直接获得触点的电压或坐标。

在本实验中,选用电阻触摸芯片NS2009来实现电阻触摸功能。以下为NS2009基础知识。

  • 1.电阻触摸芯片NS2009基本原理
  • NS2009是一种典型的逐次逼近型ADC(SAR ADC),包含采样/保持,模数转换,I2C数据输出功能。单电源供电,电源电压范围为2.0V~5.5V。通过控制寄存器的模拟输入(X,Y,Z)进入ADC,作为触摸屏应用,应将其配置为差分模式,以有效消除驱动器开关的寄生电阻和测量误差引起的外部干扰,并改善转换精度。
  • 2.模拟输入特性
  • MUX,ADC的模拟输入以及I2C接口电路如下图所示。

  • 控制字节顺序位C3,C2,C1,C0以及NS2009之间的配置关系如下表所示:

  • 3.差分模式
  • 当命令控制位C3为高电平时,NS2009处于X,Y,Z的测量模式,内部ADC参考电压源为差分模式,如下图所示。差分模式的优势:+REF和-REF直接输入YP,YN,可以消除由于开关导通电阻引起的测量误差。缺点是:无论是充裕的还是转换过程,驱动器都需要开启,相对于单端模式,功耗增加了。

  • 4.压力测量
  • NS2009可以测量触摸的压力,即Z方向的测量。通常,此类测量的性能要求不高,因此可以使用8位分辨率模式(但是,下面的计算是采用12位分辨率模式的)即可。有几种不同的方法可以实现压力测量。
  • 第一种方法需要知道X面板的电阻,X的测量位置,触摸屏面板在两个附加面板之间的测量值(Z1和Z2)。可以使用下列公式计算触摸电阻:

  • 第二种方法需要检测X和Y面板的面板电阻,X和Y位置以及Z1位置。可以使用下列公式计算触摸电阻:

  • 5.数字接口
  • 6.高速模式
  • 7.数据格式

  • 8.PENIRQ中断输出功能
  • PENIRQ可以通过PD0设置,PEN中断输出功能如下图所示。

当PD0=0时,YN驱动打开,Y触摸屏面板连接到GND。PENIRQ 输出通过两个开关连接到XP。在待机模式下,当有触摸屏操作时,XP输入通过触摸屏下拉至GND,PENIRQ输出为低电平。当没有运动的触摸屏断开至GND时,PENIRQ为高输出。在X,Y和Z的测量过程中,PENIRQ输出为低电平;

  • PD0 = 1,禁止了PEN中断功能,无法监视触摸屏上的触摸运动。如果要重新启用中断功能PEN,需要控制PD0 = 0写入NS2009,如果最后一个控制字包含PD0 = 0,则该命令完成后将使能PEN中断输出。
  • 为避免误触发,建议处理器向NS2009发送命令时,屏蔽掉PENIRQ的中断。

2.电阻触摸、电容触摸相关知识

  • 有了TFT裸屏后还要配套电阻触摸板或者电容触摸板才可以获取触摸信息。触摸板是贴到TFT屏上面的,然后再通过电阻触摸芯片就可以获取电阻触摸板的信息,通过电容触摸芯片采集电容触摸板的信息。目前市面上常用的电阻触摸IC是STMPE811,电容触摸IC是GT811、GT911和FT5X06。其中,电阻触摸和电容触摸两者的区别如下:
  • 电阻触摸芯片STMPE811其实就是ADC,返回的是ADC数值,而电容触摸芯片GT811、GT911和FT5X06返回的是显示屏实际的坐标值。
  • 使用电阻触摸芯片STMPE811需要做触摸校准,而使用电容触摸芯片GT811、GT911和FT5X06是自动校准的,无需手动校准。

3.电容触摸芯片GT911介绍

  • 在本实验中,选用电容触摸芯片GT911来实现电容触摸功能。
  • 电容触摸相比电阻触摸简单,因为电容触摸不需要做触摸校准,而且用的是触摸板和触摸芯片一体的,也不需要做寄存器初始化配置,上电后直接读取参数即可。
  • GT911、GT928、GT9147都属于GT9系列非单层多点触控芯片,他们支持的触控点数不同(GT928支持10个点、GT911支持5个点)、驱动和感应通道也可能不同。可是他们的寄存器和IIC通讯时序是相同的,也就是说驱动程序是兼容的。
  • GT911是专为7”~8”设计的新一代5点电容触控方案,拥有26个驱动通道和14个感应通道,以满足更高的touch精度要求。GT911可同时识别5个触摸点位的实时准确位置,移动轨迹及触摸面积。并可根据主控需要,读取相应点数的触摸信息。
  • 与主机的接口共有6PIN,分别为:VDD、GND、SCL、SDA、INT、RESET。
    • INT、RESET不需要接上下拉电阻,可与主机直连。
    • SCL、SDA需要接上拉电阻4.7K,毕竟400KHz的通信频率,没有上拉可能导致SCL、SDA边沿不够陡峭。
    • RST是复位引脚,拉低100us以上,即可复位。正常工作时,应该保持拉高。
    • INT是GT9xx的触摸信号输出引脚,在正常工作时,主机端要设置为悬浮输入,即不上下拉(GT9xx的驱动能力有限,如果外部上下拉,GT9xx可能驱动不了)。当有触摸发生时,INT引脚会输出上升沿或下降沿(内部寄存器可以配置),主机端可以一直读取INT脚的电平信号,也可以用端口外部中断检测。

4.电容触摸芯片GT911的I2C通讯

  • GT911提供标准的I2C通讯接口,由SCL和SDA与主CPU进行通讯。在系统中GT911始终作为从设备,所有通讯都是由主CPU发起,建议通讯速度为400Kbps或以下。其支持的I2C硬件电路支持时序如下:

  • GT911的I2C从设备地址有两组,分别为0xBA/0xBB和0x28/0x29。主控在上电初始化时控制Reset和INT口状态进行设定,设定方法及时序图如下:
  • 上电时序图:

  • 1)数据传输(以设备地址为0xBA/0xBB为例)
  • 通讯总是由主 CPU 发起,有效的起始信号为:在 SCL 保持为“1”时,SDA 上发生由“1”到“0”的跳变。地址信息或数据流均在起始信号之后传输。
  • 所有连接在I2C总线上的从设备,都要检测总线上起始信号之后所发送的8位地址信息,
  • 并做出正确反应。在收到与自己相匹配的地址信息时,GT911在第9个时钟周期,将SDA改为输出口,并置“0”,作为应答信号。若收到不与自己匹配的地址信息,即非0XBA或0XBB,GT911将保持闲置状态。
  • SDA口上的数据按9个时钟周期串行发送9位数据:8位有效数据+1位接收方发送的应答信号ACK或非应答信号NACK。数据传输在SCL为“1”时有效。
  • 当通讯完成时,由主CPU发送停止信号。停止信号是当SCL为“1”时,SDA状态由“0”到“1”的跳变。
  • 2)对GT911写操作(以设备地址为0xBA/0xBB为例)

  • 上图为主CPU对GT911进行的写操作流程图。首先主CPU产生一个起始信号,然后发送地址信息及读写位信息“0”表示写操作:0XBA。在收到应答后,主CPU发送寄存器的16位地址,随后是8位要写入到寄存器的数据内容GT911寄存器的地址指针会在写操作后自动加1,所以当主CPU需要对连续地址的寄存器进行写操作时,可以在一次写操作中连续写入。写操作完成,主CPU发送停止信号结束当前写操作。
  • 3)对GT911读操作(以设备地址为0xBA/0xBB为例)

  • 上图为主CPU对GT911进行的读操作流程图。首先主CPU产生一个起始信号,然后发送设备地址信息及读写位信息“0”表示写操作:0XBA。在收到应答后,主CPU发送首寄存器的16位地址信息,设置要读取的寄存器地址。在收到应答后,主CPU重新发送一次起始信号,发送读操作:0XBB。收到应答后,主CPU开始读取数据。
  • GT911同样支持连续的读操作,默认为连续读取数据。主CPU在每收到一个Byte数据后需发送一个应答信号表示成功接收。在接收到所需的最后一个Byte数据后,主CPU发送“非应答信号NACK”,然后再发送停止信号结束通讯。

5.电容触摸芯片GT911功能描述

  • (一)工作模式

  • a)Normal Mode
  • GT911在Normal Mode时,最快的坐标刷新周期为7ms-10ms间(依赖于配置信息的设定,配置信息可控周期步进长度为1ms)。
  • Normal mode状态下,一段时间无触摸事件发生,GT911将自动转入Green mode,以降低功耗。GT911无触摸自动进入Green mode的时间可通过配置信息设置,范围为0~15s,步进为1s。
  • b)Green Mode
  • 在Green mode下,GT911扫描周期约为40ms,若检测到有触摸动作发生,自动进入Normal mode。
  • c)Sleep Mode
  • 主CPU通过I2C命令,使GT911进入Sleep mode(需要先将INT脚输出低电平)。当需要GT911退出Sleep mode时,主机输出一个高电平到INT脚(主机打高INT脚2~5ms),唤醒后GT911将进入Normal mode。

  • (二)中断触发方式
  • 当有触摸时,GT911 每个扫描周期均会通过 INT 脚发出脉冲信号,通知主 CPU 读取坐标信息。主CPU可以通过相关的寄存器位“INT”来设置触发方式。设为“0”表示上升沿触发,即在有用户操作时,GT911会在INT口输出上升沿跳变,通知 CPU;设为“1”表示下降沿触发,即在有用户操作时,GT911会在INT口输出下降沿跳变。

四、 实验程序

1.主函数

int main(void)
{
    FATFS fatfs;
    HAL_Init();
    SystemClock_Config();
    i2c.initialize();
    axp152.initialize();
    axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER]
    axp152.set_dcdc2(1200);//[FPGA INT & PLL D]
    axp152.set_aldo1(2500);//[FPGA PLL A]
    axp152.set_dcdc4(3300);//[POWER_OUTPUT]
    axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable]
    axp152.set_aldo2(3300);//[FPGA BK3][Adjustable]
    axp152.set_dldo1(3300);//[FPGA BK7][Adjustable]
    axp152.set_dldo2(3300);//[FPGA BK5][Adjustable]
    MX_GPIO_Init();
    MX_CRC_Init();
    MX_LTDC_Init();
    MX_TIM12_Init();
    MX_SDMMC1_SD_Init();
    MX_FATFS_Init();
    MX_FMC_Init();	
    BSP_SDRAM_Init();
    lcd.initialize();
 
    GUI_Init();
    GUI_SetBkColor(GUI_BLACK);
    GUI_Clear();
    HAL_TIM_PWM_Start(&htim12,TIM_CHANNEL_1); 
    touch_type = gt911.initialize();//判断是否为电容触摸
    if(touch_type != TOUCH_CAP){
        touch_type = TOUCH_RES;
    }
    res = f_mount(&fatfs,"0:",1);
    if(res != RES_OK){
        GUI_SetColor(GUI_RED);
        GUI_SetFont(&GUI_FontFixedsys16);
        GUI_DispStringHCenterAt("f_mount Error!",480/2,272/2);		
        while(1){
        }
    }
    GUI_SetColor(GUI_BLUE);
    if(touch_type == TOUCH_RES){
	power_on.check_touch();
    }
    GUI_CURSOR_Show();
    frame.process();                  //界面处理
    LCD_ON;

2.进行GUI界面处理

static void frame_process(void)
{
	GUI_CURSOR_Show();
	WM_SetCreateFlags(WM_CF_MEMDEV);
        GUI_CreateDialogBox(_aDialogCreate,GUI_COUNTOF(_aDialogCreate), _cbDialog, WM_HBKWIN, 0, 0);
	while(1){
		if(systick._20ms_flag == 1){
			systick._20ms_flag = 0;
			if(touch_type == TOUCH_RES){
				ns2009.convert_pos();
			}else if(touch_type == TOUCH_CAP){
				gt911.scan(1);
			}
		}
		if(touch_flag == 1){
			touch_flag = 0;
			if(touch_type == TOUCH_RES){
				EDIT_SetValue(h_edit_0,pen.x0);
				EDIT_SetValue(h_edit_1,pen.y0);			
			}else{
				EDIT_SetValue(h_edit_0,gt911.x[0]);
				EDIT_SetValue(h_edit_1,gt911.y[0]);				
			}
		}
		GUI_Exec();
	}
}

3.convert_pos函数实现坐标变换

static int convert_pos(void)  //坐标变换
{
	int i;
	i = readxy(&pen.X,&pen.Y);
	if(i == 2) return 2;
	else if(i == 1){
		pen.x0 = 0;
		pen.y0 = 0;			
		return 1;
	}
	pen.x0 = (int)(rgb_cal.a[0] + ((rgb_cal.a[1] * pen.X +	rgb_cal.a[2]*pen.Y)/rgb_cal.a[6]));
	pen.y0 = (int)(rgb_cal.a[3] + ((rgb_cal.a[4] * pen.X +rgb_cal.a[5]*pen.Y)/rgb_cal.a[6]));
	if(pen.x0 > 0 && pen.x0 < 100 && pen.y0 > 240 && pen.y0 < 272){
		pen.x0 = 479;
		pen.y0 = 271;
	}return 0;

4.校正电阻屏系数

static int touch_adjust(void)
{
	int i;
	char  buf[100];
	do{
		GUI_SetBkColor(GUI_WHITE);
		GUI_Clear();
		get_sample(&rgb_cal,0,40,40);
		get_sample(&rgb_cal,1,RGB_XSIZE - 40,40);
		get_sample(&rgb_cal,2,RGB_XSIZE - 40,RGB_YSIZE - 40);
		get_sample(&rgb_cal,3,40,RGB_YSIZE - 40);		
		get_sample(&rgb_cal,4,RGB_XSIZE / 2,RGB_YSIZE / 2);
	}while(perform_calibration(&rgb_cal));
	for(i = 0; i < 7; i ++){
		sprintf(buf,"a[%d] : %d   \r\n",i,rgb_cal.a[i]);
		GUI_DispStringAt(buf,200,70 + 20 * i);
	}
	GUI_DispStringAt("calibration success",200,70 + 20 * i);
	for(i = 0; i < 30000000; i ++);
	GUI_Clear();
	return 0;
}

5.NS2009读XY坐标

static int   readxy(int *x, int *y) //读XY坐标
{
	int a[MAX_CNT_DATA],b[MAX_CNT_DATA];
	int i = 0,j = 0;
	unsigned short int datx[3];
	unsigned short int daty[3];
	unsigned short int temp_x,temp_y;
	unsigned int cnt = 0;
	*x = 0;
	*y = 0;
	memset(a,0,MAX_CNT_DATA);
	memset(b,0,MAX_CNT_DATA);
	for(i = 0; i < MAX_CNT_DATA; i ++){
			read_ads(&a[cnt],&b[cnt]);
			cnt ++;
			for(j = 0; j < 2100; j ++);
	}
	if(cnt < MAX_CNT_DATA - 5)return 3;
	qsort (a,MAX_CNT_DATA,sizeof(a[0]),acmp);	//快速排序,就是中值滤波
	qsort (b,MAX_CNT_DATA,sizeof(b[0]),acmp);
 
	datx[0] = a[MAX_CNT_DATA / 2 - 1];
	datx[1] = a[MAX_CNT_DATA / 2];
	datx[2] = a[MAX_CNT_DATA / 2 + 1];
 
	daty[0] = b[MAX_CNT_DATA / 2 - 1];
	daty[1] = b[MAX_CNT_DATA / 2];
	daty[2] = b[MAX_CNT_DATA / 2 + 1];
 
	if(
		abs(datx[0] - datx[1]) > 20 || 
		abs(datx[1] - datx[2]) > 20 ||
		abs(daty[0] - daty[1]) > 20 ||
		abs(daty[1] - daty[2]) > 20
		)return 2;
 	temp_x = (datx[0] + datx[1] + datx[2]) / 3;
 	temp_y = (daty[0] + daty[1] + daty[2]) / 3;
 
	*x = temp_x;
	*y = temp_y;
	return 0;
}

6.perform_calibration函数:使用五点校正法完成电阻触摸屏的校准

static int  perform_calibration(TOUCH_CALIBRATION_T *cal)
{
	int j;
	double n, x, y, x2, y2, xy, z, zx, zy;
	double det, a, b, c, e, f, i;
	float scaling = 32768.0;
// Get sums for matrix
	n = x = y = x2 = y2 = xy = 0;
	for(j = 0;j < 5;j++) {
		n += 1.0;
		x += (float)cal->x[j];
		y += (float)cal->y[j];
		x2 += (float)(cal->x[j]*cal->x[j]);
		y2 += (float)(cal->y[j]*cal->y[j]);
		xy += (float)(cal->x[j]*cal->y[j]);
	}
// Get determinant of matrix -- check if determinant is too small
	det = n*(x2*y2 - xy*xy) + x*(xy*y - x*y2) + y*(x*xy - y*x2);
	if(det < 0.1 && det > -0.1) {
		return 1;
	}
// Get elements of inverse matrix
	a = (x2*y2 - xy*xy)/det;
	b = (xy*y - x*y2)/det;
	c = (x*xy - y*x2)/det;
	e = (n*y2 - y*y)/det;
	f = (x*y - n*xy)/det;
	i = (n*x2 - x*x)/det;
// Get sums for x calibration
	z = zx = zy = 0;
	for(j=0;j<5;j++) {
		z += (float)cal->xfb[j];
		zx += (float)(cal->xfb[j]*cal->x[j]);
		zy += (float)(cal->xfb[j]*cal->y[j]);
	}
// Now multiply out to get the calibration for framebuffer x coord
	cal->a[0] = (int)(a*z + b*zx + c*zy);
	cal->a[1] = (int)((b*z + e*zx + f*zy)*(scaling));
	cal->a[2] = (int)((c*z + f*zx + i*zy)*(scaling));
// Get sums for y calibration
	z = zx = zy = 0;
	for(j=0;j<5;j++) {
z += (float)cal->yfb[j];
		zx += (float)(cal->yfb[j]*cal->x[j]);
		zy += (float)(cal->yfb[j]*cal->y[j]);
	}
// Now multiply out to get the calibration for framebuffer y coord
	cal->a[3] = (int)(a*z + b*zx + c*zy);
	cal->a[4] = (int)((b*z + e*zx + f*zy)*(scaling));
	cal->a[5] = (int)((c*z + f*zx + i*zy)*(scaling));
// If we got here, we're OK, so assign scaling to a[6] and return
	cal->a[6] = (int)scaling;
 
	for(j = 0; j < 5; j ++){
		x = 	cal->a[0] +
				((cal->a[1]*cal->x[j] + 
				cal->a[2]*cal->y[j] ) / cal->a[6]);		
		y = 	cal->a[3] +
				((cal->a[4]*cal->x[j] + 
				cal->a[5]*cal->y[j] ) / cal->a[6]);	
		if((fabs(x - cal->xfb[j]) > 10) || (fabs(y - cal->yfb[j]) > 10))
			return 1;
	}
	return 0;
}

五、 实验步骤

  1. 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连);
  2. 把iCore4T通过Micro USB线与计算机相连,为iCore4T供电;
  3. 将屏幕连接到4.3寸液晶屏底板上,并将液晶屏底板与iCore4T底板通过排线相连。
  4. 打开Keil MDK 开发环境,并打开本实验工程;
  5. 烧写程序到iCore4T上;
  6. 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。

六、 实验现象

触摸iCore4T(4.3寸TFT_LCD)电阻屏屏即显示当前触摸位置的坐标值。

icore4t_62.1604905130.txt.gz · 最后更改: 2020/11/09 14:58 由 fmj