【Linux】 Orangepi GPIO开发详解


最近新入手了一个OrangePi ,准备学习一下linux下的驱动开发,不过由于刚开始入门,踩到的坑有点多。


硬件环境:OrangePi PC Puls
开发工具:gcc
开发环境:vscode + Remote SSH ( 不得不说vscode真的香啊~)


1. wiringPi库驱动

在刷入linux镜像之后,第一个程序就是编写Blink程序!

安装wiringPi库

首先克隆orangepi的wiringpi库:

#获取wiringpi库
git clone https://github.com/orangepi-xunlong/wiringOP.git
#运行脚本自动编译wiringOP库
./wiringOP/build
#根据板卡型号进行选择,我是orangepi pc puls 选择3

安装完成后输入gpio readall可以查看orangepi所有了引脚序号,在后面的程序中需要使用这个序号。
可以看到下面输出:
在这里插入图片描述
这个表是引出IO的信息:
GPIO:是指内核的序号。具体的计算方法为:(字母在字母表中的位置- 1) * 32 + 引脚序号
如PC07 引脚编号为:(3 - 1) * 32 + 7 = 71。
wPi:是在wiringpi函数中使用的引脚序号,
V:是当前IO的输出电平

命令行驱动GPIO

使用wiringpi命令控制IO状态:

 # 配置GPIO12(对应wPi序号0)为为输出模式
 gpio mode 0	out	
 # 控制IO输出高电平,格式为gpio read <pin> <value>
 gpio write	0	1
 #读取IO状态
 gpio read 0
 # 以500ms的频率翻转IO状态
 gpio blink 0

C语言驱动GPIO

在使用命令行运行Blink程序之后开始通过C语言编程,点亮led
代码如下:

#include <stdio.h>
#include <wiringPi.h>

#define LED 0		//接到树莓派映射引脚0上,对应GPIO12

int main(void)
{
    printf("OrangePi blink...\r\n");
    wiringPiSetup();		//初始化GPIO配置
    pinMode(LED, OUTPUT);	//配置IO模式

    while(1)
    {
         digitalWrite(LED, HIGH);	//控制GPIO
         delay(500);
         digitalWrite(LED, LOW);
         delay(500);
    }
}

不过在这个过程中就踩到了坑:根据给的教程走时发现编译出错。
在这里插入图片描述
显示未定义引用,查找资料后发现这是由于未链接完整的库文件导致的。
正确编译参数应为
gcc led.c -L/usr/local/lib -lwiringPi -lpthread -lwiringPiDev -lm -l crypt -lrt -o LED
重新编译之后程序可以正常运行,注意:wiringPiSetup()函数需要使用root权限

更多wiringpi的函数参考此链接


2. 内核(sysfs)GPIO驱动

在点亮第一个led之后,就开始准备折腾有关GPIO的更多操作了。
注意到在orangepi的开发板上有两个led,在原理图上显示一个是PWR_LED(PA15)和Status_LED(PL10)。PWR_LED是电源指示灯,那是不是可以不接线直接驱动板载LED?

然后经过一番尝试后使用wiringpi库无法驱动板载LED灯,在和群友进行交流时提到“板载LED这么重要的一个GPIO应该不会暴露到用户空间”,我顺着这个信息查下去,果然无法直接驱动!参考资料

命令行驱动板载led

板载的两个LED都是可以进行配置的,既可以作为状态指示灯使用,也可以作为普通GPIO使用。

#以下代码请使用root用户执行
#将板载状态指示灯配置为通用GPIO
echo none | sudo tee /sys/class/leds/orangepi:red:status/trigger
#控制板载led输出低电平
echo 0 >  /sys/class/leds/orangepi:red:status/brightness
#控制板载led输出高电平
echo 0 >  /sys/class/leds/orangepi:red:status/brightness
# 还原板载LED作为指示灯
echo cpu0 | sudo tee /sys/class/leds/orangepi:red:status/trigger 

知道板载LED可以作为普通GPIO驱动,那普通GPIO怎么驱动?搜索了以下linux GPIO驱动的资料: [参考](https://www.cnblogs.com/lulipro/p/5992172.html)
在linux下,所有设备据看作为文件,GPIO也不例外,该方式就是对内核文件进行操作控制IO。不过由于GPIO在内核空间,用户无法直接对IO进行操作,需要先释放到用户空间,然后在进行读写。 有关GPIO的文件在/sys/class/gpio/目录下 ![在这里插入图片描述](https://img-blog.csdnimg.cn/202007191454275.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21pcmNvX21jdQ==,size_16,color_FFFFFF,t_70) ## 命令行驱动GPIO 控制 GPIO 的目录位于 /sys/class/gpio。 >/sys/class/gpio/export 文件用于通知系统需要导出控制的 GPIO 引脚编号。 >/sys/class/gpio/unexport 用于通知系统取消导出。 >/sys/class/gpio/gpiochipX >目录保存系统中 GPIO 寄存器的信息,包括每个寄存器控制引>脚的起始编号 base,寄存器名称,引脚总数
#暴露GPIO12到用户空间
echo 12 > /sys/class/gpio/export
#配置GPIO方向
echo "out" >/sys/class/gpio/gpio12/direction
#控制GPIO电平
echo 1 > /sys/class/gpio/gpio12/value
#隐藏GPIO到内核空间
echo 12 > /sys/class/gpio/unexport

C语言sysfs驱动GPIO

使用C语言通过sysfs方式控制GPIO状态如下:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>

void delay(uint16_t ms)
{
    usleep(ms*1000);
}

#define BUFF_SIZE   128
#define LED         12
int main(int argc, char *argv[])
{
    char buffer[BUFF_SIZE],path[128];
    int fd,len;

    printf("oraangpi sysfs drive led !\n");

    /*暴露GPIO到用户空间*/
    fd = open("/sys/class/gpio/export", O_WRONLY);
    len = snprintf(buffer, BUFF_SIZE, "%d", LED);
    write(fd, buffer, len);
    close(fd);

    /*配置GPIO方向*/
    snprintf(path, BUFF_SIZE, "/sys/class/gpio/gpio%d/direction", LED);
    fd = open(path, O_WRONLY);
    len = snprintf(buffer, BUFF_SIZE, "out");
    write(fd, buffer, len);
    close(fd);
    
    while(1)
    {
        snprintf(path, BUFF_SIZE, "/sys/class/gpio/gpio%d/value", LED);
        fd = open(path, O_WRONLY);
        len = snprintf(buffer, BUFF_SIZE, "%d", 0);
        write(fd, buffer, len);
        close(fd);

        delay(500);

        snprintf(path, BUFF_SIZE, "/sys/class/gpio/gpio%d/value", LED);
        fd = open(path, O_WRONLY);
        len = snprintf(buffer, BUFF_SIZE, "%d", 1);
        write(fd, buffer, len);
        close(fd);
        
        delay(500);
    }
     
    /*隐藏GPIO到内核空间*/
    fd = open("/sys/class/gpio/unexport", O_WRONLY);
    len = snprintf(buffer, BUFF_SIZE, "%d", LED);
    write(fd, buffer, len);
    close(fd);
} 

3. 自行编写底层驱动

在上面的方式都是通过调用已有的驱动,然后对IO进行配置,从而进行控制IO。还有一种方式就是自己编写GPIO的底层驱动。
这种方式比较复杂,由于时间和能力原因不在详细描述,在网上也有很多类似的资料。

  • 17
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值