移植openharmony之调试gt911触摸

article/2025/8/23 3:11:17

最近在调试触摸驱动,分析了一点openharmony的hdf框架下的触摸,将过程记录下,首先肯定是加载input设备管理驱动:input设备管理驱动由HDF驱动加载,完成设备manager的创建并对其初始化。如下图所示,我这里就是先加载了drivers/framework/model/input/driver/hdf_input_device_manager.c驱动文件。这种文件一般不需要修改,直接使用即可。都是提供给其他文件使用的接口居多。
在这里插入图片描述
然后就是加载平台驱动过程了,因为我们是触摸屏,所以加载的文件drivers/framework/model/input/driver/hdf_touch.c文件,这个文件可以着重分析下

struct HdfDriverEntry g_hdfTouchEntry = {.moduleVersion = 1,.moduleName = "HDF_TOUCH",.Bind = HdfTouchDriverBind, //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架.Init = HdfTouchDriverProbe, //.Release = HdfTouchDriverRelease,
};HDF_INIT(g_hdfTouchEntry);

那么首先执行的函数为HdfTouchDriverProbe,

static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device)
{int32_t ret;TouchBoardCfg *boardCfg = NULL;TouchDriver *touchDriver = NULL;HDF_LOGI("%s: enter", __func__);if (device == NULL) {HDF_LOGE("%s: param is null", __func__);return HDF_ERR_INVALID_PARAM;}boardCfg = BoardConfigInstance(device); //主要实现数据配置解析功能if (boardCfg == NULL) {return HDF_ERR_MALLOC_FAIL;}touchDriver = TouchDriverInstance(); //只是申请变量并初始化结构体if (touchDriver == NULL) {goto EXIT;}ret = TouchDriverInit(touchDriver, boardCfg);if (ret == HDF_SUCCESS) {touchDriver->hdfTouchDev = device;touchDriver->boardCfg = boardCfg;AddTouchDriver(touchDriver);device->priv = (void *)touchDriver;HDF_LOGI("%s: %s exit succ", __func__, boardCfg->attr.devName);return HDF_SUCCESS;}EXIT:OsalMemFree(boardCfg);if (touchDriver != NULL) {touchDriver->boardCfg = NULL;OsalMemFree(touchDriver);}return HDF_FAILURE;
}

重点先看下这个函数,是如何解析板级配置信息的,

static TouchBoardCfg *BoardConfigInstance(struct HdfDeviceObject *device)
{TouchBoardCfg *boardCfg = (TouchBoardCfg *)OsalMemAlloc(sizeof(TouchBoardCfg));if (boardCfg == NULL) {HDF_LOGE("%s: instance board config failed", __func__);return NULL;}(void)memset_s(boardCfg, sizeof(TouchBoardCfg), 0, sizeof(TouchBoardCfg));if (ParseTouchBoardConfig(device->property, boardCfg) != HDF_SUCCESS) {HDF_LOGE("%s: parse board config failed", __func__);OsalMemFree(boardCfg);boardCfg = NULL;}return boardCfg;
}

然后drivers/framework/model/input/driver/input_config_parser.c里面执行ParseTouchBoardConfig函数

int32_t ParseTouchBoardConfig(const struct DeviceResourceNode *node, TouchBoardCfg *config)
{int32_t ret;struct DeviceResourceIface *parser = NULL;if (node == NULL || config == NULL) {HDF_LOGE("%s: input param is null", __func__);return HDF_FAILURE;}parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if (parser == NULL) {HDF_LOGE("%s: invalid parser", __func__);return HDF_FAILURE;}config->boardNode = node;const struct DeviceResourceNode *attrNode = parser->GetChildNode(node, "inputAttr");const struct DeviceResourceNode *busNode = parser->GetChildNode(node, "busConfig");const struct DeviceResourceNode *pinsNode = parser->GetChildNode(node, "pinConfig");const struct DeviceResourceNode *powerNode = parser->GetChildNode(node, "powerConfig");const struct DeviceResourceNode *featureNode = parser->GetChildNode(node, "featureConfig");if (attrNode == NULL || busNode == NULL || pinsNode == NULL || powerNode == NULL || featureNode == NULL) {HDF_LOGE("%s: get child node fail!", __func__);return HDF_FAILURE;}ret = ParseAttr(parser, attrNode, &config->attr);CHECK_PARSER_RET(ret, "ParseAttr");ret = ParseBus(parser, busNode, &config->bus);CHECK_PARSER_RET(ret, "ParseBus");ret = ParsePins(parser, pinsNode, &config->pins);CHECK_PARSER_RET(ret, "ParsePins");ret = ParsePower(parser, powerNode, &config->power);CHECK_PARSER_RET(ret, "ParsePower");ret = ParseFeature(parser, featureNode, &config->feature);CHECK_PARSER_RET(ret, "ParseFeature");return HDF_SUCCESS;
}

重点展开此函数 DeviceResourceGetIfaceInstance,
struct DeviceResourceIface *parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
执行的是drivers/framework/ability/config/device_resource_if.c,其实就是返回一个可以操作获取hcs资源的接口函数,主要的接口函数如下

 static void HcsIfaceConstruct(struct DeviceResourceIface *instance)
{instance->GetRootNode = HcsGetRootNode;instance->GetBool = HcsGetBool;instance->GetUint8 = HcsGetUint8;instance->GetUint8ArrayElem = HcsGetUint8ArrayElem;instance->GetUint8Array = HcsGetUint8Array;instance->GetUint16 = HcsGetUint16;instance->GetUint16ArrayElem = HcsGetUint16ArrayElem;instance->GetUint16Array = HcsGetUint16Array;instance->GetUint32 = HcsGetUint32;instance->GetUint32ArrayElem = HcsGetUint32ArrayElem;instance->GetUint32Array = HcsGetUint32Array;instance->GetUint64 = HcsGetUint64;instance->GetUint64ArrayElem = HcsGetUint64ArrayElem;instance->GetUint64Array = HcsGetUint64Array;instance->GetString = HcsGetString;instance->GetStringArrayElem = HcsGetStringArrayElem;instance->GetElemNum = HcsGetElemNum;instance->GetNodeByMatchAttr = HcsGetNodeByMatchAttr;instance->GetChildNode = HcsGetChildNode;instance->GetNodeByRefAttr = HcsGetNodeByRefAttr;
}

回到之前,那我们操作const struct DeviceResourceNode *attrNode = parser->GetChildNode(node, “inputAttr”);函数,其实执行的就是HcsGetChildNode函数,此函数定义在drivers/framework/ability/config/hcs_parser/src/hcs_tree_if.c文件中

const struct DeviceResourceNode *HcsGetChildNode(const struct DeviceResourceNode *node, const char *nodeName)
{struct DeviceResourceNode *child = NULL;if ((node == NULL) || (nodeName == NULL)) {HDF_LOGE("%s failed, the node or nodeName is NULL", __func__);return NULL;}for (child = node->child; child != NULL; child = child->sibling) {if ((child->name != NULL) && (strcmp(nodeName, child->name) == 0)) {break;}}return child;
}

很简单,直接遍历查找匹配字段返回即可,所以其实就是遍历节点,然后返回对应字段的描述。通过上述函数,重要的节点信息已经保存到变量boardCfg中,然后执行TouchDriverInit函数,将会使用到这些数据进行初始化操作。

static int32_t TouchDriverInit(TouchDriver *driver, TouchBoardCfg *config)
{int32_t ret = TouchInitData(driver, config); //展开如下,可以看出其实就是给变量赋值
/*
static int32_t TouchInitData(TouchDriver *driver, TouchBoardCfg *config)
{driver->devType = config->attr.devType; //获取hcs中的inputAttr节点下的inputType字段driver->devName = config->attr.devName; //获取hcs中的inputAttr节点下的devName字段driver->i2cClient.i2cCfg.busNum = config->bus.i2c.busNum;//获取hcs中的busConfig节点下的ParseBus字段driver->irqStopFlag = false;return HDF_SUCCESS;
}*/CHECK_RETURN_VALUE(ret);ret = TouchSetupBus(driver, config); //主要打开设备操作节点,类似linux应用层,打开dev/i2c节点/*static int32_t TouchSetupBus(TouchDriver *driver, TouchBoardCfg *config)
{uint8_t busType = config->bus.busType;uint8_t busNum = config->bus.i2c.busNum;if (busType == I2C_TYPE) {uint32_t i2cClkAddr = config->bus.i2c.i2cClkReg[0];uint32_t i2cClkValue = config->bus.i2c.i2cClkReg[1];uint32_t i2cDataAddr = config->bus.i2c.i2cDataReg[0];uint32_t i2cDataValue = config->bus.i2c.i2cDataReg[1];if (InputPinMuxCfg(i2cClkAddr, REGISTER_BYTE_SIZE, i2cClkValue) != HDF_SUCCESS) {return HDF_FAILURE;}if (InputPinMuxCfg(i2cDataAddr, REGISTER_BYTE_SIZE, i2cDataValue) != HDF_SUCCESS) {return HDF_FAILURE;}//get i2c handledriver->i2cClient.i2cHandle = I2cOpen(busNum);if (driver->i2cClient.i2cHandle == NULL) {HDF_LOGE("%s: open i2c%u failed", __func__, busNum);return HDF_FAILURE;}return HDF_SUCCESS;}if (busType == SPI_TYPE) {HDF_LOGI("%s: setup spi bus succ", __func__);return HDF_SUCCESS;}return HDF_FAILURE;
}*/CHECK_RETURN_VALUE(ret);ret = OsalMutexInit(&driver->mutex);CHECK_RETURN_VALUE(ret);driver->initedFlag = true;return HDF_SUCCESS;
}

然后再加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。这里使用的是gt911触摸芯片,所以执行的文件是drivers/framework/model/input/driver/touchscreen/touch_gt911.c,
入口函数内容如下

static int32_t HdfGoodixChipInit(struct HdfDeviceObject *device)
{TouchChipCfg *chipCfg = NULL;ChipDevice *chipDev = NULL;HDF_LOGI("%s: enter", __func__);if (device == NULL) {return HDF_ERR_INVALID_PARAM;}chipCfg = ChipConfigInstance(device);if (chipCfg == NULL) {return HDF_ERR_MALLOC_FAIL;}chipDev = ChipDeviceInstance();if (chipDev == NULL) {goto EXIT;}chipDev->chipCfg = chipCfg;chipDev->ops = &g_gt911ChipOps;chipDev->chipName = chipCfg->chipName;chipDev->vendorName = chipCfg->vendorName;if (RegisterChipDevice(chipDev) != HDF_SUCCESS) {goto EXIT1;}HDF_LOGI("%s: exit succ, chipName = %s", __func__, chipCfg->chipName);return HDF_SUCCESS;EXIT1:OsalMemFree(chipDev);
EXIT:FreeChipConfig(chipCfg);return HDF_FAILURE;
}

执行函数

static TouchChipCfg *ChipConfigInstance(struct HdfDeviceObject *device)
{TouchChipCfg *chipCfg = (TouchChipCfg *)OsalMemAlloc(sizeof(TouchChipCfg));if (chipCfg == NULL) {HDF_LOGE("%s: instance chip config failed", __func__);return NULL;}(void)memset_s(chipCfg, sizeof(TouchChipCfg), 0, sizeof(TouchChipCfg));if (ParseTouchChipConfig(device->property, chipCfg) != HDF_SUCCESS) {HDF_LOGE("%s: parse chip config failed", __func__);OsalMemFree(chipCfg);chipCfg = NULL;}return chipCfg;
}
int32_t ParseTouchChipConfig(const struct DeviceResourceNode *node, TouchChipCfg *config)
{int32_t ret;struct DeviceResourceIface *parser = NULL;if (node == NULL || config == NULL) {HDF_LOGE("%s: point is null", __func__);return HDF_FAILURE;}parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if (parser == NULL) {HDF_LOGE("%s: instance parser failed", __func__);return HDF_FAILURE;}config->chipNode = node;ret = parser->GetString(node, "chipName", &config->chipName, NULL);CHECK_PARSER_RET(ret, "GetString");ret = parser->GetString(node, "vendorName", &config->vendorName, NULL);CHECK_PARSER_RET(ret, "GetString");ret = parser->GetString(node, "chipInfo", &config->chipInfo, NULL);CHECK_PARSER_RET(ret, "GetString");ret = parser->GetUint16(node, "chipVersion", &config->chipVersion, 0);CHECK_PARSER_RET(ret, "GetUint16");ret = parser->GetUint8(node, "busType", &config->bus.busType, 0);CHECK_PARSER_RET(ret, "GetUint8");if (config->bus.busType == I2C) {ret = parser->GetUint16(node, "irqFlag", &config->bus.chipI2c.irqFlag, 0);CHECK_PARSER_RET(ret, "GetUint16");ret = parser->GetUint32(node, "deviceAddr", &config->bus.chipI2c.commAddr, 0);CHECK_PARSER_RET(ret, "GetUint32");ret = parser->GetUint32(node, "maxSpeed", &config->bus.chipI2c.maxSpeed, DEFAULT_I2C_SPEED);CHECK_PARSER_RET(ret, "GetUint32");} else {ret = parser->GetUint16(node, "irqFlag", &config->bus.chipSpi.irqFlag, 0);CHECK_PARSER_RET(ret, "GetUint16");ret = parser->GetUint8(node, "wordMode", &config->bus.chipSpi.wordMode, 0);CHECK_PARSER_RET(ret, "GetUint8");ret = parser->GetUint8(node, "commMode", &config->bus.chipSpi.commMode, 0);CHECK_PARSER_RET(ret, "GetUint8");ret = parser->GetUint32(node, "maxSpeed", &config->bus.chipSpi.maxSpeed, DEFAULT_SPI_SPEED);CHECK_PARSER_RET(ret, "GetUint32");}const struct DeviceResourceNode *pwrSeqNode = parser->GetChildNode(node, "powerSequence");if (pwrSeqNode == NULL) {HDF_LOGE("%s: get powerSequence child node failed", __func__);return HDF_FAILURE;}if (ParsePowerSequence(parser, pwrSeqNode, &config->pwrSeq) != HDF_SUCCESS) {return HDF_FAILURE;}return HDF_SUCCESS;
}

总之也是获取hcs资源为主,获取完器件资源后,然后就是调用RegisterChipDevice,将实例化的器件设备向平台驱动注册,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作,然后又回到hdf_touch.c文件中执行,

int32_t RegisterChipDevice(ChipDevice *chipDev)
{int32_t ret;InputDevice *inputDev = NULL;if ((chipDev == NULL) || (chipDev->chipCfg == NULL)) {return HDF_ERR_INVALID_PARAM;}ret = DeviceBindDriver(chipDev); //复制一些解析好的资源到传进去的变量中if (ret != HDF_SUCCESS) {HDF_LOGE("%s: chip device match driver failed", __func__);return HDF_FAILURE;}ret = ChipDriverInit(chipDev);if (ret != HDF_SUCCESS) {goto EXIT;}inputDev = InputDeviceInstance(chipDev);if (inputDev == NULL) {return HDF_ERR_MALLOC_FAIL;}ret = RegisterInputDevice(inputDev);if (ret != HDF_SUCCESS) {goto EXIT1;}chipDev->driver->inputDev = inputDev;chipDev->ops->SetAbility(chipDev);return HDF_SUCCESS;EXIT1:OsalMemFree(inputDev);
EXIT:chipDev->driver->device = NULL;return HDF_FAILURE;
}
static int32_t ChipDriverInit(ChipDevice *chipDev)
{int32_t ret = SetPowerOnTiming(chipDev);CHECK_RETURN_VALUE(ret);if ((chipDev->ops == NULL) || (chipDev->ops->Detect == NULL)) {return HDF_FAILURE;}ret = chipDev->ops->Detect(chipDev);CHECK_RETURN_VALUE(ret);HDF_LOGI("%s: chipDetect succ, ret = %d ", __func__, ret);#if defined(CONFIG_ARCH_SPRD)HDF_LOGI("%s: DAYU do not update firmware", __func__);
#elseret = chipDev->ops->UpdateFirmware(chipDev);CHECK_RETURN_VALUE(ret);HDF_LOGI("%s: update firmware success", __func__);
#endifret = SetupChipIrq(chipDev);CHECK_RETURN_VALUE(ret);return HDF_SUCCESS;
}

我这边在使用的时候,发现经常会出现i2c通信不正常的问题,抓取上电时序的波形比较乱,然后产生了追踪下如何执行的,后面发现,这里会去操作IO寄存器的值,但是我的已经在linux内核里面初始化过GPIO了,我只需要申请并使用就可,所以我这边这里不需要操作。

static int32_t InputPinMuxCfg(uint32_t regAddr, int32_t regSize, uint32_t regValue)
{
#if defined(CONFIG_ARCH_SPRD)return HDF_SUCCESS;
#endif
#ifdef USER_NOT_IOSET    //add by myselfreturn HDF_SUCCESS;
#endif                   //add enduint8_t *base = NULL;if (regAddr == 0) {HDF_LOGE("%s: regAddr invalid", __func__);return HDF_FAILURE;}base = OsalIoRemap(regAddr, regSize);if (base == NULL) {HDF_LOGE("%s: ioremap failed", __func__);return HDF_FAILURE;}OSAL_WRITEL(regValue, base);OsalIoUnmap((void *)base);return HDF_SUCCESS;
}

在这里插入图片描述
目前测试很多次,不会出现偶发性I2c通信不正常的问题了。
献上失败的打印log,这种情况一般是上电时序问题造成的,我是先在linux内核调试好了触摸,再在HDF框架中调试的,所以可以排除I2C通信问题。
在这里插入图片描述
最后经过测试发现,触摸驱动是乱的,对不上屏幕,然后对应本板子,做如下修改即可

diff --git a/drivers/framework/model/input/driver/hdf_touch.c b/drivers/framework/model/input/driver/hdf_touch.c
index 9602a3e136..459ec88dd1 100644
--- a/drivers/framework/model/input/driver/hdf_touch.c
+++ b/drivers/framework/model/input/driver/hdf_touch.c
@@ -194,7 +194,6 @@ static int32_t IrqHandle(uint16_t intGpioNum, void *data)HDF_LOGE("%s: disable irq failed, ret %d", __func__, ret);return HDF_FAILURE;}
-EventHandle(driver, driver->device);ret = GpioEnableIrq(intGpioNum);
@@ -272,9 +271,9 @@ static int32_t ChipDriverInit(ChipDevice *chipDev)#if defined(CONFIG_ARCH_SPRD)HDF_LOGI("%s: DAYU do not update firmware", __func__);#else
-    ret = chipDev->ops->UpdateFirmware(chipDev);
-    CHECK_RETURN_VALUE(ret);
-    HDF_LOGI("%s: update firmware success", __func__);
+//    ret = chipDev->ops->UpdateFirmware(chipDev);
+  //  CHECK_RETURN_VALUE(ret);
+    //HDF_LOGI("%s: update firmware success", __func__);

这里修改的主要是去掉固件下发的功能,我们不需要每次都下发固件,所以我们注释掉,使用默认的有可能造成触摸硬件本身就变乱的情况,请谨慎操作。

diff --git a/drivers/framework/model/input/driver/touchscreen/touch_gt911.c b/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
index fb3f5e96fd..6aa7f85b04 100644
--- a/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
+++ b/drivers/framework/model/input/driver/touchscreen/touch_gt911.c
@@ -101,11 +101,15 @@ static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uframe->fingers[i].x = ((buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) <<ONE_BYTE_OFFSET)) * resX / resY;
-#else
+#else/*frame->fingers[i].y = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |
-                                  ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
+                                  ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);*/
+           frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |
+                                  ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
+           frame->fingers[i].y = ((buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET));#endifif (frame->fingers[i].x == 0) {frame->fingers[i].x = X_OFFSET;
@@ -122,6 +126,7 @@ static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, u((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET));}frame->fingers[i].valid = true;
+//     HDF_LOGD("fr_x = %d,fr_y = %d\n",frame->fingers[i].x,frame->fingers[i].y);}}

我这里是通过HDF_LOGD(“fr_x = %d,fr_y = %d\n”,frame->fingers[i].x,frame->fingers[i].y);把触摸点打印出来了,然后慢慢调整即可。


http://chatgpt.dhexx.cn/article/baynqtox.shtml

相关文章

使用STM32+硬件IIC+DMA驱动GT系列触摸屏(GT911)

使用STM32硬件IICDMA驱动GT系列触摸屏&#xff08;GT911&#xff09; 初始化代码 /** brief GT911 初始化程序* param None* retval None*/ void GT911_init() {Dev_Now.GT911_RST0;GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin GT911_RST_PIN | GT911_INT_PIN;…

v3S驱动gt911触摸

文章目录 一、修改设备树二、编写驱动三、运行测试四、编译进内核1. 拷贝文件2. 修改对应的 Makefile3. 编译运行4.测试1.注释掉坐标信息 五、移植tslib1. buildroot配置tslib2. 配置tslib3. 测试 一、修改设备树 在sun8i-v3s-licheepi-zero-dock.dts中添加pio节点&#xff08…

gt911多点触摸实验

文章目录 一、设备树二、驱动程序三、测试四、编译进内核1. 拷贝文件2. 修改对应的 Makefile3. 编译运行4.测试 一、设备树 记得注释掉共用的引脚&#xff08;有好几处&#xff09; 在pinctrl_tsc节点下添加&#xff1a; pinctrl_tsc: tscgrp {fsl,pins <MX6UL_PAD_GPIO1_…

野火STM32F103驱动GT911触摸芯片

GT911触摸芯片 芯片介绍 GT911 是专为 7”~8”设计的新一代 5 点电容触控方案&#xff0c;拥有 26 个驱动通道和 14 个感 应通道&#xff0c;以满足更高的 touch 精度要求。 GT911 可同时识别 5 个触摸点位的实时准确位置&#xff0c;移动轨迹及触摸面积。并可根据主控需要&…

电容触摸屏控制芯片GT911

1.接口说明 GT9 非单层多点系列&#xff08;以下简称 GT9 系列&#xff09; 与主机接口共有 6 PIN&#xff0c;分别为&#xff1a; VDD、 GND、 SCL、SDA、 INT、 RESET。 主控的 INT 口线需具有上升沿或下降沿中断触发功能&#xff0c;并且当其在输入态时&#xff0c; 主控端必…

电容触摸屏GT911、GT928、GT9147的使用

一、介绍与硬件连接 GT911、GT928、GT9147都属于GT9系列非单层多点触控芯片&#xff0c;他们支持的触控点数不同&#xff08;GT928支持10个点、GT911支持5个点&#xff09;、驱动和感应通道也可能不同。可是他们的寄存器和IIC通讯时序是相同的&#xff0c;也就是说驱动程序是兼…

29-2-电容触摸屏控制芯片GT911

1.接口说明 GT9 非单层多点系列&#xff08;以下简称 GT9 系列&#xff09; 与主机接口共有 6 PIN&#xff0c;分别为&#xff1a; VDD、 GND、 SCL、SDA、 INT、 RESET。 主控的 INT 口线需具有上升沿或下降沿中断触发功能&#xff0c;并且当其在输入态时&#xff0c; 主控端…

hal编程 gt911 触摸芯片驱动 ( 枚举 结构体 熟用)( 安富莱 f429 4.3寸电容屏 )

使用板子类型以及屏幕类型 本文使用的是安富莱的板子stm32f429, 屏幕是TR433C1的4.3寸TFT显示屏, 480*272 RGB接口, 电容触摸 . I2C I2C简介、原理、时序请看这篇文章 使用cubemx工具的stm32用AT24C02实现简单密码(一点点面向对象的思想编程) gt911 gt911简介 gt911是深圳市…

python 倒计时手机app打卡_python 实现倒计时功能(gui界面)

运行效果&#xff1a; 完整源码&#xff1a; ##import library from tkinter import * import time from playsound import playsound ## display window root tk() root.geometry(400x300) root.resizable(0,0) root.config(bg blanched almond) root.title(techvidvan - cou…

桌面美化 Python tkinter倒计时工具

桌面美化 Python tkinter倒计时工具 效果一、壁纸设计二、倒计时小工具实现1.引入库2.倒计时函数3.绘制UI载入数据以及创建窗口创建Label控件控件布局绘制分割线绘制子窗口&#xff0c;用于修改倒计时目标其它设置 完整代码打包并开机自启动打包成EXE开机自启动 效果 使用tkin…

Python 内置模块tkinter —— 秒表计时器

# 秒表计时器""" 思考&#xff1a;1、怎么创建一个最简单的窗口&#xff1f;2、怎么保持窗口一直运行&#xff1f;3、不用方法mainloop&#xff08;&#xff09;怎么实现窗口一直运行&#xff1f;4、请问窗口的宽度*高度默认值为多少个像素点&#xff1f;5、利用…

Python-桌面计时器程序设计

该程序是我个人去年学习之初练习设计&#xff0c;程序功能并没有很完善和简便。设计想法是为了能够有一个可观性高的时间报时器&#xff0c;程序设计耗时2天&#xff0c;程序分成三个部分&#xff1a;主窗体、设置窗口、运行程序。 效果展示图 功能 正/反计时功能 到时提醒/关…

专利的写作

关于专利&#xff0c;由于是研究生阶段&#xff0c;发表专利有和学校合作的机构&#xff0c;支付2000给代理人&#xff0c;只需要将想法写明白&#xff0c;和代理人沟通好&#xff0c;受理那必然是有手就行。关于研究点&#xff0c;我已经推导完毕两个月了&#xff0c;因为要做…

手把手教你如何写专利申请书

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。众所周知&#xff0c;专利是最重要的一种知识产权&#xff0c;专利制度有利于保护技术创新&#xff0c;保护专利权人的利益&#xff0c;促进社会发展&#xff0c;把我国建设成一个科技强国&#xff0c;创新大国。对于企业而…

实用新型专利撰写

文件下载 表格可在国家知识产权网下载 直达地址 说明书摘要 1、文件写法 本实用新型公开了&#xff0c;其特征在于&#xff1a;______。主要组成部分&#xff1b;主要组成部分又由哪些部分组成&#xff1b;并说明位置关系&#xff08;位于xxx一侧&#xff0c;位于顶角处…&…

专利写法与相关知识

原文&#xff1a;https://www.cnblogs.com/bozhicheng/p/7204693.html by 薄小成 https://www.jianshu.com/p/4f48add262c1 这也是一个比较好的链接 从你幸运的进入大棚124实验室那刻起&#xff0c;发论文和写专利将贯穿你整个研究生生涯。相比于发论文&#xff0c;写专利这项工…

【数据库】简介

目录 0. 文章脉络 1. 信息和数据 2. 数据处理 3. 数据库管理数据的特点 4. 数据库系统 5. 数据库管理系统 6. 数据库的三级模式 0. 文章脉络 1. 信息和数据 信息是生活中能获取的一切事物的相关描述。用书上的话来说&#xff0c;信息就是一切新的&#xff0c;有用的事实…

数据库介绍之MySQL

文章目录 数据库优点分类常见数据库RDBMSSQL定义分类sql 脚本sql 语句规范 CRUD MySQL启动连接修改密码忘记密码三层结构结构表 三范式关系数据库设计三范式经典设计多对多一对多一对一 数据库 用来存储和管理数据的仓库 优点 可存储大量数据&#xff0c;方便检索保持数据的…

Cassandra数据库介绍

Cassandra 数据库&#xff0c;值得介绍的技术细节其实挺多的。因为它很多实现思路和关系型数据库或者其他的 NoSQL 数据库&#xff0c;是有一些不同的。这种不同是在数据库设计实现思路上也是根源上的。所以衍生开来的诸多特点&#xff0c;在介绍起来就不太容易和其他数据库去类…

MySQL入门之数据库介绍及MySQL介绍

------------------------------------------------------------------------------------------------------------- 教程大纲: http://blog.csdn.net/qq78442761/article/details/76018310 ------------------------------------------------------------------------------…