GPIO编程基础介绍
GPIO(General-Purpose IO Ports),即通用IO接口。GPIO的使用较为简单,主要分为输入和输出两种功能。GPIO主要用于实现一些简单设备的控制。在作为输入型GPIO的情况下,我们可以将该IO连接外部按键或者传感器,用于检测外部状态。当作为输出时,我们可以通过输出高低电平来控制外部设备的运转。
由于GPIO的功能多种多样,我们需要首先将引脚设置为GPIO。设置为GPIO之后,我们需要设置GPIO的方向。当设置为输出时,我们可以控制输出高电平或者低电平。当设置为输入时,我们可以读取GPIO的电平来判断外部输入电平的高低。
GPIO编程软件接口
GPIO编程有多种实现方式,在这里,我们通过sysfs方式来实现GPIO的控制实现。
如果要通过sysfs方式控制gpio,首先需要底层内核的支持。为了实现内核对sysfs gpio的支持,我们需要在内核中进行设置。在编译内核的时候,加入 Device Drivers-> GPIO Support ->/sys/class/gpio/… (sysfs inteRFace)。作为GPIO的引脚,不允许在内核中被用作其他用途。
在系统正常运行之后,我们可以在/sys/class/gpio下看到sysfs控制相关的接口。有三种类型的接口, 分别是控制接口,GPIO信号和GPIO控制器三种接口。这部分的具体介绍可参考《kernel\Documentation\gpio\sysfs.txt》。
控制接口
控制接口用于实现在用户空间对GPIO的控制,主要包括/sys/class/gpio/export和/sys/class/gpio/unexport两个接口。这这两个控制接口都是只写的,/sys/class/gpio/export实现将GPIO控制从内核空间导出到用户空间,/sys/class/gpio/unexport用于实现取消GPIO控制从内核空间到用户空间的导出。
下面以引脚编号为19的GPIO为例进行说明,在/sys/class/gpio/目录下,我们执行"echo 19 > export"之后,将会产生一个”gpio19”节点来控制引脚编号为19的GPIO。我们执行"echo 19 > unexport"之后,将会删除之前通过export产生的”gpio19”节点。为了使用gpio,我们需要首先使用/sys/class/gpio/export导出gpio引脚编号。完成使用之后,通过/sys/class/gpio/unexport删除掉之前导出的gpio引脚。
GPIO信号
GPIO信号,即为GPIO本身,其路径为/sys/class/gpio/gpioN/,拥有多个属性。通过对这些属性进行控制,就可以实现对GPIO的控制
“direction”属性,读取的值为”in”或者”out”。通过对该属性写入”in”或者”out”可以设置该GPIO为输入或者输出。如果直接写入”out”,则会使GPIO直接输出低电平。也可以通过写入”low”或者”high”来直接设置输出低电平或者高电平。
”value”属性,用于读取输入电平或者控制输出电平。如果GPIO为输出,则对value写入0为输出低电平,写入非0为输出高电平。如果设置为输入的话,则读到0表示输入为低电平,1为高电平。
”edge”属性,用于设置触发电平,只有在GPIO可以设置为中断输入引脚时才会出现该属性
GPIO控制器
GPIO控制器,用于表示GPIO 控制实现的初始GPIO,其路径为/sys/class/gpio/gpiochipN/。比如/sys/class/gpio/gpiochip42/ 则表示实现GPIO控制器的初始化编号为42。GPIO控制器的属性为只读属性,包括base、label和ngpio等多个。
”base”属性,和gpiochipN的N代表的含义相同,表示被该组GPIO控制器实现的第一个GPIO.
” ngpio”属性,用于表示该控制器支持多少个GPIO,支持的GPIO编号为从N到N+ngpio-1
” label”属性,用于判断控制器,并不总是唯一的
STM32MP157(开发板GPIO编号的确定
每个芯片可以有N组GPIO,每组GPIO最多有32个GPIO,即最多有N*32个GPIO。但是在实际设计中,每组的GPIO数量各有不同。在imx6ULL中,实际每组拥有的GPIO数量如下图所示,具体详见《IMX6ULLRM.pdf》手册1347页。
- 01 #include <stdio.h>
- 02 #include <stdlib.h>
- 03 #include <unistd.h>
- 04 #include <string.h>
- 05 #include <errno.h>
- 06 #include <fcntl.h>
- 07 #include <sys/stat.h>
- 08 /****************************************************************
- 09 * 宏定义,定义GPIO编号以及LED和按键各自对应的编号 ,计算方法为GPION_X对应的编号为 (N-1)*32+X
- 10 ****************************************************************/
- 11 #define GPIO4_14 110
- 12 #define GPIO5_1 129
- 13 #define GPIO5_3 131
- 14
- 15 #define GPIO_KEY1 GPIO4_14
- 16 #define GPIO_KEY2 GPIO5_1
- 17 #define GPIO_LED GPIO5_3
- 18 //定义数组大小
- 19 #define MAX_BUF 128
- 20 //定义用于GPIO控制的统一路径
- 21 #define SYSFS_GPIO_DIR "/sys/class/gpio"
- 22 /**********************************************************************
- 23 * 函数名称: sysfs_gpio_export
- 24 * 功能描述: 向/sys/class/gpio/export写入引脚编号,即通知系统需要导出的GPIO引脚编号
- 25 * 输入参数:@GPIO :要导出的引脚编号
- 26 * 输出参数:是否成功执行
- 27 * 返 回 值: 0 成功执行;其他:执行失败
- 28 * 修改日期 版本号 修改人 修改内容
- 29 * -----------------------------------------------
- 30 * 2020/05/14 V1.0 芯晓 创建
- 31 ***********************************************************************/
- 32 int sysfs_gpio_export(unsigned int gpio)
- 33 {
- 34 int fd, len;
- 35 char buf[MAX_BUF];
- 36 // /sys/class/gpio/export
- 37 fd = open( "/sys/class/gpio/export", O_WRONLY);//打开文件
- 38 if (fd < 0) {
- 39 perror("gpio/export");
- 40 return fd;
- 41 }
- 42
- 43 len = snprintf(buf, sizeof(buf), "%d", gpio);//从数字变换为字符串,即1 变为”1“
- 44 write(fd, buf, len);//将需要导出的GPIO引脚编号进行写入
- 45 close(fd);//关闭文件
- 46
- 47 return 0;
- 48 }
- 49 /**********************************************************************
- 50 * 函数名称: sysfs_gpio_unexport
- 51 * 功能描述: 向/sys/class/gpio/unexport写入引脚编号,即通知系统需要取消导出的GPIO引脚编号
- 52 * 输入参数:@gpio :要取消导出的引脚编号
- 53 * 输出参数:是否成功执行
- 54 * 返 回 值: 0 成功执行;其他:执行失败
- 55 * 修改日期 版本号 修改人 修改内容
- 56 * -----------------------------------------------
- 57 * 2020/05/14 V1.0 芯晓 创建
- 58 ***********************************************************************/
- 59 int sysfs_gpio_unexport(unsigned int gpio)
- 60 {
- 61 int fd, len;
- 62 char buf[MAX_BUF];
- 63 // /sys/class/gpio/unexport
- 64 fd = open("/sys/class/gpio/unexport", O_WRONLY);//打开文件
- 65 if (fd < 0) {
- 66 perror("gpio/export");
- 67 return fd;
- 68 }
- 69
- 70 len = snprintf(buf, sizeof(buf), "%d", gpio);//从数字变换为字符串,即1 变为”1“
- 71 write(fd, buf, len);//将需要取消导出的GPIO引脚编号进行写入
- 72 close(fd);//关闭文件
- 73 return 0;
- 74 }
- 75 /**********************************************************************
- 76 * 函数名称: sysfs_gpio_set_dir
- 77 * 功能描述: 向/sys/class/gpio/gpioN/direction写入引脚方向,即设置导出的GPIO引脚的方向
- 78 * 输入参数:@gpio :要设置方向的引脚编号
- 79 @out_flag :要设置的引脚方向。1:表示设置为输出。0:表示设置为输入。
- 80 * 输出参数:是否成功执行
- 81 * 返 回 值: 0 成功执行;其他:执行失败
- 82 * 修改日期 版本号 修改人 修改内容
- 83 * -----------------------------------------------
- 84 * 2020/05/14 V1.0 芯晓 创建
- 85 ***********************************************************************/
- 86 int sysfs_gpio_set_dir(unsigned int gpio, unsigned int out_flag)
- 87 {
- 88 int fd, len;
- 89 char buf[MAX_BUF];
- 90 // /sys/class/gpio/gpioN/direction
- 91 len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
- 92
- 93 fd = open(buf, O_WRONLY);//打开文件
- 94 if (fd < 0) {
- 95 perror(buf);
- 96 return fd;
- 97 }
- 98
- 99 if (out_flag)//为1,则写入“out",即设置为输出
- 100 write(fd, "out", 4);
- 101 else//为0,则写入“in",即设置为输入
- 102 write(fd, "in", 3);
- 103
- 104 close(fd);//关闭文件
- 105 return 0;
- 106 }
- 107 /**********************************************************************
- 108 * 函数名称: sysfs_gpio_set_value
- 109 * 功能描述: 向/sys/class/gpio/gpioN/value写入输出电平,即设置GPION输出的电平高低
- 110 (在引脚为输出的时候进行使用)
- 111 * 输入参数:@gpio :要设置输出电平的引脚编号
- 112 @value :要设置的输出电平。1:表示设置输出为高电平。0:表示设置输出为低电平。
- 113 * 输出参数:是否成功执行
- 114 * 返 回 值: 0 成功执行;其他:执行失败
- 115 * 修改日期 版本号 修改人 修改内容
- 116 * -----------------------------------------------
- 117 * 2020/05/14 V1.0 芯晓 创建
- 118 ***********************************************************************/
- 119 int sysfs_gpio_set_value(unsigned int gpio, unsigned int value)
- 120 {
- 121 int fd, len;
- 122 char buf[MAX_BUF];
- 123 // /sys/class/gpio/gpioN/value
- 124 len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
- 125
- 126 fd = open(buf, O_WRONLY);//打开文件
- 127 if (fd < 0) {
- 128 perror(buf);
- 129 return fd;
- 130 }
- 131
- 132 if (value)//为1,则写入“1",即设置为输出高电平
- 133 write(fd, "1", 2);
- 134 else//为0,则写入“0",即设置为输出低电平
- 135 write(fd, "0", 2);
- 136
- 137 close(fd);//关闭文件
- 138 return 0;
- 139 }
- 140 /**********************************************************************
- 141 * 函数名称: sysfs_gpio_get_value
- 142 * 功能描述: 从/sys/class/gpio/gpioN/value读取引脚电平,即读取GPION输入的电平高低
- 143 (在引脚为输入的时候进行使用)
- 144 * 输入参数:@gpio :要读取输入电平的引脚编号
- 145 @value :读取的电平高低存储的位置
- 146 * 输出参数:是否成功执行
- 147 * 返 回 值: 0 成功执行;其他:执行失败
- 148 * 修改日期 版本号 修改人 修改内容
- 149 * -----------------------------------------------
- 150 * 2020/05/14 V1.0 芯晓 创建
- 151 ***********************************************************************/
- 152 int sysfs_gpio_get_value(unsigned int gpio, unsigned int *value)
- 153 {
- 154 int fd, len;
- 155 char buf[MAX_BUF];
- 156 char ch;
- 157 // /sys/class/gpio/gpioN/value
- 158 len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
- 159
- 160 fd = open(buf, O_RDONLY);//打开文件
- 161 if (fd < 0) {
- 162 perror("gpio/get-value");
- 163 return fd;
- 164 }
- 165
- 166 read(fd, &ch, 1);//读取外部输入电平
- 167
- 168 if (ch != '0') {//为'1',则设置为1,即输入为高电平
- 169 *value = 1;
- 170 } else {//为'0',则设置为0,即输入为低电平
- 171 *value = 0;
- 172 }
- 173
- 174 close(fd);//关闭文件
- 175 return 0;
- 176 }
- 177 /**********************************************************************
- 178 * 函数名称: main函数
- 179 * 功能描述: 导出相关引脚并进行功能实现
- 180
- 181 * 2020/05/14 V1.0 芯晓 创建
- 182 ***********************************************************************/
- 183 int main(int argc, char **argv) {
- 184 unsigned int i;
- 185 unsigned int value1,value2;
- 186
- 187 printf("\t********************************************\n");
- 188 printf("\t******** SYSFS_GPIO_TEST_DEMO**************\n");
- 189 printf("\t******** version date: 2020/05 **********\n");
- 190 printf("\t********************************************\n");
- 191
- 192 printf("gpio begin to export gpio\r\n");
- 193 sysfs_gpio_export(GPIO_KEY1);//export gpio key1
- 194 sysfs_gpio_export(GPIO_KEY2);//export gpio key2
- 195 sysfs_gpio_export(GPIO_LED);//export gpio led
- 196 printf("gpio export gpio ok\r\n");
- 197
- 198
- 199 return 0;
- 200 }
[color=rgb(51, 102, 153) !important]复制代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- /****************************************************************
- * 宏定义,定义GPIO编号以及LED和按键各自对应的编号 ,计算方法为GPION_X对应的编号为 (N-1)*32+X
- ****************************************************************/
- #define GPIO4_14 110
- #define GPIO5_1 129
- #define GPIO5_3 131
- #define GPIO_KEY1 GPIO4_14
- #define GPIO_KEY2 GPIO5_1
- #define GPIO_LED GPIO5_3
- //定义数组大小
- #define MAX_BUF 128
- //定义用于GPIO控制的统一路径
- #define SYSFS_GPIO_DIR "/sys/class/gpio"
- /**********************************************************************
- * 函数名称: sysfs_gpio_export
- * 功能描述: 向/sys/class/gpio/export写入引脚编号,即通知系统需要导出的GPIO引脚编号
- * 输入参数:@gpio :要导出的引脚编号
- * 输出参数:是否成功执行
- * 返 回 值: 0 成功执行;其他:执行失败
- * 修改日期 版本号 修改人 修改内容
- * -----------------------------------------------
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int sysfs_gpio_export(unsigned int gpio)
- {
- int fd, len;
- char buf[MAX_BUF];
- // /sys/class/gpio/export
- fd = open( "/sys/class/gpio/export", O_WRONLY);//打开文件
- if (fd < 0) {
- perror("gpio/export");
- return fd;
- }
- len = snprintf(buf, sizeof(buf), "%d", gpio);//从数字变换为字符串,即1 变为”1“
- write(fd, buf, len);//将需要导出的GPIO引脚编号进行写入
- close(fd);//关闭文件
- return 0;
- }
- /**********************************************************************
- * 函数名称: sysfs_gpio_unexport
- * 功能描述: 向/sys/class/gpio/unexport写入引脚编号,即通知系统需要取消导出的GPIO引脚编号
- * 输入参数:@gpio :要取消导出的引脚编号
- * 输出参数:是否成功执行
- * 返 回 值: 0 成功执行;其他:执行失败
- * 修改日期 版本号 修改人 修改内容
- * -----------------------------------------------
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int sysfs_gpio_unexport(unsigned int gpio)
- {
- int fd, len;
- char buf[MAX_BUF];
- // /sys/class/gpio/unexport
- fd = open("/sys/class/gpio/unexport", O_WRONLY);//打开文件
- if (fd < 0) {
- perror("gpio/export");
- return fd;
- }
- len = snprintf(buf, sizeof(buf), "%d", gpio);//从数字变换为字符串,即1 变为”1“
- write(fd, buf, len);//将需要取消导出的GPIO引脚编号进行写入
- close(fd);//关闭文件
- return 0;
- }
- /**********************************************************************
- * 函数名称: sysfs_gpio_set_dir
- * 功能描述: 向/sys/class/gpio/gpioN/direction写入引脚方向,即设置导出的GPIO引脚的方向
- * 输入参数:@gpio :要设置方向的引脚编号
- @out_flag :要设置的引脚方向。1:表示设置为输出。0:表示设置为输入。
- * 输出参数:是否成功执行
- * 返 回 值: 0 成功执行;其他:执行失败
- * 修改日期 版本号 修改人 修改内容
- * -----------------------------------------------
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int sysfs_gpio_set_dir(unsigned int gpio, unsigned int out_flag)
- {
- int fd, len;
- char buf[MAX_BUF];
- // /sys/class/gpio/gpioN/direction
- len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
- fd = open(buf, O_WRONLY);//打开文件
- if (fd < 0) {
- perror(buf);
- return fd;
- }
- if (out_flag)//为1,则写入“out",即设置为输出
- write(fd, "out", 4);
- else//为0,则写入“in",即设置为输入
- write(fd, "in", 3);
- close(fd);//关闭文件
- return 0;
- }
- /**********************************************************************
- * 函数名称: sysfs_gpio_set_value
- * 功能描述: 向/sys/class/gpio/gpioN/value写入输出电平,即设置GPION输出的电平高低
- (在引脚为输出的时候进行使用)
- * 输入参数:@gpio :要设置输出电平的引脚编号
- @value :要设置的输出电平。1:表示设置输出为高电平。0:表示设置输出为低电平。
- * 输出参数:是否成功执行
- * 返 回 值: 0 成功执行;其他:执行失败
- * 修改日期 版本号 修改人 修改内容
- * -----------------------------------------------
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int sysfs_gpio_set_value(unsigned int gpio, unsigned int value)
- {
- int fd, len;
- char buf[MAX_BUF];
- // /sys/class/gpio/gpioN/value
- len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
- fd = open(buf, O_WRONLY);//打开文件
- if (fd < 0) {
- perror(buf);
- return fd;
- }
- if (value)//为1,则写入“1",即设置为输出高电平
- write(fd, "1", 2);
- else//为0,则写入“0",即设置为输出低电平
- write(fd, "0", 2);
- close(fd);//关闭文件
- return 0;
- }
- /**********************************************************************
- * 函数名称: sysfs_gpio_get_value
- * 功能描述: 从/sys/class/gpio/gpioN/value读取引脚电平,即读取GPION输入的电平高低
- (在引脚为输入的时候进行使用)
- * 输入参数:@gpio :要读取输入电平的引脚编号
- @value :读取的电平高低存储的位置
- * 输出参数:是否成功执行
- * 返 回 值: 0 成功执行;其他:执行失败
- * 修改日期 版本号 修改人 修改内容
- * -----------------------------------------------
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int sysfs_gpio_get_value(unsigned int gpio, unsigned int *value)
- {
- int fd, len;
- char buf[MAX_BUF];
- char ch;
- // /sys/class/gpio/gpioN/value
- 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') {//为'1',则设置为1,即输入为高电平
- *value = 1;
- } else {//为'0',则设置为0,即输入为低电平
- *value = 0;
- }
- close(fd);//关闭文件
- return 0;
- }
- /**********************************************************************
- * 函数名称: main函数
- * 功能描述: 导出相关引脚并进行功能实现
- * 2020/05/14 V1.0 芯晓 创建
- ***********************************************************************/
- int main(int argc, char **argv) {
- unsigned int i;
- unsigned int value1,value2;
- printf("\t********************************************\n");
- printf("\t******** SYSFS_GPIO_TEST_DEMO**************\n");
- printf("\t******** version date: 2020/05 **********\n");
- printf("\t********************************************\n");
- printf("gpio begin to export gpio\r\n");
- sysfs_gpio_export(GPIO_KEY1);//export gpio key1
- sysfs_gpio_export(GPIO_KEY2);//export gpio key2
- sysfs_gpio_export(GPIO_LED);//export gpio led
- printf("gpio export gpio ok\r\n");
- return 0;
- }
[color=rgb(51, 102, 153) !important]复制代码
|
|