天天看點

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

一、前言

本文将詳細介紹Hi3861開發闆如何通過GPIO子產品控制LED燈亮和滅。

二、鴻蒙裝置開發通用架構

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"

static void* HelloWorld_Task(const char* arg)
{
    (void)arg;
    printf("[HelloWorld] HelloWorld_Task()\n");

    while(1) 
    {
        // 任務代碼,例如列印一個語句:
         printf("開源項目 OpenHarmony\n是每個人的OpenHarmony\n");
        usleep(100000);
    }

    return NULL;
}

static void HelloWorld_Entry(void)
{
    osThreadAttr_t attr = {0};//定義了一個結構體

    printf("[HelloWorld] HelloWorld_Entry()\n");

    attr.name = "HelloWorld_Task";//目前TASK的名字
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024;//整個任務的一個棧的大小
    attr.priority = osPriorityNormal;//目前任務的優先級,通常設為Normal就行
    ////osThreadNew會建立一個線程,會執行HelloWorld_Task任務
    if (osThreadNew((osThreadFunc_t)HelloWorld_Task, NULL, &attr) == NULL)
    {
        printf("[HelloWorld] Falied to create LedTask!\n");
    }
}

SYS_RUN(HelloWorld_Entry);
           

為什麼我們需要在入口函數中建立任務,而不直接寫While(1)呢?

參考上篇文章所闡述的啟動流程,如果我們的HelloWorld_Entry入口函數裡寫了一個While(1)的循環,那麼它永遠都不會傳回,進入了一個死循環,後面的流程都不會進行,将影響别的應用的初始化。是以我們隻能建立一個新的任務去實作它,在我們自己的線程裡,便可以自由的while(1)了。

那如果我們不建立任務,把相關代碼注釋掉呢:

#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"

static void* HelloWorld_Task(const char* arg)
{
    (void)arg;
    printf("[HelloWorld] HelloWorld_Task()\n");

    while(1) 
    {
        // logic code for task
         printf("開源項目 OpenHarmony\n是每個人的OpenHarmony\n");
        usleep(10000000);
    }

    return NULL;
}

static void HelloWorld_Entry(void)
{
    osThreadAttr_t attr = {0};

    printf("[HelloWorld] HelloWorld_Entry()\n");
    while(1) 
    {
        // logic code for task
        printf("開源項目 OpenHarmony\n是每個人的OpenHarmony\n");
        usleep(10000000);
    }
    /*
    attr.name = "HelloWorld_Task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024;
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)HelloWorld_Task, NULL, &attr) == NULL)
    {
        printf("[HelloWorld] Falied to create LedTask!\n");
    }*/
    
}

SYS_RUN(HelloWorld_Entry);
           

BUILD.gn如下:

static_library("hello_lib") {
    sources = [
        "HelloWorld.c"
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/peripheral/interfaces/kits",
    ]
}
           
#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

注釋掉任務代碼,直接再入口函數中While(1),編寫BUILD.gn,加入編譯依賴然後編譯燒錄檢視螢幕,我們可以看到:

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

雖然還是照常列印出了While(1)中的目智語句,但在我保留了上篇文章測試啟動流程的代碼情況下,所有的“上面那行代碼執行了.......”都沒被列印出來,說明啟動流程後面的程式沒法執行,程式卡在了前面的While(1)中,是個死循環。

三、通過GPIO子產品控制LED燈亮滅

Hi3861 WLAN模組核心闆

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

1.查原理圖,找到LED外設對應的GPIO引腳

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

原理圖中,J3預設由跳帽連接配接,為導通狀态。LED1即核心闆可程式設計LED燈,一端通過電阻R6連接配接到3V3電源,一端通過J3排針和GPIO09引腳連接配接。是以我們可以通過GPIO09引腳輸出高低電平控制LED1的亮滅。

由原理圖可知,當GPIO09引腳輸出低電平時,導通電源,LED1亮,輸出高電平時,LED1滅。

2.編寫業務邏輯代碼通過GPIO點燈

2.1 建立led.c檔案

在applications/sample/wifi-iot/app/目錄下建立led_demo目錄,在該目錄下建立led.c檔案,内容如下:

#include <unistd.h>
#include "stdio.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"

#define LED_TEST_GPIO 9 // for hispark_pegasus
#define LED_INTERVAL_TIME_US 300000
#define LED_TASK_STACK_SIZE 512
#define LED_TASK_PRIO 25 // 通常做demo開發時都被設定為25

void *LedTask(const char *arg)
{
    //初始化GPIO
    IoTGpioInit(LED_TEST_GPIO);

    //設定為輸出
    IoTGpioSetDir(LED_TEST_GPIO, IOT_GPIO_DIR_OUT);

    (void)arg;
    while (1) 
    {
        //輸出低電平
        IoTGpioSetOutputVal(LED_TEST_GPIO, 0)
        usleep(300000);
        //輸出高電平
        IoTGpioSetOutputVal(LED_TEST_GPIO, 1);
        usleep(300000);
    }

    return NULL;
}

void led_demo_entry(void)
{
    osThreadAttr_t attr;
    
    attr.name = "LedTask";//目前任務的名字
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = LED_TASK_STACK_SIZE;//整個任務的一個棧的大小
    attr.priority = LED_TASK_PRIO;//目前任務的優先級,通常做demo開發時我們設為25

    //osThreadNew會建立一個線程,會執行LedTask任務
    if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
    
}
SYS_RUN(led_demo_entry);
           

API功能描述

  • IoTGpioInit()用于GPIO子產品初始化,
  • IoTGpioSetDir用于設定GPIO引腳方向,id第一個參數用于指定引腳,dir第二個參數用于指定輸入或輸出。
  • IoTGpioSetOutputVal函數用于設定引腳的輸出狀态。函數的第一個參數用于指定引腳,第二個參數使用的枚舉IOT_GPIO_VALUE0和IOT_GPIO_VALUE1對應的值分别為0和1,用于指定高電平或低電平,直接使用0或1程式也同樣運作。
2.2 建立BUILD.gn檔案

在applications/sample/wifi-iot/app/led_demo目錄下建立BUILD.gn檔案

static_library("led_lib") {
    sources = [
        "led.c"
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/peripheral/interfaces/kits",
    ]
}
           

在本BUILD.gn檔案中,定義了一個名為led_demo的靜态庫,同時指定了編譯該靜态庫所需的源代碼檔案清單和包含目錄清單。

2.3 在applications/sample/wifi-iot/app目錄下的BUILD.gn的feartures中添加編譯依賴
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "startup",
        "led_demo:led_lib"
    ]
}
           

3.燒錄和運作

編譯燒錄運作後,将會看到主機闆上的LED燈開始閃爍。

更多關于OpenHarmony輕量系統驅動架構的介紹,可以參照

OpenHarmony輕量系統開發【5】驅動之GPIO點燈~

四、GPIO點燈進階之流水燈

掌握了最基礎的點燈操作後,我們可以來試試流水燈玩玩。因為我手邊沒有紅綠燈闆,是以我将Hi3861 WLAN模組與Hi3861底闆連接配接,外接了六個LED燈管構成了流水燈

my_led.c如下:

#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"

#define LED_INTERVAL_TIME_US 300000
#define LED_TASK_STACK_SIZE 512
#define LED_TASK_PRIO 25 // 通常做demo開發時都被設定為25

static led[] = 
{
    9,11,12,10,7,8   // 六個燈管依次接9,11,12,10,7,8
};
static void *LedTask(const char *arg)
{
    (void)arg;
    printf("ledTask start!\r\n");

    int i = 0;
    while (1)
    {
        int j = 0;

        while( j < 6 )
        {
            IoTGpioSetOutputVal(led[j++], 0);
        }

        i = (i + 1) % 6;

        IoTGpioSetOutputVal(led[i], 1);
        
        usleep(500000);

    }
    return NULL;
}

static void LedExampleEntry(void)
{
    osThreadAttr_t attr;//定義了一個結構體

    for(int i=0; i<6; i++)
    {
        IoTGpioInit(led[i]);
        //設定為輸出
        IoTGpioSetDir(led[i], IOT_GPIO_DIR_OUT);
    }

    attr.name = "LedTask";//目前TASK(任務)的名字
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = LED_TASK_STACK_SIZE;//整個任務的一個棧的大小
    attr.priority = LED_TASK_PRIO;//目前任務的優先級,通常做demo開發時我們設為25

    //osThreadNew會建立一個線程,會執行LedTask任務
    if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {
        printf("[LedExample] Falied to create LedTask!\n");
    }
}

SYS_RUN(LedExampleEntry);

           

BUILD.gn:

static_library("led_lib") {
    sources = [
        "myled.c"
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/peripheral/interfaces/kits",
        "//device/soc/hisilicon/hi3861v100/hi3861_adapter/hals/communication/wifi_lite/wifiservice",
        "//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal",
    ]
}
           

再在app目錄下的BUILD.gn中加入編譯依賴:

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "startup",
        "my_led:led_lib"
    ]
}
           

視訊在這:

#物聯網征文#【FFH】OpenHarmony裝置開發基礎(五)GPIO點燈

五、後記

參考文檔及教程

penHarmony輕量系統開發【5】驅動之GPIO點燈

三周帶你上手OpenHarmony裝置開發

有興趣的小夥伴趕緊玩起來吧!

如果發現本篇文章有不對的地方,歡迎交流探讨哦!

【本文正在參加物聯網有獎征文活動】,活動連結:https://ost.51cto.com/posts/14758;

繼續閱讀