詳解Node.js API系列C/C++ Addons(4) Javascript也能搞嵌入式?

回憶一下,我們已經完成了addon的相關學習了
詳解Node.js API系列C/C++ Addons(1) API文檔
詳解Node.js API系列C/C++ Addons(2) Google V8引擎
詳解Node.js API系列C/C++ Addons(3) 程序實例

利用這些知識,讓我們做一些瘋狂的事情吧,利用Node.js控制嵌入式系統硬件

工作原理

利用Node.js的Addon模塊作爲調用硬件控制C庫的中間件,Node.js異步的特性,非常適合處理各種硬件的IO。本次實踐使用的是cubieboard的開發板,Node.js將會控制板子的GPIO的PD0,讓它1000ms產生一個高低電平,使LED燈能夠一閃一閃的樣子。

執行代碼

vi run.js

var GPIO = require('./build/Release/gpio');

var LED = GPIO.PD0;
var status = 0;
GPIO.init();

GPIO.setcfg(LED, GPIO.OUT);

// 讓led 一閃一閃
var blink = function(){
    if(status){
        GPIO.output(LED, GPIO.LOW);
        status = 0;
    } else {
        GPIO.output(LED, GPIO.HIGH);
        status = 1;
    }
}

setInterval(blink, 1000);

vi gpio.cpp

#include <node.h>
// 調用cubieboard的硬件控制庫
extern "C"{
#include "gpio_lib.h"
}
// 定義一些工具宏
#define WIRING_DEFINE_CONSTANT(NAME, VALUE) (target)->Set( \
        v8::String::NewSymbol(NAME), \
        v8::Integer::New(VALUE), \
        static_cast<v8::PropertyAttribute>(v8::ReadOnly|v8::DontDelete) \
);
#define PD0    SUNXI_GPD(0)
using namespace v8;
// 初始化gpio的寄存器
Handle<Value> GPIO_init(const Arguments& args) {
    HandleScope scope;
    int32_t result;
    result = sunxi_gpio_init();
    if(result == SETUP_DEVMEM_FAIL){
    return ThrowException(
            Exception::TypeError(String::New("SETUP_DEVMEM_FAIL Error"))
        );
    }
    if(result == SETUP_MALLOC_FAIL){
        return ThrowException(
            Exception::TypeError(String::New("SETUP_MALLOC_FAIL Error"))
        );
    }
    if(result == SETUP_MMAP_FAIL){
        return ThrowException(
            Exception::TypeError(String::New("SETUP_MMAP_FAIL Error"))
        ); 
    }
    return scope.Close(Integer::New(SETUP_OK));
}
Handle<Value> GPIO_cleanup(const Arguments& args) {
    HandleScope scope;
    sunxi_gpio_cleanup();
    return scope.Close(Undefined());
}
// 獲取引腳當狀態 IN,OUT,PRE?
Handle<Value> GPIO_getcfg(const Arguments& args) {
    HandleScope scope;

    if (args.Length() < 1){
        return ThrowException(
            Exception::TypeError(String::New("Wrong number of arguments"))
        );
    }
    if (!args[0]->IsNumber()){
        return ThrowException(
             Exception::TypeError(String::New("Wrong arguments"))
        );
    }
    int32_t result;
    int32_t gpio = args[0]->ToInteger()->Value();
    result = sunxi_gpio_get_cfgpin(gpio);
    return scope.Close(Integer::New(result));
}
// 讀取的電平狀態 HIGH?LOW?
Handle<Value> GPIO_input(const Arguments& args) {
    HandleScope scope;
    if (args.Length() < 1){
        return ThrowException(
            Exception::TypeError(String::New("Wrong number of arguments"))
        );
    }
    if (!args[0]->IsNumber()){
        return ThrowException(
             Exception::TypeError(String::New("Wrong arguments"))
        );
    }
    int32_t result;
    int32_t gpio = args[0]->ToInteger()->Value();
    result = sunxi_gpio_input(gpio);
    if(result == -1){
        return ThrowException(
             Exception::TypeError(String::New("Reading pin failed"))
        );
    }
    return scope.Close(Integer::New(result));
}

// 輸出電平
Handle<Value> GPIO_output(const Arguments& args) {
    HandleScope scope;
    if (args.Length() < 2){
        return ThrowException(
            Exception::TypeError(String::New("Wrong number of arguments"))
        );    
    }
    if (!args[0]->IsNumber() || !args[1]->IsNumber()){
        return ThrowException(           
         Exception::TypeError(String::New("Wrong arguments"))
        );
    }
    int32_t gpio = args[0]->ToInteger()->Value();
    int32_t value = args[1]->ToInteger()->Value();
    if( value != 0 && value != 1) {
        return ThrowException(                        
         Exception::TypeError(String::New("Invalid output state"))
        );
    }
    if(sunxi_gpio_get_cfgpin(gpio) != SUNXI_GPIO_OUTPUT) {
    return ThrowException( 
             Exception::TypeError(String::New("Invalid output state"))
        );
    }
    sunxi_gpio_output(gpio, value);
    return scope.Close(Undefined());
}
// 設置GPIO功能 IN?OUT?PRE?
Handle<Value> GPIO_setcfg(const Arguments& args) {
    HandleScope scope;
    if (args.Length() < 2){
        return ThrowException(
            Exception::TypeError(String::New("Wrong number of arguments"))
        );
    }
    if (!args[0]->IsNumber() || !args[1]->IsNumber()){
        return ThrowException(
             Exception::TypeError(String::New("Wrong arguments"))
        );
    }
    int32_t gpio = args[0]->ToInteger()->Value();
    int32_t direction = args[1]->ToInteger()->Value();
    if(direction != 0 && direction != 1 && direction != 2) {
        return ThrowException(
             Exception::TypeError(String::New("Invalid direction"))
        );
    }
    sunxi_gpio_set_cfgpin(gpio, direction);
    return scope.Close(Undefined());
}
void RegisterModule(Handle<Object> target) {
    NODE_SET_METHOD(target, "init", GPIO_init);
    NODE_SET_METHOD(target, "cleanup", GPIO_cleanup);
    NODE_SET_METHOD(target, "output", GPIO_output);
    NODE_SET_METHOD(target, "setcfg", GPIO_setcfg);
    NODE_SET_METHOD(target, "input", GPIO_input);
    NODE_SET_METHOD(target, "getcfg", GPIO_getcfg);
    WIRING_DEFINE_CONSTANT("HIGH", HIGH)
    WIRING_DEFINE_CONSTANT("LOW", LOW)
    WIRING_DEFINE_CONSTANT("PD0", PD0)
    WIRING_DEFINE_CONSTANT("IN", INPUT)
    WIRING_DEFINE_CONSTANT("OUT", OUTPUT)
    WIRING_DEFINE_CONSTANT("PER", PER)
}
NODE_MODULE(gpio, RegisterModule);

vi binding.gyp

{
  "targets": [
    {
      "target_name": "gpio",
      "include_dirs": ["lib"],
      "sources": [ 
    "gpio.cpp",
    "lib/gpio_lib.c",
    "lib/gpio_lib.h"
      ]
    }
  ]
}

測試

利用萬用表對準 GND 和 PD0,可以發現程序運行後,電壓3V - 0V 每隔1000ms產生一次變化,如果接上LED,LED就會一閃一閃的樣子。打算去買一塊麪包板,演示一下。

視頻 演示

http://v.youku.com/v_show/id_XNjA5MzI0OTQ0.html

項目地址:https://github.com/youyudehexie/node-cubieboard-gpio

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章