Orange pi GPIO输出控制,裸机点灯大法(一)!

裸机点灯大法

玩树莓派或者香橙派,如果不玩裸机点灯,那岂不是不完整。所谓裸机点灯,即一块裸板,通过gpio输出控制,实现控制板载绿色的电源指示灯以及红色的状态指示灯

裸机点灯(GPIO输出控制)的两种方法

首先总结一下实现对OrangePi GPIO控制的两种方法,第一种是通过Linux内存映射的方式,将实际CPU硬件的内存地址映射到用户程序的内存空间,再进行操作;第二种是通过sysfs方式控制GPIO,在程序中,操作/sys/class/gpio目录实现io口的控制。

这两种方式都有现成已完成的案例,例如在python环境使用的pyH3库、C环境的WiringPi库使用的就是第一种方式;从树莓派移植的OPi.GPIO库使用的是第二种方式。其中第二种方式个人感觉更加简单,因为只需要在用户的程序里面读写系统目录的文件,即可实现对GPIO的控制,非常方便,但是经过试验发现这种方式在armbian系统上有个严重的问题,就是它无法使用那些板子上没引出来的IO口,因为板载的两个LED(红灯和绿灯)分别是使用了PA17和PL10引脚,如果使用第二种方式控制这两个引脚,会提示“Device or resource busy”的错误,但是在orangpi官方网站提供的ubuntu镜像以及Debian下,均可完美实现。通过以下命令:

cat /sys/kernel/debug/gpio

可以看出系统已经占用的IO口如下:
在这里插入图片描述

第二种方法

其实Linux下面有一个通用的GPIO操作接口,那就是我要介绍的 “/sys/class/gpio” 方式。

虽然我的系统是armbian,不能使用第二种方法,还是简单的说一下第二种操作吧,如果你和我一样是armbian系统,那就可以直接跳到下一节,看另一种方法吧

通过上图我们能看到powerLED的gpio编号是362,statusLED的编号是17,接下来我们看看系统中有没有“/sys/class/gpio”这个文件夹
如果没有就需要在编译内核的时候加入 Device Drivers —> GPIO Support —> /sys/class/gpio/… (sysfs interface)

我试过armbian的系统、ubuntu的系统还有Debian都是有这个文件夹的,那就可以直接操作了
看一下/sys/class/gpio 的使用说明:

1、gpio_operation 通过/sys/文件接口操作IO端口 GPIO到文件系统的映射;
2、控制GPIO的目录位于/sys/class/gpio;
3、 /sys/class/gpio/export文件用于通知系统需要导出控制的GPIO引脚编号;
4、/sys/class/gpio/unexport 用于通知系统取消导出;
5、/sys/class/gpio/gpiochipX目录保存系统中GPIO寄存器的信息,包括每个寄存器控制引脚的起始编号base,寄存器名称,引脚总数 导出一个引脚的操作步骤;
6、首先计算此引脚编号,引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数;
7、向/sys/class/gpio/export写入此编号,比如12号引脚,在shell中可以通过以下命令实现,命令成功后生成/sys/class/gpio/gpio12目录,如果没有出现相应的目录,说明此引脚不可导出:echo 12 > /sys/class/gpio/export;
8、direction文件,定义输入输入方向,可以通过下面命令定义为输出;
9、echo out > direction, direction接受的参数:in, out, high, low。high/low同时设置方向为输出,并将value设置为相应的1/0;
10、value文件是端口的数值,为1或0.echo 1 > value

在终端中敲入以下命令

cd /sys/class/gpio/

ls 一下看看有没有 gpio362或者gpio17 这个目录,正常是没有的
接下来GPIO控制测试,在终端中敲入以下指令

通知系统需要导出控制的GPIO引脚编号为17
echo 17 > /sys/class/gpio/export
定义输入输入方向为输出
echo out > /sys/class/gpio/gpio139/direction
设置17号引脚的数值为1,即输出高电平,灯亮
echo 1 > /sys/class/gpio/gpio139/value
设置17号引脚的数值为0,即输出低电平,灯灭
echo 0 > /sys/class/gpio/gpio139/value

powerLED的控制也是一样,只需要把17换成362就可以了
需要注意的是,如果你是armbian的系统,在导出17号引脚的时候会提示设备忙,在ubuntu以及Debian下正常,这个在前面有提到过

在这里插入图片描述

第一种方法

我是参考这位大神的博客,不知道是不是他的原创,附上链接:python环境下实现OrangePi Zero寄存器访问及GPIO控制
作者讲的非常详细,这里贴出他的代码吧

root@orangepi:~# vim OPiZero_GPIO.py

import mmap
import struct
class GPIO:   
#-------------------------------------------------------------------------------------#
#定义GPIO相对0x01C20000的偏移地址
    PIO_ADDR_OFFSET = 0x0800    
#定义GPIOA的寄存器相对0x01C20000的偏移地址
#作者只写了GPIOA的寄存器定义,如果需要使用其他IO,请参考datasheet在下面增加定义
    PIO_PA_CFG0_REG = PIO_ADDR_OFFSET + 0x00
    PIO_PA_CFG1_REG = PIO_ADDR_OFFSET + 0x04
    PIO_PA_CFG2_REG = PIO_ADDR_OFFSET + 0x08
    PIO_PA_CFG3_REG = PIO_ADDR_OFFSET + 0x0C
    PIO_PA_DATA_REG = PIO_ADDR_OFFSET + 0x10

    PIO_PA_DRV0_REG = PIO_ADDR_OFFSET + 0x14
    PIO_PA_DRV1_REG = PIO_ADDR_OFFSET + 0x18
    PIO_PA_PUL0_REG = PIO_ADDR_OFFSET + 0x1C
    PIO_PA_PUL1_REG = PIO_ADDR_OFFSET + 0x20

#-------------------------------------------------------------------------------------#
    #以下是构造函数和析构函数
    def __init__(self):
        self.m_mmap = None
        self.fd = None

    def __del__(self):
        if(self.m_mmap != None):
            self.m_mmap.close()
        if(self.fd != None):
            self.fd.close()
    
#-------------------------------------------------------------------------------------#
    #以下是成员函数
    def Init(self):
        """
        GPIO初始化函数
        函数会打开/dev/mem文件,并映射从0x01C20000地址开始,共8192字节长度(2页)的内存空间到用户的虚拟地址
        返回值:无
        """
        START_ADDR = 0x01C20000
        self.fd = open("/dev/mem", "rb+")
        self.m_mmap = mmap.mmap(self.fd.fileno(), 4096 * 2, mmap.MAP_SHARED, mmap.PROT_WRITE | mmap.PROT_READ, mmap.ACCESS_WRITE, START_ADDR)
        assert self.m_mmap != None,"Init Fails"

    def ReadReg(self,reg_addr):
        """
        读取一个寄存器的值
        reg_addr:要读取的寄存器地址(必须为4的倍数),且范围在2个pagesize内,即小于8192
        返回值:寄存器的值(4字节)
        """
        assert self.m_mmap != None,"Init Fails"
        assert reg_addr%4 == 0,"reg_addr must be mutiple of 4"
        assert 0<=reg_addr<=8192,"reg_addr must be less than 8192,which is 2 pagesize"
        
        self.m_mmap.seek(reg_addr)
        ReadBytes = self.m_mmap.read(4)
        return struct.unpack('L',ReadBytes)[0]

    def WriteReg(self,reg_addr,value):
        """
        写一个寄存器的值
        reg_addr:要写入的寄存器地址(必须为4的倍数),且范围在2个pagesize内,即小于8192
        value:要写入的值,整形,一次写入四个字节长度的整数,即0xffffffff
        返回值:无
        """     
        assert self.m_mmap != None,"Init Fails"
        assert reg_addr%4 == 0,"reg_addr must be mutiple of 4"
        assert 0<=reg_addr<=8192,"reg_addr must be less than 8192,which is 2 pagesize"
        assert 0<=value<=0xFFFFFFFF,"value must be less than 0xFFFFFFFF,which is 4 bytes"
        
        self.m_mmap.seek(reg_addr)
        BytesToWrite = struct.pack('L',value)
        self.m_mmap.write(BytesToWrite)
        return
root@orangepi:~# vim LED_Blink.py

import OPiZero_GPIO
import time

#以下为主程序
GPIO = OPiZero_GPIO.GPIO()
GPIO.Init();

#PA17配置为输出模式
GPIO.WriteReg(GPIO.PIO_PA_CFG2_REG,GPIO.ReadReg(GPIO.PIO_PA_CFG2_REG) | 0x00000010)
while(1):
    GPIO.WriteReg(GPIO.PIO_PA_DATA_REG,GPIO.ReadReg(GPIO.PIO_PA_DATA_REG) ^ 0x00020000)
    time.sleep(0.3)

运行程序即可看到板子上led闪起来了

root@orangepi:~# python3 LED_Blink.py 

猜你喜欢

转载自blog.csdn.net/Running_free/article/details/103060934