开发板
亚博K210开发板
实验目的
主要学习 K210 通过 I2C 读取触摸屏的坐标,并打印出来,显示在 LCD上。
实验准备
实验元件
LCD 显示屏+触摸板
元件特性
K210 开发板自带 2.0 寸触摸屏,其实是 LCD 显示屏上贴一个触摸板组成,LCD显示屏上一节课已经学过,而触摸板为电容触摸板,与手机上使用的电容屏原理一样,可以直接用手指触摸,而不像电阻屏一样要用指甲按。电容屏具有相应时间短,精确度高,使用寿命长,操作简单方便等特点。触摸板使用的是 I2C 通讯,能够稳定传输数据,并且支持与其他 I2C 设备并联到同一个 I2C 接口上通讯。
硬件连接
K210 开发板出厂默认已经安装好 LCD 显示屏和触摸板,其中 LCD 显示屏的LCD_D0~D7 总共八个引脚连接到 SPI0_D0~D7 上,LCD_CS 连接到 IO36 上,LCD_RST连接到 IO37 上,LCD_RS 连接 IO3 上,LCD_WR 连接 IO39 上;触摸板的 I2C_SCL连接到 IO9,I2C_SDA 连接到 IO10,FT_INT 连接到 IO12,FT_RST 连接到 IO37,与 LCD 显示屏共用使用一个 RST 接口。
SDK 中对应 API 功能
以头文件 i2c.h为例
- I2C 总线用于和多个外部设备进行通信。多个外部设备可以共用一个 I2C总线。
- I2C 模块具有独立的 I2C 设备封装外设相关参数,自动处理多设备总线争用的功能。
- K210 芯片集成电路总线有 3个 I2C总线接口,都可以作为 I2C 主机(MASTER)模式或从机(SLAVE)模式来使用。
- I2C 接口支持标准模式(0 到 100kb/s),快速模式(<=400kb/s),7 位或10 位寻址模式,批量传输模式,中断或轮询模式操作。
• i2c_init:初始化 I2C,配置从机地址、寄存器位宽度和 I2C 速率。
• i2c_init_as_slave:配置 I²C 为从模式。
• i2c_send_data:I2C 写数据。
• i2c_send_data_dma:I2C 通过 DMA 写数据。
• i2c_recv_data:I2C 通过 CPU 读数据。
• i2c_recv_data_dma:I2C 通过 dma 读数据。
• i2c_handle_data_dma:I2C 使用 dma 传输数据。
实验原理
- 电容式触摸屏技术是利用人体的电流感应进行工作的。电容式触摸屏是一块 四层复合玻璃屏,玻屏的内表面和夹层各涂有一层 ITO,最外层是一薄层矽土 玻璃保护层,夹层 ITO 涂层作为工作面,角上引出四个电极,内层ITO 为屏 蔽层以保证良好的工作环境。当手指触摸在金属层上时,由于人体电场,用户 和触摸屏表面形成以一个耦合电容,对于高频电流来说,电容是直接导体,于是手指从接触点吸走一个很小的电流。这个电流分别从触摸屏的四角上的电极中流出,并且流经这四个电极的电流与手指到四角的距离成正比,控制器通过对这四 个电流比例的精确计算,得出触摸点的位置。
- I2C 是一种总线式结构,它只需要 SCL 时钟信号线与 SDA 数据线,两根线就能将连接与总线上设备实现数据通信,由于它的简便的构造设计,于是成为一种较为常用的通信方式。由于 I2C 采用的是主从式通信方式,所以,通信的过程完全由主设备仲裁。在通信之前,必须由主设备发送一个起始信号,决定数据是否可以开始传送,并且在结束通信时,必须再由主设备发送一个结束信号,以表示通信已经结束。
I2C 向寄存器写入数据的过程:
I2C 从寄存器读取数据的过程:
实验过程
- 首先初始化 K210 的硬件引脚和软件功能使用的是 FPIOA 映射关系
#define PIN_LCD_CS (36)
#define PIN_LCD_RST (37)
#define PIN_LCD_RS (38)
#define PIN_LCD_WR (39)
#define PIN_FT_RST (37)
#define PIN_FT_INT (12)
#define PIN_FT_SCL (9)
#define PIN_FT_SDA (10)
/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LCD_RST_GPIONUM (0)
#define LCD_RS_GPIONUM (1)
#define FT_INT_GPIONUM (2)
#define FT_RST_GPIONUM (3)
/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_LCD_CS (FUNC_SPI0_SS3)
#define FUNC_LCD_RST (FUNC_GPIOHS0 + LCD_RST_GPIONUM)
#define FUNC_LCD_RS (FUNC_GPIOHS0 + LCD_RS_GPIONUM)
#define FUNC_LCD_WR (FUNC_SPI0_SCLK)
#define FUNC_FT_RST (FUNC_GPIOHS0 + FT_RST_GPIONUM)
#define FUNC_FT_INT (FUNC_GPIOHS0 + FT_INT_GPIONUM)
#define FUNC_FT_SCL (FUNC_I2C0_SCLK)
#define FUNC_FT_SDA (FUNC_I2C0_SDA)
void hardware_init(void)
{
/**
*lcd_cs 36
*lcd_rst 37
*lcd_rs 38
*lcd_wr 39
**/
fpioa_set_function(PIN_LCD_CS, FUNC_LCD_CS);
fpioa_set_function(PIN_LCD_RST, FUNC_LCD_RST);
fpioa_set_function(PIN_LCD_RS, FUNC_LCD_RS);
fpioa_set_function(PIN_LCD_WR, FUNC_LCD_WR);
/* 使能SPI0和DVP */
sysctl_set_spi0_dvp_data(1);
/* I2C FT6236 */
// fpioa_set_function(PIN_FT_RST, FUNC_FT_RST);
fpioa_set_function(PIN_FT_INT, FUNC_FT_INT);
fpioa_set_function(PIN_FT_SCL, FUNC_FT_SCL);
fpioa_set_function(PIN_FT_SDA, FUNC_FT_SDA);
}
- 设置 LCD 的 IO 口电平电压为 1.8V。
void io_set_power(void)
{
sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
}
- 由于触摸板需要使用中断来判断屏幕是否有触摸,所有需要初始化中断并使能全局中断。
/* 系统中断初始化,并使能全局中断 */
plic_init();
sysctl_enable_irq();
- 初始化 LCD 显示屏,并显示图片和字符串欢迎语
/* 初始化LCD */
lcd_init();
/* 显示图片 */
uint16_t * img = &gImage_logo;
lcd_draw_picture_half(0, 0, 320, 240, img);
sleep(1);
lcd_draw_string(16, 40, "Hello Yahboom", RED);
lcd_draw_string(16, 60, "Nice to meet you!", BLUE);
- 初始化触摸板,并通过 LCD 显示和串口打印触摸提示。
/* 初始化触摸板 */
ft6236_init();
printf("Hi!Please touch the screen to get coordinates!\n");
lcd_draw_string(16, 180, "Please touch the screen to get coord!", RED);
触摸板 FT6236 的初始化比较简单,分为硬件初始化和软件初始化,软件初始化主要是设置 FT6236 的寄存器,唤醒 FT6236 设置触摸灵敏度和扫描周期。
/* 初始化ft6236 */
void ft6236_init(void)
{
ft6236.touch_state = 0;
ft6236.touch_x = 0;
ft6236.touch_y = 0;
/* 硬件初始化 */
ft6236_hardware_init();
/* 软件初始化 */
i2c_hardware_init(FT6236_I2C_ADDR);
ft_i2c_write(FT_DEVIDE_MODE, 0x00);
/* 设置触摸有效值,越小越灵敏,def=0xbb */
ft_i2c_write(FT_ID_G_THGROUP, 0x12); // 0x22
/* 工作扫描周期,用于控制报点率,def=0x08, 0x04~0x14 */
ft_i2c_write(FT_ID_G_PERIODACTIVE, 0x06);
}
- 硬件引脚初始化,主要是修改触摸板复位引脚的电平,这里与屏幕使用同一个复位引脚,所以不需要再复位操作。再设置 FT_INT 中断引脚为输入,中断回调函数为 ft6236_isr_cb,并在中断函数中修改触摸屏的状态。
void ft6236_hardware_init(void)
{
/* 与屏幕使用不同复位引脚时设置为1 */
#if (0)
{
gpiohs_set_drive_mode(FT_RST_GOIONUM, GPIO_DM_OUTPUT);
ft6236_reset_pin(LEVEL_LOW);
msleep(50);
ft6236_reset_pin(LEVEL_HIGH);
msleep(120);
}
#endif
gpiohs_set_drive_mode(FT_INT_GPIONUM, GPIO_DM_INPUT);
gpiohs_set_pin_edge(FT_INT_GPIONUM, GPIO_PE_RISING);
gpiohs_irq_register(FT_INT_GPIONUM, FT6236_IRQ_LEVEL, ft6236_isr_cb, NULL);
msleep(5);
}
- FT6236通过I2C通讯的方式来读和写数据,以下是触摸板 I2C控制的函数:
/* I2C写数据 */
static void ft_i2c_write(uint8_t reg, uint8_t data)
{
i2c_hd_write(FT6236_I2C_ADDR, reg, data);
}
/* I2C读数据 */
static void ft_i2c_read(uint8_t reg, uint8_t *data_buf, uint16_t length)
{
i2c_hd_read(FT6236_I2C_ADDR, reg, data_buf, length);
}
初始化 I2C,设置从机地址,数据位宽度,I2C 通讯速率等,
static uint16_t _current_addr = 0x00;
/* 硬件初始化I2C,设置从机地址,数据位宽度,I2C通讯速率 */
void i2c_hardware_init(uint16_t addr)
{
i2c_init(I2C_DEVICE_0, addr, ADDRESS_WIDTH, I2C_CLK_SPEED);
_current_addr = addr;
}
向寄存器 reg 写入一个数据 data ,写入成功返回 0,失败则返回非 0,
/* 向寄存器reg写入一个数据data ,写入成功返回0,失败则返回非0*/
uint16_t i2c_hd_write(uint8_t addr, uint8_t reg, uint8_t data)
{
if (_current_addr != addr)
{
i2c_hardware_init(addr);
}
uint8_t cmd[2];
cmd[0] = reg;
cmd[1] = data;
uint16_t error = 1;
error = i2c_send_data(I2C_DEVICE_0, cmd, 2);
return error;
}
从寄存器 reg 读取 length 个数据保存到 data_buf,读取成功返回 0,失败
则返回非 0。
/* 从寄存器reg读取length个数据保存到data_buf,读取成功返回0,失败则返回非0 */
uint16_t i2c_hd_read(uint8_t addr, uint8_t reg, uint8_t *data_buf, uint16_t length)
{
if (_current_addr != addr)
{
i2c_hardware_init(addr);
}
uint16_t error = 1;
error = i2c_recv_data(I2C_DEVICE_0, ®, 1, data_buf, length);
return error;
}
- main 函数里最后是一个 while(1)循环,读取触摸屏的坐标 XY 值,然后通过串口打印出来,再显示到 LCD 显示屏上。每次显示完成后都需要刷新以下显示的位置,否则旧数据会重叠到一起,所以 lcd_clear_coord 函数就是清除坐标的作用。
while (1)
{
/* 刷新数据位,清空上次显示的数据 */
if (is_refresh)
{
lcd_clear_coord();
is_refresh = 0;
}
/* 如果触摸到触摸屏的时候 */
if (ft6236.touch_state & TP_COORD_UD)
{
ft6236.touch_state &= ~TP_COORD_UD;
/* 扫描触摸屏 */
ft6236_scan();
/* 串口打印X Y 坐标 */
printf("X=%d, Y=%d \n ", ft6236.touch_x, ft6236.touch_y);
sprintf(coord, "(%d, %d)", ft6236.touch_x, ft6236.touch_y);
lcd_draw_string(120, 200, coord, BLUE);
is_refresh = 1;
}
/* 延迟80毫秒保证屏幕数据正常刷新 */
msleep(80);
}
- 先使用 lcd_set_area 函数设定显示坐标的区域,然后再写入白色的值(0XFFFFFFFF),以此来刷新显示的内容。如果背景图片的坐标区域不是空白的,则无法使用此方法来刷新。
void lcd_clear_coord(void)
{
uint32_t color = 0xFFFFFFFF;
uint8_t x1 = 120;
uint8_t y1 = 200;
uint8_t width = 100;
uint8_t height = 16;
lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
tft_fill_data(&color, width * height / 2);
}
10.编译调试,烧录运行
进入自己项目 build目录,运行以下命令编译。
cmake .. -DPROJ=watchdog -G "MinGW Makefiles"
make
实验现象
烧录完成固件后,系统会弹出一个终端界面,如果没有弹出终端界面的可以打开串口助手显示调试内容。
同时 LCD 显示屏上也会显示当前触摸的坐标,当松开手时,坐标也会消失。每次移动手指,改变触摸的位置,对应的触摸点坐标也会改变。
实验总结
- K210 开发板的触摸屏是电容式触摸屏,可以使用手指直接触摸使用。
- 触摸板使用的是 I2C 通讯,读取数据后需要转化计算一下才能得到实际的触摸 坐标。
- 触摸板的相关寄存器放在项目的 README.md 文件中,具体寄存器功能请查看硬 件相关资料中触摸屏资料