在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) ;
}