正点原子linux应用编程——提高篇1

在之前的入门篇学习中,都是直接在Ubuntu中进行验证的,对于嵌入式Linux系统来说,也是可以直接移植的,只需要使用嵌入式硬件平台对应的交叉编译工具编译应用程序即可运行

在嵌入式Linux系统中,编写的应用程序通常需要与硬件设备进行交互、操控硬件,譬如点亮开发板上的一颗LED灯、获取按键输入数据、在LCD屏上显示摄像头采集的图像、应用程序向串口发送数据或采集串口数据、网络编程等,那么本篇开始学习如何编写应用程序控制开发板上的各种硬件外设;Linux系统下,一切皆文件,也包括各种硬件设备,所以在Linux系统下,各种硬件设备是以文件的形式呈现给用户层,应用程序通过对文件的I/O操作来控制硬件设备

点亮LED

正点原子MP157/Mini开发板(包括核心板和底板)上一共有2颗供用户使用的LED小灯;LED通常是由GPIO所控制的,本章来学习如何编写应用程序控制LED灯的亮灭

应用层操控硬件的两种方法

设备文件便是各种硬件设备向应用层提供的一个接口,应用层通过对设备文件的I/O操作来操控硬件设备,设备文件通常在/dev/目录下,也把/dev 目录下的文件称为设备节点。当然还可以通过sysfs文件系统对硬件设备进行操控

sysfs文件系统

sysfs是一个基于内存的文件系统,同devfs、proc文件系统一样,称为虚拟文件系统;它的作用是将内核信息以文件的方式提供给应用层使用。sysfs文件系统的主要功能便是对系统设备进行管理,它可以产生一个包含所有系统硬件层次的视图

sysfs文件系统把连接在系统上的设备和总线组织成为一个分级的文件、展示设备驱动模型中各组件的层次关系。sysfs提供了一种机制,可以显式的描述内核对象、对象属性及对象间关系,用来导出内核对象(kernel object,譬如一个硬件设备)的数据、属性到用户空间,以文件目录结构的形式为用户空间提供对这些数据、属性的访问支持,如下图:

内核对象、对象属性及对象间关系

sysfs与/sys

sysfs文件系统挂载在/sys目录下。包括 block、bus、class、dev、devices、firmware、fs、kernel、module、power等,每个目录下又有许多文件或子目录。

devices就是设备存放的目录;bus是按照总线类型分类的目录;class是按照功能分类的,例如会有leds和input这些子目录;dev是按照设备号放置的目录。

总结

一般简单的设备会使用sysfs操控,例如LED、GPIO等;较复杂设备会使用设备节点操作/dev目录,例如LCD、触摸屏、摄像头等。

标准接口与非标准接口

Linux针对各种常见的设备进行分类,譬如LED类设备、输入类设备、FrameBuffer类设备、video类设备、PWM设备等等,并为每一种类型的设备设计了一套成熟的、标准的、典型的驱动实现的框架,这个就叫做设备驱动框架

如果不用内核的驱动框架而是自己写,那就是非标准接口。除此之外,还有很多被Linux系统归为杂散设备(misc device)。

LED硬件控制方式

MP157上有两个LED:

MP157的LED灯

对于MP157/Mini开发板出厂系统来说,这两颗LED设备使用的是Linux内核标准LED驱动框架注册而成,在/dev目录下并没有其对应的设备节点,其实现使用sysfs方式控制

可以进入/sys/class/leds目录进行查看,可以看到例如sys-led都是链接文件,链接到/sys/devices/platform/leds/leds/sys-led;而这个设备文件中,有三个文件,brightness,max_brightness以及trigger这三个关心的文件,分别控制亮度,显示最大亮度以及触发模式

如果通过cat命令进入trigger触发模式文件,方括号括起来的就是当前的触发方式。

直接控制,可以通过echo命令,示例如下:

echo timer > trigger //将 LED 触发模式设置为 timer
echo none > trigger //将 LED 触发模式设置为 none
echo 1 > brightness //点亮 LED echo 0 > brightness//熄灭 LED

编写LED应用程序

可以先通过宏定义完成文件路径的配置。

宏定义还可以用来直接定义传参错误时的printf信息,非常方便。

通过open打开LED灯的trigger和brightness文件,之后通过strcmp比较传参,借由write写入命令(均需要把trigger设置为none)。

开发板测试

把编译好的可执行文件,复制到开发板根文件系统中,然后可通过如下命令测试:

./testApp on # 点亮 LED
./testApp off # 熄灭 LED
./testApp trigger heartbeat # 将 LED 触发模式设置为 heartbeat

GPIO应用编程

应用层操控GPIO

进入到/sys/class/gpio目录下,包含了export、unexport以及许多gpiochipX的文件。

gpiochipX,就是当前SoC包含的GPIO控制器,而STM32MP157共有12个控制器,为GPIOA-GPIOK以及GPIOZ,分别对应gpiochip0、gpiochip16、……以此类推。

每一个gpiochipX中,还有base、label、ngpio以及其他一些不太关心的文件,这三个是属性文件,均为只读文件。base也就是最小的编号,label就是标签,ngpio就是引脚的个数

export,就是指定编号的GPIO引脚引出。导出成功后才能使用该GPIO。这是个只写文件,写入该文件即导出对应的GPIO引脚。导出后就会在/sys/class/gpio生成对应的文件夹

unexport,就是与export对立,取掉导出的GPIO。同样也是只写文件,使用完GPIO后需要调用来取消导出。

成功导出就会生成gpioX,其中主要关心四个属性文件active_low、direction、edge以及value。

  • direction:配置引脚的输入或输出模式。输出out,输入in。
  • value:输出模式下,配置0与1来对应低电平和高电平;输入模式下,读取value获取输入电平。
  • active_low:控制极性。
  • edge:控制中断触发模式。配置前需要先设为输入模式,通过none、rising、falling、both控制触发沿。

GPIO应用编程输出

gpio_config函数来配置GPIO,传入attr和val对应文件以及传入的值,通过sprintf来查看传入参数,通过open打开文件后,write写入命令。

main函数中,先通过access并掺入F_OK判断目录是否存在,如果为1,说明不存在,需要导出。此时open打开export文件,write写入命令来导出gpio。

之后调用gpio_config配置direction、active_low以及value。

GPIO应用编程输入

gpio_config是一样的,这里不再赘述。

main函数也类似,通过access判断是否存在,不存在则需要导出,open打开export后write写入来导出gpio。

然后gpio_config配置,direction就需要配为in,设置active_low然后设置edge为none非中断。

最后通过open打开文件后,read读取value的电平状态。

GPIO应用编程中断

其余的操作与输入是类似的,这里只看中断特有的代码。

gpio_config中,需要配置edge的中断触发方式,这里配置为both。

读取文件,需要用struct pollfd结构体,open打开存入pfd.fd中,然后设置pfd.events为POLLPRI(只关心高优先级数据可读,中断就是高优先级数据),之后先read一次后进入死循环中:调用poll,之后先判断pfd.revents&POLLPRI,为真后进入读取,lseek先把读位置移到头部后再read读取值

开发板测试

可以选择PE13测试,也就是编号为77的引脚:

MP157的PE13

GPIO输出

执行如下命令可测试:

./testApp 77 1 #控制 PE13 输出高电平
./testApp 77 0 #控制 PE13 输出低电平

GPIO输入

可通过如下命令读取:

./testApp 77

GPIO中断

本实验选用PE4,因为PE13是悬空的,电平状态不确定。PE4的编号就是68,执行如下命令测试:

./testApp 68 # 监测 PE4 引脚中断触发情况

输入设备应用程序

对于输入设备的应用编程其主要是获取输入设备上报的数据、输入设备当前状态等,譬如获取触摸屏当前触摸点的X、Y轴位置信息以及触摸屏当前处于按下还是松开状态

输入类设备编程

input子系统

基于input子系统注册成功的输入设备,都会在/dev/input 目录下生成对应的设备节点,设备节点名称通常为eventX(X表示一个数字编号0、1、2、3等),如/dev/input/event0、/dev/input/event1、
/dev/input/event2等,通过读取这些设备节点可以获取输入设备上报的数据。

读取数据流程

需要先打开设备文件;之后发起读操作(如read),如果无数据会进入休眠(阻塞I/O);有数据则会被唤醒,督导数据返回;应用程序处理读取数据。

应用程序解析数据

read操作获取的就是struct input_event结构体数据。主要关心齐总的type、code以及value成员变量。

type就是用来描述事件的类型;code是具体的事件,每一个事件类型均有不同的对应事件;value就是code对应事件所读取到的值。

读取完成,就是通过同步事件完成的,就是EV_SYN,内核完成了所有数据上报就会上报EV_SYN同步事件。

上报的同步事件通常为SYN_REPORT,value通常为0。

读取struct input_event数据

定义好对应的结构体后,open打开文件,并在死循环中调用read读取并printf打印出来。

开发板验证

MP157有两个按键,就是典型的输入设备:

MP157用户按键

在/dev/input目录下存在按键对应的设备节点;也可以查看/proc/bus/input/devices文件查询。

可通过如下命令执行:

./testApp /dev/input/event1

按键应用编程

对于按键,按下value=1,松开则value=0,长按则value=2。

main函数中,通过open打开文件,之后进入死循环:通过read读取传入struct input_event的结构体指针in_ev中,之后通过in_ev.value成员变量判断,按键的事件为EV_KEY,然后switch判断value的大小并执行printf打印。

开发板上验证可通过如下命令:

./testApp /dev/input/event1 # 测试开发板上的 KEY0 和 KEY1

触摸屏应用编程

解析触摸屏设备上报数据

触摸屏分为多点触摸设备和单点触摸设备。单点触摸一次完整数据只有一个触摸点数据:ABS_XXX时间承载上报触摸点信息;多点触摸则可能一次包含多个触摸点信息,大多是以ABS_MT_XXX事件承载上报数据。

MT的协议在触摸屏驱动的时候已经学过了,这里就不再多记录了。大多使用Type B协议,会先生成ABS_MT_SLOT事件并生成ABS_MT_TRACKING_ID之后上报坐标值。

可通过“cat /proc/bus/input/devices”查询LCD的设备名称来找到对应事件,然后同样执行之前的命令,把事件换成触摸屏就可以了。

获取触摸屏信息

可通过ioctl()函数一区触摸屏设备信息。原型如下:

#include <sys/ioctl.h>int ioctl(int fd, unsigned long request, ...);

第一个参数fd对应文件描述符;第二个参数request与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作,也就是请求指令;此函数是一个可变参函数,第三个参数需要根据request参数来决定,配合request来使用。

可在input.h中查询对应事件的宏定义。

可通过下面的宏,获取触摸屏的slot:

#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo)

例如获取触摸屏的最大触摸点数:定义struct input_absinfo结构体info,然后open打开设备文件后,通过ioctl,第二个参数为EVIOCGABS(ABS_MT_SLOT),读取之后info.maximum-info.minimum+1就是多大点数。

单点触摸应用程序

open打开设备文件,进入死循环:read读取输入事件,通过in_ev.type判断事件类型,如果是EV_ABS就是绝对位移事件,然后可通过in_ev.code判断是x还是y坐标;如果是EV_SYN同步事件,就可以通过in_ev.code判断是否为SYN_REPORT判断是什么事件,printf打印对应信息。

多点触摸应用程序

这里的区别就是定义了几个结构体来存储多个点的数据。

编写ts_read来读取数据,传入fd、max_slots以及自定义的ts_mt结构体指针mt(该结构体存储了每一个触摸点的信息)。其中定义了input_event的in_ev,static的slot以及tp_xy结构体数组xy(存储x和y坐标),之后通过memset先清空mt,然后将mt的id成员变量全部初始化为-2(-1表示触摸点删除,id>=0就是创建)。进入死循环中,read读取事件到in_ev中,通过switch判断in_ev.type,如果是EV_ABS那就通过in_ev.code判断是什么触摸屏事件并存储对应值;如果是EV_SYN那就进行数据上报,在in_ev.code是SYN_REPORT时将xy[]中数据存到mt[]中。

main函数中,open打开设备文件,然后通过ioctl获取最大触摸点数,并通过calloc初始化mt,之后进入死循环中,调用ts_read读取,并把所有数据都printf出来。

使用tslib库

这是Linux系统下,专门为触摸屏开发的应用层函数库。

tslib简介

tslib为触摸屏驱动和应用层之间的适配层,它把应用程序中读取触摸屏struct input_event 类型数据(这是输入设备上报给应用层的原始数据)并进行解析的操作过程进行了封装,向使用者提供了封装好的API接口。tslib从触摸屏中获得原始的坐标数据,并通过一系列的去噪、去抖、坐标变换等操作,来去除噪声并将
原始的触摸屏坐标转换为相应的屏幕坐标。

tslib有一个配置文件ts.conf,该配置文件中提供了一些配置参数,可进行修改。tslib可以作为Qt触摸屏输入插件,为Qt提供输入支持。

tslib移植

这里就直接看教程就好了。

这里感觉驱动教程那边更好,直接在buildroot里面使能编译就可以了。

tslib库函数

使用tslib库函数需要在应用程序中包含tslib的头文件tslib.h,使用tslib编程其实非常简单,基本步骤如下所示:

  • 第一步打开触摸屏设备;
  • 第二步配置触摸屏设备;
  • 第三步读取触摸屏数据。

打开触摸屏设备

使用tslib提供的库函数ts_open打开触摸屏设备,其函数原型如下所示:

#include "tslib.h"struct tsdev *ts_open(const char *dev_name, int nonblock);

参数dev_name指定了触摸屏的设备节点;参数nonblock表示是否以非阻塞方式打开触摸屏设备,如果nonblock等于0表示阻塞方式,如果为非0值则表示以非阻塞方式打开。调用成功返回一个struct tsdev *指针,指向触摸屏设备句柄;如果打开设备失败,将返回NULL。

还可以使用ts_setup()函数,其函数原型如下所示:

#include "tslib.h"struct tsdev *ts_setup(const char *dev_name, int nonblock)

参数dev_name可以设置为NULL,ts_setup()函数内部会读取TSLIB_TSDEVICE环境变量,获取该环境变量的内容以得知触摸屏的设备节点。

关闭触摸屏设备使用ts_close()函数:

int ts_close(struct tsdev *);

配置触摸屏设备

调用ts_config()函数进行配置,其函数原型如下所示:

#include "tslib.h"int ts_config(struct tsdev *ts);

参数ts指向触摸屏句柄。成功返回0,失败返回-1。

读取触摸屏数据

读取触摸屏数据使用ts_read()或ts_read_mt()函数,区别在于ts_read用于读取单点触摸数据,而ts_read_mt则用于读取多点触摸数据,其函数原型如下所示:

#include "tslib.h"int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr);
int ts_read_mt(struct tsdev *ts, struct ts_sample_mt **samp, int max_slots, int nr);

参数ts指向一个触摸屏设备句柄,参数nr表示对一个触摸点的采样数,设置为1即可!

ts_read_mt()函数有一个max_slots参数,表示触摸屏支持的最大触摸点数,应用程序可以通过调用ioctl()函数来获取触摸屏支持的最大触摸点数以及触摸屏坐标的最大分辨率等信息。

ts_read()函数的samp参数是一个struct ts_sample *类型的指针,指向一个struct ts_sample对象,struct ts_sample数据结构描述了触摸点的信息;调用ts_read()函数获取到的数据会存放在samp指针所指向的内存中。

ts_read_mt()函数的samp参数是一个struct ts_sample_mt **类型的指针,多点触摸应用程序,每一个触摸点的信息使用struct ts_sample_mt数据结构来描述;一个触摸点的数据使用一个struct ts_sample_mt对象
来装载,将它们组织成一个struct ts_sample_mt数组,调用ts_read_mt()时,将数组地址赋值给samp参数。

基于tslib编写触摸屏应用程序

单点触摸

需要定义tsdev结构体指针ts,ts_sample_mt结构体指针mt_ptr,input_absinfo结构体slot。

通过ts_setup打开触摸屏,第一个参数可以直接NULL就打开环境变量中的设备。

然后进入死循环,通过ts_read读取数据,通过samp.pressure判断是否按下,而保存的上一个pressure可辅助判断移动、按下与松开。

多点触摸

这个跟前面差不多,这里只列出区别。

通过ioctl函数获取最大触摸点数,同时mt_ptr需要calloc初始化。

死循环中,通过ts_read_mt读取数据,然后通过mt_ptr[].valid,如果为真就是数据有更新,之后一样通过pressure判断触摸情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180471.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Prometheus的详细部署

普罗米修斯下载网址: Download | Prometheus 准备两台机器&#xff1a; 192.168.58.152 prometheus 192.168.58.142 node_exporter 关闭防火墙和selinux&#xff1a; [rootlocalhost ~]# setenforce 0 && systemctl stop firewalld[rootlocalhost ~]# seten…

机器视觉双目测宽仪具体有什么优势?

双目测宽仪是机器视觉原来制造而成的智能宽度检测设备&#xff0c;广泛应用于板材类产品的宽度检测。通过测宽仪的使用&#xff0c;实时了解产品宽度品质&#xff0c;进行超差提示&#xff0c;减少废品的生产。 双目测宽仪优势 测量软件界面显示&#xff1a;产品规格、标称宽…

Android控件全解手册 - 任意View缩放平移工具-源码

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

竞赛选题 题目:基于机器视觉的图像矫正 (以车牌识别为例) - 图像畸变校正

文章目录 0 简介1 思路简介1.1 车牌定位1.2 畸变校正 2 代码实现2.1 车牌定位2.1.1 通过颜色特征选定可疑区域2.1.2 寻找车牌外围轮廓2.1.3 车牌区域定位 2.2 畸变校正2.2.1 畸变后车牌顶点定位2.2.2 校正 7 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享…

yolov8-pose姿势估计,站立识别

系列文章目录 基于yolov8-pose的姿势估计模式,实现站姿,坐姿,伏案睡姿识别,姿态动作识别接口逻辑作参考。本文以学习交流,分享,欢迎留言讨论优化。 yoloPose-姿势动作识别 系列文章目录前言一、环境安装二、使用yolov8-pose1.导入模型,预测图像三.姿势动作识别之站立总…

人工智能_机器学习053_支持向量机SVM目标函数推导_SVM条件_公式推导过程---人工智能工作笔记0093

然后我们再来看一下支持向量机SVM的公式推导情况 来看一下支持向量机是如何把现实问题转换成数学问题的. 首先我们来看这里的方程比如说,中间的黑线我们叫做l2 那么上边界线我们叫l1 下边界线叫做l3 如果我们假设l2的方程是上面这个方程WT.x+b = 0 那么这里 我们只要确定w和…

<Linux> 文件理解与操作

目录 前言&#xff1a; 一、关于文件的预备知识 二、C语言文件操作 1. fope 2. fclose 3. 文件写入 3.1 fprintf 3.2 snprintf 三、系统文件操作 1. open 2. close 3. write 4. read 四、C文件接口与系统文件IO的关系 五、文件描述符 1. 理解文件描述符 2. 文…

一则 MongoDB 副本集迁移实操案例

文中详细阐述了通过全量 增量 Oplog 的迁移方式&#xff0c;完成一套副本集 MongoDB 迁移的全过程。 作者&#xff1a;张然&#xff0c;DBA 数据库技术爱好者~ 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。 本文约 900…

python炒股自动化(1),量化交易接口区别

要实现股票量化程序化自动化&#xff0c;就需要券商提供的API接口&#xff0c;重点是个人账户小散户可以申请开通&#xff0c;上手要简单&#xff0c;接口要足够全面&#xff0c;功能完善&#xff0c;首先&#xff0c;第一步就是要找对渠道和方法&#xff0c;这里我们不讨论量化…

linux 内核等待队列

等待队列在Linux内核中用来阻塞或唤醒一个进程&#xff0c;也可以用来同步对系统资源的访问&#xff0c;还可以实现延迟功能 在软件开发中任务经常由于某种条件没有得到满足而不得不进入睡眠状态&#xff0c;然后等待条件得到满足的时候再继续运行&#xff0c;进入运行状态。这…

网络安全--基于Kali的网络扫描基础技术

文章目录 1. 标准ICMP扫描1.1使用Ping命令1.1.1格式1.1.2实战 1.2使用Nmap工具1.2.1格式1.2.2实战1.2.2.1主机在线1.2.2.2主机不在线 1.3使用Fping命令1.3.1格式1.3.2实战 2. 时间戳查询扫描2.1格式2.2实战 3. 地址掩码查询扫描3.1格式3.2实战 2. TCP扫描2.1TCP工作机制2.2TCP …

位运算总结

文章目录 &#x1f348;1. 基础位运算&#x1f34c;2. 给一个数n&#xff0c;确定它的二进制表示中的第x位是0还是1&#x1f34f;3. 将一个数n的二进制表示的第x位修改成1&#x1f353;4. 将一个数的n的二进制表示的第x位修改成0&#x1f954;5. 位图的思想&#x1fad2;6. 提前…

医保移动支付程序开发

作为公司最苦命的开发&#xff0c;年初接到任务开发医保移动支付程序&#xff08;微信小程序和支付宝小程序&#xff09;&#xff0c;为医疗机构提供线上医保结算。好家伙&#xff0c;我一看解压后资料大于一个G&#xff0c;内心无比的惊慌。 一、技术流程图 图太大了显示不全需…

0-1背包的初始化问题

题目链接 这道题的状态转移方程比较易于确定。dp[i][j]表示能放前i个物品的情况下&#xff0c;容量为j时能放物品的数量&#xff08;这道题歌曲数量对应物品数量&#xff0c;容量对应时间&#xff09;。 技巧&#xff08;收获&#xff09; 二维dp数组可以视情况优化为一维dp数组…

Linux——vim编辑文件时——.swp文件解决方案

test.cpp样例 当我们vim test.cpp进入编辑文件。 却忘记了保存退出 再次进入就会出现一下画面 当你摁下Enter键位 出现以下几个选项 O——是只读不写 E——是正常打开文件但不会载入磁盘内容 R——覆盖——是加载存储磁盘的文件(当我们忘记保存时&#xff0c;系统会自动帮我…

事件代理?

1.什么是事件代理&#xff1f; 事件代理也叫事件委托&#xff0c;只指定一个事件处理程序&#xff0c;就可以管理某一类型得事件。 可以简单理解为&#xff0c;事件代理就是将本应该绑定子元素事件绑定给父元素代理。它的优点就是&#xff1a;减少事件得执行&#xff0c;减少浏…

CentOS 7 部署 MariaDB 的 2 种方法

有两种安装 MariaDB 服务器的方法。您可以安装 CentOS 7 存储库中可用的默认版本&#xff0c;也可以通过手动添加 MariaDB 存储库来安装最新版本。 如果安装过MariaDB或MySQL&#xff0c;使用以下命令彻底删除它们: yum remove mariadb* yum remove mysql* 方法一: 使用 Yum…

Make Pixels Dance: High-Dynamic Video Generation论文解析

高动态视频生成的新进展 Make Pixels Dance: High-Dynamic Video Generation高动态视频生成的新进展前言视频生成模式摘要论文十问实验数据集定量评估指标消融研究 训练和推理技巧训练技术推理技术 更多的应用 Make Pixels Dance: High-Dynamic Video Generation 高动态视频生…

VBA技术资料MF87:创建固定顺序名称的一组文件夹

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

gRPC Java、Go、PHP使用例子

文章目录 1、Protocol Buffers定义接口1.1、编写接口服务1.2、Protobuf基础数据类型 2、服务器端实现2.1、生成gRPC服务类2.2、Java服务器端实现 3、java、go、php客户端实现3.1、Java客户端实现3.2、Go客户端实现3.3、PHP客户端实现 4、运行效果 本文例子是在Window平台测试&a…