当前位置: 首页 > news >正文

Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记

文章目录

  • 1.启动流程
    • 1.1 最先进入的文件:head_s.S
    • 1.2 start_kernel()函数所在的文件:init.c
    • 1.3 input_init()函数所在文件:sys_input.c
    • 1.4 INPUT_LKeyDevInit()所在文件:keyboarddev.c
    • 1.5 esINPUT_RegLdev()所在文件:input.c
      • 1.5.1 来到这里,无法与后面的硬件初始化搭上关系。
  • 2.从底层操作硬件的函数往前面跟踪
    • 2.1 实现对adc按键硬件初始化的函数 sunxi_keyboard_init()
      • 2.1.1 本函数是被do_initcalls()调用的
      • 2.1.2 本函数注册了中断函数keyboard_irq_callback(),直接产生按键消息
  • 3.根据分压电阻的实际阻值修改代码
    • 3.1 关键代码分析
    • 3.1 根据硬件不同,重新计算参数
  • 4. mq-r(F133)按键接法

本文是自己为了厘清Melis4.0[D1s]启动时加载输入按键驱动流程而做的笔记。
开发板使用了mangopi-MQ-R(F133),melis只支持spinor flash,不支持spinand和sd卡。而mangopi-MQ-R(F133)没有焊接spinor flash,必须自己购买补焊。
我在立创商城买的华邦的 W25Q128JVSIQ
nor flash W25Q128JVSIQ
参考文章:

  1. 作者:waxly-,文章 :全志 Melis-4.0(rt-thread内核) 环境搭建与初步编译介绍

1.启动流程

Melis4.0的RTOS内核有2种选择,我们选的是RT-Thread:
在这里插入图片描述
关于RT-Thread启动流程的详细资料可以参考官方文档:RT-Thread Nano 移植原理。
但是Melis的启动流程似乎与RT-Thread关系不大,参考全志官方文档《Melis4.0 RTOS系统开发指南》。
下面做部分摘录,稍作整理:

1.1 最先进入的文件:head_s.S

该文件路径为 《D1s-Melis\ekernel\arch\riscv\rv64gc\head_s.S》,完成以下功能:

• bss 段的清零;
• sp 栈指针的初始化;
• mmu 初始化和页表基地址赋值;
• 异常统一入口赋值;
• 跳转至 start_kernel 函数;

1.2 start_kernel()函数所在的文件:init.c

该文件路径为 《D1s-Melis\ekernel\arch\riscv\sunxi\init.c》start_kernel()函数间接调用input_init()函数完成输入设备初始化函数的调用。
在这里插入图片描述
这里的awos_init_thread()函数还调用do_initcalls(),而do_initcalls()调用了sunxi_keyboard_init()。下面摘录官方文章介绍do_initcalls()的内容:

do_initcalls()函数通过层层调用,调用了initcall_levels数组定义的函数地址标识,这些地址标识在riscv/lds/kernel.lds中定义,表示代码段名称为initcallxx.init类的代码,c 文件通过__attribute__((section(“text”))),指定函数或变量在链接时存放的代码段段名称。这个由source/include/melis/init.h文 件 中 的 宏 定 义___define_initcall(fn, id, .initcall##id)来 声 明 实现。
例 如:subsys_initcall(drv_dma_init);将 函 数 指 定 到 代 码 段.initcall4.init, 将 会 在 调用__initcall4_start时,把__initcall4_start到__initcall5_start代码段地址区间的函数接口执行一遍。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 input_init()函数所在文件:sys_input.c

该文件路径为 《D1s-Melis\ekernel\legacy\input\sys_input.c》,按键初始化是默认有的,触摸则根据配置参数决定是否初始化,鼠标则默认没有。按键设备的初始化函数为INPUT_LKeyDevInit(),继续跟踪。

int32_t input_init(void)
{__inf("input system initialize....");if (INPUT_CoreInit() != EPDK_OK){__wrn("INPUT_CoreInit failed");return EPDK_FAIL;}if (INPUT_LKeyDevInit() != EPDK_OK){__wrn("INPUT_LkeyDevInit failed");INPUT_CoreExit();return EPDK_FAIL;}
#if 0if (INPUT_LMouseDevInit() != EPDK_OK){__wrn("INPUT_LMouseDevInit failed");INPUT_LKeyDevExit();INPUT_CoreExit();return EPDK_FAIL;}
#endif#if CONFIG_SUPPORT_TOUCHPANELif (INPUT_LTSDevInit() != EPDK_OK){__wrn("INPUT_LTPDevInit failed");//INPUT_LMouseDevExit();INPUT_LKeyDevExit();INPUT_CoreExit();return EPDK_FAIL;}
#endifreturn EPDK_OK;
}

1.4 INPUT_LKeyDevInit()所在文件:keyboarddev.c

该文件路径为 《D1s-Melis\ekernel\legacy\input\keyboard\keyboarddev.c》,调用了esINPUT_RegLdev()

1.5 esINPUT_RegLdev()所在文件:input.c

该文件路径为 《D1s-Melis\ekernel\legacy\input\input\input.c》

1.5.1 来到这里,无法与后面的硬件初始化搭上关系。

上面是从开始往后面跟踪调用子函数,下面是从子函数跟踪被哪个上级函数调用,来到这里失联了。

2.从底层操作硬件的函数往前面跟踪

根据本节的分析,adc按键的功能是默认的,不用使用 make menuconfig 进行配置。不过为了保险起见,还是做足下面的配置:
在这里插入图片描述
在这里插入图片描述

2.1 实现对adc按键硬件初始化的函数 sunxi_keyboard_init()

该文件路径为 《D1s-Melis\ekernel\drivers\drv\source\input\keyboard\sunxi_keyboard.c》

2.1.1 本函数是被do_initcalls()调用的

在文件sunxi_keyboard.c有下面的语句:

late_initcall(sunxi_keyboard_init);

对应的宏定义在文件 《D1s-Melis\include\melis\init.h》

#define late_initcall(fn)		__define_initcall(fn, 7)

于是变成了指针数组 initcall_levels 的一员:

static initcall_entry_t *initcall_levels[] =
{__initcall0_start,__initcall1_start,__initcall2_start,__initcall3_start,__initcall4_start,__initcall5_start,__initcall6_start,__initcall7_start,__initcall_end,
};

最终在do_initcalls()被调用,do_initcalls()所在的文件为 《D1s-Melis\ekernel\arch\common\initcall.c》

2.1.2 本函数注册了中断函数keyboard_irq_callback(),直接产生按键消息

int sunxi_keyboard_init(void)
{.......hal_gpadc_init();hal_gpadc_channel_init(GP_CH_0);hal_gpadc_register_callback(GP_CH_0, keyboard_irq_callback);return 0;
}

keyboard_irq_callback()可以直接发送系统消息:

int keyboard_irq_callback(uint32_t data_type, uint32_t data)
{......if (key_data->key_code  < key_config.key_num){if (key_flag == 0){console_LKeyDevEvent(NULL,  EV_KEY,  key_data->scankeycodes[key_data->key_code],  1);console_LKeyDevEvent(NULL,  EV_SYN,  0,  0);key_flag = 1;}......
}

3.根据分压电阻的实际阻值修改代码

官方的adc按键部分电路:
在这里插入图片描述
我用万能板焊接的电路板,使用了手头已有的电阻4.7k,10k,20k,30k:
在这里插入图片描述

3.1 关键代码分析

计算键值的关键代码:

struct sunxikbd_config key_config =
{.measure = 1800,.key_num = 5,.key_vol = {210, 410, 590, 750, 880},.scankeycodes = {KPAD_UP, KPAD_DOWN, KPAD_ENTER, KPAD_MENU, KPAD_RETURN},.name = "sunxi-keyboard"
};static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,      /* key 1, 0-8 */1, 1, 1, 1, 1,                  /* key 2, 9-13 */2, 2, 2, 2, 2, 2,               /* key 3, 14-19 */3, 3, 3, 3, 3, 3,               /* key 4, 20-25 */4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,    /* key 5, 26-36 */5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,    /* key 6, 37-39 */6, 6, 6, 6, 6, 6, 6, 6, 6,      /* key 7, 40-49 */7, 7, 7, 7, 7, 7, 7             /* key 8, 50-63 */
};

大概思路是将AD值处理后(大约是除以32),在keypad_mapindex[]里面查表,得到一个在0-4(共5个按键)范围内的值,再从key_config. scankeycodes[]里面查表得到最终的键值。以key1为例,key1按下时的AD值(理论值) 经过处理,应该是4,这样可以使允许误差最大化。

3.1 根据硬件不同,重新计算参数

K0对应的AD理论值为183,除以32得 5.7,约等于6,那么可以取:

static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,     /* key 1, 0-10 */

K1对应的AD理论值为524,除以32得 16.3,约等于16,那么可以取:

static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,     /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1,         /* key 2, 11-20 */

K2对应的AD理论值为1055,除以32得 33,那么可以取:

static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,     /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1,         /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,					  /* key 3, 21-36 */

K3对应的AD理论值为1448,除以32得 45.2,约等于45,那么可以取:

static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,     /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1,         /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 			 /* key 3, 21-39 */3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3/* key 4, 40-50 */

K3对应的AD理论值为1878,除以32得 58.6,约等于58,那么可以取:

static unsigned char keypad_mapindex[128] =
{0, 0, 0, 0, 0, 0, 0, 0, 0,  0, 0,     /* key 1, 0-10 */1, 1, 1, 1, 1, 1, 1, 1, 1, 1,         /* key 2, 11-20 */2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 			 /* key 3, 21-39 */3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3/* key 4, 40-50 */4, 4, 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4, 4, 4, 4, 4, 4,          /* key 5, 51-69 */

其实,这个表是由下面的代码重新计算,并覆盖掉的:

static int sunxikbd_data_init(struct sunxikbd_drv_data *key_data, struct sunxikbd_config *sunxikbd_config)
{int i, j = 0;int key_num = 0;unsigned int resol;unsigned int key_vol[KEY_MAX_CNT];key_num = sunxikbd_config->key_num;if (key_num < 1 || key_num > KEY_MAX_CNT){return -1;}resol = sunxikbd_config->measure / MAXIMUM_SCALE;for (i = 0; i < key_num; i++){key_data->scankeycodes[i] = sunxikbd_config->scankeycodes[i];}for (i = 0; i < key_num; i++){key_vol[i] = sunxikbd_config->key_vol[i];}for (i = 0; i < (key_num - 1); i++){key_vol[i] += (key_vol[i + 1] - key_vol[i]) / 2;}
/*for (i = 0; i < MAXIMUM_SCALE; i++){if (i * resol > key_vol[j]){j++;}keypad_mapindex[i] = j;}
*/key_data->last_key_code = INITIAL_VALUE;return 0;
}

我因为还没看懂这个函数的逻辑,把其中覆盖keypad_mapindex[128]的代码屏蔽了。

4. mq-r(F133)按键接法

在这里插入图片描述

相关文章:

Melis4.0[D1s]:1.启动流程(与adc按键初始化相关部分)跟踪笔记

文章目录1.启动流程1.1 最先进入的文件&#xff1a;head_s.S1.2 start_kernel()函数所在的文件&#xff1a;init.c1.3 input_init()函数所在文件&#xff1a;sys_input.c1.4 INPUT_LKeyDevInit()所在文件&#xff1a;keyboarddev.c1.5 esINPUT_RegLdev()所在文件&#xff1a;in…...

GNU make 中文手册 第三章:Makefile 总述

一、Makefile 总述 3.1 Makefile 的内容 在一个完整的 Makefile 中&#xff0c;包含了 5 个东西&#xff1a;显式规则、隐含规则、变量定义、指示符和注释。关于“规则”、“变量” 和 “Makefile 指示符” 将在后续的章节进行详细的讨论。本章讨论的是一些基本概念。 显式规…...

简历的专业技能怎么写?排版需要注意的事项

一、简历的专业技能怎么写? 首先,先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几 天时间学习一下,然后在简历上可以写上自己了解这个技…...

【Git】为什么需要版本控制?版本控制工具有那些?

目录 一、为什么需要版本控制&#xff1f; 二、版本控制工具有那些&#xff1f; &#x1f49f; 创作不易&#xff0c;不妨点赞&#x1f49a;评论❤️收藏&#x1f499;一下 一、为什么需要版本控制&#xff1f; 首先我们要知道什么是版本控制&#xff1f;对版本控制进行文字…...

SSH远程执行Python3 Error: UnicodeEncodeError: ‘ascii‘ codec

首先确定要执行脚本服务器的语言编码环境&#xff0c;执行 # locale -a C en_US.utf8 POSIX # locale LANGen_US.utf8 LC_CTYPE"en_US.utf8" LC_NUMERIC"en_US.utf8" LC_TIME"en_US.utf8" LC_COLLATE"en_US.utf8" LC_MONETARY"…...

极简TypeScript教程--面向对象

在早期的JavaScript开发中&#xff08;ES5&#xff09;我们需要通过函数和原型链来实现类和继承&#xff0c;从ES6开始&#xff0c;引入了class关键字&#xff0c;可以更加方便的定义和使用类。TypeScript作为JavaScript的超集&#xff0c;也是支持使用class关键字的&#xff0…...

java TCP/UDP、Socket、URL网络编程详解

文章目录网络通信协议通信双方地址端口号IP地址InetAddress类Socket 网路编程Socket类的常用构造器Socket类的常用方法UDP协议什么是UDP协议UDP网络编程DatagramSocket 构造方法DatagramSocket 常用方法DatagramPacket常用方法实现步骤单向数据发收的UDP程序双向数据发收的UDP程…...

【C语言】宏

&#x1f680;write in front&#x1f680; &#x1f4dc;所属专栏&#xff1a;> c语言学习 &#x1f6f0;️博客主页&#xff1a;睿睿的博客主页 &#x1f6f0;️代码仓库&#xff1a;&#x1f389;VS2022_C语言仓库 &#x1f3a1;您的点赞、关注、收藏、评论&#xff0c;是…...

【测试面试】自我分析+功能+接口自动化+性能测试面试题(大全),知己知彼百战百胜......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 分析自己和面试企业…...

ASE4N65SE-ASEMI高压MOS管ASE4N65SE

编辑-Z ASE4N65SE在TO-220F封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为2.5Ω&#xff0c;是一款N沟道高压MOS管。ASE4N65SE的最大脉冲正向电流ISM为16A&#xff0c;零栅极电压漏极电流(IDSS)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。ASE4N65S…...

MyBatis概述环境搭建(一)

&#x1f697;MyBatis学习起始站~ &#x1f6a9;本文已收录至专栏&#xff1a;数据库学习之旅 &#x1f44d;希望您能有所收获 一.什么是MyBatis (1) 引言 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDB…...

3.8国际妇女节即将到来,跨境卖家如何做好选品和营销?

不知不觉&#xff0c;时间已来到了2月末&#xff0c;一年一度的三八国际妇女节也即将来临。三八节又称女神节&#xff0c;这不仅是庆祝女性伟大贡献的日子&#xff0c;也是跨境卖家们促销的大好时机。 有数据显示&#xff0c;女性是跨境消费的主力人群&#xff0c;占比超七成&…...

Glue Connector 和 Connection 的关系与区别

AWS Glue作为一种无服务器产品&#xff0c;其运行环境是“不可预知”的&#xff0c;也就是“一个黑盒”&#xff0c;所以如何能连接一些自有数据源是Glue必须考虑并给予满足的&#xff0c;为此&#xff0c;Glue给出的解决方案就是Connector和Connection&#xff0c;一个connect…...

如何使用ngxin的 upstream

1.引言&#xff1a; 1.1反向代理&#xff1a; 反向代理是充当Web服务器网关的代理服务器。当您将请求发送到使用反向代理的Web服务器时&#xff0c;他们将先转到反向代理&#xff0c;由该代理将确定是将其路由到Web服务器还是将其阻止。 这意味着有了反向代理&#xff0c;您…...

Java数组,超详细整理,适合新手入门

目录 一、什么是Java中的数组&#xff1f; 二、数组有哪些常见的操作&#xff1f; 三、数组的五种赋值方法和使用方法 声明数组 声明数组并且分配空间 声明数组同时赋值(1) 声明数组同时赋值(2) 从控制台输入向数组赋值 四、求总和平均 五、求数组中最大值最小值 六…...

1.3数据传输控制方式:IO数据传输控制方式、程序控制(查询)方式、程序中断方式、DMA方式、通道方式、I/O处理机

1.3数据传输控制方式&#xff1a;IO数据传输控制方式、程序控制&#xff08;查询&#xff09;方式、程序中断方式、DMA方式、通道方式、I/O处理机程序控制&#xff08;查询&#xff09;方式程序中断方式DMA方式通道方式、I/O处理机I/O数据传输方式&#xff0c;由软件到硬件发展…...

Linux 设置语言

文章目录1. 临时设置环境变量2. 默认语言设置3. 语言包4. 安装浏览器 chromium1. 临时设置环境变量 通过设置环境变量&#xff0c;可以使单个命令使用另一种语言LANG $ LANGfr_FR.utf8 date mar. mai 24 12:16:51 CDT 2022后续命令将恢复为使用系统的默认语言进行输出。该loc…...

Python基础-数据类型之集合

一、集合的定义 集合&#xff1a;是一个无序的没有重复元素的序列&#xff0c;因此不能通过索引来进行操作 1&#xff1a;使用set()创建集合 set(object) # 参数为一个序列&#xff0c;整型不能作为参数 set_a set("abcb") print(set_a) # {b, a, c} 2&…...

[Css]Grid属性简单陈列(适合开发时有基础的快速过一眼)

[css进阶]Grid属性简介 文章目录[css进阶]Grid属性简介典型需求网格容器的属性displaygrid-template-columns和grid-template-rowsgrid-template-areasgrid-templategrid-column-gap grid-row-gapgrid-gapjustify-itemsalign-itemsjustify-contentalign-contentgrid-auto-colum…...

100种思维模型之启发式偏差思维模型-017

曾国藩在给儿子的一封家书中曾写道&#xff1a;余于凡事皆用困知勉行工夫&#xff0c;尔不可求名太骤&#xff0c;求效太捷也。熬过此关&#xff0c;便可少进。再进再困&#xff0c;再熬再奋&#xff0c;自有亨通精进之日。 不急躁不求捷径&#xff0c;小火慢炖&#xff0c;将事…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...