Node.js 控制硬件,cubieboard的GPIO(更新了测试视频,本人亲身上阵)
发布于 11 年前 作者 hexie 9967 次浏览 最后一次编辑是 8 年前

排版有点吃力,看原博客会好点 博客地址:http://blog.whattoc.com/2013/09/08/nodejs_api_addon_4/

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

演示视频:http://v.youku.com/v_show/id_XNjA5MzI0OTQ0.html = =本人亲身上阵。

工作原理

利用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就会一闪一闪的样子。打算去买一块面包,演示一下。

5 回复

支持啊~我想知道你用什么办法把代码录入到芯片里去?

不错,不过如果node能直接调用c的接口就好了,你这个cpp只是传递了一下就这么长的代码。

那个开发板,自带4G nand flash,系统也在里面,将代码通过网络拷贝进去,然后利用node-gyp 编译就好了,现在板子的性能都不错。能直接编译了。

更新了,顶一下

用个视屏录像器吧

回到顶部