Thermal Flashlight (RGB LED + Melexis 90614 + Arduino)
#ifndef _I2CMASTER_H | |
#define _I2CMASTER_H 1 | |
/************************************************************************* | |
* Title: C include file for the I2C master interface | |
* (i2cmaster.S or twimaster.c) | |
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury | |
* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $ | |
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 | |
* Target: any AVR device | |
* Usage: see Doxygen manual | |
**************************************************************************/ | |
#ifdef DOXYGEN | |
/** | |
@defgroup pfleury_ic2master I2C Master library | |
@code #include <i2cmaster.h> @endcode | |
@brief I2C (TWI) Master Software Library | |
Basic routines for communicating with I2C slave devices. This single master | |
implementation is limited to one bus master on the I2C bus. | |
This I2c library is implemented as a compact assembler software implementation of the I2C protocol | |
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c). | |
Since the API for these two implementations is exactly the same, an application can be linked either against the | |
software I2C implementation or the hardware I2C implementation. | |
Use 4.7k pull-up resistor on the SDA and SCL pin. | |
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module | |
i2cmaster.S to your target when using the software I2C implementation ! | |
Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion. | |
@note | |
The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted | |
to GNU assembler and AVR-GCC C call interface. | |
Replaced the incorrect quarter period delays found in AVR300 with | |
half period delays. | |
@author Peter Fleury pfleury@gmx.ch http://jump.to/fleury | |
@par API Usage Example | |
The following code shows typical usage of this library, see example test_i2cmaster.c | |
@code | |
#include <i2cmaster.h> | |
#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet | |
int main(void) | |
{ | |
unsigned char ret; | |
i2c_init(); // initialize I2C library | |
// write 0x75 to EEPROM address 5 (Byte Write) | |
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode | |
i2c_write(0x05); // write address = 5 | |
i2c_write(0x75); // write value 0x75 to EEPROM | |
i2c_stop(); // set stop conditon = release bus | |
// read previously written value back from EEPROM address 5 | |
i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode | |
i2c_write(0x05); // write address = 5 | |
i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode | |
ret = i2c_readNak(); // read one byte from EEPROM | |
i2c_stop(); | |
for(;;); | |
} | |
@endcode | |
*/ | |
#endif /* DOXYGEN */ | |
/**@{*/ | |
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 | |
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" | |
#endif | |
#include <avr/io.h> | |
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */ | |
#define I2C_READ 1 | |
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */ | |
#define I2C_WRITE 0 | |
/** | |
@brief initialize the I2C master interace. Need to be called only once | |
@param void | |
@return none | |
*/ | |
extern void i2c_init(void); | |
/** | |
@brief Terminates the data transfer and releases the I2C bus | |
@param void | |
@return none | |
*/ | |
extern void i2c_stop(void); | |
/** | |
@brief Issues a start condition and sends address and transfer direction | |
@param addr address and transfer direction of I2C device | |
@retval 0 device accessible | |
@retval 1 failed to access device | |
*/ | |
extern unsigned char i2c_start(unsigned char addr); | |
/** | |
@brief Issues a repeated start condition and sends address and transfer direction | |
@param addr address and transfer direction of I2C device | |
@retval 0 device accessible | |
@retval 1 failed to access device | |
*/ | |
extern unsigned char i2c_rep_start(unsigned char addr); | |
/** | |
@brief Issues a start condition and sends address and transfer direction | |
If device is busy, use ack polling to wait until device ready | |
@param addr address and transfer direction of I2C device | |
@return none | |
*/ | |
extern void i2c_start_wait(unsigned char addr); | |
/** | |
@brief Send one byte to I2C device | |
@param data byte to be transfered | |
@retval 0 write successful | |
@retval 1 write failed | |
*/ | |
extern unsigned char i2c_write(unsigned char data); | |
/** | |
@brief read one byte from the I2C device, request more data from device | |
@return byte read from I2C device | |
*/ | |
extern unsigned char i2c_readAck(void); | |
/** | |
@brief read one byte from the I2C device, read is followed by a stop condition | |
@return byte read from I2C device | |
*/ | |
extern unsigned char i2c_readNak(void); | |
/** | |
@brief read one byte from the I2C device | |
Implemented as a macro, which calls either i2c_readAck or i2c_readNak | |
@param ack 1 send ack, request more data from device<br> | |
0 send nak, read is followed by a stop condition | |
@return byte read from I2C device | |
*/ | |
extern unsigned char i2c_read(unsigned char ack); | |
#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); | |
/**@}*/ | |
#endif |
// See http://bildr.org/2011/02/mlx90614-arduino/ for i2c library and instructions | |
// You must download the "twimaster.cpp" and "i2cmaster.h" files, and place them in a folder called "I2Cmaster". This must be placed in a folder called "libraries" which in turn should be placed in your Sketchbook folder (see Arduino's Preferences menu item to see where this is on your machine.). | |
// Typically, once you install these files, you must relaunch Arduino. | |
// The extra files are included in this Gist, as well as attached to the page http://publiclaboratory.org/tool/thermal-camera | |
#include <i2cmaster.h> | |
#include "Wire.h" | |
//#include "BlinkM_funcs.h" | |
const float lowReading = 60; | |
const float highReading = 75; | |
const unsigned char separatorCharacter = 255; | |
void setup(){ | |
pinMode(9,OUTPUT); | |
pinMode(10,OUTPUT); | |
pinMode(11,OUTPUT); | |
Serial.begin(9600); | |
Serial.println("starting setup..."); | |
i2c_init(); //Initialise the i2c bus | |
PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups | |
Serial.println("completed setup"); | |
} | |
float normf(float x, float low, float high) { | |
float y = (x - low) * 255.f / (high - low); | |
if(y > 255) { | |
y = 255; | |
} | |
if(y < 0) { | |
y = 0; | |
} | |
return y; | |
} | |
void loop(){ | |
int dev = 0x5A<<1; | |
int data_low = 0; | |
int data_high = 0; | |
int pec = 0; | |
i2c_start_wait(dev+I2C_WRITE); | |
i2c_write(0x07); | |
// read | |
i2c_rep_start(dev+I2C_READ); | |
data_low = i2c_readAck(); //Read 1 byte and then send ack | |
data_high = i2c_readAck(); //Read 1 byte and then send ack | |
pec = i2c_readNak(); | |
i2c_stop(); | |
//This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps | |
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614) | |
double tempData = 0x0000; // zero out the data | |
int frac; // data past the decimal point | |
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte. | |
tempData = (double)(((data_high & 0x007F) << 8) + data_low); | |
tempData = (tempData * tempFactor)-0.01; | |
float celcius = tempData - 273.15; | |
float fahrenheit = (celcius*1.8) + 32; | |
//Serial.println(fahrenheit); | |
float state = normf(fahrenheit, lowReading, highReading); | |
//Serial.write((unsigned int) state); | |
//Serial.write(separatorCharacter); | |
// BlinkM MaxM super-bright LED: | |
// 165 is blue, 0 is red | |
//BlinkM_fadeToHSB(blinkm_addr, map(state, 0, 255, 165, 0), 255, 255); | |
// Regular ol' RGB LED: | |
int hue = map(state,0,255,359,(359*0.5)); // not the whole color wheel | |
setLedColorHSV(hue,1,1); //We are using Saturation and Value constant at 1 | |
Serial.print(fahrenheit); | |
Serial.print(" degrees F, hue: "); | |
Serial.println(+hue); | |
} | |
//Convert a given HSV (Hue Saturation Value) to RGB(Red Green Blue) and set the led to the color | |
// h is hue value, integer between 0 and 360 | |
// s is saturation value, double between 0 and 1 | |
// v is value, double between 0 and 1 | |
//http://splinter.com.au/blog/?p=29 | |
void setLedColorHSV(int h, double s, double v) { | |
//this is the algorithm to convert from RGB to HSV | |
double r=0; | |
double g=0; | |
double b=0; | |
double hf=h/60.0; | |
int i=(int)floor(h/60.0); | |
double f = h/60.0 - i; | |
double pv = v * (1 - s); | |
double qv = v * (1 - s*f); | |
double tv = v * (1 - s * (1 - f)); | |
switch (i) | |
{ | |
case 0: //rojo dominante | |
r = v; | |
g = tv; | |
b = pv; | |
break; | |
case 1: //verde | |
r = qv; | |
g = v; | |
b = pv; | |
break; | |
case 2: | |
r = pv; | |
g = v; | |
b = tv; | |
break; | |
case 3: //azul | |
r = pv; | |
g = qv; | |
b = v; | |
break; | |
case 4: | |
r = tv; | |
g = pv; | |
b = v; | |
break; | |
case 5: //rojo | |
r = v; | |
g = pv; | |
b = qv; | |
break; | |
} | |
//set each component to a integer value between 0 and 255 | |
int red=constrain((int)255*r,0,255); | |
int green=constrain((int)255*g,0,255); | |
int blue=constrain((int)255*b,0,255); | |
setLedColor(red,green,blue); | |
} | |
//Sets the current color for the RGB LED | |
void setLedColor(int red, int green, int blue) { | |
//Note that we are reducing 1/4 the intensity for the green and blue components because | |
// the red one is too dim on my LED. You may want to adjust that. | |
analogWrite(9,red); //Red pin attached to 9 | |
analogWrite(10,green); //Red pin attached to 9 | |
analogWrite(11,blue); //Red pin attached to 9 | |
} |
/************************************************************************* | |
* Title: I2C master library using hardware TWI interface | |
* Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury | |
* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ | |
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 | |
* Target: any AVR device with hardware TWI | |
* Usage: API compatible with I2C Software Library i2cmaster.h | |
**************************************************************************/ | |
#include <inttypes.h> | |
#include <compat/twi.h> | |
#include <i2cmaster.h> | |
/* define CPU frequency in Mhz here if not defined in Makefile */ | |
#ifndef F_CPU | |
#define F_CPU 16000000UL | |
#endif | |
/* I2C clock in Hz */ | |
#define SCL_CLOCK 50000L | |
/************************************************************************* | |
Initialization of the I2C bus interface. Need to be called only once | |
*************************************************************************/ | |
void i2c_init(void) | |
{ | |
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ | |
TWSR = 0; /* no prescaler */ | |
TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */ | |
}/* i2c_init */ | |
/************************************************************************* | |
Issues a start condition and sends address and transfer direction. | |
return 0 = device accessible, 1= failed to access device | |
*************************************************************************/ | |
unsigned char i2c_start(unsigned char address) | |
{ | |
uint8_t twst; | |
// send START condition | |
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); | |
// wait until transmission completed | |
while(!(TWCR & (1<<TWINT))); | |
// check value of TWI Status Register. Mask prescaler bits. | |
twst = TW_STATUS & 0xF8; | |
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; | |
// send device address | |
TWDR = address; | |
TWCR = (1<<TWINT) | (1<<TWEN); | |
// wail until transmission completed and ACK/NACK has been received | |
while(!(TWCR & (1<<TWINT))); | |
// check value of TWI Status Register. Mask prescaler bits. | |
twst = TW_STATUS & 0xF8; | |
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; | |
return 0; | |
}/* i2c_start */ | |
/************************************************************************* | |
Issues a start condition and sends address and transfer direction. | |
If device is busy, use ack polling to wait until device is ready | |
Input: address and transfer direction of I2C device | |
*************************************************************************/ | |
void i2c_start_wait(unsigned char address) | |
{ | |
uint8_t twst; | |
while ( 1 ) | |
{ | |
// send START condition | |
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); | |
// wait until transmission completed | |
while(!(TWCR & (1<<TWINT))); | |
// check value of TWI Status Register. Mask prescaler bits. | |
twst = TW_STATUS & 0xF8; | |
if ( (twst != TW_START) && (twst != TW_REP_START)) continue; | |
// send device address | |
TWDR = address; | |
TWCR = (1<<TWINT) | (1<<TWEN); | |
// wail until transmission completed | |
while(!(TWCR & (1<<TWINT))); | |
// check value of TWI Status Register. Mask prescaler bits. | |
twst = TW_STATUS & 0xF8; | |
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) | |
{ | |
/* device busy, send stop condition to terminate write operation */ | |
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | |
// wait until stop condition is executed and bus released | |
while(TWCR & (1<<TWSTO)); | |
continue; | |
} | |
//if( twst != TW_MT_SLA_ACK) return 1; | |
break; | |
} | |
}/* i2c_start_wait */ | |
/************************************************************************* | |
Issues a repeated start condition and sends address and transfer direction | |
Input: address and transfer direction of I2C device | |
Return: 0 device accessible | |
1 failed to access device | |
*************************************************************************/ | |
unsigned char i2c_rep_start(unsigned char address) | |
{ | |
return i2c_start( address ); | |
}/* i2c_rep_start */ | |
/************************************************************************* | |
Terminates the data transfer and releases the I2C bus | |
*************************************************************************/ | |
void i2c_stop(void) | |
{ | |
/* send stop condition */ | |
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); | |
// wait until stop condition is executed and bus released | |
while(TWCR & (1<<TWSTO)); | |
}/* i2c_stop */ | |
/************************************************************************* | |
Send one byte to I2C device | |
Input: byte to be transfered | |
Return: 0 write successful | |
1 write failed | |
*************************************************************************/ | |
unsigned char i2c_write( unsigned char data ) | |
{ | |
uint8_t twst; | |
// send data to the previously addressed device | |
TWDR = data; | |
TWCR = (1<<TWINT) | (1<<TWEN); | |
// wait until transmission completed | |
while(!(TWCR & (1<<TWINT))); | |
// check value of TWI Status Register. Mask prescaler bits | |
twst = TW_STATUS & 0xF8; | |
if( twst != TW_MT_DATA_ACK) return 1; | |
return 0; | |
}/* i2c_write */ | |
/************************************************************************* | |
Read one byte from the I2C device, request more data from device | |
Return: byte read from I2C device | |
*************************************************************************/ | |
unsigned char i2c_readAck(void) | |
{ | |
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); | |
while(!(TWCR & (1<<TWINT))); | |
return TWDR; | |
}/* i2c_readAck */ | |
/************************************************************************* | |
Read one byte from the I2C device, read is followed by a stop condition | |
Return: byte read from I2C device | |
*************************************************************************/ | |
unsigned char i2c_readNak(void) | |
{ | |
TWCR = (1<<TWINT) | (1<<TWEN); | |
while(!(TWCR & (1<<TWINT))); | |
return TWDR; | |
}/* i2c_readNak */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment