树莓派使用C/C++基于Bcm2835操作GPIO学习记录

1 前言

借助Bcm2835库可以快速使用C/C++开发树莓派的GPIO功能,像玩单片机一样玩树莓派。安装教程可以参考这篇文章
可以直接查看Bcm2835库的官方文档

2 Bcm模块

在这里插入图片描述

2.1 Constants for passing to and from library functions

该模块中定义了一些宏,枚举等,方便开发者使用。
如宏定义:

#define 	HIGH   0x1
#define 	LOW   0x0
#define 	MIN(a, b)   (a < b ? a : b)
#define 	BCM2835_CORE_CLK_HZ   250000000
#define 	BMC2835_RPI2_DT_FILENAME   "/proc/device-tree/soc/ranges"

如枚举类bcm2835PUDControl,该类给出了GPIO的上拉下拉参数。bcm2835I2CClockDivider为I2C的时钟分频器。bcm2835I2CReasonCodes 列举了I2C通信出错的原因。对引脚编号的枚举RPiGPIOPin 。值得关注的是J8指的是那两排20的排针, RPI_BPLUS_GPIO_J8_*指的的物理编号,等号右边的是Bcm编号。

enum  	bcm2835PUDControl { BCM2835_GPIO_PUD_OFF = 0x00, BCM2835_GPIO_PUD_DOWN = 0x01, BCM2835_GPIO_PUD_UP = 0x02 }
enum  	bcm2835I2CClockDivider { BCM2835_I2C_CLOCK_DIVIDER_2500 = 2500, BCM2835_I2C_CLOCK_DIVIDER_626 = 626, BCM2835_I2C_CLOCK_DIVIDER_150 = 150, BCM2835_I2C_CLOCK_DIVIDER_148 = 148 }
enum  	bcm2835I2CReasonCodes { BCM2835_I2C_REASON_OK = 0x00, BCM2835_I2C_REASON_ERROR_NACK = 0x01, BCM2835_I2C_REASON_ERROR_CLKT = 0x02, BCM2835_I2C_REASON_ERROR_DATA = 0x04 }
enum  	RPiGPIOPin {...... RPI_BPLUS_GPIO_J8_03 = 2,
  RPI_BPLUS_GPIO_J8_05 = 3, RPI_BPLUS_GPIO_J8_07 = 4, RPI_BPLUS_GPIO_J8_08 = 14, RPI_BPLUS_GPIO_J8_10 = 15,
  RPI_BPLUS_GPIO_J8_11 = 17, RPI_BPLUS_GPIO_J8_12 = 18, RPI_BPLUS_GPIO_J8_13 = 27, RPI_BPLUS_GPIO_J8_15 = 22,
  RPI_BPLUS_GPIO_J8_16 = 23, RPI_BPLUS_GPIO_J8_18 = 24, RPI_BPLUS_GPIO_J8_19 = 10, RPI_BPLUS_GPIO_J8_21 = 9,
  RPI_BPLUS_GPIO_J8_22 = 25, RPI_BPLUS_GPIO_J8_23 = 11, RPI_BPLUS_GPIO_J8_24 = 8, RPI_BPLUS_GPIO_J8_26 = 7,
  RPI_BPLUS_GPIO_J8_29 = 5, RPI_BPLUS_GPIO_J8_31 = 6, RPI_BPLUS_GPIO_J8_32 = 12, RPI_BPLUS_GPIO_J8_33 = 13,
  RPI_BPLUS_GPIO_J8_35 = 19, RPI_BPLUS_GPIO_J8_36 = 16, RPI_BPLUS_GPIO_J8_37 = 26, RPI_BPLUS_GPIO_J8_38 = 20,
  RPI_BPLUS_GPIO_J8_40 = 21
}

2.2 Library initialisation and management

提供Bcm库的初始化和管理函数。里面只有四个函数。

函数:int bcm2835_init (void)
描述:通过打开/dev/mem(如果您是root用户)或/dev/gpiomem(如果您不是root用户)并获取指向BCM 2835设备寄存器的内部存储器的指针来初始化库。在调用此库中的任何其他函数(bcm2835_set_debug除外)之前,必须(成功)调用此函数。如果bcm2835_init()返回0失败,则调用任何其他函数都可能导致崩溃或其他失败。如果bcm2835_init()成功,但您不是以root身份运行,则只允许执行gpio操作,调用任何其他函数都可能导致崩溃或其他失败。出错时会将消息打印到stderr。
返回:1-成功;0-失败

函数:int bcm2835_close (void)
描述:关闭库,释放所有分配的内存并关闭/dev/mem
返回:1-成功;0失败

函数:void bcm2835_set_debug (uint8_t debug)
描述:设置库的调试级别。值为1将阻止映射到/dev/mem,并使库打印出它将执行的操作,而不是访问GPIO寄存器。默认值为0会导致正常操作。在调用bcm2835_init()之前调用此函数;
参数:1-开启调试,默认不开启

函数:unsigned int bcm2835_version (void)
描述: 返回Bcm库的版本号
返回:版本号

2.3 Low level register access

这些函数提供低级寄存器访问,通常不需要使用。

2.4 GPIO register access

这些函数允许您控制GPIO接口。您可以设置每个GPIO引脚的功能读取输入状态设置输出状态。详细见第3节。

2.5 SPI access

这些函数允许您使用SPI0(串行外围接口)与外部SPI设备接口.

2.6 I2C access

这些功能允许您使用I2C(Broadcom串行控制总线和飞利浦I2C总线/接口版本2.1 2000年1月)与外部I2C设备接口。

2.7 System Timer access

允许访问和延迟使用系统计时器计数器。

函数:uint64_t bcm2835_st_read (void)
描述:读取系统定时器计数器寄存器。(可能是读取系统时间,类似于millis()或者micros())
返回:从系统计时器计数器低32位寄存器读取的值

函数:void bcm2835_st_delay (uint64_t offset_micros, uint64_t micros)
描述:具有偏移量的指定微秒数的延迟。
参数: offset_micros 偏移量 单位:us
参数:micros 延时量 单位:us

2.8 Pulse Width Modulation

允许控制2个独立的PWM通道。有限的GPIO引脚子集可以连接到这2个通道中的一个,允许对GPIO引脚进行PWM控制。您必须将所需的引脚设置为特定的Alt-Fun-PWM输出。请参阅主页上的PWM文档。使用树莓派输出PWM可以看这篇

3 GPIO基础操作

毫秒延时函数:void bcm2835_delay (unsigned int millis)
微妙延时函数:void bcm2835_delayMicroseconds(uint64_t micros)
设置引脚的功能:void bcm2835_gpio_fsel (uint8_t pin, uint8_t mode),其中mode可选
在这里插入图片描述
设置指定引脚输出高电平:void bcm2835_gpio_set (uint8_t pin)
设置指定引脚输出低电平:void bcm2835_gpio_clr (uint8_t pin)
设置前32个引脚中多个指定引脚输出高电平:void bcm2835_gpio_set_multi (uint32_t mask)
设置前32个引脚中多个指定引脚输出低电平:void bcm2835_gpio_clr_multi (uint32_t mask),其中mask这样表示,如设置BCM编号引脚17和18为高电平,那么 mask = (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05)
设置指定引脚高或低:void bcm2835_gpio_write (uint8_t pin, uint8_t on)
设置多个引脚同时高或低:void bcm2835_gpio_write_multi (uint32_t mask, uint8_t on)
设置多个引脚对应高低:void bcm2835_gpio_write_mask (uint32_t value, uint32_t mask)
设置上下拉:void bcm2835_gpio_set_pud (uint8_t pin, uint8_t pud),pud的参数
在这里插入图片描述
读取指定引脚电平:uint8_t bcm2835_gpio_lev (uint8_t pin)
事件监听函数集:
首先使用void bcm2835_gpio_ren (uint8_t pin),void bcm2835_gpio_fen (uint8_t pin),void bcm2835_gpio_hen (uint8_t pin),void bcm2835_gpio_len (uint8_t pin)来在指定引脚注册要监听的上升沿,下降沿,高电平,低电平。
然后使用uint8_t bcm2835_gpio_eds (uint8_t pin)或uint32_t bcm2835_gpio_eds_multi (uint32_t mask)来获取单个引脚或多个引脚的事件是否触发。如果触发了,需要void bcm2835_gpio_set_eds (uint8_t pin)或void bcm2835_gpio_set_eds_multi (uint32_t mask)来重置这个引脚。
void bcm2835_gpio_clr_ren (uint8_t pin),void bcm2835_gpio_clr_fen (uint8_t pin),void bcm2835_gpio_clr_hen (uint8_t pin),void bcm2835_gpio_clr_len (uint8_t pin)函数注销监听。
特别的:void bcm2835_gpio_aren (uint8_t pin)和void bcm2835_gpio_afen (uint8_t pin)注册异步监听。为指定的引脚启用异步上升或下降沿检测。当检测到上升沿时,在事件检测状态中设置相应的引脚。异步意味着传入信号不被系统时钟采样。因此,可以检测到持续时间很短的上升沿。对应的也有void bcm2835_gpio_clr_aren (uint8_t pin)和void bcm2835_gpio_clr_afen (uint8_t pin)

//事件监听示例
#include <bcm2835.h>
#include <stdio.h>
 
// Input on RPi pin GPIO 15
#define PIN RPI_GPIO_P1_15
 
int main(int argc, char **argv)
{
    // If you call this, it will not actually access the GPIO
    // Use for testing
    if (!bcm2835_init())
        return 1;
    // Set RPI pin P1-15 to be an input
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
    //  with a pullup
    bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP);
    // And a low detect enable
    bcm2835_gpio_len(PIN);
    while (1)
    {
        if (bcm2835_gpio_eds(PIN))
        {
            // Now clear the eds flag by setting it to 1
            bcm2835_gpio_set_eds(PIN);
            printf("low event detect for pin 15\n");
        }
 
        // wait a bit
        delay(500);
    }
    bcm2835_close();
    return 0;
}

4 SPI使用

待续…

5 IIC使用

5.1树莓派IIC配置

首先需要打开树莓派的IIC,使用

sudo raspi-config

然后Interface Options》I2C,然后打开,然后Finish,可能需要重启一下。
一般使用的SDA.1和SCL.1引脚来连接一般的IIC从设备(i2c1是为了控制大部分i2c设备的,i2c0是为了控制摄像头或者显示屏等外设用的,深究可以查看这篇博客)。
检验线路是否连接好或者设备是否正常可以使用指令 i2cdetect -y 1 来扫描i2c1总线上的设备.

5.2 BCM库IIC使用

函数:int bcm2835_i2c_begin (void)
描述:启动I2C操作。强制RPi I2C引脚P1-03(SDA)和P1-05(SCL)交替运行ALT0,从而启用I2C接口的这些引脚。当所有i2c函数都完成时,应该调用bcm2835_ i2c_end(),以将管脚返回到其默认函数.
返回:1-成功;0-其他(可能没有root运行)

函数:void bcm2835_i2c_end (void)
描述:结束I2C操作。I2C引脚P1-03(SDA)和P1-05(SCL)返回其默认输入行为。

函数:void bcm2835_i2c_setSlaveAddress (uint8_t addr)
描述:设置从设备地址

函数:void bcm2835_i2c_setClockDivider (uint16_t divider)
描述:设置I2C时钟分频器,从而设置I2C时钟速度。一般不调用该函数,通过bcm2835_i2c_set_baudrate来设置。
参数:从以下枚举中选择
在这里插入图片描述
void bcm2835_i2c_set_baudrate (uint32_t baudrate)
描述:通过将波特率参数转换为等效的I2C时钟分频器来设置I2C时钟分频器。

函数:uint8_t bcm2835_i2c_write (const char *buf, uint32_t len)

描述:向从设备写入数据,如果是直接向从设备发送数据,则直接将数据填入buf中,len为数据长度。如果向从设备的寄存器写数据,那么buf[0]里先填写寄存器地址,从buf[1]开始放数据。总之,len是要发送数据的总长度。

函数:uint8_t bcm2835_i2c_read (char *buf, uint32_t len)
描述:从从设备读取长度为len的数据放入buf里。

函数:uint8_t bcm2835_i2c_read_register_rs (char *regaddr, char *buf, uint32_t len)
描述:读寄存器的值。允许在设置所需的从寄存器后读取需要重复启动(无任何预先停止)的I2C从寄存器。(不大懂,连续读寄存器?)请注意,您的设备必须支持或需要此模式。

函数:uint8_t bcm2835_i2c_write_read_rs (char *cmds, uint32_t cmds_len, char *buf, uint32_t buf_len)
描述:又写又读。允许在发出重复启动(没有预先停止)和读取响应之前向I2C从机发送任意数量的字节。(不懂)

IIC读写函数都有返回值表述错误代码:
在这里插入图片描述
注意:在使用IIC与从设备通信时,首先需要调用bcm2835_i2c_begin 初始化,如果总线上的IIC从设备都是一个通信速率,那么在初始化只需调用一次bcm2835_i2c_set_baudrate。如果多个从设备速率还不一样,每次和一个设备通信时,都需要bcm2835_i2c_set_baudrate来改变。在与一个从设备通信读写前,需要先调用bcm2835_i2c_setSlaveAddress来设置该从设备的地址,最后再调用读写函数。
使用Bcm的IIC接口来开发PCA9685可以看这篇

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值