天天看點

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

本文正在參加星光計劃3.0–夏日挑戰賽

一.前言

自從去年12月底無意中得知小熊派釋出了一款折疊屏開發闆,就一直心心念念的想要弄一塊玩玩,當然花錢買是不能買的,就等着哪天意外能得到,這次意外終于來了,開發闆順利到手,因為一直在智能家居物聯網行業,肯定先做一個物聯網的智能家居小案例出來啦.

先爆美照:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

二.開發環境搭建和代碼擷取

因為我也算"老鴻蒙"了,自己親手和不親手搭建的環境有一百多份了,搭建環境這肯定難不到我了,然後就是代碼拉取了,跑到小熊派官方倉庫去:https://gitee.com/bearpi/bearpi-hm_micro_small

先fork到自己倉庫來,然後克隆下載下傳一氣呵成,美滋滋.

三.驅動編寫

驅動這塊就是用的官方的E53案例的驅動,使用的是IA1智慧農業,唯一不同的是我這邊風扇不是直接GPIO驅動的,而是采用PWM驅動,具體請看代碼:

int E53_IA1_Init(void)
{
    E53_GPIOInit(E53_IA1_LIGHT_GPIO,E53_GPIO_Out_PullNone);
    #if (defined MOTOR_WITH_PWM )&& (MOTOR_WITH_PWM==1)
        E53_PWMOpen(3);
        E53_PWMSetPeriod(4000);
        E53_PWMSetPolarity(0);
        // E53_PWMSetDuty(1);
        // E53_PWMStart();
    #else
    E53_GPIOInit(E53_IA1_MOTOR_GPIO,E53_GPIO_Out_PullNone);
    #endif
    E53_IICOpen();
    
    int ret0, ret1;
	ret0 = Init_BH1750();
    ret1 = Init_SHT30();
    OsalMDelay(180);
    return ret0 | ret1;
}
           
int E53_IA1_SetFanLevel(int level)
{
    int ret = -1;
#if (defined MOTOR_WITH_PWM )&& (MOTOR_WITH_PWM==1)
    if(level == 0){
        ret = E53_PWMStop();
    }else{

        if(level >5){
            level = 5;
        }
        E53_PWMSetDuty( (level*20)*MOTOR_DEFAULT_PERIOD/100 - 1);

        ret = E53_PWMStart();
    }
#else
    ret = E53_GPIOWrite(E53_IA1_LIGHT_GPIO,level? 1:0);

#endif

    return ret;
}
           

這裡采用PWM通道3來達到控制風扇的目的,至于為什麼是通道3,那個pwm的hcs檔案裡面寫了呀(由原理圖可知,風扇就在PA6):

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

還有一點需要注意的:這裡的E53_PWMSetDuty()接口傳入的并不是常見的百分比,而是一個實際的數字,如果我們需要按百分比調節馬達的轉速,需要自己去進行轉化.

四.界面編寫

界面這裡用DevcoStudio3Beta4編寫,首先要去官網下載下傳工具,然後再建立工程,注意建立工程的時候選擇(Lite)Empty Ablility,如下圖:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

然後是相關參數的填寫,注意裝置類型選SmartVision智慧屏:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

然後就進入工程界面了,等待一會等系統配置好工程之後,打開右邊的模拟器,添加一個新裝置或者修改裝置的分辨率為800*480,如下圖:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

做好這些事情之後就可以安心的編寫界面了,值得一提的是,API6還有好多東西不支援,比如button組建,竟然沒有,比如圖檔的縮放屬性:object-fit就沒有 用圖檔的時候就相當難受了,隻能忍一忍吧,還能怎麼辦,期待早點做好.

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例
#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

值得一提的是,咱們OpenHarmony的北向程式設計是有專門的教程網址的,大家可别迷路了:

https://docs.openharmony.cn/pages/v3.1/zh-cn/application-dev/application-dev-guide.md/

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

下面是我的拙作及相關代碼:

模拟器界面:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

實際界面會有點不同:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

相關hml代碼:

<div class="container">
    <div class="title-view">
        <text class="btn_exit" onclick="onExit">
            {{textExit}}
        </text>
        <text  onclick="onSetting">
            設定
        </text>

    </div>
    <text class="title">
        {{ title }}
    </text>

    <image class="img" src="/common/head.png">    </image>
    <text >目前風速:{{currentLevel}}</text>
    <slider class="fan-level"  min="0" max="5" value="0" step="1" mode="inset" showtips="true" onchange="setLevel"></slider>
    <div class="led-div">

        <text >LED燈</text>
        <switch class="led-switch" showtext="true" texton="open" textoff="close" checked="true" @change="switchChange"></switch>
    </div>


</div>

           

css代碼:

.container {
    width: 100%;
    height: 100%;
    justify-content: flex-start;
    align-items: center;
    flex-direction: column;
}

.title {
    width: 100%;
    font-size: 30px;
    justify-content: center;
    text-align: center;
/*    align-items: center;*/
/*    flex-direction: row;*/

}

.img{
    width:120px;
    height: 120px;
    justify-content: center;
    object-fit: cover;


}

.led-div{
    flex-direction: row;
    width:100%;
    height: 50;

    justify-content: space-around;
}

.title-view{
    width:100%;
    height: 50;
    flex-direction: row;
    justify-content: space-between;
}

.fan-level{
    flex-direction: row;
    scrollbar-color: aqua;
    background-color: #b7e3f3;
    width:400;
    height: 50;

}

.btn_exit{
    font-size: 30fp;
    background-color: red;
    align-items: center;
/*    width:60;*/
/*    height: 30;*/
}

.led-switch{
    width: 50;
    height: 50;

}

.prg{
    width:100px;
    height: 100px;
    justify-content: center;
/*    object-fit: contain;*/


}
           

然後是js代碼:

import app from "@system.app"

export default {
    data: {
        textExit:"<退出",
        title: "物聯風景-智能風扇",
        currentLevel:0,
    },
    onInit() {

    },

    onExit() {
        console.log("on exit")
        app.terminate()
    },
    setLevel(e){

        this.currentLevel = e.value;

        console.debug("fan level " +e.value+" send success")

        app.fan_level({
            level:e.value,
            success:(res) =>{
                console.log("fan level send success:"+res)
            } ,
            fail:(res,code) =>{
                console.log("fan level send failed:"+res+",code:"+code)
            } ,
            complete:() =>{
                console.log("fan level complete")
            } ,
        })

    },

    switchChange(e){
        if(e.checked){

            console.debug("打開燈")
        }else{

            console.debug("關閉燈")
        }

        app.set_led({
            onOff:e.checked ? 1 : 0 ,
            success:(res) =>{
                console.debug("set_led send success:"+res)
            } ,
            fail:(res,code) =>{
                console.debug("set_led send failed:"+res+",code:"+code)
            } ,
            complete:() =>{
                console.debug("set_led complete")
            } ,

        })
    },
}

           

五.JSI接口添加

在liteOS-a核心上,想要用UI控制硬體,就必須制作JSI接口,這個在小熊派官方文檔裡面也有介紹,制作JSI接口之前必須保證指令行方式綁定服務和驅動都OK,這裡給出小熊派的官方文檔吧:

https://gitee.com/bearpi/bearpi-hm_micro_small/blob/master/applications/BearPi/BearPi-HM_Micro/docs/device-dev/%E9%80%9A%E8%BF%87JS%E5%BA%94%E7%94%A8%E6%8E%A7%E5%88%B6LED%E7%81%AF.md

然後是北向程式設計的文檔位址:

https://gitee.com/bearpi/bearpi-hm_micro_app/blob/master/docs/led%E6%8E%A7%E5%88%B6%E6%A1%88%E4%BE%8B.md

有的這些位址,你也能通過漂亮的UI界面來控制硬體了.

下面的我的代碼示例:

JSIValue AppModule::FanLevel(const JSIValue thisVal, const JSIValue* args, uint8_t argsNum)
{
    HILOG_INFO(HILOG_MODULE_ACE, "==> FanLevel\n");
    struct HdfIoService *serv = HdfIoServiceBind(E53_IA1_SERVICE);
    if (serv == NULL)
    {
        HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service %s\n", E53_IA1_SERVICE);
        return JSI::CreateUndefined();
    }

    if ((args == nullptr) || (argsNum == 0) || (JSI::ValueIsUndefined(args[0]))) {
        return JSI::CreateUndefined();
    }

    JSIValue success = JSI::GetNamedProperty(args[0], CB_SUCCESS);
    JSIValue fail = JSI::GetNamedProperty(args[0], CB_FAIL);
    JSIValue complete = JSI::GetNamedProperty(args[0], CB_COMPLETE);

    int cmd = E53_IA1_FanLevel;
    // int32_t cmd = (int32_t)JSI::GetNumberProperty(args[0], "cmd");  
    int level= (int)JSI::GetNumberProperty(args[0], "level");
    char data =level+'0';
    HILOG_ERROR(HILOG_MODULE_ACE, "cmd is: %d\n", cmd);
    HILOG_ERROR(HILOG_MODULE_ACE,"level is: %d\n", level);
    HILOG_ERROR(HILOG_MODULE_ACE,"data is: %c\n", data);
    char *replyData;

    if (E53IA1Control(serv, cmd, &data, &replyData))
    {
        HILOG_ERROR(HILOG_MODULE_ACE,"fail to send event\n");
        JSI::CallFunction(fail, thisVal, nullptr, 0);
        JSI::CallFunction(complete, thisVal, nullptr, 0);
        JSI::ReleaseValueList(success, fail, complete);
        return JSI::CreateUndefined();
    }

    JSIValue result = JSI::CreateObject();

    JSI::SetStringProperty(result, "fan level", replyData);
    JSIValue argv[ARGC_ONE] = {result};
    JSI::CallFunction(success, thisVal, argv, ARGC_ONE);
    JSI::CallFunction(complete, thisVal, nullptr, 0);
    JSI::ReleaseValueList(success, fail, complete, result);

    HdfIoServiceRecycle(serv);

    return JSI::CreateUndefined();
}

JSIValue AppModule::SetLed(const JSIValue thisVal, const JSIValue* args, uint8_t argsNum)
{
    HILOG_INFO(HILOG_MODULE_ACE, "==> SetLed\n");
    struct HdfIoService *serv = HdfIoServiceBind(E53_IA1_SERVICE);
    if (serv == NULL)
    {
        HILOG_ERROR(HILOG_MODULE_ACE,"fail to get service %s\n", E53_IA1_SERVICE);
        return JSI::CreateUndefined();
    }

    if ((args == nullptr) || (argsNum == 0) || (JSI::ValueIsUndefined(args[0]))) {
        return JSI::CreateUndefined();
    }

    JSIValue success = JSI::GetNamedProperty(args[0], CB_SUCCESS);
    JSIValue fail = JSI::GetNamedProperty(args[0], CB_FAIL);
    JSIValue complete = JSI::GetNamedProperty(args[0], CB_COMPLETE);

   int cmd = E53_IA1_SetLight;
    // int32_t cmd = (int32_t)JSI::GetNumberProperty(args[0], "cmd");  
    int onOff= (int)JSI::GetNumberProperty(args[0], "onOff");
    const char *data = onOff ? "ON" : "OFF";
    HILOG_ERROR(HILOG_MODULE_ACE, "cmd is: %d\n", cmd);
    HILOG_ERROR(HILOG_MODULE_ACE,"data is: %s\n", data);
    char *replyData;

    if (E53IA1Control(serv, cmd, data, &replyData))
    {
        HILOG_ERROR(HILOG_MODULE_ACE,"fail to send event\n");
        JSI::CallFunction(fail, thisVal, nullptr, 0);
        JSI::CallFunction(complete, thisVal, nullptr, 0);
        JSI::ReleaseValueList(success, fail, complete);
        return JSI::CreateUndefined();
    }

    JSIValue result = JSI::CreateObject();

    JSI::SetStringProperty(result, "set led", replyData);
    JSIValue argv[ARGC_ONE] = {result};
    JSI::CallFunction(success, thisVal, argv, ARGC_ONE);
    JSI::CallFunction(complete, thisVal, nullptr, 0);
    JSI::ReleaseValueList(success, fail, complete, result);

    HdfIoServiceRecycle(serv);

    return JSI::CreateUndefined();
}
           

六.安裝Hap包

安裝Hap包首先需要編譯然後導出hap包,在編譯出的hap包上右鍵選擇在檔案管理器打開:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例
#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

然後需要準備一張SD卡和讀卡器,按照小熊派官方的教程很輕松就能做到.

文檔位址:https://gitee.com/bearpi/bearpi-hm_micro_small/blob/master/applications/BearPi/BearPi-HM_Micro/docs/device-dev/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%BC%80%E5%8F%91%E6%9D%BF%E4%B8%8A%E5%AE%89%E8%A3%85HAP%E5%BA%94%E7%94%A8.md

實際過程如圖所示:

#夏日挑戰賽# 開發一個折疊屏micro的智能風扇案例

七.作品展示

到這一步就算完成作品了,請看視訊效果:

https://ost.51cto.com/show/15314

繼續閱讀