GD32入门到实战41--触摸屏

发布于:2025-09-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

我们板子用的时电容式触摸屏

我们用的触摸芯片是GT911(I2C)

INT:触摸时会产生中断,初始化时配置设备地址

我们配置的设备地址为0x28/0x29

一定一定要注意读取触摸芯片的周期不要大于10ms!!!!

可以检测按下的坐标,按下的面积

下面我们用软件模拟I2C的方式驱动触摸芯片

touch_drv.c

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "gd32f30x.h"
#include "delay.h"
#include "touch_drv.h"
#include "systick.h"

#define GET_I2C_SDA()             gpio_input_bit_get(GPIOF, GPIO_PIN_9)    // 读取SDA端口
#define SET_I2C_SCL()             gpio_bit_set(GPIOF, GPIO_PIN_10)          // 时钟线SCL输出高电平
#define CLR_I2C_SCL()             gpio_bit_reset(GPIOF, GPIO_PIN_10)        // 时钟线SCL输出低电平
#define SET_I2C_SDA()             gpio_bit_set(GPIOF, GPIO_PIN_9)          // 数据线SDA输出高电平
#define CLR_I2C_SDA()             gpio_bit_reset(GPIOF, GPIO_PIN_9)        // 数据线SDA输出低电平

static void GpioInit(void)
{
	rcu_periph_clock_enable(RCU_GPIOF);
    gpio_init(GPIOF, GPIO_MODE_OUT_OD, GPIO_OSPEED_10MHZ, GPIO_PIN_9 | GPIO_PIN_10);  // SDA SCL
	
	rcu_periph_clock_enable(RCU_GPIOB);
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);  // RST
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_12); // INT
}


/**
*******************************************************************
* @function 产生IIC起始时序,准备发送或接收数据前必须由起始序列开始 
* @param
* @return 
* @brief    SCL为高电平时,SDA由高电平向低电平跳变,开始传输数据 
*           生成下图所示的波形图,即为起始时序 
*                1 2    3     4   
*                    __________     
*           SCL : __/          \_____ 
*                 ________          
*           SDA :         \___________ 
*******************************************************************
*/
static void I2CStart(void)
{
	SET_I2C_SDA();          // 1#数据线SDA输出高电平
	SET_I2C_SCL();          // 2#时钟线SCL输出高电平   
	DelayNus(4);            // 延时4us
	CLR_I2C_SDA();          // 3#数据线SDA输出低电平 
	DelayNus(4);            // 延时4us
	CLR_I2C_SCL();          // 4#时钟线SCL输出低电平,保持I2C的时钟线SCL为低电平,准备发送或接收数据 
	DelayNus(4);            // 延时4us
}

/**
*******************************************************************
* @function 产生IIC停止时序  
* @param
* @return 
* @brief    SCL为高电平时,SDA由低电平向高电平跳变,结束传输数据 
*          生成下图所示的波形图,即为停止时序 
*                1 2   3  4   
*                       _______________     
*          SCL : ______/          
*                __        ____________  
*          SDA:    \______/
*******************************************************************
*/
static void I2CStop(void)
{
	CLR_I2C_SDA();          //2#数据线SDA输出低电平
	DelayNus(4);            //延时4us
	SET_I2C_SCL();          //3#时钟线SCL输出高电平
	DelayNus(4);  
	SET_I2C_SDA();          //4#数据线SDA输出高电平,发送I2C总线结束信号
}

/**
*******************************************************************
* @function 发送一字节,数据从高位开始发送出去
* @param    byte
* @return 
* @brief    下面是具体的时序图 
*                1 2     3      4
*                         ______
*           SCL: ________/      \______    
*                ______________________    
*           SDA: \\\___________________
*******************************************************************
*/
static void I2CSendByte(uint8_t byte)
{                          
	for (uint8_t i = 0; i < 8; i++)   // 循环8次,从高到低取出字节的8个位
	{     
		if ((byte & 0x80))            // 2#取出字节最高位,并判断为‘0’还是‘1’,从而做出相应的操作
		{
			SET_I2C_SDA();            // 数据线SDA输出高电平,数据位为‘1’
		}
		else
		{  
			CLR_I2C_SDA();      	  // 数据线SDA输出低电平,数据位为‘0’
		}
		
		byte <<= 1;            		  // 左移一位,次高位移到最高位
		
		DelayNus(4);          		  // 延时4us
		SET_I2C_SCL();                // 3#时钟线SCL输出高电平
		DelayNus(4);          		  // 延时4us
		CLR_I2C_SCL();        		  // 4#时钟线SCL输出低电平
		DelayNus(4);                  // 延时4us  
	}  
}

/**
*******************************************************************
* @function 读取一字节数据
* @param    
* @return   读取的字节
* @brief    下面是具体的时序图
*                       ______
*           SCL: ______/      \___        
*                ____________________    
*           SDA: \\\\______________\\\
*******************************************************************
*/
static uint8_t I2CReadByte(void)
{
	uint8_t byte = 0;           		// byte用来存放接收的数据
	SET_I2C_SDA();                      // 释放SDA
	for (uint8_t i = 0; i < 8; i++)     // 循环8次,从高到低读取字节的8个位
	{
		SET_I2C_SCL();          		// 时钟线SCL输出高电平
		DelayNus(4);            		// 延时4us
		byte <<= 1;          			// 左移一位,空出新的最低位

		if (GET_I2C_SDA())       		// 读取数据线SDA的数据位
		{
			byte++;            			// 在SCL的上升沿后,数据已经稳定,因此可以取该数据,存入最低位
		}
		CLR_I2C_SCL();          		// 时钟线SCL输出低电平
		DelayNus(4);            		// 延时4us
	} 

	return byte;           				// 返回读取到的数据
}

/**
*******************************************************************
* @function 等待接收端的应答信号
* @param    
* @return   1,接收应答失败;0,接收应答成功
* @brief    当SDA拉低后,表示接收到ACK信号,然后,拉低SCL,
*           此处表示发送端收到接收端的ACK
*                _______|____     
*           SCL:        |    \_________    
*                _______|     
*           SDA:         \_____________ 
*******************************************************************
*/
static bool I2CWaitAck(void)
{
	uint8_t errTimes = 0;
	
	SET_I2C_SDA();             // 释放SDA总线,很重要
	DelayNus(4);               // 延时4us
	
	SET_I2C_SCL();             // 时钟线SCL输出高电平
	DelayNus(4);               // 延时4us

	while (GET_I2C_SDA())      // 读回来的数据如果是高电平,即接收端没有应答
	{
		errTimes++;            // 计数器加1

		if (errTimes > 250)    // 如果超过250次,则判断为接收端出现故障,因此发送结束信号
		{
			I2CStop();         // 产生一个停止信号
			return false;      // 返回值为1,表示没有收到应答信号
		}
	}

	CLR_I2C_SCL();             // 表示已收到应答信号,时钟线SCL输出低电平
	DelayNus(4);               // 延时4us
	
	return true;               // 返回值为0,表示接收应答成功  
}

/**
*******************************************************************
* @function 发送应答信号
* @param    
* @return   
* @brief    下面是具体的时序图 
*                 1 2     3      4      5     
*                         ______
*           SCL: ________/      \____________    
*                __                     ______
*           SDA:   \___________________/        
*******************************************************************
*/
static void I2CSendAck(void)
{
	CLR_I2C_SDA();          // 2#数据线SDA输出低电平
	DelayNus(4);            // 延时4us
	SET_I2C_SCL();          // 3#时钟线SCL输出高电平,在SCL上升沿前就要把SDA拉低,为应答信号
	DelayNus(4);            // 延时4us
	CLR_I2C_SCL();          // 4#时钟线SCL输出低电平
	DelayNus(4);            // 延时4us
	SET_I2C_SDA();          // 5#数据线SDA输出高电平,释放SDA总线,很重要
}

/**
*******************************************************************
* @function 发送非应答信号
* @param    
* @return   
* @brief    下面是具体的时序图 
*               1 2     3      4
*                        ______
*          SCL: ________/      \______    
*               __ ___________________    
*          SDA: __/
*******************************************************************
*/
static void I2CSendNack(void)
{
	SET_I2C_SDA();          // 2#数据线SDA输出高电平
	DelayNus(4);            // 延时4us
	SET_I2C_SCL();          // 3#时钟线SCL输出高电平,在SCL上升沿前就要把SDA拉高,为非应答信号
	DelayNus(4);            // 延时4us
	CLR_I2C_SCL();          // 4#时钟线SCL输出低电平
	DelayNus(4);            // 延时4us
}

#define TOUCH_I2C_WR			  	0		    // 写控制bit
#define TOUCH_I2C_RD	         	1		    // 读控制bit


/* GT911 部分寄存器定义 */ 
#define TOUCH_DEV_ADDR 	 			0x28        //设备地址
#define GT911_CTRL_REG   			0x8040      // GT911控制寄存器
#define GT911_CFGS_REG   			0x8050      // GT911配置起始地址寄存器
#define GT911_PID_REG    			0x8140      // GT911产品ID寄存器

#define GT911_STATUS_REG 			0x814E      // GT911当前检测到的触摸情况
#define GT911_TP1_REG    			0x8150      // 第一个触摸点数据地址
#define GT911_TP2_REG    			0x8158      // 第二个触摸点数据地址
#define GT911_TP3_REG    			0x8160      // 第三个触摸点数据地址
#define GT911_TP4_REG    			0x8168      // 第四个触摸点数据地址
#define GT911_TP5_REG    			0x8170      // 第五个触摸点数据地址

#define DETECT_INTERVAL_TIME        20          // GT911检测间隔时间要求10ms以上

/**
*******************************************************************
* @function 配置触摸芯片的设备地址 0x28/0x29
* @param    
* @return                                                        
*******************************************************************
*/
static void ConfigDevAddr(void)            
{
	gpio_bit_reset(GPIOB, GPIO_PIN_9);    	// RST拉低,复位GT911
 
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);  	// INT设为输出
	gpio_bit_reset(GPIOB, GPIO_PIN_12);

	DelayNms(1);  	// 延时1毫秒

	gpio_bit_set(GPIOB, GPIO_PIN_12);  	// 拉高INT

	DelayNms(1);  	// 延时1毫秒

	gpio_bit_set(GPIOB, GPIO_PIN_9);   // RST拉高,释放复位状态

	DelayNms(10);  	// 延时10毫秒

	gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_12);  	// INT设为输入
}

/**
*******************************************************************
* @function 向触摸芯片的寄存器写入数据
* @param    reg,寄存器地址
* @param    pBuffer,数组首地址
* @param    numToWrite,要写入的数据个数,不大于256
* @return   写入是否成功                                                      
*******************************************************************
*/
static bool WriteTouchReg(uint16_t reg, uint8_t *pBuffer, uint8_t numToWrite)
{
    I2CStart();

    I2CSendByte(TOUCH_DEV_ADDR | TOUCH_I2C_WR);
	if (!I2CWaitAck())
	{
		goto i2c_err;	// 器件无应答
	}

    I2CSendByte((uint8_t)(reg >> 8) & 0xFF);
	if (!I2CWaitAck())
	{
		goto i2c_err;	// 器件无应答
	}
    I2CSendByte((uint8_t)reg & 0xFF);
    if (!I2CWaitAck())
	{
		goto i2c_err;	// 器件无应答
	}

    for (uint8_t i = 0; i < numToWrite; i++)
    {
        I2CSendByte(pBuffer[i]);
        if (!I2CWaitAck())
		{
			goto i2c_err;	// 器件无应答
		}
    }

	I2CStop();
	return true;

i2c_err:          // 命令执行失败后,要发送停止信号,避免影响I2C总线上其他设备
	I2CStop();
	return false;
}

/**
*******************************************************************
* @function 指定地址开始读出指定个数的数据
* @param    readAddr,读取地址,0~255
* @param    pBuffer,数组首地址
* @param    numToRead,要读出的数据个数,不大于256
* @return   
*******************************************************************
*/
static bool ReadTouchReg(uint16_t reg, uint8_t *pBuffer, uint8_t numToRead)
{	
	I2CStart();                       				  // 发送起始信号
	
	I2CSendByte(TOUCH_DEV_ADDR | TOUCH_I2C_WR);      // 发送器件地址和读写模式
	if (!I2CWaitAck())                                 // 等待应答
	{
		goto i2c_err;
	}
	
    I2CSendByte((uint8_t)(reg >> 8) & 0xFF);
	if (!I2CWaitAck())
	{
		goto i2c_err;	// 器件无应答
	}
    I2CSendByte((uint8_t)reg & 0xFF);
    if (!I2CWaitAck())
	{
		goto i2c_err;	// 器件无应答
	}
				 
	I2CStart();                                        // 发送起始信号          
	I2CSendByte(TOUCH_DEV_ADDR | TOUCH_I2C_RD);      // 发送器件地址和读写模式      
	if (!I2CWaitAck())                                 // 等待应答
	{
		goto i2c_err;
	}
	
	numToRead--;	
	while(numToRead--)                                // 数据未读完
	{
		*pBuffer++ = I2CReadByte();                   // 逐字节读出存放到数据数组
		I2CSendAck(); 
	}
	*pBuffer = I2CReadByte();                         // 最后一个字节发送非应答
	I2CSendNack();  
	
	I2CStop(); 
	return true;
	
i2c_err:
	I2CStop(); 
	return false;
}

void TouchDrvInit(void)
{
	GpioInit();
	ConfigDevAddr();
	
	uint8_t id[5];
	if (ReadTouchReg(GT911_PID_REG, id, 4))
	{
		id[4] = '\0';
		printf("Touch ID: %s\n", id);
		return;
	}
	printf("Touch init error\n");
}
#if 0
void TouchScan(TouchInfo_t *touchInfo)
{
	uint8_t statRegVal;
	uint8_t buff[6];
		
	if (!ReadTouchReg(GT911_STATUS_REG, &statRegVal, 1))
	{
		printf("read GT911_STATUS_REG error\n");
		touchInfo->state = UP;
		return;
	}
	
	if ((statRegVal & 0x80) == 0)  // 读取最高位查看是否有按下
	{
		printf("It has not been touched\n");
		touchInfo->state = UP;
		return;
	}
	
	uint8_t touchNums = statRegVal & 0x0F;
    printf("It has been touched, touch nums = %d\n", touchNums);
	
	statRegVal = 0;
	WriteTouchReg(GT911_STATUS_REG, &statRegVal, 1); // 清除数据标志位
	
	if (touchNums == 0 || touchNums > TOUCH_POINT_MAX) //如果触摸点为0或>5个
	{
		touchInfo->state = UP;
		return;
	}
	
	ReadTouchReg(GT911_TP1_REG, buff, 6);	// 读出触摸点x y坐标和面积
	touchInfo->point.x = (uint16_t)(buff[1] << 8) | buff[0];
	touchInfo->point.y = (uint16_t)(buff[3] << 8) | buff[2];
	touchInfo->point.size = (uint16_t)(buff[5] << 8) | buff[4];
//	printf("point[%d].x = %d, point[%d].y = %d, point[%d].size = %d\n", \
//			0, touchInfo->point.x, 0, touchInfo->point.y, 0, touchInfo->point.size);
		
	touchInfo->state = DOWN;
	return;	
}
#endif
/* 扫描电容触摸芯片 GT911,输出最新触摸点信息
 * 入口:touchInfo 结构体指针,用于返回坐标/面积/状态
 * 特性:带防抖间隔、自动清标志、只处理第 1 指 */
void TouchScan(TouchInfo_t *touchInfo)
{
	/* 静态变量:保存上一次触摸状态与系统时间,用于防抖 */
	static TouchInfo_t lastTouchInfo = {UP};
	static uint64_t lastSysTime = 0;

	/* 若距离上次调用时间不足 DETECT_INTERVAL_TIME ms,直接返回旧状态 */
	if ((GetSysRunTime() - lastSysTime) < DETECT_INTERVAL_TIME)  // 判断两次调用接口函数的时间间隔是否小于DETECT_INTERVAL_TIME ms
	{
		*touchInfo = lastTouchInfo; //小于触摸芯片的时间间隔返回上一次的状态
		return;
	}
	lastSysTime = GetSysRunTime();          // 记录本次扫描时刻

	uint8_t statRegVal;
	uint8_t buff[6];

	/* 读取状态寄存器,失败则标记为抬起并返回 */
	if (!ReadTouchReg(GT911_STATUS_REG, &statRegVal, 1))
	{
		printf("read GT911_STATUS_REG error\n");
		touchInfo->state = UP;
		lastTouchInfo = *touchInfo;
		return;
	}

	/* 状态寄存器最高位为0表示无触摸,直接返回 UP */
	if ((statRegVal & 0x80) == 0)  // 读取最高位查看是否有按下
	{
		//printf("It has not been touched\n");
		touchInfo->state = UP;
		lastTouchInfo = *touchInfo;
		return;
	}

	/* 低4位表示当前触摸点数,只做日志打印 */
	uint8_t touchNums = statRegVal & 0x0F;
	printf("touch nums = %d\n", touchNums);

	/* 清状态寄存器(写0清标志),准备下一次中断/查询 */
	statRegVal = 0;
	WriteTouchReg(GT911_STATUS_REG, &statRegVal, 1);//清除数据标志位

	/* 触摸数为0或超过最大支持点数,视为无效,返回 UP */
	if (touchNums == 0 || touchNums > TOUCH_POINT_MAX) 
	{
		touchInfo->state = UP;
		lastTouchInfo = *touchInfo;
		return;
	}

	/* 读取第1个触摸点寄存器(X/Y/面积共6字节) */
	ReadTouchReg(GT911_TP1_REG, buff, 6);	// 读出触摸点x y坐标和面积
	/* 组合出16位坐标与面积 */
	touchInfo->point.x = (uint16_t)(buff[1] << 8) | buff[0];
	touchInfo->point.y = (uint16_t)(buff[3] << 8) | buff[2];
	touchInfo->point.size = (uint16_t)(buff[5] << 8) | buff[4];
	//printf("point[%d].x = %d, point[%d].y = %d, point[%d].size = %d\n", \
			0, touchInfo->point.x, 0, touchInfo->point.y, 0, touchInfo->point.size);
		
	/* 标记为按下,并缓存本次结果供下次防抖使用 */
	touchInfo->state = DOWN;
	lastTouchInfo = *touchInfo;
	return;
}

.h

#ifndef _TOUCH_DRV_H_
#define _TOUCH_DRV_H_

#include <stdint.h>

#define   TOUCH_POINT_MAX  5

/* 触摸点坐标数据结构 */
typedef struct
{
    uint16_t x;           // 触摸点X坐标
    uint16_t y;           // 触摸点Y坐标
    uint16_t size;        // 触摸点大小
} TouchPoint_t;

#define UP    0
#define DOWN  1
/* 触摸信息结构体 */
typedef struct
{
	uint8_t state;        // 1:按下 or 0:未按下
	TouchPoint_t point;
} TouchInfo_t;	          //触摸信息结构体

void TouchDrvInit(void);
void TouchScan(TouchInfo_t *touchInfo);

#endif

我们要实现画布的功能

在人机交互文件hmi_app.c里实现

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "rtc_drv.h"
#include "sensor_drv.h"
#include "led_drv.h"
#include "key_drv.h"
#include "touch_drv.h"
#include "lcd_drv.h"
#include "store_app.h"

/**
*******************************************************************
* @function 绘制实心圆
* @param    x0、y0:圆心坐标
* @param    r:半径
* @param    color:颜色
* @return                                                     
*******************************************************************
*/
static void DrawSolidCircle(uint16_t x0,uint16_t y0, uint16_t r, uint16_t color)
{
	int a = 0;
	int b = r;	  
	int di = 3 - (r << 1);             // 判断下个点位置的标志
	while (a <= b)
	{
		int i = a, p = b;
		while (i > 0)
		{
			LcdDrawPoint(x0+b,y0-i, color);
			LcdDrawPoint(x0-i,y0+b, color);
			i--;
		}
		while ( p > 0)
		{
			LcdDrawPoint(x0 - a, y0 - p, color);
			LcdDrawPoint(x0 - p, y0 - a, color);
			LcdDrawPoint(x0 + a, y0 - p, color);
			LcdDrawPoint(x0 - p, y0 + a, color);
			LcdDrawPoint(x0 + a, y0 + p, color);
			LcdDrawPoint(x0 + p, y0 + a, color);
			p--;
		}
		a++;

		/* Bresenham算法画圆 */
		if (di < 0)
		{
			di += 4 * a + 6;
		}
		else
		{
			di += 10 + 4 * (a - b);
			b--;
		}
	}
	LcdDrawPoint(x0, y0, color); // 圆心坐标
}

/**
*******************************************************************
* @function 绘制直线
* @param    x0、y0:起点坐标
* @param    x1、y1:终点坐标
* @param    size:直线粗细
* @param    color:颜色
* @return                                                     
*******************************************************************
*/
static void DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t size, uint16_t color)
{
	uint16_t t; 
	int xerr = 0, yerr = 0, delta_x, delta_y, distance; 
	int incx, incy, uRow, uCol; 
	delta_x = x1 - x0; // 计算坐标增量 
	delta_y = y1 - y0; 
	uRow = x0; 
	uCol = y0; 

	// 设置单步方向 
	if (delta_x > 0)
	{
		incx=1;
	}

	// 垂直线
	else if (delta_x == 0)
	{
		incx=0;
	}
	else 
	{
		incx = -1;
		delta_x = -delta_x;
	} 

	if (delta_y > 0)
	{
		incy = 1;
	}

	// 水平线
	else if (delta_y == 0)
	{
		incy = 0;
	}
	else
	{
		incy = -1;
		delta_y = -delta_y;
	} 

	// 选取基本增量坐标轴
	if (delta_x > delta_y)
	{
		distance = delta_x;
	}
	else 
	{
		distance = delta_y;
	}

	// 画线输出
	for (t = 0; t <= distance + 1; t++)
	{ 
		DrawSolidCircle(uRow, uCol, size, color);
		xerr += delta_x ; 
		yerr += delta_y ; 
		if (xerr > distance) 
		{ 
			xerr -= distance; 
			uRow += incx; 
		} 
		if (yerr > distance) 
		{ 
			yerr -= distance; 
			uCol += incy; 
		}
	}
}

/**
****************************************************************
* @brief  触摸画板任务:手指/笔触移动时实时绘制轨迹
* @note   1. 首次按下画实心圆作为起点
*         2. 后续移动画线段形成连续轨迹
*         3. 触点面积映射为笔刷粗细
****************************************************************
*/
void CanvasTask(void)
{	
	/* 静态变量:线条是否已开始、上一帧坐标 */
	static bool s_lineFlag = false;       // 标记线条是否已开始绘制
	static TouchPoint_t s_arrLastPoint;   // 上一个点的坐标
	
	/* 当前帧触摸信息清零并扫描 */
	TouchInfo_t touchInfoNow;
	memset(&touchInfoNow, 0, sizeof(touchInfoNow));
	TouchScan(&touchInfoNow);
	
	/* 手指抬起:重置标志,退出本次任务 */
	if (touchInfoNow.state == UP)
	{
		s_lineFlag = false;
		return;
	}

	uint16_t x0, y0, x1, y1, size;

	/* 提取起点、终点、笔刷半径 */
	x0 = s_arrLastPoint.x;
	y0 = s_arrLastPoint.y;
	x1 = touchInfoNow.point.x;
	y1 = touchInfoNow.point.y;
	size  = touchInfoNow.point.size;

	/* 将触摸面积映射到 1~15 像素笔刷:过大则缩小,过小则保底 */
	size = size / 5;
	if (0 == size)
	{
		size = 1;
	}
	else if (size > 15)
	{
		size = 15;
	}
	
	/* 首次触点:画实心圆作为“落笔”起点 */
	if (!s_lineFlag)
	{
		DrawSolidCircle(x1, y1, size, YELLOW); // 线条第一个点用画点方式
		s_lineFlag = true;  // 标记线条已经开始绘制
	}
	else
	{
		/* 非首次:从前一坐标到当前坐标画线段,形成连续轨迹 */
		DrawLine(x0, y0, x1, y1, size, YELLOW); // 后边的用画线方式 
	}

	/* 保存当前坐标,供下一帧画线使用 */
	s_arrLastPoint.x = touchInfoNow.point.x;
	s_arrLastPoint.y = touchInfoNow.point.y;
}
/**
***********************************************************
* @brief 人机交互任务处理函数
* @param 
* @return 
***********************************************************
*/
void HmiTask(void)
{
	CanvasTask();
	
//	TouchInfo_t touchInfoNow;
//	memset(&touchInfoNow, 0, sizeof(touchInfoNow));
//	TouchScan(&touchInfoNow);
	
	uint8_t keyVal;
	keyVal = GetKeyVal();
	switch (keyVal)
	{
		case KEY1_SHORT_PRESS:
			TurnOnLed(LED1);
			if (SetModbusParam(2))
			{
				printf("SetModbusParam sucess\n");
			}
			else
			{
				printf("SetModbusParam fail\n");
			}
			break;
		case KEY1_LONG_PRESS:
			TurnOffLed(LED1);
			break;
		case KEY2_SHORT_PRESS:
			TurnOnLed(LED2);
			break;
		case KEY2_LONG_PRESS:
			TurnOffLed(LED2);
			break;
		case KEY3_SHORT_PRESS:
			TurnOnLed(LED3);
			break;
		case KEY3_LONG_PRESS:
			TurnOffLed(LED3);
			break;
		default:
			break;
	}
}