LinuxGPIO驱动使用其实很简单

Author:DriverMonkey

Mail:bookworepeng@Hotmail.com

Phone:13410905075

QQ:196568501


本文资料主要来自互联网,并通过本人亲测试正确性

How to use GPIO signals

Contents

  [hide]

References

GPIO Usage from a Linux Application

Overview

The following table summarizes the steps to configuring and using GPIO signals from a Linux application.

Step
Number
ActionDescription
1Configure the kernel for GPIO support in sysfsAllow GPIO configuration and control from Linux applications (user space). The GPIO shoulw up in the system file system, sysfs, at /sys/class/gpio
2Export GPIO to user spaceEach GPIO is are not accessible from user space until the GPIO has been exported. You can only export a GPIO that isn't owned by a Linux kernel driver
3Configure GPIO for input or outputTo avoid hardware issues where two devices are driving the same signal, GPIOs default to be configured as an input. If you want to use the GPIO as an output, you need to change the configuration
4Configure GPIO an an interrupt sourceIf you have a GPIO that is an input, and you have an application you want to block waiting for the GPIO to change level, you can configure the GPIO as an interrupt source. You also need to configure if the interrupt occurs when the GPIO signal has a rising edge, a falling edge, or interrupts on both rising and falling edges. Once configured as an interrupt, your application can read the value file and the read will block until the interrupt occurs, then your application will return from the read system call and continue running.

The sysfs directory /sys/class/gpio contains subdirectories and files that are used for configuring and using GPIO signals from a Linux application.


File or
directory
MeaningNotes
/sys/class/gpiosysfs GPIO subdirectoryLinux applications can configuration and use GPIO signals by accessing files in this subdirectory.
/sys/class/gpio/exportWrite-only file to expose a GPIOBefore a Linux application can configuration and use a GPIO, the GPIO first has to beexported to user space by writing the GPIO number to this file.
/sys/class/gpio/gpio<<<number>>>Subdirectory for configuring and reading a specific GPIO signalOnce a GPIO has been exported to user space, a new directory appears with a set of files that allow the GPIO to be configured and used by a Linux application
/sys/class/gpio/gpio<<<number>>>/directionRead-write supporting values of inand out 
/sys/class/gpio/gpio<<<number>>>/valueRead-write supporting values of 0 and1 
/sys/class/gpio/gpio<<<number>>>/edgeRead-write supporting values ofrisingfalling, and bothCheck your processor documentation. Not all GPIO pins support interrupts.

Configure the kernel for GPIO support in sysfs

Symbol: GPIO_SYSFS [=y]
  Prompt: /sys/class/gpio/... (sysfs interface)
    Defined at drivers/gpio/Kconfig:51
    Depends on: GPIOLIB && SYSFS && EXPERIMENTAL
     Location:
      -> Kernel configuration
        -> Device Drivers
         -> GPIO Support (GPIOLIB [=y])
 

Enable GPIO access from user space

GPIO=22

cd /sys/class/gpio
ls
echo $GPIO > export
ls

Notice on the first ls that gpio22 doesn't exist, but does after you export GPIO 22 to user space.

cd /sys/class/gpio/gpio$GPIO
ls

There are files to set the direction and retrieve the current value.

echo "in" > direction
cat value

You can configure the GPIO for output and set the value as well.


echo "out" > direction
echo 1 > value

GPIO interrupts from user space

Reference
LeopoardBoard 365 GPIO 0 connection

On the LeopardBoard 365, the only GPIO I could find that was usable for interrupt input is GPIO0, also called CMOS_TRIGGER in the schematics. In looking at the schematics resistor R12 is not loaded and one of the pads connects to CMOS_TRIGGER. This R12 pad is the one closest to R11. If you hold the leopardboard 365 with the SD card slot facing you and rotate the board until the SD card slot is on the bottom edge, the the R12 pads are to the right of J6 and to the left of the SD card slot upper left corner.

Leopardboard365-gpio0-haywire.jpg

Using poll() to monitor for GPIO 0 change

The gpio-int-test.c program (or gpiopin.cpp for those who prefer C++) shows one way of using the sysfs file /sys/class/gpio/gpio0/value to block program execution using poll() until the input level on GPIO0 changes. The tricky part was figuring out to use POLLPRI instead of POLLIN as the event to monitor. You must have GPIO support in sysfs for this program to work (or you will not see the /sys/class/gpio directory).


The gpio-int-test.c program uses poll() to wake up every 3 seconds (using poll() timeout mechanism) at which time it prints a period. The poll() function is also watching for input from stdin and for an interrupt from GPIO 0.

Here is an example output. I started gpio-int to watch GPIO 0. I waited around 12 seconds (4 timeout periods), then pressed the letter 'a' twice followed by enter key. Then I shorted the haywire to 3.3V that is accessible on pin 5 on the JTAG connector. JTAG pin 5 is across from the JTAG missing pin). I exited the program using cntl-C.

/root # gpio-int 0 

....aa

poll() stdin read 0xA61

poll() stdin read 0xA61

poll() stdin read 0xA0A
..
poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)
..^C

Viewing GPIO Configuration

You can use debugfs to videw the current GPIO configuration. You may also be able to use debugfs to see if the GPIO pin is multiplex as a GPIO or is dedicated to some other function.

Configure the kernel to enable debugfs:

Symbol: DEBUG_FS [=y]
   Prompt: Debug Filesystem
     Defined at lib/Kconfig.debug:77
     Depends on: SYSFS     
     Location:
       -> Kernel configuration
         -> Kernel hacking         

Boot the target hardware and mount debugfs:

mount -t debugfs none /sys/kernel/debug

Dump the GPIO configuration.

cat /sys/kernel/debug/gpio

Dump the pin multiplexing configuration.

cat /sys/kernel/debug/omap_mux/board      # for OMAP
cat /sys/kernel/debug/dm365_mux           # for DM36x

Example shell script making it easy to set GPIOs from the command line

If you want to have a simple way to control a GPIO signal from the Linux command line, try the gpio.sh script below.

For examaple, if you want to read the value of GPIO 72 without setting its direction, try

gpio.sh 72


If you want to force GPIO 35 to be in input and read the current value, try

gpio.sh 35 in

If you want to configure GPIO 4 to be an output and set the value high, try

gpio.sh 4 out 1

For the script below to work, you need to first make sure you have build busybox with printf enabled.

#!bin/sh

show_usage()
{
    printf "\ngpio.sh <gpio pin number> [in|out [<value>]]\n"
}

if [ \( $# -eq 0 \) -o \( $# -gt 3 \) ] ; then
    show_usage
    printf "\n\nERROR: incorrect number of parameters\n"
    exit 255
fi

#doesn't hurt to export a gpio more than once
echo $1 > /sys/class/gpio/export

if [  $# -eq 1 ] ; then
   cat /sys/class/gpio/gpio$1/value
   exit 0
fi

if [ \( "$2" != "in" \) -a  \( "$2" != "out" \) ] ; then
    show_usage
    printf "\n\nERROR: second parameter must be 'in' or 'out'\n"
    exit 255
fi

echo $2 > /sys/class/gpio/gpio$1/direction

if [  $# -eq 2 ] ; then
   cat /sys/class/gpio/gpio$1/value
   exit 0
fi


VAL=$3

if [ $VAL -ne 0 ] ; then
    VAL=1
fi

echo $VAL > /sys/class/gpio/gpio$1/value
以下是C语言测试代码:
/* Copyright (c) 2011, RidgeRun
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the RidgeRun.
 * 4. Neither the name of the RidgeRun nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>

 /****************************************************************
 * Constants
 ****************************************************************/
 
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
#define MAX_BUF 64

/****************************************************************
 * gpio_export
 ****************************************************************/
int gpio_export(unsigned int gpio)
{
	int fd, len;
	char buf[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[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, unsigned int out_flag)
{
	int fd, len;
	char buf[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 (out_flag)
		write(fd, "out", 4);
	else
		write(fd, "in", 3);
 
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_set_value
 ****************************************************************/
int gpio_set_value(unsigned int gpio, unsigned int value)
{
	int fd, len;
	char buf[MAX_BUF];
 
	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_WRONLY);
	if (fd < 0) {
		perror("gpio/set-value");
		return fd;
	}
 
	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, unsigned int *value)
{
	int fd, len;
	char buf[MAX_BUF];
	char ch;

	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_RDONLY);
	if (fd < 0) {
		perror("gpio/get-value");
		return fd;
	}
 
	read(fd, &ch, 1);

	if (ch != '0') {
		*value = 1;
	} else {
		*value = 0;
	}
 
	close(fd);
	return 0;
}


/****************************************************************
 * gpio_set_edge
 ****************************************************************/

int gpio_set_edge(unsigned int gpio, char *edge)
{
	int fd, len;
	char buf[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;
	}
 
	write(fd, edge, strlen(edge) + 1); 
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_fd_open
 ****************************************************************/

int gpio_fd_open(unsigned int gpio)
{
	int fd, len;
	char buf[MAX_BUF];

	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_RDONLY | O_NONBLOCK );
	if (fd < 0) {
		perror("gpio/fd_open");
	}
	return fd;
}

/****************************************************************
 * gpio_fd_close
 ****************************************************************/

int gpio_fd_close(int fd)
{
	return close(fd);
}

/****************************************************************
 * Main
 ****************************************************************/
int main(int argc, char **argv, char **envp)
{
	struct pollfd fdset[2];
	int nfds = 2;
	int gpio_fd, timeout, rc;
	char *buf[MAX_BUF];
	unsigned int gpio;
	int len;



	if (argc < 2) {
		printf("Usage: gpio-int <gpio-pin>\n\n");
		printf("Waits for a change in the GPIO pin voltage level or input on stdin\n");
		exit(-1);
	}

	gpio = atoi(argv[1]);

	gpio_export(gpio);
	gpio_set_dir(gpio, 0);
	gpio_set_edge(gpio, "rising");
	gpio_fd = gpio_fd_open(gpio);

	timeout = POLL_TIMEOUT;
 
	while (1) {
		memset((void*)fdset, 0, sizeof(fdset));

		fdset[0].fd = STDIN_FILENO;
		fdset[0].events = POLLIN;
      
		fdset[1].fd = gpio_fd;
		fdset[1].events = POLLPRI;

		rc = poll(fdset, nfds, timeout);      

		if (rc < 0) {
			printf("\npoll() failed!\n");
			return -1;
		}
      
		if (rc == 0) {
			printf(".");
		}
            
		if (fdset[1].revents & POLLPRI) {
			len = read(fdset[1].fd, buf, MAX_BUF);
			printf("\npoll() GPIO %d interrupt occurred\n", gpio);
		}

		if (fdset[0].revents & POLLIN) {
			(void)read(fdset[0].fd, buf, 1);
			printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
		}

		fflush(stdout);
	}

	gpio_fd_close(gpio_fd);
	return 0;
}


 
<think> 嗯,用户想要一个适合不会Linux的人的简单SLAM毕业设计,这确实是个挑战,因为传统SLAM项目通常严重依赖Linux和ROS环境。不过既然用户明确提到参考了Jetson Nano的案例,说明对硬件平台有一定接受度。 用户可能是个本科毕业生,计算机基础一般但希望完成一个能展示的毕业设计。ta特意强调“不会Linux”,说明对操作系统门槛有顾虑。深层需求应该是:在避免复杂系统配置的前提下,实现一个能直观演示的SLAM相关项目。 从技术角度看,需要避开ROS和复杂编译环境。Jetson Nano是个好选择,因为它: 1)支持完整的Python生态,避免编译麻烦 2)有预装SDK可即插即用 3)社区资源丰富 我想到三个梯度方案: 最简方案是激光雷达避障小车,因为: - 思岚A1雷达提供Python SDK - 避障算法只需简单距离检测 - 运动控制用GPIO就能实现 中等难度是视觉里程计,虽然需要OpenCV但代码量可控: - 特征点匹配算法现成 - 用matplotlib就能可视化轨迹 - 数据集可用公开KITTI简化版 高阶的cartographer精简版其实也可行,因为: - 官方提供Python绑定 - 2D建图流程文档完善 - 用户只需调参和采集数据 特别要注意的是,所有方案都强调“开箱即用”: - 使用预装系统的SD卡镜像 - 提供完整的pip安装命令 - 规避任何需要编译的环节 演示效果上,激光雷达方案最直观——小车实际移动并生成地图的场景很吸引人。而视觉方案适合做论文展示,轨迹对比图直接体现算法效果。 硬件成本可能是个问题,但Jetson Nano套件+思岚A1总价约2000元,属于毕业设计常见预算。如果实验室有现成设备就更理想了。 最后补充的替代方案很关键:用树莓派+超声波方案能把成本压缩到500元内,虽然建图效果打折扣,但符合“简单”的核心需求。 </think> 针对**不会Linux但需完成SLAM毕业设计**的需求,结合Jetson Nano的易用性和Python生态,推荐以下**零Linux基础可实现的方案**(按难度递增排序): --- ### 一、激光雷达避障小车(3-4周) > **核心**:用Python直接控制雷达+电机,跳过ROS > **硬件**:Jetson Nano + RPLidar A1 + 4轮小车底盘 > **关键代码**(简化版): > ```python > # 1. 雷达数据获取(Python库直接驱动) > import pyrplidar > lidar = pyrplidar.RpLidar("/dev/ttyUSB0") > scan_generator = lidar.iterate_scans() > > # 2. 避障逻辑(检测前方障碍) > for scan in scan_generator: > front_scan = [point for point in scan if 350 < point[0] < 10] # 取正前方角度 > if any(distance < 0.5 for _, distance, _ in front_scan): > motor.turn_right() # 遇障碍右转 > else: > motor.forward() > ``` > **效果**:实时构建2D障碍地图并自主避障 > **优势**: > - 无需编译,直接`pip install pyrplidar` > - 可视化用Matplotlib即可[^1] --- ### 二、单目视觉里程计(4-5周) > **核心**:用OpenCV实现简易SLAM前端 > **硬件**:普通USB摄像头 + Jetson Nano > **步骤**: > 1. 特征点提取(ORB算法) > ```python > orb = cv2.ORB_create() > kp, des = orb.detectAndCompute(frame, None) > ``` > 2. 相邻帧匹配(BFMatcher) > ```python > bf = cv2.BFMatcher(cv2.NORM_HAMMING) > matches = bf.match(des1, des2) > ``` > 3. 运动估计(本质矩阵分解) > ```python > E, _ = cv2.findEssentialMat(points1, points2, focal=1.0) > _, R, t, _ = cv2.recoverPose(E, points1, points2) > ``` > **输出**:实时绘制相机运动轨迹(2D/3D) > **数据集**:用手机拍摄走廊视频即可测试 --- ### 三、预装系统的Cartographer建图(2-3周) > **核心**:直接使用预编译的SLAM工具 > **方案**: > 1. 刷写**预装Ubuntu+Cartographer**的Jetson Nano镜像 > 2. 连接雷达后一键运行: > ```bash > # 无需编译,直接运行预装包 > ./prebuilt_cartographer_2d_mapping.launch > ``` > 3. 手持设备行走生成地图(无需编程) > **效果**: > ![Cartographer建图效果](https://google-cartographer-ros.readthedocs.io/en/latest/_images/2d_map.png) > **优势**:完全避开Linux编译,专注数据采集与分析[^1] --- ### 硬件替代方案(低成本) | 组件 | 推荐型号 | 成本 | 备注 | |---------------|----------------------|--------|--------------------------| | 主控 | Jetson Nano 4GB | ¥800 | 预装Ubuntu无需配置 | | 激光雷达 | RPLidar A1 | ¥600 | 即插即用Python驱动 | | 摄像头 | Logitech C920 | ¥200 | 免驱OpenCV直接调用 | | 底盘 | 4WD智能小车套件 | ¥300 | 带电机驱动板 | > **总成本约¥1900**,实验室常备设备可减免 --- ### 关键问题解决 1. **如何免ROS开发?** - 使用**Python硬件库**(如`pyrplidar`、`Adafruit_MotorHAT`) - 通信改用**Socket或HTTP**(例:Jetson Nano作服务端,手机APP控制) 2. **可视化怎么做?** ```python # 实时绘制激光雷达地图 plt.scatter(x_points, y_points, s=1) plt.pause(0.01) # 动态更新 ``` --- ### 成果展示建议 | 方案 | 展示形式 | 技术亮点 | |---------------|---------------------------|------------------------| | 避障小车 | 现场演示绕障视频 | 实时地图构建 | | 视觉里程计 | 对比ORB/SIFT算法精度曲线 | 轨迹误差分析 | | Cartographer | 生成实验室平面图 | 实际场景应用 | > **优先推荐激光雷达方案**:硬件集成简单,效果直观震撼,代码不超过200行[^1] --- ### 替代方案(无硬件时) **仿真SLAM:Webots+Python** 1. 安装Webots(Windows/macOS版) 2. 调用TurtleBot3模型: ```python from controller import Robot robot = Robot() lidar = robot.getDevice("LDS-01") ``` 3. 实现虚拟环境建图(无实物成本) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值