若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/79771763
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)

树莓派开发专栏(点击传送门)

上一篇:《树莓派开发笔记(六):GPIO口的UART的使用(串口通讯)》

下一篇:《树莓派开发笔记(八):GPIO口的I2C使用(BME280三合一传感器:测量温度、湿度、气压、海拔高度) 》

前话

本章节我们开发GPIO口的SPI使用,连接BME280三合一传感器,采集气压、温度、湿度,计算海拔高度。

Demo:GPIO口的SPI通讯

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性。

SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。

(1)SDI – SerialData In,串行数据输入;

(2)SDO – SerialData Out,串行数据输出;

(3)SCLK – Serial Clock,时钟信号,由主设备产生;

(4)CS – Chip Select,从设备使能信号,由主设备控制,注意:如果示波器测量不到,请降低频率到10000;SPI在发送接收数据的时候CS片选才会拉低生效。

其中,CS是从芯片是否被主芯片选中的控制信号,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),主芯片对此从芯片的操作才有效。这就使在同一条总线上连接多个SPI设备成为可能。

负责通讯的3根线SDI、SDO、SCLK。通讯是通过数据交换完成的,SPI是串行通讯协议,数据是一位一位的传输的。这就是SCLK时钟线存在的原因,由SCLK提供时钟脉冲,SDI,SDO则基于此脉冲完成数据传输。数据输出通过SDO线,数据在时钟上升沿或下降沿时改变,在紧接着的下降沿或上升沿被读取。完成一位数据传输,输入也使用同样原理。因此,至少需要8次时钟信号的改变(上沿和下沿为一次),才能完成8位数据的传输。

SCLK信号线只由主设备控制,从设备不能控制信号线。同样,在一个基于SPI的设备中,至少有一个主控设备。这样传输的特点:这样的传输方式有一个优点,与普通的串行通讯不同,普通的串行通讯一次连续传送至少8位数据,而SPI允许数据一位一位的传送,甚至允许暂停,因为SCLK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据。也就是说,主设备通过对SCLK时钟线的控制可以完成对通讯的控制。

SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。

BME280

BME280是一款集成温度、湿度、气压,三位一体的环境传感器。具有高精度,多功能,小尺寸等特点,如下图:

BME280模块,设备地址默认为0x77。下面是读取数据的指令,数据的读出是从0xf7到0xfc读做(温度和压力)或从0xf7到0xfe(温度、压力、湿度等)数据以无符号形式读出。

控制指令集,如下图:

读取数据指令集,分为压力,温度,适度,如下图:

BME280的SPI写入方法(特别注意)

查看数据手册,我们看到BME280的写入方法,需要将第七位置0。

如上图,读取F4h则发送F4h,写入F4h则是发送4h。

开启SPI接口

sudo raspi-config

按照下图步骤选取

然后重启。

查看系统是否启动spi,如下图:

电路原理图

关键代码

初始化代码

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);_bme280ForSpi.initPressureTemperatureMode();_bme280ForSpi.initHumidity();startTimer(1000);
}

每隔1s获取一次

void MainWindow::timerEvent(QTimerEvent *event)
{Q_UNUSED(event);ui->label_i2cP->setText(QString("%1 Pa").arg(_bme280ForSpi.getPressure()));ui->label_i2cT->setText(QString("%1 ℃").arg(_bme280ForSpi.getTemperatureC()));ui->label_i2cH->setText(QString("%1 %").arg(_bme280ForSpi.getHumidity()));ui->label_i2cA->setText(QString("%1 m").arg(_bme280ForSpi.getAltitudeMeters()));
}

模块代码

bme280forspi.h

#ifndef BME280FORSPI_H
#define BME280FORSPI_H
#include <QObject>
#include "spi.h"
//Register names:
#define BME280_DIG_T1_LSB_REG           0x88
#define BME280_DIG_T1_MSB_REG           0x89
#define BME280_DIG_T2_LSB_REG           0x8A
#define BME280_DIG_T2_MSB_REG           0x8B
#define BME280_DIG_T3_LSB_REG           0x8C
#define BME280_DIG_T3_MSB_REG           0x8D
#define BME280_DIG_P1_LSB_REG           0x8E
#define BME280_DIG_P1_MSB_REG           0x8F
#define BME280_DIG_P2_LSB_REG           0x90
#define BME280_DIG_P2_MSB_REG           0x91
#define BME280_DIG_P3_LSB_REG           0x92
#define BME280_DIG_P3_MSB_REG           0x93
#define BME280_DIG_P4_LSB_REG           0x94
#define BME280_DIG_P4_MSB_REG           0x95
#define BME280_DIG_P5_LSB_REG           0x96
#define BME280_DIG_P5_MSB_REG           0x97
#define BME280_DIG_P6_LSB_REG           0x98
#define BME280_DIG_P6_MSB_REG           0x99
#define BME280_DIG_P7_LSB_REG           0x9A
#define BME280_DIG_P7_MSB_REG           0x9B
#define BME280_DIG_P8_LSB_REG           0x9C
#define BME280_DIG_P8_MSB_REG           0x9D
#define BME280_DIG_P9_LSB_REG           0x9E
#define BME280_DIG_P9_MSB_REG           0x9F
#define BME280_DIG_H1_REG               0xA1
#define BME280_CHIP_ID_REG              0xD0 //Chip ID Online value is 0x60 all the time
#define BME280_RST_REG                  0xE0 //Softreset Reg
#define BME280_DIG_H2_LSB_REG           0xE1
#define BME280_DIG_H2_MSB_REG           0xE2
#define BME280_DIG_H3_REG               0xE3
#define BME280_DIG_H4_MSB_REG           0xE4
#define BME280_DIG_H4_LSB_REG           0xE5
#define BME280_DIG_H5_MSB_REG           0xE6
#define BME280_DIG_H6_REG               0xE7
#define BME280_CTRL_HUMIDITY_REG        0xF2 //Ctrl Humidity Reg
#define BME280_STAT_REG                 0xF3 //Status Reg
#define BME280_CTRL_MEAS_REG            0xF4 //Ctrl Measure Reg
#define BME280_CONFIG_REG               0xF5 //Configuration Reg
#define BME280_PRESSURE_MSB_REG         0xF7 //Pressure MSB
#define BME280_PRESSURE_LSB_REG         0xF8 //Pressure LSB
#define BME280_PRESSURE_XLSB_REG        0xF9 //Pressure XLSB
#define BME280_TEMPERATURE_MSB_REG      0xFA //Temperature MSB
#define BME280_TEMPERATURE_LSB_REG      0xFB //Temperature LSB
#define BME280_TEMPERATURE_XLSB_REG     0xFC //Temperature XLSB
#define BME280_HUMIDITY_MSB_REG         0xFD //Humidity MSB
#define BME280_HUMIDITY_LSB_REG         0xFE //Humidity LSBclass BME280ForSpi : public QObject
{Q_OBJECT
public:enum PRESSURE_OVERSAMPLING{PRESSURE_OVERSAMPLING_SKIPPED         = 0x00,PRESSURE_OVERSAMPLING_PLUS_ONE        = 0x01,PRESSURE_OVERSAMPLING_PLUS_TWO        = 0x02,PRESSURE_OVERSAMPLING_PLUS_FOUR       = 0x03,PRESSURE_OVERSAMPLING_PLUS_EIGHT      = 0x04,PRESSURE_OVERSAMPLING_PLUS_SIXTEEN    = 0x05};enum TEMPERATURE_OVERSAMPLING{TEMPERATURE_OVERSAMPLING_SKIPPED      = 0x00,TEMPERATURE_OVERSAMPLING_PLUS_ONE     = 0x01,TEMPERATURE_OVERSAMPLING_PLUS_TWO     = 0x02,TEMPERATURE_OVERSAMPLING_PLUS_FOUR    = 0x03,TEMPERATURE_OVERSAMPLING_PLUS_EIGHT   = 0x04,TEMPERATURE_OVERSAMPLING_PLUS_SIXTEEN = 0x05};enum MODE_OF_PRESSURE_TEMPERATUR{MODE_OF_PRESSURE_TEMPERATUR_SLEEP     = 0x00,MODE_OF_PRESSURE_TEMPERATUR_FORCED    = 0x01,MODE_OF_PRESSURE_TEMPERATUR_MORMAL    = 0x03};enum HUMIDITY_OVERSAMPLING{HUMIDITY_OVERSAMPLING_SKIPPED        = 0x00,HUMIDITY_OVERSAMPLING_PLUS_ONE       = 0x01,HUMIDITY_OVERSAMPLING_PLUS_TWO       = 0x02,HUMIDITY_OVERSAMPLING_PLUS_FOUR      = 0x03,HUMIDITY_OVERSAMPLING_PLUS_EIGHT     = 0x04,HUMIDITY_OVERSAMPLING_PLUS_SIXTEEN   = 0x05};struct Calibration{uint16_t dig_T1;int16_t dig_T2;int16_t dig_T3;uint16_t dig_P1;int16_t dig_P2;int16_t dig_P3;int16_t dig_P4;int16_t dig_P5;int16_t dig_P6;int16_t dig_P7;int16_t dig_P8;int16_t dig_P9;uint8_t dig_H1;int16_t dig_H2;uint8_t dig_H3;int16_t dig_H4;int16_t dig_H5;uint8_t dig_H6;};
public:explicit BME280ForSpi(QObject *parent = 0);bool isOnline();void initPressureTemperatureMode(PRESSURE_OVERSAMPLING p = PRESSURE_OVERSAMPLING_PLUS_ONE,TEMPERATURE_OVERSAMPLING t = TEMPERATURE_OVERSAMPLING_PLUS_ONE,MODE_OF_PRESSURE_TEMPERATUR m = MODE_OF_PRESSURE_TEMPERATUR_MORMAL);void initHumidity(HUMIDITY_OVERSAMPLING h = HUMIDITY_OVERSAMPLING_PLUS_ONE);void reset();
public slots:float getTemperatureC();float getTemperatureF();float getPressure();float getHumidity();float getAltitudeMeters();float getAltitudeFeet();
private:Spi _spi;Calibration _calibration;int32_t _tFine;int _channel;int _speed;
};
#endif // BME280FORSPI_H

bme280forspi.cpp

#include "bme280forspi.h"
BME280ForSpi::BME280ForSpi(QObject *parent) : QObject(parent)
{_spi.init();...
}bool BME280ForSpi::isOnline()
{// according to 0xD0 "id", value is 0x60return _spi.readData(BME280_CHIP_ID_REG) == 0x60;
}void BME280ForSpi::initPressureTemperatureMode(BME280ForSpi::PRESSURE_OVERSAMPLING p, BME280ForSpi::TEMPERATURE_OVERSAMPLING t, BME280ForSpi::MODE_OF_PRESSURE_TEMPERATUR m)
{...
}void BME280ForSpi::initHumidity(BME280ForSpi::HUMIDITY_OVERSAMPLING h)
{uchar uc;uc = (uchar)h;_spi.writeData(BME280_CTRL_HUMIDITY_REG, uc);
}void BME280ForSpi::reset()
{_spi.writeData(BME280_RST_REG, 0xB6);
}float BME280ForSpi::getTemperatureC()
{...int32_t adc_T = ((uint32_t)_spi.readData(BME280_TEMPERATURE_MSB_REG) << 12) | ((uint32_t)_spi.readData(BME280_TEMPERATURE_LSB_REG) << 4) | ((_spi.readData(BME280_TEMPERATURE_XLSB_REG) >> 4) & 0x0F);...output = output / 100;return output;
}float BME280ForSpi::getTemperatureF()
{float output = getTemperatureC();output = (output * 9) / 5 + 32;return output;
}float BME280ForSpi::getPressure()
{int32_t adc_P = ((uint32_t)_spi.readData(BME280_PRESSURE_MSB_REG) << 12) | ((uint32_t)_spi.readData(BME280_PRESSURE_LSB_REG) << 4) | ((_spi.readData(BME280_PRESSURE_XLSB_REG) >> 4) & 0x0F);int64_t var1, var2, p_acc;...return (float)p_acc;
}float BME280ForSpi::getHumidity()
{...int32_t adc_H = ((uint32_t)_spi.readData(BME280_HUMIDITY_MSB_REG) << 8) | ((uint32_t)_spi.readData(BME280_HUMIDITY_LSB_REG));...return (float)((var1>>12) >> 10);
}float BME280ForSpi::getAltitudeMeters()
{...return heightOutput;
}float BME280ForSpi::getAltitudeFeet()
{...heightOutput = getAltitudeMeters() * 3.28084;return heightOutput;
}

SPI模块代码

spi.h

class Spi : public QObject
{Q_OBJECT
public:enum CHOICE {CHOICE_CE0 = 0x00,CHOICE_CE1 = 0x01};public:explicit Spi(QObject *parent = 0);bool init(CHOICE c = CHOICE_CE0, int speed = 500000);
signals:public slots:void writeData(int reg, uchar data);uchar readData(int reg);private:int _fd;int _channel;int _speed;
};
#endif // SPI_H

spi.cpp

#include "spi.h"
#include "wiringPi.h"
#include "wiringPiSPI.h"
#include <QDebug>
#include <QByteArray>
Spi::Spi(QObject *parent): QObject(parent)
{wiringPiSetup();…
}
bool Spi::init(Spi::CHOICE c, int speed)
{…_fd = wiringPiSPISetup(_channel, _speed);…
}void Spi::writeData(int reg, uchar data)
{…ret = wiringPiSPIDataRW(_channel, ch, 2);
}uchar Spi::readData(int reg)
{…wiringPiSPIDataRW(_channel, data, 3);…
}

运行效果

上一篇:《树莓派开发笔记(六):GPIO口的UART的使用(串口通讯)》

下一篇:《树莓派开发笔记(八):GPIO口的I2C使用(BME280三合一传感器:测量温度、湿度、气压、海拔高度) 》

原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/79771763

树莓派开发笔记(七):GPIO口的SPI使用(BME280三合一传感器:测量温度、湿度、气压、海拔高度)相关推荐

  1. 树莓派开发笔记(九):基于CSI口的摄像头拍照程序(同样适用USB摄像头)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  2. 树莓派开发笔记(五):GPIO引脚介绍和GPIO的输入输出使用(驱动LED灯、检测按键)

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  3. 树莓派开发笔记(十四):入手研华ADVANTECH工控树莓派UNO-220套件(三):使用研发自带系统测试rtc、gpio、232和485套件接口

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/124754769 红胖子(红模仿)的博文大全:开发技术集 ...

  4. qml开发笔记(七):输入元素鼠标输入MouseArea和键盘输入Keys

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 原博主博客导航:https://blog.csdn.net/qq21497936/ ...

  5. 树莓派开发笔记(十七):树莓派4B+上Qt多用户连接操作Mysql数据库同步(单条数据悲观锁)

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/125188715 红胖子(红模仿)的博文大全:开发技术集 ...

  6. 树莓派开发笔记(十一):蓝牙的使用,BlueZ协议(双树莓探测rssi并通过蓝牙互传获取的rssi信号强度)

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/110940484 长期持续带来更多项目与技术分 ...

  7. windows内核开发笔记七:内核开发OVERLAPPED结构体详解

    windows内核开发笔记七:内核开发OVERLAPPED结构体详解 typedef struct _OVERLAPPED {   DWORD Internal;   DWORD InternalHi ...

  8. 树莓派android摄像头驱动开发,树莓派开发笔记(九):基于CSI口的摄像头拍照程序(同样适用USB摄像头)...

    前话 前面开发完GPIO口的功能,还剩下2个接口,一个是摄像头,一个是显示屏.本篇我们开发一个基于CSI接口的摄像头拍照程序. Demo:摄像头CSI的拍照程序 树莓派摄像头 笔者买的不是USB网络摄 ...

  9. 启明云端分享|ESP32学习笔记参考GPIO口操作

    提示:作为Espressif(乐鑫科技)大中华区合作伙伴及sigmastar(厦门星宸)VAD合作伙伴,我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考.同时也用 ...

  10. 全志H6方案板香橙派OrangePi 3开发板26pin GPIO口测试

    wiringOP 已适配 Orange Pi 3 开发板,使用 wiringOP 可以测试 GPIO.I2C.UART 和 SPI 的功能,下文先介绍26pin GPIO口测试 测试前先安装wirin ...

最新文章

  1. 阿里巴巴Druid,轻松实现MySQL数据库加密!
  2. 彻底搞懂Java内存泄露
  3. 【IT笔试面试题整理】连续子数组的最大和
  4. Regex解析字符串
  5. 爬虫实战:链接爬虫实战
  6. 2010.7.29 模式对话框
  7. PHP无法执行MySQL语句,解决PHP执行批量MySQL语句的问题
  8. 使用Jenkins来实现内部的持续集成流程(上)
  9. 开发者神器!Windows上最强大的虚拟桌面工具-Dexpot
  10. radio选中事件怎么绑定_Vue双向绑定
  11. 深度好文:云网络丢包故障定位,看这一篇就够了~
  12. 程序员薪资怎么论高级还是初级_和程序员一样高薪,却过着清闲生活,测试员什么人都可做吗?...
  13. 艾默生Ovation DCS OPC服务分析
  14. MarkDown安装后不能预览问题(awesomium_sdk的下载)
  15. 【小技巧】苹果手机获取UDID的方法【两种UID的获取方法,非常实用】
  16. java操作word的方法(总结)
  17. 票务公司加价将儿童机票售成年人赚取差价
  18. python123作业题
  19. anaconda and jupyterhub 配置部署
  20. 万由u-nas系统用上Let’s Encrypt 免费Https安全证书

热门文章

  1. 擦黑板特效表白H5源码+非常浪漫/附BGM
  2. DCDC的PCB布局常见错误及避免方式
  3. JS 常见的 6 种继承方式
  4. 输出希腊字母表(JAVA实验)
  5. 滑动窗口协议如何实现流量控制
  6. matlab圆孔孔壁应力集中,具有功能梯度加强环的有限尺寸开孔板应力集中问题
  7. 2021 年最受欢迎的深度学习软件
  8. 英语单词-每天10个
  9. python itchat文档_python itchat简介
  10. 9.20残差网络 ResNet