標籤:easyarm sysfs gpio
0 前言 本文描述如果通過檔案IO sysfs方式控制EasyARM GPIO連接埠。通過sysfs方式控制GPIO,先訪問/sys/class/gpio目錄,向export檔案寫入GPIO編號,使得該GPIO的操作介面從核心空間暴露到使用者空間,GPIO的操作介面包括direction和value等,direction控制GPIO方向,而value可控制GPIO輸出或獲得GPIO輸入。 Linux學習可從應用出發,先不糾結Linux驅動編寫,先把Linux給玩起來。
【相關博文】 【EasyARM i.mx28學習筆記——安裝和使用tftp】 【樹莓派學習筆記——Shell指令碼操作GPIO】 【 Linux學習筆記——例說makefile 索引博文】
【代碼倉庫】 代碼倉庫位於bitbucket——easyarm-gpio-sysfs,請使用Hg複製或者直接下載zip包。請不要使用任何版本的IE瀏覽器訪問連結,除非你已經知道所使用的IE瀏覽器符合HTML5標準。推薦使用Google或者Firefox瀏覽器訪問,若使用國產雙核瀏覽器請切換到極速模式。
1 暴露GPIO操作介面
static int gpio_export(int pin){ char buffer[BUFFER_MAX]; int len; int fd; fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) { fprintf(stderr, "Failed to open export for writing!\n"); return(-1); } len = snprintf(buffer, BUFFER_MAX, "%d", pin); if (write(fd, buffer, len) < 0) { fprintf(stderr, "Fail to export gpio!"); return -1; } close(fd); return 0;}
2 隱藏GPIO操作介面
static int gpio_unexport(int pin){ char buffer[BUFFER_MAX]; int len; int fd; fd = open("/sys/class/gpio/unexport", O_WRONLY); if (fd < 0) { fprintf(stderr, "Failed to open unexport for writing!\n"); return -1; } len = snprintf(buffer, BUFFER_MAX, "%d", pin); if (write(fd, buffer, len) < 0) { fprintf(stderr, "Fail to unexport gpio!"); return -1; } close(fd); return 0;}
3 配置GPIO方向
static int gpio_direction(int pin, int dir){ static const char dir_str[] = "in\0out"; char path[DIRECTION_MAX]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); if (fd < 0) { fprintf(stderr, "failed to open gpio direction for writing!\n"); return -1; } if (write(fd, &dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3) < 0) { fprintf(stderr, "failed to set direction!\n"); return -1; } close(fd); return 0;} 【簡單說明】 【1】dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3 如果輸入為常數宏IN, 取dir_str[0]=“in”;若輸入常數宏為OUT,取dir_str[0]=“out”。此處巧妙的使用了在數組中的“\0”。
4 控制GPIO輸出
static int gpio_write(int pin, int value){ static const char values_str[] = "01"; char path[DIRECTION_MAX]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_WRONLY); if (fd < 0) { fprintf(stderr, "failed to open gpio value for writing!\n"); return -1; } if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) { fprintf(stderr, "failed to write value!\n"); return -1; } close(fd); return 0;}
5 獲得GPIO輸入
static int gpio_read(int pin){ char path[DIRECTION_MAX]; char value_str[3]; int fd; snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, "failed to open gpio value for reading!\n"); return -1; } if (read(fd, value_str, 3) < 0) { fprintf(stderr, "failed to read value!\n"); return -1; } close(fd); return (atoi(value_str));}
6 GPIO翻轉操作 【main函數】
int main(int argc, char *argv[]){ int i = 0; gpio_export(P24); gpio_direction(P24, OUT); // GPIO為輸出狀態 for (i = 0; i < 10; i++) { printf("LED Blink\n"); gpio_write(P24, i % 2); usleep(500 * 1000); } gpio_write(P24, 0); // 恢複輸出低電平 gpio_unexport(P24); return 0;}
【makefile】——此處的代碼tab顯示可能存在問題,請以代碼倉庫為主。
# 可執行檔TARGET=test# 源檔案SRCS=gpio-sysfs.c# 目標檔案OBJS=$(SRCS:.c=.o)# 指令編譯器和選項CROSS=arm-fsl-linux-gnueabi-CC=$(CROSS)gccSTRIP=$(CROSS)stripCFLAGS=-Wall -std=gnu99 -O2$(TARGET):$(OBJS) $(CC) -o [email protected] $^ $(STRIP) [email protected]clean: rm -rf $(TARGET) $(OBJS)# 連續動作,先清除再編譯連結,複製到tftpboot中install:clean $(TARGET) @echo 複製到tftpboot目錄 cp $(TARGET) ~/tftpboot @echo 複製結束# 編譯規則 [email protected]代表目標檔案 $< 代表第一個依賴檔案%.o:%.c $(CC) $(CFLAGS) -o [email protected] -c $<
【交叉編譯並複製到tftp根目錄】 make 再把可執行檔test複製到tftp根目錄中,makefile的使用詳見【 Linux學習筆記——例說makefile 索引博文】
【目標板中使用tftp獲得可執行檔】 為了方便操作,在目標板中建立一個名為run-test.sh的指令碼並修改執行許可權,tftp的使用方法詳見【EasyARM i.mx28學習筆記——安裝和使用tftp】
#!/bin/sh tftp -g -r test 192.168.1.106 chmod a+x test echo "start to run test." ./test
【執行指令碼 運行test】 ./run-test.sh
圖1 最終效果
7 總結【1】檔案IO方式操作GPIO,使用到了4個函數open close read write。【2】向export寫入具體的GPIO編號便可把控制介面從核心空間暴露到使用者空間。【3】使用檔案IO操作Linux外設的方法具有通用性,樹莓派同樣可以使用該方法。