嵌入式Linux系統(tǒng)中對GPIO操作的方法總結(jié)

在Linux系統(tǒng)里操作GPIO的方法有以下幾個(gè):

1. 寫驅(qū)動的方式

需要自己編寫linux驅(qū)動,在驅(qū)動里操控GPIO,應(yīng)用通過驅(qū)動提供的節(jié)點(diǎn)來控制GPIO。優(yōu)點(diǎn)是結(jié)構(gòu)清晰,可擴(kuò)展性強(qiáng),比較靈活。缺點(diǎn)是實(shí)現(xiàn)的過程比較繁瑣。

編寫驅(qū)動可能會用到的kernel函數(shù):

檢查GPIO是不是有效的:

int gpio_is_valid(int number);

設(shè)備GPIO的方向(輸入/輸出):

/* set as input or output, returning 0 or negative errno */

int gpio_direction_input(unsigned gpio);

int gpio_direction_output(unsigned gpio, int value);

請求GPIO的資源:

/* request GPIO, returning 0 or negative errno.

* non-null labels may be useful for diagnostics.

*/

int gpio_request(unsigned gpio, const char *label);

清除GPIO資源:

/* release previously-claimed GPIO */

void gpio_free(unsigned gpio);

讀取GPIO的狀態(tài):

/* GPIO INPUT: ?return zero or nonzero */

int gpio_get_value(unsigned gpio);

設(shè)備GPIO的狀態(tài):

/* GPIO OUTPUT */

void gpio_set_value(unsigned gpio, int value);

詳情請參考linuxdir/documentation/gpio.txt

2. 通過linux提供的用戶空間

通過在用戶空間上來操作GPIO,控制入口在:/sys/class/gpio/。不過需要打開kernel中的相應(yīng)的選項(xiàng):Device Drivers->GPIO Support->/sys/class/gpio/... (sysfs nterface)。

優(yōu)點(diǎn)是簡單方便,缺點(diǎn)是可擴(kuò)展性差。

往export中寫入GPIO的號,將會打開Kernel提供的GPIO的用戶空間入口。

?例如: ?"echo 19 > export" 將會創(chuàng)建一個(gè) "gpio19" 的文件夾。

往unexport文件中寫入GPIO號,將會關(guān)閉之前用export打開的入口。


例如: ?"echo 19 > unexport" 將會回收"gpio19"的文件夾。

GPIO文件夾中的屬性有以下幾個(gè)(如/sys/class/gpio/gpio19)

? ? /sys/class/gpio/gpioN/

"direction" 用來設(shè)置或讀取GPIO的方向??梢栽O(shè)置成"in" 或者 "out".

"value" 用來設(shè)置或讀取GPIO的值:0或者1. "echo 1 > value"將會把GPION設(shè)置成高電平。

"edge" 用來設(shè)置中斷類型。可以是"none", "rising", "falling", 或者

"both". 只有中斷類型可以配置的GPIO才會有這個(gè)屬性。

"active_low" 設(shè)置低電平有效。可以是0或1。

詳情請參考linuxdir/documentation/gpio.txt

3. 直接操作/dev/mem

可以直接對/dev/mem節(jié)點(diǎn)的內(nèi)存進(jìn)行讀寫來操作GPIO。不過需要參考CPU的datasheet,找到相應(yīng)的GPIO的寄存器地址。

優(yōu)點(diǎn)是方便,靈活,缺點(diǎn)是GPIO的寄存器地址不易得到。

下面的函數(shù)可以得到GPIO的起始地址,然后可以參考datasheet,對GPIO的方向,功能,和值進(jìn)行設(shè)備。只需要對下面函數(shù)中得到的gpio的地址進(jìn)行操作即可。

int GPIOSetup()

{

int fd = -1;

if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0)

{

printf ("wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ;

return 0;

}

// GPIO:

gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ;

if ((int32_t)gpio == -1)

{

printf("wiringPiSetup: mmap (GPIO) failed: %s\n", strerror (errno)) ;

return 0;

}

return 1;

}

這個(gè)是完整的程序,是在基于Raspberry Pi的平臺上進(jìn)行操作的。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define BCM2708_PERI_BASE?? ? ? ? ? ? ? ? ? ? 0x20000000

#define GPIO_BASE?(BCM2708_PERI_BASE + 0x00200000)

#define?BLOCK_SIZE?(4*1024)

#define?INPUT?0

#define?OUTPUT?1

#define?LOW?0

#define?HIGH?1

static volatile uint32_t *gpio ;

static uint8_t gpioToGPSET [] =

{

? ?7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,

? ?8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,

} ;

// gpioToGPCLR:

//?(Word) offset to the GPIO Clear registers for each GPIO pin

static uint8_t gpioToGPCLR [] =

{

? 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,

? 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,

} ;

// gpioToGPFSEL:

//?Map a BCM_GPIO pin to it's Function Selection

//?control port. (GPFSEL 0-5)

//?Groups of 10 - 3 bits per Function - 30 bits per port

static uint8_t gpioToGPFSEL [] =

{

? 0,0,0,0,0,0,0,0,0,0,

? 1,1,1,1,1,1,1,1,1,1,

? 2,2,2,2,2,2,2,2,2,2,

? 3,3,3,3,3,3,3,3,3,3,

? 4,4,4,4,4,4,4,4,4,4,

? 5,5,5,5,5,5,5,5,5,5,

} ;

// gpioToShift

//?Define the shift up for the 3 bits per pin in each GPFSEL port

static uint8_t gpioToShift [] =

{

? 0,3,6,9,12,15,18,21,24,27,

? 0,3,6,9,12,15,18,21,24,27,

? 0,3,6,9,12,15,18,21,24,27,

? 0,3,6,9,12,15,18,21,24,27,

? 0,3,6,9,12,15,18,21,24,27,

} ;

int GPIOSetup()

{

int fd = -1;

if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0)

{

printf ("wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ;

return 0;

}

// GPIO:

gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ;

if ((int32_t)gpio == -1)

{

printf("wiringPiSetup: mmap (GPIO) failed: %s\n", strerror (errno)) ;

return 0;

}

return 1;

}

int GPIOSetPinMode(int nPin, int mode)

{

int ? ?fSel = 0, shift = 0;

? ? fSel ? ?= gpioToGPFSEL [nPin] ;

? ? shift ? = gpioToShift ?[nPin] ;

if (mode == INPUT)

?*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input

else if (mode == OUTPUT)

?*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ;

return 0;

}

int GPIOSetPin(int nPin, int value)

{

? ? if (value == LOW)

? ? ? *(gpio + gpioToGPCLR [nPin]) = 1 << (nPin & 31) ;

? ? else

? ? ? *(gpio + gpioToGPSET [nPin]) = 1 << (nPin & 31) ;

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容