747|5

521

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【兆易GD32H759I-EVAL】--13.LCD触摸功能 [复制链接]

 
本帖最后由 dirty 于 2024-6-14 09:10 编辑

      前面展示了LVGL的移植与界面显示,本篇承接其上讲述LCD触摸功能。

一.原理了解

      开发板LCD接口带有触摸引脚如下图,显示屏上带有触摸芯片 XPT2046,通过SPI接口与主控制器通信。

图1:触摸原理引脚

 

引脚定义

LCD_Touch_PENIRQ-----------PG3      笔触中断信号。当触摸屏被按下,该引脚被拉为低电平。
LCD_SPI4_MOSI----------------PF9       SPI串行数据输出

LCD_SPI4_MISO----------------PH7      SPI串行数据输入
LCD_SPI4_SCK-----------------PH6      SPI时钟
LCD_SPI4_NSS-----------------PF6      片选。拉低输入输出数据有效
LCD_PWM_BackLight---------PG13   背光控制
LCD_Touch_Busy---------------PF8     忙输出信号

 

二.代码准备

1.触摸引脚初始化。

/* SPI SCK pin */
#define SPI_SCK_PIN             GPIO_PIN_6
#define SPI_SCK_PORT            GPIOH
#define SPI_SCK_LOW()           gpio_bit_reset(SPI_SCK_PORT, SPI_SCK_PIN)
#define SPI_SCK_HIGH()          gpio_bit_set(SPI_SCK_PORT, SPI_SCK_PIN)
/* SPI MOSI pin */
#define SPI_MOSI_PIN            GPIO_PIN_9
#define SPI_MOSI_PORT           GPIOF
#define SPI_MOSI_LOW()          gpio_bit_reset(SPI_MOSI_PORT, SPI_MOSI_PIN)
#define SPI_MOSI_HIGH()         gpio_bit_set(SPI_MOSI_PORT, SPI_MOSI_PIN)
/* SPI MISO pin */
#define SPI_MISO_PIN            GPIO_PIN_7
#define SPI_MISO_PORT           GPIOH
#define SPI_MISO_READ()         gpio_input_bit_get(SPI_MISO_PORT, SPI_MISO_PIN)
/* SPI Chip select pin */
#define SPI_TOUCH_CS_PIN        GPIO_PIN_6
#define SPI_TOUCH_CS_PORT       GPIOF
#define SPI_TOUCH_CS_LOW()      gpio_bit_reset(SPI_TOUCH_CS_PORT,SPI_TOUCH_CS_PIN)
#define SPI_TOUCH_CS_HIGH()     gpio_bit_set(SPI_TOUCH_CS_PORT,SPI_TOUCH_CS_PIN)
/* LCD touch interrupt request pin */
#define TOUCH_PEN_INT_PIN       GPIO_PIN_3
#define TOUCH_PEN_INT_PORT      GPIOG

#define TOUCH_PEN_INT_READ()    gpio_input_bit_get(TOUCH_PEN_INT_PORT,TOUCH_PEN_INT_PIN)

void touch_panel_gpio_configure(void)
{
	/* GPIO clock enable */
	rcu_periph_clock_enable(RCU_GPIOG);
	rcu_periph_clock_enable(RCU_GPIOH);
	rcu_periph_clock_enable(RCU_GPIOF);
	gpio_af_set(SPI_SCK_PORT, GPIO_AF_5, SPI_SCK_PIN);
	gpio_mode_set(SPI_SCK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,SPI_SCK_PIN);
	gpio_output_options_set(SPI_SCK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ,SPI_SCK_PIN);
	gpio_af_set(SPI_MOSI_PORT, GPIO_AF_5, SPI_MOSI_PIN);
	gpio_mode_set(SPI_MOSI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,SPI_MOSI_PIN);
	gpio_output_options_set(SPI_MOSI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ,SPI_MOSI_PIN);
	gpio_af_set(SPI_MISO_PORT, GPIO_AF_5, SPI_MISO_PIN);
	gpio_mode_set(SPI_MISO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE,SPI_MISO_PIN);
	gpio_output_options_set(SPI_MISO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ,SPI_MISO_PIN);
	gpio_mode_set(SPI_TOUCH_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,SPI_TOUCH_CS_PIN);
	gpio_output_options_set(SPI_TOUCH_CS_PORT, GPIO_OTYPE_PP,GPIO_OSPEED_60MHZ, SPI_TOUCH_CS_PIN);
	/* touch pen IRQ pin PI3 configure */
	gpio_mode_set(TOUCH_PEN_INT_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE,TOUCH_PEN_INT_PIN);
	gpio_output_options_set(TOUCH_PEN_INT_PORT, GPIO_OTYPE_PP,GPIO_OSPEED_60MHZ, TOUCH_PEN_INT_PIN);
	/* set chip select pin high */
	SPI_TOUCH_CS_HIGH();
}

 

2.触摸驱动。这部分驱动会被用在LVGL 关于触摸功能lv_port_indev.c里。

(1)触摸开始,写数据到触摸屏,读触摸ad值

/*!
\brief touch start
\param[in] none
\param[out] none
\retval none
*/
void touch_start(void)
{
	spi_clk(0);
	spi_cs(1);
	spi_mosi(1);
	spi_clk(1);
	spi_cs(0);
}

/*!
\brief write data to touch screen
\param[in] d: the data to be written
\param[out] none
\retval none
*/
void touch_write(uint8_t d)
{
	uint8_t buf, i ;
	spi_clk(0);
	for( i = 0; i < 8; i++)
	{
		buf = ((d >> (7-i)) & 0x1);
		spi_mosi(buf);
		spi_clk(0);
		spi_clk(1);
		spi_clk(0);
	}
}

/*!
\brief read the touch AD value
\param[in] None
\param[out] none
\retval the value of touch AD
*/
uint16_t touch_read(void)
{
	uint16_t buf ;
	uint8_t i ;
	buf=0;
	for(i = 0; i < 12; i++)
	{
		buf = buf << 1 ;
		spi_clk(1);
		spi_clk(0);
		if(RESET != spi_miso())
		{
			buf = buf + 1 ;
		}
	}
	return( buf );
}

(2)获取触摸X轴、Y轴坐标及防抖平均值

/*!
\brief get the AD sample value of touch location at X coordinate
\param[in] none
\param[out] none
\retval channel X+ AD sample value
*/
uint16_t touch_ad_x_get(void)
{
	if (RESET != touch_pen_irq())
	{
		/* touch pen is inactive */
		return 0;
	}
	touch_start();
	touch_write(0x00);
	touch_write(CH_X);
	return (touch_read());
}

/*!
\brief get the AD sample value of touch location at Y coordinate
\param[in] none
\param[out] none
\retval channel Y+ AD sample value
*/
uint16_t touch_ad_y_get(void)
{
	if (RESET != touch_pen_irq())
	{
		/* touch pen is inactive */
		return 0;
	}
	touch_start();
	touch_write(0x00);
	touch_write(CH_Y);
	return (touch_read());
}

/*!
\brief get channel X+ AD average sample value
\param[in] none
\param[out] none
\retval channel X+ AD average sample value
*/
uint16_t touch_average_ad_x_get(void)
{
	uint8_t i;
	uint16_t temp=0;
	for (i=0;i<8;i++)
	{
		temp+=touch_ad_x_get();
		spi_delay(1000);
	}
	temp>>=3;
	return temp;
}

/*!
\brief get channel Y+ AD average sample value
\param[in] none
\param[out] none
\retval channel Y+ AD average sample value
*/
uint16_t touch_average_ad_y_get(void)
{
	uint8_t i;
	uint16_t temp=0;
	for (i=0;i<8;i++)
	{
		temp+=touch_ad_y_get();
		spi_delay(1000);
	}
	temp>>=3;
	return temp;
}

(3)获取映射到屏幕上的像素点X轴、Y轴坐标及数据过滤

/*!
\brief get X coordinate value of touch point on LCD screen
\param[in] adx : channel X+ AD average sample value
\param[out] none
\retval X coordinate value of touch point
*/
uint16_t touch_coordinate_x_get(uint16_t adx)
{
	uint16_t sx = 0;
	uint32_t
	r = adx - AD_Left;
	r *= LCD_X - 1;
	sx = r / (AD_Right - AD_Left);
	if (sx <= 0 || sx > LCD_X)
	{
		return 0;
	}
	
	return sx;
}

/*!
\brief get Y coordinate value of touch point on LCD screen
\param[in] ady : channel Y+ AD average sample value
\param[out] none
\retval Y coordinate value of touch point
*/
uint16_t touch_coordinate_y_get(uint16_t ady)
{
	uint16_t sy = 0;
	uint32_t
	r = ady - AD_Top;
	r *= LCD_Y - 1;
	sy = r / (AD_Bottom - AD_Top);
	if (sy <= 0 || sy > LCD_Y)
	{
		return 0;
	}
	
	return sy;
}

/*!
\brief get a value (X or Y) for several times. Order these values,
remove the lowest and highest and obtain the average value
\param[in] channel_select: select channel X or Y
\arg CH_X: channel X
\arg CH_Y: channel Y
\param[out] none
\retval a value(X or Y) of touch point
*/
uint16_t touch_data_filter(uint8_t channel_select)
{
	uint16_t i=0, j=0;
	uint16_t buf[FILTER_READ_TIMES];
	uint16_t sum=0;
	uint16_t temp=0;
	/* Read data in FILTER_READ_TIMES times */
	for(i=0; i < FILTER_READ_TIMES; i++)
	{
		if (CH_X == channel_select)
		{
			buf[i] = touch_ad_x_get();
		}
		else
		{ 
			/* CH_Y == channel_select */
			buf[i] = touch_ad_y_get();
		}
	}
	/* Sort in ascending sequence */
	for(i = 0; i < FILTER_READ_TIMES - 1; i++)
	{
		for(j = i + 1; j < FILTER_READ_TIMES; j++)
		{
			if(buf[i] > buf[j])
			{
				temp = buf[i];
				buf[i] = buf[j];
				buf[j] = temp;
			}
		}
	}
	sum = 0;
	for(i = FILTER_LOST_VAL; i < FILTER_READ_TIMES - FILTER_LOST_VAL; i++)
	{
		sum += buf[i];
	}
	temp = sum / (FILTER_READ_TIMES - 2 * FILTER_LOST_VAL);
	return temp;
}

(4)获取过滤处理后触摸位置


/*
\brief get the AD sample value of touch location.
get the sample value for several times,order these values,remove the lowest and
highest and obtain the average value
\param[in] channel_select: select channel X or Y
\param[out] none
\arg ad_x: channel X AD sample value
\arg ad_y: channel Y AD sample value
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus touch_ad_xy_get(uint16_t *ad_x, uint16_t *ad_y)
{
	uint16_t ad_x1=0, ad_y1=0, ad_x2=0, ad_y2=0;
	ad_x1 = touch_data_filter(CH_X);
	ad_y1 = touch_data_filter(CH_Y);
	ad_x2 = touch_data_filter(CH_X);
	ad_y2 = touch_data_filter(CH_Y);
	if((abs(ad_x1 - ad_x2) > AD_ERR_RANGE) || (abs(ad_y1 - ad_y2) > AD_ERR_RANGE))
	{
		return ERROR;
	}
	*ad_x = (ad_x1 + ad_x2) / 2;
	*ad_y = (ad_y1 + ad_y2) / 2;
	return SUCCESS;
}

(5)触摸扫描。用来探测触摸事件


/*!
\brief detect the touch event
\param[in] none
\param[out] none
\retval ErrStatus: SUCCESS or ERROR
*/
ErrStatus touch_scan(void)
{
	uint8_t invalid_count = 0;
	if (RESET == touch_pen_irq())
	{
		/* touch pen is active */
		while((SUCCESS != touch_ad_xy_get(&touch_ad_x, &touch_ad_y))&& (invalid_count <20))
		{
			invalid_count++;
		}
		if(invalid_count >= 20)
		{
			touch_ad_x = 0;
			touch_ad_y = 0;
			return ERROR;
		}
	}
	else
	{
		touch_ad_x = 0;
		touch_ad_y = 0;
		return ERROR;
	}
	return SUCCESS;
}

 

3.lvgl触摸功能源文件lv_port_indev.c代码移植

(1)lv_port_indev_init屏蔽除触摸功能外的外设,如下图。这里注册了触摸读函数touchpad_read。

 

图2:触摸外设裁剪

(2)回调触摸读函数实现。这里调用了touch_scan触摸扫描函数。

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /*Save the pressed coordinates and the state*/
    if(touch_scan())
    {
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Set the last pressed coordinates*/
    data->point.x = last_x;
    data->point.y = last_y;
}

(3)获取触摸的X、Y轴坐标

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/

    // (*x) = 0;
    // (*y) = 0;
    (*x) = touch_coordinate_x_get(touch_ad_x);
    (*y) = LCD_Y - touch_coordinate_y_get(touch_ad_y);
}

      经过这几步lvgl 触摸移植完成。

 

4.设计触摸按钮居中,实现触摸后按钮颜色及数值循环递变。

static void btn_event_cb(lv_event_t* e) 
{
    static uint8_t cnt = 0;
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t* btn = lv_event_get_target(e);
    if (code == LV_EVENT_CLICKED) 
    {
        
        cnt++;
        lv_obj_t* label = lv_obj_get_child(btn, 0);
        if(cnt>=_LV_PALETTE_LAST)
        {
            cnt=0;
        }
        lv_label_set_text_fmt(label, "Button: %d", cnt);
        lv_obj_set_style_bg_color(btn, lv_palette_main(cnt) ,0);//设置背景颜色
    }
}

static void lv_example(void) 
{
    lv_obj_t* btn = lv_btn_create(lv_scr_act());
    lv_obj_set_pos(btn, 180, 111);//10,10
    lv_obj_set_size(btn, 120, 50);
    lv_obj_set_style_bg_color(btn, lv_palette_main(LV_PALETTE_YELLOW) ,0);//设置背景颜色
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
    lv_obj_t* label = lv_label_create(btn);
    lv_label_set_text(label, "Button");
    lv_obj_center(label);
}

5.main函数如下

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/

int main(void)
{
    ov2640_id_struct ov2640id;
    BaseType_t ret;
    
    /* enable the CPU cache */
    cache_enable();
    /* initialize the LEDs */
    test_status_led_init();

    /* configure systick */
    systick_config();
    
   

    /* flash the LEDs for 2 time */
    led_flash(2);

    /* configure USART0 */
    usart_config();

    /* configure TAMPER key */
    gd_eval_key_init(KEY_TAMPER, KEY_MODE_EXTI);

    /* output a message on hyperterminal using printf function */
    printf("\r\n =================  LVGL =================   \r\n");

    /**********************LCD Application**********************/
    
    /* config the EXMC access mode */
    exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);
    printf("\r\nSDRAM Init \r\n");


    /* camera initialization */
    dci_ov2640_init();
    dci_ov2640_id_read(&ov2640id);
    
    nvic_configuration();

    /* DMA interrupt and channel enable */
    dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_enable(DMA1, DMA_CH7);
    /* DCI enable */
    dci_enable();
    dci_capture_enable();
    delay_1ms(100);

    dma_interrupt_disable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_disable(DMA1, DMA_CH7);
    dci_capture_disable();


    timer_config();
    
    lcd_config();
    lcd_init();
    /* configure the GPIO of SPI touch panel */
    touch_panel_gpio_configure();
    #if (LVGL_DMA)
    delay_1ms(50);
    dma_config();
    delay_1ms(1000);
    #endif

    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    lv_example();
    // lv_demo_music();
    //lv_demo_widgets();

    while(1)
    {
        delay_1ms(5);
        lv_task_handler();
    }
    
}

 

三.测验

      编译烧录后,屏幕中间显示黄色按钮如下图,触摸后变色及附带数值循环递变,如下视屏。

图3:触摸按钮

      至此实现LCD屏触摸功能。

 

LCD触摸

 

最新回复

我Sy+=了30   详情 回复 发表于 2024-8-11 16:03
点赞 关注(1)
个人签名

保持热爱

 
 

回复
举报

521

帖子

0

TA的资源

纯净的硅(初级)

来自 4楼
 
本帖最后由 dirty 于 2024-6-24 23:40 编辑

LCD触摸工程代码

 

GD32H759I_LVGL_Touch.rar

36.54 MB, 下载次数: 10

LVGL Touch工程

个人签名

保持热爱

 
 
 

回复

7063

帖子

11

TA的资源

版主

沙发
 
看起来效果挺好的了,我原来就是没有把触摸搞定。

点评

一步步来,花点时间,可以搞定的  详情 回复 发表于 2024-6-15 09:35
 
 
 

回复

521

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
lugl4313820 发表于 2024-6-14 11:38 看起来效果挺好的了,我原来就是没有把触摸搞定。

一步步来,花点时间,可以搞定的

个人签名

保持热爱

 
 
 

回复

194

帖子

4

TA的资源

纯净的硅(初级)

5
 

X轴有点偏移,怎么校准下。 大概偏移了30

 
 
 

回复

194

帖子

4

TA的资源

纯净的硅(初级)

6
 

我Sy+=了30

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表