GPIO应用编程
对于给定的一个 GPIO 引脚,如何计算它在 sysfs 中对应的编号呢?其实非常简单,譬如给定一个 GPIO引脚为 GPIO4_IO16,那它对应的编号是多少呢?首先我们要确定 GPIO4 对应于 gpiochip96,该组 GPIO 引 脚的最小编号是 96(对应于 GPIO4_IO0),所以 GPIO4_IO16 对应的编号自然是 96 + 16 = 112;同理GPIO3_IO20 对应的编号是 64 + 20 = 84。
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
gpio_ctrl.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "gpio_ctrl.h"
/****************************************************************
* Constants
****************************************************************/
#define GPIO_CMD_MAX_BUF 64
#ifdef PLATFORM_X86
#define PERROR
#else
#define PERROR perror
#endif
#ifndef RT_KERNEL
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define SYSFS_PWM_DIR "/sys/class/pwm/pwmchip0/"
/****************************************************************
* gpio_export
****************************************************************/
int gpio_export(unsigned int gpio)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
if (fd < 0) {
PERROR("gpio/export");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
/****************************************************************
* gpio_unexport
****************************************************************/
int gpio_unexport(unsigned int gpio)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
if (fd < 0) {
PERROR("gpio/export");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
/****************************************************************
* gpio_set_dir
****************************************************************/
int gpio_set_dir(unsigned int gpio, int dir)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("gpio/direction");
return fd;
}
if (dir == GPIO_DIR_OUT)
write(fd, "out", 4);
else
write(fd, "in", 3);
close(fd);
return 0;
}
/****************************************************************
* gpio_set_edge
****************************************************************/
int gpio_set_edge(unsigned int gpio, int edge)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("gpio/set-edge");
return fd;
}
const char *pedge;
if(edge==EDGE_TYPE_RISING){
pedge = "rising";
}
else if(edge==EDGE_TYPE_FALLING){
pedge = "falling";
}
else if(edge==EDGE_TYPE_BOTH){
pedge = "both";
}
else{
pedge = "none";
}
write(fd, pedge, strlen(pedge) + 1);
close(fd);
return 0;
}
int gpio_open_value(unsigned int gpio, int flag)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
char ch;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, flag);
if (fd < 0) {
PERROR("gpio/get-value");
return fd;
}
return fd;
}
/****************************************************************
* gpio_set_value
****************************************************************/
int gpio_set_value(unsigned int gpio, int value)
{
int fd;
fd = gpio_open_value(gpio, O_WRONLY);
if (value)
write(fd, "1", 2);
else
write(fd, "0", 2);
close(fd);
return 0;
}
/****************************************************************
* gpio_get_value
****************************************************************/
int gpio_get_value(unsigned int gpio)
{
int fd;
char ch;
fd = gpio_open_value(gpio, O_RDONLY);
read(fd, &ch, 1);
close(fd);
return ch == '0' ? 0:1;
}
void gpio_set_value_by_fd(int fd, int value)
{
write(fd, value ? "1":"0", 2);
}
int gpio_get_value_by_fd(int fd)
{
char ch;
read(fd, &ch, 1);
lseek(fd, 0, SEEK_SET);
return ch == '0' ? 0:1;
}
void gpio_pulse_by_fd(int fd, int pulse, int time)
{
gpio_set_value_by_fd(fd, pulse);
usleep(time*1000);
gpio_set_value_by_fd(fd, !pulse);
}
int gpio_open(int gpio, GPIO_DIR_TYPE inout, EDGE_TYPE edge, int flag)
{
//printf("gpio_open+++gpio=%d, inout=%d, edge=%d\n", gpio, inout, edge);
gpio_export(gpio);
gpio_set_dir(gpio, inout);
gpio_set_edge(gpio, edge);
return gpio_open_value(gpio, flag);
}
int gpio_read_only_open(int gpio)
{
return gpio_open(gpio, GPIO_DIR_IN, EDGE_TYPE_NONE, O_RDONLY);
}
int gpio_write_only_open(int gpio, int init_value)
{
int fd = gpio_open(gpio, GPIO_DIR_OUT, EDGE_TYPE_NONE, O_WRONLY);
if(fd >= 0 && init_value>=0){
gpio_set_value_by_fd(fd, init_value);
}
return fd;
}
int gpio_select_open(int gpio, int edge)
{
return gpio_open(gpio, GPIO_DIR_IN, (EDGE_TYPE)edge, O_RDONLY);
}
int pwm_open(int pwm, int fre, int duty, int init_value)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
//open export
fd = open(SYSFS_PWM_DIR "/export", O_WRONLY);
if (fd < 0) {
PERROR("export");
return fd;
}
//write export
len = snprintf(buf, sizeof(buf), "%d", pwm);
write(fd, buf, len);
close(fd);
//open period
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/period", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
//write period
len = snprintf(buf, sizeof(buf), "%d", fre);
write(fd, buf, len);
close(fd);
//open duty_cycle
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/duty_cycle", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
//write duty
len = snprintf(buf, sizeof(buf), "%d", duty);
write(fd, buf, len);
close(fd);
//open enable
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/enable", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
if(init_value>=0){
gpio_set_value_by_fd(fd, init_value);
}
return fd;
}
#else
#define DEV_GPIO_DIR "/dev/rtdm/gpio"
int gpio_read_only_open(int gpio)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
len = snprintf(buf, sizeof(buf), DEV_GPIO_DIR "/gpio%d", gpio);
fd = open(buf, O_RDONLY | O_NONBLOCK );
if(fd >= 0){
ioctl(fd, GPIO_RTIOC_DIR_IN);
}
return fd;
}
int gpio_write_only_open(int gpio, int init_value)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
len = snprintf(buf, sizeof(buf), DEV_GPIO_DIR "/gpio%d", gpio);
fd = open(buf, O_WRONLY);
if(fd >= 0){
ioctl(fd, GPIO_RTIOC_DIR_OUT, &init_value);
}
return fd;
}
int gpio_select_open(int gpio, int edge)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
len = snprintf(buf, sizeof(buf), DEV_GPIO_DIR "/gpio%d", gpio);
fd = open(buf, O_RDWR);
if(fd >= 0){
int trigger;
if(edge==EDGE_TYPE_RISING){
trigger = GPIO_TRIGGER_EDGE_RISING;
}
else if(edge==EDGE_TYPE_FALLING){
trigger = GPIO_TRIGGER_EDGE_FALLING;
}
else if(edge==EDGE_TYPE_BOTH){
trigger = GPIO_TRIGGER_EDGE_RISING | GPIO_TRIGGER_EDGE_FALLING;
}
else{
trigger = GPIO_TRIGGER_EDGE_RISING;
}
ioctl(fd, GPIO_RTIOC_IRQEN, &trigger);
}
return fd;
}
/****************************************************************
* gpio_set_value
****************************************************************/
void gpio_set_value_by_fd(int fd, int value)
{
write(fd, &value, sizeof(value));
}
int gpio_get_value_by_fd(int fd)
{
int value = 10;
int ret = read(fd, &value, sizeof(value));
//lseek(fd, 0, SEEK_SET);
return value;
}
void gpio_pulse_by_fd(int fd, int pulse, int time)
{
gpio_set_value_by_fd(fd, pulse);
usleep(time*1000);
gpio_set_value_by_fd(fd, !pulse);
}
#endif
gpio_ctrl.h
#ifndef _GPIO_CTRL_H_
#define _GPIO_CTRL_H_
#ifdef RT_KERNEL
#include <rtdm/gpio.h>
#endif
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
typedef enum
{
GPIO_DIR_IN,
GPIO_DIR_OUT,
}GPIO_DIR_TYPE;
typedef enum
{
EDGE_TYPE_NONE,
EDGE_TYPE_RISING,
EDGE_TYPE_FALLING,
EDGE_TYPE_BOTH,
}EDGE_TYPE;
int gpio_read_only_open(int gpio);
int gpio_write_only_open(int gpio, int init_value);
int gpio_select_open(int gpio, int trigger);
void gpio_set_value_by_fd(int fd, int value);
int gpio_get_value_by_fd(int fd);
void gpio_pulse_by_fd(int fd, int pulse, int time);
int pwm_open(int pwm, int fre, int duty, int init_value);
#endif
测试代码如下
#include "gpio_ctrl.h"
#define BEEP_GPIO_NUM GPIO_TO_PIN(0, 7)
void main(void)
{
int beep_gpio_fd = gpio_write_only_open(BEEP_GPIO_NUM, 0);
sleep(1000);
gpio_set_value_by_fd(beep_gpio_fd, 1);
sleep(1000);
gpio_set_value_by_fd(beep_gpio_fd, 0);
sleep(1000);
close(beep_gpio_fd);
reutrn 0;
}
#include "gpio_ctrl.h"
#define KEY_GPIO_NUM GPIO_TO_PIN(0, 8)
void main(void)
{
int value;
int key_gpio_fd = gpio_read_only_open(BEEP_GPIO_NUM);
while(1)
{
value=gpio_get_value_by_fd(key_gpio_fd);
printf("value:%d\n",value);
sleep(100);
}
close(key_gpio_fd);
reutrn 0;
}
#include "gpio_ctrl.h"
#include <poll.h>
#define KEY1_GPIO_NUM GPIO_TO_PIN(0, 7)
#define KEY2_GPIO_NUM GPIO_TO_PIN(0, 8)
#define KEY3_GPIO_NUM GPIO_TO_PIN(0, 9)
void main(void)
{
int ret;
char buf[16];
struct pollfd fds[3];
int key1_gpio_fd = gpio_select_open(KEY1_GPIO_NUM, EDGE_TYPE_BOTH);
int key2_gpio_fd = gpio_select_open(KEY1_GPIO_NUM, EDGE_TYPE_RISING);
int key3_gpio_fd = gpio_select_open(KEY1_GPIO_NUM, EDGE_TYPE_FALLING);
fds[0].fd = key1_gpio_fd;
fds[0].events = POLLPRI;
fds[1].fd = key2_gpio_fd;
fds[1].events = POLLPRI;
fds[2].fd = key3_gpio_fd;
fds[2].events = POLLPRI;
while(1)
{
ret = poll(fds, ARRAYLEN(fds), -1);
if (ret > 0){
if(fds[0].revents & POLLPRI){
read(fds[0].fd, buf, sizeof(buf));
lseek(fds[0].fd, 0, SEEK_SET);
}
if(fds[1].revents & POLLPRI){
read(fds[1].fd, buf, sizeof(buf));
lseek(fds[1].fd, 0, SEEK_SET);
}
if(fds[2].revents & POLLPRI){
read(fds[2].fd, buf, sizeof(buf));
lseek(fds[2].fd, 0, SEEK_SET);
}
}
}
close(key1_gpio_fd);
close(key2_gpio_fd);
close(key3_gpio_fd);
reutrn 0;
}
PWM 应用编程
//pwm_open接口这里只是 对pwmchip0这个pwm控制器生效,一般SOC都会有多个PWM控制器,每个控制器又有多路pwm输出
#define SYSFS_PWM_DIR "/sys/class/pwm/pwmchip0/"
int pwm_open(int pwm, int fre, int duty, int init_value)
{
int fd, len;
char buf[GPIO_CMD_MAX_BUF];
//open export
fd = open(SYSFS_PWM_DIR "/export", O_WRONLY);
if (fd < 0) {
PERROR("export");
return fd;
}
//write export
len = snprintf(buf, sizeof(buf), "%d", pwm);
write(fd, buf, len);
close(fd);
//open period
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/period", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
//write period
len = snprintf(buf, sizeof(buf), "%d", fre);
write(fd, buf, len);
close(fd);
//open duty_cycle
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/duty_cycle", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
//write duty
len = snprintf(buf, sizeof(buf), "%d", duty);
write(fd, buf, len);
close(fd);
//open enable
len = snprintf(buf, sizeof(buf), SYSFS_PWM_DIR "/pwm%d/enable", pwm);
fd = open(buf, O_WRONLY);
if (fd < 0) {
PERROR("period");
return fd;
}
if(init_value>=0){
gpio_set_value_by_fd(fd, init_value);
}
return fd;
}
测试代码
#include "gpio_ctrl.h"
void main(void)
{
int beep_gpio_fd = pwm_open(0, 4000, 60, 0);//以 ns(纳秒)为单位
sleep(2000);
reutrn 0;
}