soloforce 发表于 2013-5-7 22:26:31

【原创】用C控制GPIO的代码[可以直接看CPU占用率了]

本帖最后由 soloforce 于 2013-5-20 12:15 编辑

现在不需要通过写IO文件来操作GPIO了,请参考这个帖子:http://forum.cubietech.com/forum.php?mod=viewthread&tid=464&page=1&extra=#pid2719

写了个C语言控制GPIO的代码,目前只支持数字IO(只有0和1),分享一下。API模仿Arduino的风格,比较简单易用。#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/**
* Here we use the GPIO expansion near the SATA connector, from PD1 ~ PD7
* */
#define MIN_PIN 1
#define MAX_PIN 7

/**
* Binary value that GPIO pins could accept
* */
typedef enum{
    LOW=0,
    HIGH=1
}value_t;

/**
* GPIO pins get/set direction
* */
typedef enum{
   IN=0,
   OUT=1
}direction_t;

FILE* value_fp;

/**
* @brief Initialize the GPIO ports' value file pointers
*
* */
void gpio_init()
{
    int i;
    for(i=MIN_PIN;i<=MAX_PIN;i++)
      value_fp=NULL;
}

/**
* @brief Uninitialize the GPIO ports, unexport those exported and close files.
*
* */
int gpio_uninit()
{
    int i;
    FILE *unexport_fp=fopen("/sys/class/gpio/unexport","w");
    if(!unexport_fp) return -1;

    for(i=MIN_PIN;i<=MAX_PIN;i++){
      if(value_fp){
            fclose(value_fp);
            fprintf(unexport_fp,"%d",i);
            fflush(unexport_fp);
      }   
    }

    fclose(unexport_fp);

    return 0;
}

/**
* @brief Set the GPIO pins to specified direction
*
* @param pin: GPIO pin to set direction
* @param dir: IN or OUT
*
* */
int pinMode(int pin, direction_t dir)
{
    char direction_file;
    char value_file;

    FILE *export_fp=fopen("/sys/class/gpio/export","w");
    if(!export_fp) return -1;
   
    fprintf(export_fp,"%d",pin);
    sleep(1);
    fclose(export_fp);

    sprintf(direction_file,"/sys/class/gpio/gpio%d_pd%d/direction", pin, pin);
    FILE *direction_fp=fopen(direction_file,"w");
    if(!direction_fp) return -2;

    if(dir==OUT){
      fprintf(direction_fp,"out");
    }else fprintf(direction_fp,"in");

    fclose(direction_fp);

    sprintf(value_file,"/sys/class/gpio/gpio%d_pd%d/value", pin, pin);
    value_fp=fopen(value_file,"w");

    if(!value_fp) return -3;


    return 0;

}

/**
* @brief Set the GPIO pins to specified binary value
*
* @param pin: GPIO pin to set value
* @param value: LOW or HIGH
*
* */
int digitalWrite(int pin, value_t value)
{

    if(!value_fp)return -1;

    if(pin<MIN_PIN) pin=MIN_PIN;
    if(pin>MAX_PIN) pin=MAX_PIN;

    fprintf(value_fp,"%d", value);
    fflush(value_fp);

    return 0;
}

/**
* @brief A demo to alternately set two GPIO pin's power level (LOW or HIGH),
*       to flash a LED connected between the two pins.
* */
int main()
{
    gpio_init();

    pinMode(1,OUT);
    pinMode(2,OUT);

    int i;
    for(i=0;i<10;i++){
      digitalWrite(1,HIGH);
      digitalWrite(2,LOW);
      sleep(1);

      digitalWrite(1,LOW);
      digitalWrite(2,HIGH);
      sleep(1);
    }

    gpio_uninit();
}

soloforce 发表于 2013-5-8 18:16:53

本帖最后由 soloforce 于 2013-5-9 21:35 编辑

再发一个用GPIO控制LED显示当前CPU繁忙情况的小程序。

在GPIO的LD1~LD6接了3只LED,以二进制码形式显示CPU使用率。#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>


/**
* Here we use the GPIO expansion near the SATA connector, from PD1 ~ PD7
* */
#define MIN_PIN 1
#define MAX_PIN 7

/**
* Binary value that GPIO pins could accept
* */
typedef enum{
    LOW=0,
    HIGH=1
}value_t;

/**
* GPIO pins get/set direction
* */
typedef enum{
   IN=0,
   OUT=1
}direction_t;

typedef struct{
    long int user,nice,sys,idle,iowait,irq,softirq;
}jiffies_t;


/**
* GPIO pin values' file pointers
* */
FILE* value_fp={NULL};

/**
* Signal actions structures
* */
struct sigaction int_act,term_act, old_act;


/**
* @brief Signal INT handler
* */
void sigint_handler(int sig_num)
{
    printf("Uninitialzing GPIO...\n");

    /* uninitialize the GPIO */
    gpio_uninit();

    /* change back to the original handler */
    sigaction(SIGINT, &old_act,NULL);

   
    /* emit the SIGINT again */
    kill(0,SIGINT);
}

/**
* @brief Signal TERM handler
* */
void sigterm_handler(int sig_num)
{
    printf("Uninitialzing GPIO...\n");

    /* uninitialize the GPIO */
    gpio_uninit();

    /* change back to the original handler */
    sigaction(SIGTERM, &old_act,NULL);

    /* emit the SIGTERM again */
    kill(0,SIGTERM);
}


/**
* @brief Initialize signals
* * */
void catch_signal_init()
{
    memset(&int_act,0,sizeof(int_act));
    memset(&term_act,0,sizeof(int_act));
    memset(&old_act,0,sizeof(old_act));
    int_act.sa_handler=&sigint_handler;
    term_act.sa_handler=&sigterm_handler;
    sigaction(SIGINT, &int_act, &old_act);
    sigaction(SIGTERM, &term_act, &old_act);
}


/**
* @brief Initialize the GPIO ports' value file pointers
*
* */
void gpio_init()
{
    int i;
    for(i=MIN_PIN;i<=MAX_PIN;i++)
      value_fp=NULL;

    pinMode(1,OUT);
    pinMode(2,OUT);
    pinMode(3,OUT);
    pinMode(4,OUT);
    pinMode(5,OUT);
    pinMode(6,OUT);
}

/**
* @brief Uninitialize the GPIO ports, unexport those exported and close files.
*
* */
int gpio_uninit()
{
    int i;
    FILE *unexport_fp=fopen("/sys/class/gpio/unexport","w");
    if(!unexport_fp) return -1;

    for(i=MIN_PIN;i<=MAX_PIN;i++){
      if(value_fp){
            fclose(value_fp);
            fprintf(unexport_fp,"%d",i);
            fflush(unexport_fp);
      }   
    }

    fclose(unexport_fp);

    return 0;
}

/**
* @brief Set the GPIO pins to specified direction
*
* @param pin: GPIO pin to set direction
* @param dir: IN or OUT
*
* */
int pinMode(int pin, direction_t dir)
{
    char direction_file;
    char value_file;

    FILE *export_fp=fopen("/sys/class/gpio/export","w");
    if(!export_fp) return -1;
   
    fprintf(export_fp,"%d",pin);
    sleep(1);
    fclose(export_fp);

    sprintf(direction_file,"/sys/class/gpio/gpio%d_pd%d/direction", pin, pin);
    FILE *direction_fp=fopen(direction_file,"w");
    if(!direction_fp) return -2;

    if(dir==OUT){
      fprintf(direction_fp,"out");
    }else fprintf(direction_fp,"in");

    fclose(direction_fp);

    sprintf(value_file,"/sys/class/gpio/gpio%d_pd%d/value", pin, pin);
    value_fp=fopen(value_file,"w");

    if(!value_fp) return -3;


    return 0;

}

/**
* @brief Set the GPIO pins to specified binary value
*
* @param pin: GPIO pin to set value
* @param value: LOW or HIGH
*
* */
int digitalWrite(int pin, value_t value)
{

    if(!value_fp)return -1;

    if(pin<MIN_PIN) pin=MIN_PIN;
    if(pin>MAX_PIN) pin=MAX_PIN;

    fprintf(value_fp,"%d", value);
    fflush(value_fp);

    return 0;
}

/**
* @brief Get CPU jiffies from /proc/stat
*
* @param s(OUTPUT) Point of CPU jiffies structure
*
* */
int get_jiffies(jiffies_t *s)
{
    char buf={0};
    char cpu={0};

    if(!s) return -1;
    FILE* cpu_stat_fp = fopen("/proc/stat","r");
    if(cpu_stat_fp == NULL){
      return -1;
    }

    fgets(buf,sizeof(buf),cpu_stat_fp);
    sscanf(buf,"%s%d%d%d%d%d%d%d",cpu, &(s->user),&(s->nice),&(s->sys),&(s->idle),&(s->iowait),&(s->irq),&(s->softirq));

    fclose(cpu_stat_fp);
    return 0;
}

/**
* @brief Get CPU usage
*
* @param usage(OUTPUT): CPU usage in a short time
*
* */
int get_cpu_usage(float * usage)
{
    jiffies_t j1,j2;
    float all1, all2;
    int status;

    if(!usage) return -1;

    status=get_jiffies(&j1);
    if(status) return -2;
    usleep(100000);
    status=get_jiffies(&j2);
    if(status) return -2;

   
    all1=j1.user+j1.nice+j1.sys+j1.idle+j1.iowait+j1.irq+j1.softirq;
    all2=j2.user+j2.nice+j2.sys+j2.idle+j2.iowait+j2.irq+j2.softirq;

    *usage=((all2-j2.idle)-(all1-j1.idle))/(all2-all1) ;

    return 0;
}

/**
* @brief Show CPU usage to LEDs in binary-mode
*
* @param n(INPUT): CPU usage level, from 0~7
*
* */
void show_cpu_usage(int n)
{

    if(n & 0x04){
      digitalWrite(1,LOW);
      digitalWrite(2,HIGH);
    }else{
      digitalWrite(1,HIGH);
      digitalWrite(2,LOW);
    }


    if(n & 0x02){
      digitalWrite(3,LOW);
      digitalWrite(4,HIGH);
    }else{
      digitalWrite(3,HIGH);
      digitalWrite(4,LOW);
    }


    if(n & 0x01){
      digitalWrite(5,LOW);
      digitalWrite(6,HIGH);
    }else{
      digitalWrite(5,HIGH);
      digitalWrite(6,LOW);
    }
}



/**
* @brief A daemon to show CPU usage through GPIO expansion
*       to flash a LED connected between the two pins. Press Ctrl+C to Quit.
* */
int main()
{
    float usage;
    pid_t pid=fork();
   

    /* Create a daemon process, and terminate the parent process. */
    if(pid>0) exit(0);
    if(pid<0) {
      printf("Failed to create sub-process!\n");
      exit(-1);
    }
    setsid();
    catch_signal_init();
    gpio_init();
   
    while(1){
      if(get_cpu_usage(&usage)){
            printf("Failed to get CPU usage!\n");
            break;
      }

      int n=(int)(usage*8);
      if(n>7) n=7;
      show_cpu_usage(n);
      sleep(1);
    }

   
}

cubieplayer 发表于 2013-5-8 22:01:10

赞!代码很工整

jarry 发表于 2013-5-8 23:04:26

{:soso_e100:} 看到使用了两种不同函数命名规则 :)

hipboi 发表于 2013-5-10 10:44:27

unix风格和arduino风格。。。

gootoomoon 发表于 2013-6-17 15:32:54

有没有可能把树莓派的 WiringPi 直接移植过来? 貌似他们的东西做得挺全的,有机会可以探讨一下

pc3000 发表于 2013-6-19 11:29:46

学习了,这个也是直接调用Python GPIO库?

tll 发表于 2013-6-29 20:17:33

特别喜欢arduino风格,和以前我学的Action Script 2&3很像~

寒寒 发表于 2013-7-8 13:31:01

py的库好像内容不丰富啊

f839903061 发表于 2013-7-9 15:00:04

:)

版主有没有android的gpio的读写工具类或者源码
I2C读写的工具栏或源码呢?能否发一份呢?


谢谢!
页: [1] 2
查看完整版本: 【原创】用C控制GPIO的代码[可以直接看CPU占用率了]