当前位置:   article > 正文

鸿蒙OpenHarmony hi3516开发板,标准系统按钮开关灯_鸿蒙系统如何实现充电指示灯

鸿蒙系统如何实现充电指示灯

背景

HarmonyOS应用开发玩到OpenHarmony应用开发,前前后后也有大半年了,北向HelloWorld的应用从JAVA写到了JS,又写到了eTS。北向应用的开发不说是精通,至少也早已是个半吊子,查查文档和参考下开发样例,还是能慢慢的写出个应用。然而,南向设备的开发,却一直拖着不知道如何上手。于是,最近终于狠下决心了: 从设备开发的HelloWorld---点灯开始,先在OpenHarmony标准设备上,使用linux自带的GPIO点个灯,走出第一步,后续再使用HDF,NAPI等能力,持续探索南向设备开发。

那么,这次我想做的是使用OpenHarmony3.0 LTS版本的标准系统上,开发一个应用程序,通过调用linux自带通用GPIO驱动,实现点击按钮实现点灯和关灯。这次我使用的开发板是润和hi3516 dv300。最终效果如下:

什么是GPIO?

这个问题,对于搞单片机,嵌入式的同学来说,估计第一天就会了。而对于我们搞软件的同学来说,却很少听过,其实我之前就没听说过。。。

GPIO,英文全称为General-Purpose IO ports,也就是 通用IO口。嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路有的需要CPU为之提供控制手段,有的则需要被CPU用作输入信号。而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了,比如灯亮与灭。对这些设备/电路的控制,使用传统的串行口或并行口都不合适。所以在微控制器芯片上一般都会提供一个“通用可编程IO接口”,即GPIO。

我个人的理解是单片机这类设备,是可以通过直接操作寄存器,或者是厂商提供的函数控制GPIO,而linux嵌入式设备,则可以使用linux自带通用GPIO驱动来控制GPIO,或者是自写驱动。而OpenHarmony在此之上,又封装了一层HDF,通过HDF这层封装,可以适配不同操作系统控制GPIO.

润和hi3516dv300 按钮和灯的GPIO口

这些信息可以从原理图中获取:

  • 可以看到两个自定义按钮的GPIO口分别是:GPIO0_1,GPIO0_2

  • 三个LED的GPIO口分别是:核心板的红色LED在GPIO3_4,绿色LED指示灯在GPIO2_3,最上层板的红灯接在GPIO5_1

使用linux自带通用GPIO驱动开灯关灯

文档,了解到Hi3516DV300有控制器管理12组GPIO管脚,每组8个。

GPIO号 = GPIO组索引 (0~11) * 每组GPIO管脚数(8) + 组内偏移

举例:GPIO10_3的GPIO号 = 10 * 8 + 3 = 83

所以,按钮

GPIO0_1 = 0 * 8 + 1 = 1

GPIO0_2 = 0 * 8 + 2 = 2

三个灯

GPIO5_1 = 5 * 8 + 1;

GPIO2_3 = 2 * 8 + 3;

GPIO3_4 = 3 * 8 + 4;

所以通过学习Linux操作GPIO,了解到可以使用echo的形式,通过linux自带通用GPIO驱动来控制GPIO。于是乎,我们可以直接通过hiTools的串口连接到开发板上,使用如下命令实现点亮红灯:

  1. /sys/class/gpio# echo 41 > export     # 设置红灯GPIO口为导出
  2. /sys/class/gpio/gpio41# echo out > direction # 设置红灯GPIO口为输出
  3. /sys/class/gpio/gpio41# echo 1 > value # 设置红灯GPIO口为1

通过代码来实现

通过代码来实现,是通过文件的形式来调用linux自带通用GPIO驱动。

此外,针对按钮,需要使用poll的方式监控文件变化,响应GPIO中断

  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<unistd.h>
  5. #include<fcntl.h>
  6. #include<poll.h>
  7. #define MSG(args...) printf(args)
  8. //函数声明
  9. static int gpio_export(int pin);
  10. static int gpio_unexport(int pin);
  11. static int gpio_direction(int pin, int dir);
  12. static int gpio_write(int pin, int value);
  13. static int gpio_read(int pin);
  14. static int gpio_edge(int pin, int edge);
  15. static int gpio_export(int pin)  
  16. {  
  17.   char buffer[64];  
  18.   int len;  
  19.   int fd;  
  20.  
  21.   fd = open("/sys/class/gpio/export", O_WRONLY);  
  22.   if (fd < 0)
  23.   {  
  24.       MSG("Failed to open export for writing!\n");  
  25.       return(-1);  
  26.   }  
  27.  
  28.   len = snprintf(buffer, sizeof(buffer), "%d", pin);  
  29.   printf("%s,%d,%d\n",buffer,sizeof(buffer),len);
  30.   if (write(fd, buffer, len) < 0)
  31.   {  
  32.       MSG("Failed to export gpio!");  
  33.       return -1;  
  34.   }  
  35.    
  36.   close(fd);  
  37.   return 0;  
  38. }  
  39. static int gpio_unexport(int pin)  
  40. {  
  41.   char buffer[64];  
  42.   int len;  
  43.   int fd;  
  44.  
  45.   fd = open("/sys/class/gpio/unexport", O_WRONLY);  
  46.   if (fd < 0)
  47.   {  
  48.       MSG("Failed to open unexport for writing!\n");  
  49.       return -1;  
  50.   }  
  51.  
  52.   len = snprintf(buffer, sizeof(buffer), "%d", pin);  
  53.   if (write(fd, buffer, len) < 0)
  54.   {  
  55.       MSG("Failed to unexport gpio!");  
  56.       return -1;  
  57.   }  
  58.    
  59.   close(fd);  
  60.   return 0;  
  61. }
  62. //dir: 0-->IN, 1-->OUT
  63. static int gpio_direction(int pin, int dir)  
  64. {  
  65.   static const char dir_str[] = "in\0out";  
  66.   char path[64];  
  67.   int fd;  
  68.  
  69.   snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);  
  70.   fd = open(path, O_WRONLY);  
  71.   if (fd < 0)
  72.   {  
  73.       MSG("Failed to open gpio direction for writing!\n");  
  74.       return -1;  
  75.   }  
  76.  
  77.   if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) < 0)
  78.   {  
  79.       MSG("Failed to set direction!\n");  
  80.       return -1;  
  81.   }  
  82.  
  83.   close(fd);  
  84.   return 0;  
  85. }  
  86. //value: 0-->LOW, 1-->HIGH
  87. static int gpio_write(int pin, int value)  
  88. {  
  89.   static const char values_str[] = "01";  
  90.   char path[64];  
  91.   int fd;  
  92.  
  93.   snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
  94.   fd = open(path, O_WRONLY);  
  95.   if (fd < 0)
  96.   {  
  97.       MSG("Failed to open gpio value for writing!\n");  
  98.       return -1;  
  99.   }  
  100.  
  101.   if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0)
  102.   {  
  103.       MSG("Failed to write value!\n");  
  104.       return -1;  
  105.   }  
  106.  
  107.   close(fd);  
  108.   return 0;  
  109. }
  110. static int gpio_read(int pin)  
  111. {  
  112.   char path[64];  
  113.   char value_str[3];  
  114.   int fd;  
  115.  
  116.   snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
  117.   fd = open(path, O_RDONLY);  
  118.   if (fd < 0)
  119.   {  
  120.       MSG("Failed to open gpio value for reading!\n");  
  121.       return -1;  
  122.   }  
  123.  
  124.   if (read(fd, value_str, 3) < 0)
  125.   {  
  126.       MSG("Failed to read value!\n");  
  127.       return -1;  
  128.   }  
  129.  
  130.   close(fd);  
  131.   return (atoi(value_str));
  132. }  
  133. // none表示引脚为输入,不是中断引脚
  134. // rising表示引脚为中断输入,上升沿触发
  135. // falling表示引脚为中断输入,下降沿触发
  136. // both表示引脚为中断输入,边沿触发
  137. // 0-->none, 1-->rising, 2-->falling, 3-->both
  138. static int gpio_edge(int pin, int edge)
  139. {
  140. const char dir_str[] = "none\0rising\0falling\0both";
  141. int ptr;
  142. char path[64];  
  143.   int fd;
  144. switch(edge)
  145. {
  146.   case 0:
  147.       ptr = 0;
  148.       break;
  149.   case 1:
  150.       ptr = 5;
  151.       break;
  152.   case 2:
  153.       ptr = 12;
  154.       break;
  155.   case 3:
  156.       ptr = 20;
  157.       break;
  158.   default:
  159.       ptr = 0;
  160. }
  161.  
  162.   snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin);  
  163.   fd = open(path, O_WRONLY);  
  164.   if (fd < 0)
  165.   {  
  166.       MSG("Failed to open gpio edge for writing!\n");  
  167.       return -1;  
  168.   }  
  169.  
  170.   if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0)
  171.   {  
  172.       MSG("Failed to set edge!\n");  
  173.       return -1;  
  174.   }  
  175.  
  176.   close(fd);  
  177.   return 0;  
  178. }
  179. int main()  
  180. {  
  181.   int gpio_fd, ret;
  182.   struct pollfd fds[1];
  183.   char buff[10];
  184.   //41为红灯, 1为1号按键
  185.   gpio_unexport(41);
  186.   gpio_unexport(1);
  187.    
  188.   //41红灯亮起
  189.   gpio_export(41);
  190.   gpio_direction(41, 1);//output out
  191.   gpio_write(41, 1);
  192.    
  193.   //1按钮初始化
  194.   gpio_export(1);
  195.   gpio_direction(1, 0);//input in
  196.   gpio_edge(1,2);
  197.   gpio_fd = open("/sys/class/gpio/gpio1/value",O_RDONLY);
  198.   if(gpio_fd < 0)
  199.   {
  200.       MSG("Failed to open value!\n");  
  201.       return -1;  
  202.   }
  203.   fds[0].fd = gpio_fd;
  204.   fds[0].events = POLLPRI;
  205.    
  206.   while(1)
  207.   {
  208.       ret = poll(fds,1,5000);
  209.       if( ret == -1 )
  210.       MSG("poll\n");
  211.       if( fds[0].revents & POLLPRI)
  212.       {
  213.           ret = lseek(gpio_fd,0,SEEK_SET);
  214.           if( ret == -1 )
  215.           MSG("lseek\n");
  216.             ret = read(gpio_fd,buff,10);//读取按钮值,但这里没使用
  217.           if( ret == -1 )
  218.           MSG("read\n");
  219.           //切换红灯
  220.           int status = gpio_read(41);
  221.           printf("41 = %d\n",status);
  222.           gpio_write(41, 1 - status);
  223.    
  224.        
  225.           //gpio_write(44, cnt++%2);
  226.           printf("**********************************\n");
  227.       }
  228.       printf("one loop\n");
  229.       //usleep(5);
  230.   }
  231.   return 0;
  232. }

将上述程序烧录标准系统镜像

步骤1: 下载OpenHarmony 3.0LTS版本,编译和烧录标准镜像

可参考我之前的文章

步骤2: 编写上述程序

新建并保存在applications/standard/app/hello.c

步骤3: hello.c同级目录下创建BUILD.gn

  1. import("//build/ohos.gni")
  2. import("//drivers/adapter/uhdf2/uhdf.gni")
  3. ohos_executable("hello") {
  4. sources = [
  5. "hello.c"
  6. ]
  7. subsystem_name = "applications"
  8. part_name = "prebuilt_hap"
  9. }

步骤4: 修改applications\standard\hap\ohos.build

module_list里增加 "//applications/standard/app:hello"

步骤5:重新编译和烧录,可参考步骤1

./build.sh --product-name Hi3516DV300 --ccache

步骤6:使用串口连接,执行bin目录下的hello

  1. cd bin
  2. ./hello

则可以点击按钮1,来点亮和熄灭led红灯

快速调试方法

编写和修改hello.c时,每次不想重新烧录镜像,目前只找到如下方法快速编译和烧录

步骤1:增加--ccache参数增量编译(倒也没必要单独也makefile了)

./build.sh --product-name Hi3516DV300 --ccache

步骤2:在out目录中,通过find找到hello文件,并拷贝到本地(windows)

步骤3:使用hdc_std单独更新hello程序

hdc_std file send 本地路径\hello /data/

注意:默认只有data目录下才能上传文件,如果需要放到类似bin等其他目录,则可以使用

hdc_std smode # 授予后台服务进程root权限

或者

mount -oremount,rw  /       # 更改文件系统的读写权限

近期还有很多事待验证,一步一个脚印吧

  • 尝试小型系统控制GPIO

  • 尝试使用HDF控制GPIO

  • 尝试扩展NAPI,从应用端控制GPIO

源代码

https://gitee.com/42690727/my-open-harmony-sample/tree/master/%E6%A0%87%E5%87%86%E8%AE%BE%E5%A4%87/3.1%20Beta/gpio%E7%82%B9%E7%81%AF

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/304507
推荐阅读
相关标签
  

闽ICP备14008679号