この記事は、MIDI&Audioをは無関係です。
Adafruit MCP9808は高精度な温度計です。インターフェースはI2Cです。 このモジュールをRaspberry Pi Zeroに接続し、WiringPiライブラリを使って動作させます。
物理的な接続は基本的に4本です。電源2本をI2Cのデータ(SDA)とクロック(SCL)を接続します。
プログラムをGithubに置きました。
// main.cpp
#include <stdio.h>
#include <stdint.h>
#include "Wiringpi_MCP9808.h"
#include <wiringPi.h>
int main()
{
// Make sure the sensor is found, you can also pass in a different i2c
// address with tempsensor.begin(0x19) for example, also can be left in blank for default address use
// Also there is a table with all addres possible for this sensor, you can connect multiple sensors
// to the same i2c bus, just configure each sensor with a different address and define multiple objects for that
// A2 A1 A0 address
// 0 0 0 0x18 this is the default address
// 0 0 1 0x19
// 0 1 0 0x1A
// 0 1 1 0x1B
// 1 0 0 0x1C
// 1 0 1 0x1D
// 1 1 0 0x1E
// 1 1 1 0x1F
Wiringpi_MCP9808 mcp9808;
bool result = mcp9808.init(MCP9808_I2CADDR_DEFAULT);
if(result){
fprintf(stderr,"Success to create the interface for MCP9808\n");
} else {
fprintf(stderr,"Fale to create the interface for MCP9808\n");
}
// sets the resolution mode of reading, the modes are defined in the table bellow:
// Mode Resolution SampleTime
// 0 0.5°C 30 ms
// 1 0.25°C 65 ms
// 2 0.125°C 130 ms
// 3 0.0625°C 250 ms
mcp9808.write8(MCP9808_REG_RESOLUTION, 3); //Set Resolution
fprintf(stderr,"Resolution = %d\n",mcp9808.read8(MCP9808_REG_RESOLUTION)); //Read Resolution
while(1){
mcp9808.wake_shutdown(true);
fprintf(stderr,"%5.2f *C\n",mcp9808.readTempC());
mcp9808.wake_shutdown(false);
delay(1000);
}
}
/*
* Wiringpi_MCP9808.h
* MCP9808 for using WiringPi
* by MikataHara
* 2024.10.22
*/
#include <wiringPiI2C.h>
#ifndef _WIRINGPI_MCP9808_H
#define _WIRINGPI_MCP9808_H
#define MCP9808_I2CADDR_DEFAULT 0x18 ///< I2C address
#define MCP9808_REG_CONFIG 0x01 ///< MCP9808 config register
#define MCP9808_REG_CONFIG_SHUTDOWN 0x0100 ///< shutdown config
#define MCP9808_REG_CONFIG_CRITLOCKED 0x0080 ///< critical trip lock
#define MCP9808_REG_CONFIG_WINLOCKED 0x0040 ///< alarm window lock
#define MCP9808_REG_CONFIG_INTCLR 0x0020 ///< interrupt clear
#define MCP9808_REG_CONFIG_ALERTSTAT 0x0010 ///< alert output status
#define MCP9808_REG_CONFIG_ALERTCTRL 0x0008 ///< alert output control
#define MCP9808_REG_CONFIG_ALERTSEL 0x0004 ///< alert output select
#define MCP9808_REG_CONFIG_ALERTPOL 0x0002 ///< alert output polarity
#define MCP9808_REG_CONFIG_ALERTMODE 0x0001 ///< alert output mode
#define MCP9808_REG_UPPER_TEMP 0x02 ///< upper alert boundary
#define MCP9808_REG_LOWER_TEMP 0x03 ///< lower alert boundery
#define MCP9808_REG_CRIT_TEMP 0x04 ///< critical temperature
#define MCP9808_REG_AMBIENT_TEMP 0x05 ///< ambient temperature
#define MCP9808_REG_MANUF_ID 0x06 ///< manufacture ID
#define MCP9808_REG_DEVICE_ID 0x07 ///< device ID
#define MCP9808_REG_RESOLUTION 0x08 ///< resolutin
/* Class for MCP9808 Temp Sensor */
#define NAN -1
class Wiringpi_MCP9808 {
public:
Wiringpi_MCP9808(){}
bool init(uint8_t addr);
void write16(uint8_t reg, uint16_t val);
uint16_t read16(uint8_t reg);
void write8(uint8_t reg, uint8_t val);
uint8_t read8(uint8_t reg);
void setResolution(uint8_t value);
void wake_shutdown(bool sw);
private:
uint8_t _i2caddr;
};
#endif
(注)16ビットのRead/Writeの関数では、LSB Firstのuint16_tの値をMSB Firstに変換しています。 Raspberry Pi上はLSB First、I2CはMSB FIrstで扱う為、変換する必要があります。 swapBytesはChatGPTを参考に記載しています。
/*
* Wiringpi_MCP9808.cpp
* Modified for Trinket by MikataHara
* 2024.10.19
*/
#include <stdint.h>
#include <stdio.h>
#include "Wiringpi_MCP9808.h"
// LSBとMSBを交換
uint16_t swapBytes(uint16_t num) {
return ((num&0xFF00) >> 8) | ((num << 8)&0xFF00);
}
/* Initialize */
bool Wiringpi_MCP9808::init(uint8_t addr) {
uint16_t manuf_id, device_id;
_i2caddr = wiringPiI2CSetup (addr);
fprintf(stderr,"_i2caddr=%d\n",_i2caddr);
if (_i2caddr > 0){
manuf_id = read16(MCP9808_REG_MANUF_ID);
device_id = read16(MCP9808_REG_DEVICE_ID);
fprintf(stderr,"MCP9808_REG_MANUF_ID=%04x\n",manuf_id);
fprintf(stderr,"MCP9808_REG_DEVICE_ID=%04x\n",device_id);
if (manuf_id != 0x0054) return false;
if (device_id != 0x0400) return false;
write16(MCP9808_REG_CONFIG, 0x0);
} else {
return false;
}
return true;
}
void Wiringpi_MCP9808::write8(uint8_t reg, uint8_t val){
wiringPiI2CWriteReg8 (_i2caddr, reg, val);
}
uint8_t Wiringpi_MCP9808::read8(uint8_t reg){
uint16_t result = wiringPiI2CReadReg8 (_i2caddr,reg);
return result;
}
void Wiringpi_MCP9808::write16(uint8_t reg, uint16_t val){
wiringPiI2CWriteReg16 (_i2caddr, reg, swapBytes(val));
}
uint16_t Wiringpi_MCP9808::read16(uint8_t reg){
uint16_t result = wiringPiI2CReadReg16 (_i2caddr,reg);
return swapBytes(result);
}
/* Read Temperature */
float Wiringpi_MCP9808::readTempC() {
float temp = NAN;
uint16_t t = read16(MCP9808_REG_AMBIENT_TEMP);
if (t != 0xFFFF) {
temp = t & 0x0FFF;
temp /= 16.0;
if (t & 0x1000)
temp -= 256;
}
return temp;
}
/* Wakeup and Shutdown */
/* true : wake */
/* false : shutdown */
void Wiringpi_MCP9808::wake_shutdown(bool sw) {
uint16_t conf_shutdown;
uint16_t conf_register = read16(MCP9808_REG_CONFIG);
if (sw == true) {
conf_shutdown = conf_register | MCP9808_REG_CONFIG_SHUTDOWN;
write16(MCP9808_REG_CONFIG, conf_shutdown);
}
else if (sw == false) {
conf_shutdown = conf_register & ~MCP9808_REG_CONFIG_SHUTDOWN;
write16(MCP9808_REG_CONFIG, conf_shutdown);
}
}