前言:OpenHarmony分为轻量系统、小型系统、标准系统,目前对应LiteOS-M、LiteOS-A、Linux内核。但好像并没有说一定是按照使用内核来划分。我们这里姑且先这么区分。本文使用的是比较新的OpenHarmony 3.0 LTS版本,Linux内核,编译标准系统。官方文档已经说明了,如何使用DevEco Studio开发hap包,并运行在开发板,但是ACE框架能力有限。设备硬件开发还是需要C,所以这篇文章,将在标准系统下编译C控制Hi3516开发板的LED闪烁。
1.环境准备3.0源码下载:
repo init -u ;
区别于2.0需要安装ruby,其他基本都一样。
sudo apt-get install ruby-full
编译命令
build/prebuilts_download.sh./build.sh --product-name Hi3516DV300
2.编写helloworld.c在applications\standard目录下新建一个app目录来存放.c的业务代码。比如applications\standard\app\helloworld.c内容容下:
#include <stdio.h>int main(){printf("Hello world.\n");return 0;}
然后在当前目录新建编译脚本BUILD.gn内容如下:
import("//build/ohos.gni")import("//drivers/adapter/uhdf2/uhdf.gni")ohos_executable("helloworld") {sources = ["helloworld.c"]subsystem_name = "applications"part_name = "prebuilt_hap"}
然后添加到编译框架applications\standard\hap\ohos.build增加如下内容。
"//applications/standard/app:helloworld"
最后执行编译命令即可,开发板使用的是Hi3516,在不指定out目录时,缺省生成在/system/lib64或/system/lib下。
3.点亮开发板LED能打印helloworld说明环境是没问题的,接下来尝试点亮开发板的LED。查看Hi3516DV300原理图,下载地址。
Hi3516DV300共有4层板,由原理图可知:最上层板的红外补光灯接在GPIO5_1,绿色LED指示灯在GPIO2_3,核心板的红色LED在GPIO3_4。
接下来参考OpenHarmony GPIO驱动说明。
确定GPIO管脚号不同SOC芯片由于其GPIO控制器型号、参数、以及控制器驱动的不同,GPIO管脚号的换算方式不一样。
Hi3516DV300控制器管理12组GPIO管脚,每组8个。GPIO号 = GPIO组索引 (0~11) * 每组GPIO管脚数(8) + 组内偏移举例:GPIO10_3的GPIO号 = 10 * 8 + 3 = 83Hi3518EV300控制器管理10组GPIO管脚,每组10个。GPIO号 = GPIO组索引 (0~9) * 每组GPIO管脚数(10) + 组内偏移举例:GPIO7_3的GPIO管脚号 = 7 * 10 + 3 = 73由此可以得出:
GPIO5_1 = 5 * 8 + 1;GPIO2_3 = 2 * 8 + 3;GPIO3_4 = 3 * 8 + 4;
然后新建applications\standard\app\ledtest.c内容如下
#include <stdlib.h> // standard library 标准库函数头文件#include <stdio.h> // standard input output 标准输入输出函数#include <stdint.h> // 定义了扩展的整数类型和宏#include <unistd.h> // POSIX 系统 API 访问功能的头文件#include <fcntl.h> // unix标准中通用的头文件 define O_WRONLY and O_RDONLY // #include <string.h>#define GPIO_DIR_IN "in"#define GPIO_DIR_OUT "out"#define GPIO_VAL_LOW 0#define GPIO_VAL_HIGHT 1// int32_t GpioSetDir(uint16_t gpio, char *dir){// int fd; // if ((fd = open("/sys/class/gpio/export", O_WRONLY)) == -1)// return -1;// if (write(fd, &gpio, sizeof(gpio)) != sizeof(gpio)) {// close(fd);// return -1;// }// close(fd);// char path[100] = {0};// sprintf(path,"/sys/class/gpio/gpio%d/direction",gpio);// if ((fd = open(path, O_WRONLY)) == -1)// return -1;// write(fd, dir, sizeof(dir));// close(fd); // return 0;// }// int32_t GpioWrite(uint16_t gpio, uint16_t val)// {// int fd;// char path[100] = {0};// sprintf(path,"/sys/class/gpio/gpio%d/value",gpio);// if ((fd = open(path, O_RDWR)) == -1)// return -1;// write(fd, &val, sizeof(val));// close(fd);// return 0;// }int32_t GpioSetDir(uint16_t gpio, char* dir){char path[100] = {0};sprintf(path,"echo %d > /sys/class/gpio/export",gpio);system(path);printf("info:%s\n",path);char direction[100] = {0};sprintf(direction,"echo %s > /sys/class/gpio/gpio%d/direction",dir,gpio);system(direction);printf("info:%s\n",direction);return 0;}int32_t GpioWrite(uint16_t gpio, uint16_t val){char path[100] = {0};sprintf(path,"echo %d > /sys/class/gpio/gpio%d/value",val,gpio);system(path);printf("info:%s\n",path);return 0;}int main(){uint16_t GPIO5_1 = 5 * 8 + 1;uint16_t GPIO2_3 = 2 * 8 + 3;uint16_t GPIO3_4 = 3 * 8 + 4;printf("LED test start\n");int32_t ret;// uint16_t val;ret = GpioSetDir(GPIO5_1,GPIO_DIR_OUT);if (ret != 0) {printf("GpioSerDir: failed, ret %d\n", ret);return 0;}ret = GpioSetDir(GPIO2_3,GPIO_DIR_OUT);if (ret != 0) {printf("GpioSerDir: failed, ret %d\n", ret);return 0;}ret = GpioSetDir(GPIO3_4,GPIO_DIR_OUT);if (ret != 0) {printf("GpioSerDir: failed, ret %d\n", ret);return 0;}while(1){GpioWrite(GPIO5_1, GPIO_VAL_HIGHT);usleep(1000000);GpioWrite(GPIO5_1, GPIO_VAL_LOW);usleep(1000000);GpioWrite(GPIO2_3, GPIO_VAL_HIGHT);usleep(1000000);GpioWrite(GPIO2_3, GPIO_VAL_LOW);usleep(1000000);GpioWrite(GPIO3_4, GPIO_VAL_HIGHT);usleep(1000000);GpioWrite(GPIO3_4, GPIO_VAL_LOW);usleep(1000000);}return 0;}
将业务代码添加到BUILD.gn
import("//build/ohos.gni")import("//drivers/adapter/uhdf2/uhdf.gni")ohos_executable("helloworld") {sources = ["helloworld.c"]subsystem_name = "applications"part_name = "prebuilt_hap"}ohos_executable("ledtest") {sources = ["ledtest.c"]subsystem_name = "applications"part_name = "prebuilt_hap"}
applications\standard\hap\ohos.build
"//applications/standard/app:ledtest"
之后将程序烧录到开发板,执行./system/bin/ledtest
就可以看到LED闪烁起来了。
本来是打算使用鸿蒙的GPIO接口来实现这个功能的,不过调试了很久也没调通,最后无奈还是用的system自己实现的GPIO函数。有没使用OpenHarmony的GPIO成功的小伙伴可以留言一起交流啊。
下面的不要
applications\standard\hap\mysample\mysample.c
#include <stdlib.h> // standard library 标准库函数头文件#include <stdio.h> // standard input output 标准输入输出函数#include <unistd.h> // POSIX 系统 API 访问功能的头文件#include <fcntl.h> // unix标准中通用的头文件 define O_WRONLY and O_RDONLY #include <string.h>// int main()// {// printf("my Hello world.\n");LOGE("---Start open LED---");// system("echo 28 > /sys/class/gpio/export"); // system("echo out > /sys/class/gpio/gpio28/direction"); // system("echo 1 > /sys/class/gpio/gpio28/value");// system("echo 19 > /sys/class/gpio/export"); // execl("/bin/sh","sh","-c","echo 19 > /sys/class/gpio/export",NULL); // LOGE("echo 19 > /sys/class/gpio/export");// system("echo out > /sys/class/gpio/gpio19/direction"); // execl("/bin/sh","sh","-c","echo out > /sys/class/gpio/gpio19/direction",NULL); // LOGE("echo out > /sys/class/gpio/gpio19/direction"); // system("echo 1 > /sys/class/gpio/gpio19/value"); // execl("/bin/sh","sh","-c","echo 1 > /sys/class/gpio/gpio19/value",NULL); // LOGE("echo 1 > /sys/class/gpio/gpio19/value"); LOGE("---End open LED---\n");// return 0;// }void initGpio(int n){FILE * fp = fopen("/sys/class/gpio/export","w");if (fp == NULL)perror("export open filed");elsefprintf(fp,"%d",n);fclose(fp);} //create gpio filevoid setGpioDirection(int n,char *direction){char path[100] = {0};sprintf(path,"/sys/class/gpio/gpio%d/direction",n);FILE * fp = fopen(path,"w");if (fp == NULL)perror("direction open filed");elsefprintf(fp,"%s",direction);fclose(fp);} //set gpio "in" or "out"int getGpioValue(int n){char path[64];char value_str[3];int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", n);fd = open(path, O_RDONLY);if (fd < 0) {perror("Failed to open gpio value for reading!");return -1;} if (read(fd, value_str, 3) < 0) {perror("Failed to read value!");return -1;} close(fd);return (atoi(value_str));} //get gpio(n)'s value// int main() // {// printf("my Hello world.\n");// initGpio(41);// setGpioDirection(41,"in");// // while(1)// // {// // printf("%d\n",getGpioValue(41));//每隔1s输出一次gpio18的值// // sleep(1);// // } // FILE * fp =fopen("/sys/class/gpio/gpio41/value","w");// if (fp == NULL)// perror("export open filed");// else// fprintf(fp,"%d",1);// fclose(fp);// return 0; // }int main(){printf("my Hello world.\n");int fd; //打开端口/sys/class/gpio# echo 48 > exportfd = open("/sys/class/gpio/export", O_WRONLY);if(fd == -1){printf("ERR: Radio hard reset pin open error.\n");return EXIT_FAILURE;}write(fd, "19",sizeof("19")); close(fd); //设置端口方向/sys/class/gpio/gpio19# echo out > directionfd = open("/sys/class/gpio/gpio19/direction", O_WRONLY);if(fd == -1){printf("ERR: Radio hard reset pin direction open error.\n");return EXIT_FAILURE;}write(fd, "out", sizeof("out"));close(fd); //输出复位信号: 拉高>100nsfd = open("/sys/class/gpio/gpio19/value", O_RDWR);if(fd == -1){printf("ERR: Radio hard reset pin value open error.\n");return EXIT_FAILURE;} while(1){write(fd, "1", sizeof("1"));usleep(1000000);write(fd, "0", sizeof("0"));usleep(1000000);}close(fd);printf("INFO: Radio hard reset pin value open error.\n");return 0;}
applications\standard\hap\mysample\BUILD.gn
# Copyright (c) 2020 Huawei Device Co., Ltd.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## ;}
applications\standard\hap\ohos.build
"//applications/standard/hap/mysample:mysample",
默认编译完的位置
现在3.0依然是make和gn混合编译,目前的大方向是去make,使用gn应该是没问题的。