Ставим датчик температуры к Orange Pi / Raspberry Pi
Датчик DS18B20 - один из самых популярных датчиков температуры в мире. Где его только не используют: в Arduino, Banana Pi и, конечно, в Orange Pi и Raspberry Pi.
Чтобы всё работало, нужно к GPIO установить WiringOP и BPI-WiringPi, и IDE Code::Blocks.
OneWire библиотека
OneWire.h
#ifndef ONEWIRE_H
#define ONEWIRE_H
#define CMD_CONVERTTEMP 0x44
#define CMD_RSCRATCHPAD 0xbe
#define CMD_WSCRATCHPAD 0x4e
#define CMD_CPYSCRATCHPAD 0x48
#define CMD_RECEEPROM 0xb8
#define CMD_RPWRSUPPLY 0xb4
#define CMD_SEARCHROM 0xf0
#define CMD_READROM 0x33
#define CMD_MATCHROM 0x55
#define CMD_SKIPROM 0xcc
#define CMD_ALARMSEARCH 0xec
#include
class OneWire {
private:
int pin;
uint64_t searchNextAddress(uint64_t, int&);
public:
OneWire(int);
virtual ~OneWire();
int reset(void);
int crcCheck(uint64_t, uint8_t);
uint8_t crc8(uint8_t*, uint8_t);
void oneWireInit();
void writeBit(uint8_t);
void writeByte(uint8_t);
void setDevice(uint64_t);
void searchRom(uint64_t*, int&);
void skipRom(void);
uint8_t readByte(void);
uint8_t readBit(void);
uint64_t readRoom(void);
};
#endif // ONEWIRE_H
#define ONEWIRE_H
#define CMD_CONVERTTEMP 0x44
#define CMD_RSCRATCHPAD 0xbe
#define CMD_WSCRATCHPAD 0x4e
#define CMD_CPYSCRATCHPAD 0x48
#define CMD_RECEEPROM 0xb8
#define CMD_RPWRSUPPLY 0xb4
#define CMD_SEARCHROM 0xf0
#define CMD_READROM 0x33
#define CMD_MATCHROM 0x55
#define CMD_SKIPROM 0xcc
#define CMD_ALARMSEARCH 0xec
class OneWire {
private:
int pin;
uint64_t searchNextAddress(uint64_t, int&);
public:
OneWire(int);
virtual ~OneWire();
int reset(void);
int crcCheck(uint64_t, uint8_t);
uint8_t crc8(uint8_t*, uint8_t);
void oneWireInit();
void writeBit(uint8_t);
void writeByte(uint8_t);
void setDevice(uint64_t);
void searchRom(uint64_t*, int&);
void skipRom(void);
uint8_t readByte(void);
uint8_t readBit(void);
uint64_t readRoom(void);
};
#endif // ONEWIRE_H
OneWire.cpp
#include "OneWire.h"
#include
#include
#include
OneWire::OneWire(int _pin) :
pin(_pin) {
}
OneWire::~OneWire() {
}
void OneWire::oneWireInit() {
if (wiringPiSetup() == -1) {
throw std::logic_error("WiringPi Setup error");
}
pinMode(pin, INPUT);
}
/*
* сброс
*/
int OneWire::reset() {
int response;
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(480);
// Когда ONE WIRE устройство обнаруживает положительный перепад, он ждет от 15us до 60us
pinMode(pin, INPUT);
delayMicroseconds(60);
// и затем передает импульс присутствия, перемещая шину в логический «0» на длительность от 60us до 240us.
response = digitalRead(pin);
delayMicroseconds(410);
// если 0, значит есть ответ от датчика, если 1 - нет
return response;
}
/*
* отправить один бит
*/
void OneWire::writeBit(uint8_t bit) {
if (bit & 1) {
// логический «0» на 10us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(10);
pinMode(pin, INPUT);
delayMicroseconds(55);
} else {
// логический «0» на 65us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(65);
pinMode(pin, INPUT);
delayMicroseconds(5);
}
}
/*
* отправить один байт
*/
void OneWire::writeByte(uint8_t byte) {
uint8_t i = 8;
while (i--) {
writeBit(byte & 1);
byte >>= 1;
}
}
/*
* получить один байт
*/
uint8_t OneWire::readByte() {
uint8_t i = 8, byte = 0;
while (i--) {
byte >>= 1;
byte |= (readBit() << 7);
}
return byte;
}
/*
* получить один бит
*/
uint8_t OneWire::readBit(void) {
uint8_t bit = 0;
// логический «0» на 3us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(3);
// освободить линию и ждать 10us
pinMode(pin, INPUT);
delayMicroseconds(10);
// прочитать значение
bit = digitalRead(pin);
// ждать 45us и вернуть значение
delayMicroseconds(45);
return bit;
}
/*
* читать ROM подчиненного устройства (код 64 бита)
*/
uint64_t OneWire::readRoom(void) {
uint64_t oneWireDevice;
if (reset() == 0) {
writeByte (CMD_READROM);
// код семейства
oneWireDevice = readByte();
// серийный номер
oneWireDevice |= (uint16_t) readByte() << 8 | (uint32_t) readByte() << 16 | (uint32_t) readByte() << 24 | (uint64_t) readByte() << 32 | (uint64_t) readByte() << 40
| (uint64_t) readByte() << 48;
// CRC
oneWireDevice |= (uint64_t) readByte() << 56;
} else {
return 1;
}
return oneWireDevice;
}
/*
* Команда соответствия ROM, сопровождаемая последовательностью
* кода ROM на 64 бита позволяет устройству управления шиной
* обращаться к определенному подчиненному устройству на шине.
*/
void OneWire::setDevice(uint64_t rom) {
uint8_t i = 64;
reset();
writeByte (CMD_MATCHROM);
while (i--) {
writeBit(rom & 1);
rom >>= 1;
}
}
/*
* провеска CRC, возвращает "0", если нет ошибок
* и не "0", если есть ошибки
*/
int OneWire::crcCheck(uint64_t data8x8bit, uint8_t len) {
uint8_t dat, crc = 0, fb, stByte = 0;
do {
dat = (uint8_t)(data8x8bit >> (stByte * 8));
// счетчик битов в байте
for (int i = 0; i < 8; i++) {
fb = crc ^ dat;
fb &= 1;
crc >>= 1;
dat >>= 1;
if (fb == 1) {
crc ^= 0x8c; // полином
}
}
stByte++;
} while (stByte < len); // счетчик байтов в массиве
return crc;
}
uint8_t OneWire::crc8(uint8_t addr[], uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) {
crc ^= 0x8c;
}
inbyte >>= 1;
}
}
return crc;
}
/*
* поиск устройств
*/
void OneWire::searchRom(uint64_t * roms, int & n) {
uint64_t lastAddress = 0;
int lastDiscrepancy = 0;
int err = 0;
int i = 0;
do {
do {
try {
lastAddress = searchNextAddress(lastAddress, lastDiscrepancy);
int crc = crcCheck(lastAddress, 8);
if (crc == 0) {
roms[i++] = lastAddress;
err = 0;
} else {
err++;
}
} catch (std::exception & e) {
std::cout << e.what() << std::endl;
err++;
if (err > 3) {
throw e;
}
}
} while (err != 0);
} while (lastDiscrepancy != 0 && i < n);
n = i;
}
/*
* поиск следующего подключенного устройства
*/
uint64_t OneWire::searchNextAddress(uint64_t lastAddress, int & lastDiscrepancy) {
uint64_t newAddress = 0;
int searchDirection = 0;
int idBitNumber = 1;
int lastZero = 0;
reset();
writeByte (CMD_SEARCHROM);
while (idBitNumber < 65) {
int idBit = readBit();
int cmpIdBit = readBit();
// id_bit = cmp_id_bit = 1
if (idBit == 1 && cmpIdBit == 1) {
throw std::logic_error("error: id_bit = cmp_id_bit = 1");
} else if (idBit == 0 && cmpIdBit == 0) {
// id_bit = cmp_id_bit = 0
if (idBitNumber == lastDiscrepancy) {
searchDirection = 1;
} else if (idBitNumber > lastDiscrepancy) {
searchDirection = 0;
} else {
if ((uint8_t)(lastAddress >> (idBitNumber - 1)) & 1) {
searchDirection = 1;
} else {
searchDirection = 0;
}
}
if (searchDirection == 0) {
lastZero = idBitNumber;
}
} else {
// id_bit != cmp_id_bit
searchDirection = idBit;
}
newAddress |= ((uint64_t) searchDirection) << (idBitNumber - 1);
writeBit(searchDirection);
idBitNumber++;
}
lastDiscrepancy = lastZero;
return newAddress;
}
/*
* пропустить ROM
*/
void OneWire::skipRom() {
reset();
writeByte (CMD_SKIPROM);
}
OneWire::OneWire(int _pin) :
pin(_pin) {
}
OneWire::~OneWire() {
}
void OneWire::oneWireInit() {
if (wiringPiSetup() == -1) {
throw std::logic_error("WiringPi Setup error");
}
pinMode(pin, INPUT);
}
/*
* сброс
*/
int OneWire::reset() {
int response;
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(480);
// Когда ONE WIRE устройство обнаруживает положительный перепад, он ждет от 15us до 60us
pinMode(pin, INPUT);
delayMicroseconds(60);
// и затем передает импульс присутствия, перемещая шину в логический «0» на длительность от 60us до 240us.
response = digitalRead(pin);
delayMicroseconds(410);
// если 0, значит есть ответ от датчика, если 1 - нет
return response;
}
/*
* отправить один бит
*/
void OneWire::writeBit(uint8_t bit) {
if (bit & 1) {
// логический «0» на 10us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(10);
pinMode(pin, INPUT);
delayMicroseconds(55);
} else {
// логический «0» на 65us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(65);
pinMode(pin, INPUT);
delayMicroseconds(5);
}
}
/*
* отправить один байт
*/
void OneWire::writeByte(uint8_t byte) {
uint8_t i = 8;
while (i--) {
writeBit(byte & 1);
byte >>= 1;
}
}
/*
* получить один байт
*/
uint8_t OneWire::readByte() {
uint8_t i = 8, byte = 0;
while (i--) {
byte >>= 1;
byte |= (readBit() << 7);
}
return byte;
}
/*
* получить один бит
*/
uint8_t OneWire::readBit(void) {
uint8_t bit = 0;
// логический «0» на 3us
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
delayMicroseconds(3);
// освободить линию и ждать 10us
pinMode(pin, INPUT);
delayMicroseconds(10);
// прочитать значение
bit = digitalRead(pin);
// ждать 45us и вернуть значение
delayMicroseconds(45);
return bit;
}
/*
* читать ROM подчиненного устройства (код 64 бита)
*/
uint64_t OneWire::readRoom(void) {
uint64_t oneWireDevice;
if (reset() == 0) {
writeByte (CMD_READROM);
// код семейства
oneWireDevice = readByte();
// серийный номер
oneWireDevice |= (uint16_t) readByte() << 8 | (uint32_t) readByte() << 16 | (uint32_t) readByte() << 24 | (uint64_t) readByte() << 32 | (uint64_t) readByte() << 40
| (uint64_t) readByte() << 48;
// CRC
oneWireDevice |= (uint64_t) readByte() << 56;
} else {
return 1;
}
return oneWireDevice;
}
/*
* Команда соответствия ROM, сопровождаемая последовательностью
* кода ROM на 64 бита позволяет устройству управления шиной
* обращаться к определенному подчиненному устройству на шине.
*/
void OneWire::setDevice(uint64_t rom) {
uint8_t i = 64;
reset();
writeByte (CMD_MATCHROM);
while (i--) {
writeBit(rom & 1);
rom >>= 1;
}
}
/*
* провеска CRC, возвращает "0", если нет ошибок
* и не "0", если есть ошибки
*/
int OneWire::crcCheck(uint64_t data8x8bit, uint8_t len) {
uint8_t dat, crc = 0, fb, stByte = 0;
do {
dat = (uint8_t)(data8x8bit >> (stByte * 8));
// счетчик битов в байте
for (int i = 0; i < 8; i++) {
fb = crc ^ dat;
fb &= 1;
crc >>= 1;
dat >>= 1;
if (fb == 1) {
crc ^= 0x8c; // полином
}
}
stByte++;
} while (stByte < len); // счетчик байтов в массиве
return crc;
}
uint8_t OneWire::crc8(uint8_t addr[], uint8_t len) {
uint8_t crc = 0;
while (len--) {
uint8_t inbyte = *addr++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) {
crc ^= 0x8c;
}
inbyte >>= 1;
}
}
return crc;
}
/*
* поиск устройств
*/
void OneWire::searchRom(uint64_t * roms, int & n) {
uint64_t lastAddress = 0;
int lastDiscrepancy = 0;
int err = 0;
int i = 0;
do {
do {
try {
lastAddress = searchNextAddress(lastAddress, lastDiscrepancy);
int crc = crcCheck(lastAddress, 8);
if (crc == 0) {
roms[i++] = lastAddress;
err = 0;
} else {
err++;
}
} catch (std::exception & e) {
std::cout << e.what() << std::endl;
err++;
if (err > 3) {
throw e;
}
}
} while (err != 0);
} while (lastDiscrepancy != 0 && i < n);
n = i;
}
/*
* поиск следующего подключенного устройства
*/
uint64_t OneWire::searchNextAddress(uint64_t lastAddress, int & lastDiscrepancy) {
uint64_t newAddress = 0;
int searchDirection = 0;
int idBitNumber = 1;
int lastZero = 0;
reset();
writeByte (CMD_SEARCHROM);
while (idBitNumber < 65) {
int idBit = readBit();
int cmpIdBit = readBit();
// id_bit = cmp_id_bit = 1
if (idBit == 1 && cmpIdBit == 1) {
throw std::logic_error("error: id_bit = cmp_id_bit = 1");
} else if (idBit == 0 && cmpIdBit == 0) {
// id_bit = cmp_id_bit = 0
if (idBitNumber == lastDiscrepancy) {
searchDirection = 1;
} else if (idBitNumber > lastDiscrepancy) {
searchDirection = 0;
} else {
if ((uint8_t)(lastAddress >> (idBitNumber - 1)) & 1) {
searchDirection = 1;
} else {
searchDirection = 0;
}
}
if (searchDirection == 0) {
lastZero = idBitNumber;
}
} else {
// id_bit != cmp_id_bit
searchDirection = idBit;
}
newAddress |= ((uint64_t) searchDirection) << (idBitNumber - 1);
writeBit(searchDirection);
idBitNumber++;
}
lastDiscrepancy = lastZero;
return newAddress;
}
/*
* пропустить ROM
*/
void OneWire::skipRom() {
reset();
writeByte (CMD_SKIPROM);
}
Как подключить несколько датчиков к Апельсинке.
Если подключать такие датчики на одну и ту же шину, то нужно чтоб Orange Pi либо Raspberry Pi определяла коды ROM подключённых устройств на этой шине. Для этого можно использовать команду SEARCH ROM [F0h] - она ищет все устройства и определяет их номера. Если Вы подключили только один датчик, то можно использовать команду READ ROM [33h].
main.cpp
#include
#include
#include "OneWire.h"
using namespace std;
double getTemp(OneWire * oneWire, uint64_t ds18b20s) {
uint8_t data[9];
do {
oneWire->setDevice(ds18b20s);
oneWire->writeByte(CMD_CONVERTTEMP);
delay(750);
oneWire->setDevice(ds18b20s);
oneWire->writeByte(CMD_RSCRATCHPAD);
for (int i = 0; i < 9; i++) {
data[i] = oneWire->readByte();
}
} while (oneWire->crc8(data, 8) != data[8]);
return ((data[1] << 8) + data[0]) * 0.0625;
}
int main() {
OneWire * ds18b20 = new OneWire(24);
try {
ds18b20->oneWireInit();
double temperature;
int n = 100;
uint64_t roms[n];
ds18b20->searchRom(roms, n);
cout << "---------------------------------" << endl;
cout << "devices = " << n << endl;
cout << "---------------------------------" << endl;
for (int i = 0; i < n; i++) {
cout << "addr T[" << (i + 1) << "] = " << roms[i] << endl;
}
cout << "---------------------------------" << endl;
while (1) {
for (int i = 0; i < n; i++) {
temperature = getTemp(ds18b20, roms[i]);
cout << "T[" << (i + 1) << "] = " << temperature << "°C" << endl;
}
cout << "---------------------------------" << endl;
delay(500);
}
} catch (exception & e) {
cout << e.what() << endl;
}
}
#include "OneWire.h"
using namespace std;
double getTemp(OneWire * oneWire, uint64_t ds18b20s) {
uint8_t data[9];
do {
oneWire->setDevice(ds18b20s);
oneWire->writeByte(CMD_CONVERTTEMP);
delay(750);
oneWire->setDevice(ds18b20s);
oneWire->writeByte(CMD_RSCRATCHPAD);
for (int i = 0; i < 9; i++) {
data[i] = oneWire->readByte();
}
} while (oneWire->crc8(data, 8) != data[8]);
return ((data[1] << 8) + data[0]) * 0.0625;
}
int main() {
OneWire * ds18b20 = new OneWire(24);
try {
ds18b20->oneWireInit();
double temperature;
int n = 100;
uint64_t roms[n];
ds18b20->searchRom(roms, n);
cout << "---------------------------------" << endl;
cout << "devices = " << n << endl;
cout << "---------------------------------" << endl;
for (int i = 0; i < n; i++) {
cout << "addr T[" << (i + 1) << "] = " << roms[i] << endl;
}
cout << "---------------------------------" << endl;
while (1) {
for (int i = 0; i < n; i++) {
temperature = getTemp(ds18b20, roms[i]);
cout << "T[" << (i + 1) << "] = " << temperature << "°C" << endl;
}
cout << "---------------------------------" << endl;
delay(500);
}
} catch (exception & e) {
cout << e.what() << endl;
}
}
Получить температуру по Цельсию:
double getTemp(OneWire * oneWire, uint64_t ds18b20s)
Источник
19.01.2020 в 14:09, Просмотров: 8969
Опубликовал: ak167