• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# gpio app demo
2gpio的相关操作app demo
3## 开发环境
41. 搭载OpenHarmony-4.0-Release版本的Unionpi Tiger开发板
52. Microsoft VS Code 1.80.2
63. DevEco Studio 4.0 Beta2
74. 一堆led灯
8## gpio简介
9通用输入输出端口的简称。可以通过软件控制其输出和输入,通俗来说就是常用引脚,可以控制引脚的高低电平,对其进行读取或者写入。
10## 操作方式
11### Linux编程
12首先在/sys/class/gpio/export中写入具体的gpio号即可导出相应的设备文件
13不知道gpio号的可以执行以下命令查看
14> cat /sys/kernel/debug/gpio
15
16导出成功后,/sys/class/gpio/目录下会出现gpio[gpio号]文件夹,进入此文件夹,可操作以下设备文件用于操作gpio
171. direction 写入in, out, high, low。high/low会同时设置方向为输出,并将value设置为相应的1/0。
182. value文件是端口的数值,为1或0。1为高电平,0为低电平
19### hdf方式编程
20详见: [OpenHarmony hdf的gpio驱动文档](https://docs.openharmony.cn/pages/v3.2/zh-cn/device-dev/driver/driver-platform-gpio-des.md/)
21## NAPI导出
22众所周知,arkts支持面向对象编程,那么如何使用napi将c++类包装为一个arkts类?
23### 新建Napi类对应c++类的接口
24C++类
25```C++
26class GpioCtl
27{
28protected:
29    uint32_t gpio;
30
31public:
32    GpioCtl(uint32_t gpio,uint32_t direction);
33    uint16_t read();
34    bool write(uint16_t data);
35};
36```
37Napi类,napi不支持传入c++成员函数指针,因此只能用全静态函数
38```C++
39class  GpioNapi
40{
41protected:
42    static napi_ref gpioClassRef;
43
44public:
45    static napi_value define(napi_env env);
46
47    static napi_value Constructor(napi_env env, napi_callback_info cb);
48
49    static void Destructor(napi_env env,void* nativeObject,void* finalize_hint);
50
51    static napi_value read(napi_env env, napi_callback_info cb);
52
53    static napi_value write(napi_env env, napi_callback_info cb);
54};
55napi_ref GpioNapi::gpioClassRef = nullptr;
56```
57### 定义arkts类
58在define函数中,调用napi_define_class定义一个arkts类,并传入构造时的回调函数,并将该类返回
59```C++
60static napi_value define(napi_env env)
61{
62    napi_value gpioClass;
63    napi_property_descriptor desc[]={
64        DECLARE_NAPI_FUNCTION("read",read),
65        DECLARE_NAPI_FUNCTION("write",write)
66    };
67    napi_define_class(env,"Gpio",NAPI_AUTO_LENGTH,Constructor,nullptr,sizeof(desc)/sizeof(desc[0]) ,desc,&gpioClass);
68            napi_create_reference(env,gpioClass,1,&gpioClassRef);
69    return gpioClass;
70}
71```
72### 绑定c++对象
73在构造时的回调函数中,接收参数,并将参数转换为c++变量用于构造c++对象,调用napi_warp将真正的c++对象指针绑定到arkts对象中,同时绑定析构时的回调函数,析构时的回调函数会删除c++对象以释放相关资源
74```C++
75static napi_value Constructor(napi_env env, napi_callback_info cb)
76{
77    napi_value this_var;
78    size_t argc=2;
79    napi_value argv[2];
80    napi_get_cb_info(env,cb,&argc,argv,&this_var,nullptr);
81    NAPI_ASSERT(env,argc==2,"requires 2 parameter");
82    napi_valuetype type;
83    napi_typeof(env,argv[0],&type);
84    NAPI_ASSERT(env,type==napi_number,"frist parameter type requires number");
85    napi_typeof(env,argv[1],&type);
86    NAPI_ASSERT(env,type==napi_number,"2nd parameter type requires number");
87
88    uint32_t gpioNum,dir;
89    napi_get_value_uint32(env,argv[0],&gpioNum);
90    napi_get_value_uint32(env,argv[1],&dir);
91
92    auto *gpio=new GpioCtl(gpioNum,dir);
93    napi_wrap(env,this_var,gpio,Destructor,nullptr,nullptr);
94    return this_var;
95}
96```
97### 编写arkts成员函数对应的NAPI函数
98首先通过napi_get_cb_info获取this对象以及参数,然后检查this对象是否是之前定义的arkts类的一个实例(如果是JavaScript调用,因为没有类型检查,可能存在被当成静态函数调用的情况,arkts则无此问题),然后调用napi_unwarp取出之前绑定的c++对象指针,然后操作此c++对象完成实际操作
99```C++
100static napi_value read(napi_env env, napi_callback_info cb)
101{
102    size_t argc=0;
103    napi_value this_var,gpioClass;
104    napi_get_cb_info(env,cb,&argc,nullptr,&this_var,nullptr);
105
106    napi_get_reference_value(env,gpioClassRef,&gpioClass);
107
108    bool isInstance;
109    napi_instanceof(env,this_var,gpioClass,&isInstance);
110    NAPI_ASSERT(env,isInstance,"this read function isn't static function!");
111
112    GpioCtl* gpio;
113    napi_unwrap(env,this_var,reinterpret_cast<void**>(&gpio));
114    /*使用C++对象完成相关操作...*/
115    return ret;
116}
117```
118### 定义枚举
119定义枚举可以有效约束接口参数的合法性以及使代码更加易读
120
121定义gpio名称枚举
122```C++
123static napi_value defineGpioName(napi_env env)
124{
125    napi_value gpioName,gpio1,gpio2,gpio3,gpio4,gpio5,gpio6,gpio7,gpio8,gpio9,gpio10,gpio11,gpio12,gpio13,gpio14,gpio15,gpio16;
126    napi_create_object(env,&gpioName);
127
128    napi_create_uint32(env,Gpio::GPIO_01,&gpio1);
129    ......//此处省略
130    napi_create_uint32(env,Gpio::GPIO_16,&gpio16);
131
132    napi_property_descriptor desc[]={
133        DECLARE_NAPI_STATIC_PROPERTY("GPIO_01",gpio1),
134        ......//此处省略
135        DECLARE_NAPI_STATIC_PROPERTY("GPIO_16",gpio16)
136    };
137    napi_define_properties(env,gpioName,sizeof(desc)/sizeof(desc[0]) ,desc);
138    return gpioName;
139}
140```
141定义gpio输入输出等方向枚举
142```C++
143static napi_value defineDir(napi_env env)
144{
145    napi_value dir,input,output,error;
146    napi_create_object(env,&dir);
147
148    napi_create_uint32(env,direction::input,&input);
149    napi_create_uint32(env,direction::output,&output);
150    napi_create_uint32(env,direction::error,&error);
151
152    napi_property_descriptor desc[]={
153        DECLARE_NAPI_STATIC_PROPERTY("input",input),
154        DECLARE_NAPI_STATIC_PROPERTY("output",output),
155        DECLARE_NAPI_STATIC_PROPERTY("error",error)
156    };
157    napi_define_properties(env,dir, sizeof(desc)/sizeof(desc[0]) ,desc);
158    return dir;
159}
160```
161定义高电平,低电平等枚举
162```C++
163static napi_value defineVal(napi_env env)
164{
165    napi_value val,low,height;
166    napi_create_object(env,&val);
167
168    napi_create_uint32(env,val::low,&low);
169    napi_create_uint32(env,val::height,&height);
170
171    napi_property_descriptor desc[]={
172        DECLARE_NAPI_STATIC_PROPERTY("low",low),
173        DECLARE_NAPI_STATIC_PROPERTY("height",height)
174    };
175    napi_define_properties(env,val, sizeof(desc)/sizeof(desc[0]) ,desc);
176    return val;
177}
178```
179###  编写arkts模块接口定义文件
180编写完napi接口后,还需要让方舟编译器知道模块里提供了哪些接口,有什么参数,各个参数的类型又是什么。这就需要模块接口定义文件(.d.ts)来说明,这里采用es6的模块声明方式来编写,将napi定义的枚举与类进行显式说明。
181```TypeScript
182export enum GpioName {
183  GPIO_01,
184  GPIO_02,
185  GPIO_03,
186  GPIO_04,
187  GPIO_05,
188  GPIO_06,
189  GPIO_07,
190  GPIO_08,
191  GPIO_09,
192  GPIO_10,
193  GPIO_11,
194  GPIO_12,
195  GPIO_13,
196  GPIO_14,
197  GPIO_15,
198  GPIO_16,
199}
200
201export enum Dir {
202  input,
203  output,
204  error
205}
206
207export enum Val {
208  low,
209  height
210}
211
212export class Gpio {
213  constructor(gpio: GpioName, direction: Dir);
214
215  read(): Val;
216
217  write(val: Val): void;
218}
219```
220### 编写app
221创建一个api10的app项目,创建一个选择框和开关,选择框用于选gpio针脚,开关控制gpio的高电平和低电平
222```TypeScript
223    Row(){
224        Text("选择pin: ")
225        Select([
226            { value: "GPIO_01" },
227            { value: "GPIO_02" },
228            { value: "GPIO_03" },
229            { value: "GPIO_04" },
230            { value: "GPIO_05" },
231            { value: "GPIO_06" },
232            { value: "GPIO_07" },
233            { value: "GPIO_08" },
234            { value: "GPIO_09" },
235            { value: "GPIO_10" },
236            { value: "GPIO_11" },
237            { value: "GPIO_12" },
238            { value: "GPIO_13" },
239            { value: "GPIO_14" },
240            { value: "GPIO_15" },
241            { value: "GPIO_16" },
242          ])
243        .selected(0)
244        .value(this.gpioSelectValue)
245        .onSelect((index: number, value: string) => {
246            this.gpioSelectValue = value;
247            this.gpio = new Gpio(GpioName[value], Dir.output);
248            let val = this.gpio.read();
249            this.gpioIsOpen = (val === Val.height);
250        })
251    }
252    Row() {
253        Text("开关: ")
254        Toggle({ type: ToggleType.Switch, isOn: this.gpioIsOpen })
255        .onChange((isOn: boolean) => {
256            this.gpioIsOpen = isOn;
257            if (isOn) {
258                this.gpio.write(Val.height);
259            }
260            else {
261                this.gpio.write(Val.low);
262            }
263            Prompt.showToast({message:isOn?"打开":"关闭"});
264        })
265    }
266```