I tend to be a diletant when it comes to microprocessors. At the moment, I have an Uno R3, Teensy 3.0, Digispark, Gemma, 5v Trinket, and I am waiting for the DigiX. I primarily use the Teensy, but I've been wanting to use the ATtiny85 processors for doing simple things like running the two Neopixel rings on my steampunk goggles.
At the moment, I am starting to add I2C devices. On the Uno/Teensy I use Wire.h to talk to the i2c devices. On the Digispark, you use TinyWireM.h. However, I want to have sketches and libraries that can run on both the Uno/Teensy/DigiX as well as the ATtiny85 devices. I can use #ifdef's to determine which pins to use, but the IDE is trying to be 'too' helpful, and it includes Wire.h even though I have it #ifdef'ed out. Is there some way of having a Wire.h in the tiny directory that is a subset of the normal Wire.h, so I don't have to use #ifdef to select the right header. Or can we convince the Arduino guys to fix their %#!$ IDE to allow #ifdef's with different headers.
For example, my main code is:
// Like blink, but turn on multiple lights, via I2c using a MCP23017 i2c chip with 16 digital input/outputs
//
// Pins: Left Right
// ===== ==== =====
// Pin 1: Port 8 (GPB0) Port 0 (GPA0)
// Pin 2: Port 9 (GPB1) Port 1 (GPA1)
// Pin 3: Port 10 (GPB2) Port 2 (GPA2)
// Pin 4: Port 11 (GPB3) Port 3 (GPA3)
// Pin 5: Port 12 (GPB4) Port 4 (GPA4)
// Pin 6: Port 13 (GPB5) Port 5 (GPA5)
// Pin 7: Port 14 (GPB6) Port 6 (GPA6)
// Pin 8: Port 15 (GPB7) Port 7 (GPA7)
// Pin 9: Power (2.7-5.5V) Interupt A
// Pin 10: Ground Interupt B
// Pin 11: Not connected Reset
// Pin 12: SCL (A5, blue) Adress 2
// Pin 13: SDA (A4, green) Address 1
// Pin 14: Not connected Address 0
//
// Reset (pin 11 left) must be wired to power.
// Default address begins at 0x20
#include <stddef.h>
#if defined(__AVR_ATtiny85__)
#include <TinyWireM.h>
#else
#include <Wire.h>
#endif
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
const int i2c_addr = 0; // i2c address select bits of the MCP23008 i2c device
const int ms = 2000; // 2 seconds
const bool trace = true; // whether to trace to the serial port
const bool knight = true; // whether to do lights 'knight rider' style
const size_t first_led = 8; // first led to turn on
const size_t mirror_led = 0; // possibly mirror to second set of LEDs
const size_t n_leds = 8; // number of leds to write to
const unsigned int mask = (1U << n_leds) - 1; // mask of available leds
unsigned int state = 0; // cycle between 0 .. mask to turn on leds
bool kn_up = true; // whether knight rider is cycling up or down
// initialize the digital pins as outputs.
void setup() {
size_t i;
mcp.begin (i2c_addr & 0xf); // pass in address bits for mcp23008
for (i = 0; i < n_leds; i++)
{
mcp.pinMode (first_led + i, OUTPUT);
if (mirror_led > 0)
mcp.pinMode (mirror_led + i, OUTPUT);
}
if (knight)
state = 1;
#if !defined(__AVR_ATtiny85__)
if (trace)
{
Serial.begin (9600);
Serial.print ("Start, number of leds=");
Serial.print (n_leds);
Serial.print (", mask");
Serial.print (mask);
Serial.print (", First led=");
Serial.print (first_led);
if (mirror_led > 0)
{
Serial.print (", Mirror led=");
Serial.print (mirror_led);
}
Serial.println ("");
Serial.flush ();
}
#endif
}
// the loop routine runs over and over again forever:
void loop() {
#if !defined(__AVR_ATtiny85__)
const char *sep = "";
#endif
size_t i;
if (!knight || n_leds < 3)
{
// do lights as a counter
state = (state + 1) & mask;
}
else
{
// do lights 'knight rider' style where they cycle up and then down
if (kn_up)
{
state <<= 1;
if (state == (1U << n_leds))
{
state >>= 1;
kn_up = false;
}
}
else
{
state >>= 1;
if (state == 0)
{
state = 2;
kn_up = true;
}
}
}
for (i = 0; i < n_leds; i++)
{
int on_off = ((state & (1U << i)) != 0) ? HIGH : LOW;
#if !defined(__AVR_ATtiny85__)
if (trace)
{
Serial.print (sep);
Serial.print ("led");
Serial.print (first_led + i);
Serial.print ("=");
Serial.print (on_off);
sep = ", ";
}
#endif
mcp.digitalWrite (first_led + i, on_off);
if (mirror_led > 0)
mcp.digitalWrite (mirror_led + i, on_off);
}
#if !defined(__AVR_ATtiny85__)
if (trace)
Serial.println ("");
#endif
delay (ms);
}
And I've modified the Adafruit MCP23017 library as follows:
/***************************************************
This is a library for the MCP23017 i2c port expander
These displays use I2C to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#if defined(__AVR_ATtiny85__)
#include <TinyWireM.h>
#else
#include <Wire.h>
#endif
#include <avr/pgmspace.h>
#include "Adafruit_MCP23017.h"
//#if defined(__AVR__) || defined(__MK20DX128__) || defined(__AVR_ATtiny85__) // meissner, teensy/digispark/gemma/trinket mod
#define WIRE Wire
//#else // Arduino Due
// #define WIRE Wire1
//#endif
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// minihelper
static inline void wiresend(uint8_t x) {
#if ARDUINO >= 100
WIRE.write((uint8_t)x);
#else
WIRE.send(x);
#endif
}
static inline uint8_t wirerecv(void) {
#if ARDUINO >= 100
return WIRE.read();
#else
return WIRE.receive();
#endif
}
////////////////////////////////////////////////////////////////////////////////
void Adafruit_MCP23017::begin(uint8_t addr) {
if (addr > 7) {
addr = 7;
}
i2caddr = addr;
WIRE.begin();
// set defaults!
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_IODIRA);
wiresend(0xFF); // all inputs on port A
WIRE.endTransmission();
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_IODIRB);
wiresend(0xFF); // all inputs on port B
WIRE.endTransmission();
}
void Adafruit_MCP23017::begin(void) {
begin(0);
}
void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) {
uint8_t iodir;
uint8_t iodiraddr;
// only 16 bits!
if (p > 15)
return;
if (p < 8)
iodiraddr = MCP23017_IODIRA;
else {
iodiraddr = MCP23017_IODIRB;
p -= 8;
}
// read the current IODIR
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(iodiraddr);
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
iodir = wirerecv();
// set the pin and direction
if (d == INPUT) {
iodir |= 1 << p;
} else {
iodir &= ~(1 << p);
}
// write the new IODIR
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(iodiraddr);
wiresend(iodir);
WIRE.endTransmission();
}
uint16_t Adafruit_MCP23017::readGPIOAB() {
uint16_t ba = 0;
uint8_t a;
// read the current GPIO output latches
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPIOA);
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 2);
a = wirerecv();
ba = wirerecv();
ba <<= 8;
ba |= a;
return ba;
}
void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) {
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(MCP23017_GPIOA);
wiresend(ba & 0xFF);
wiresend(ba >> 8);
WIRE.endTransmission();
}
void Adafruit_MCP23017::digitalWrite(uint8_t p, uint8_t d) {
uint8_t gpio;
uint8_t gpioaddr, olataddr;
// only 16 bits!
if (p > 15)
return;
if (p < 8) {
olataddr = MCP23017_OLATA;
gpioaddr = MCP23017_GPIOA;
} else {
olataddr = MCP23017_OLATB;
gpioaddr = MCP23017_GPIOB;
p -= 8;
}
// read the current GPIO output latches
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(olataddr);
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
gpio = wirerecv();
// set the pin and direction
if (d == HIGH) {
gpio |= 1 << p;
} else {
gpio &= ~(1 << p);
}
// write the new GPIO
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(gpioaddr);
wiresend(gpio);
WIRE.endTransmission();
}
void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
uint8_t gppu;
uint8_t gppuaddr;
// only 16 bits!
if (p > 15)
return;
if (p < 8)
gppuaddr = MCP23017_GPPUA;
else {
gppuaddr = MCP23017_GPPUB;
p -= 8;
}
// read the current pullup resistor set
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(gppuaddr);
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
gppu = wirerecv();
// set the pin and direction
if (d == HIGH) {
gppu |= 1 << p;
} else {
gppu &= ~(1 << p);
}
// write the new GPIO
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(gppuaddr);
wiresend(gppu);
WIRE.endTransmission();
}
uint8_t Adafruit_MCP23017::digitalRead(uint8_t p) {
uint8_t gpioaddr;
// only 16 bits!
if (p > 15)
return 0;
if (p < 8)
gpioaddr = MCP23017_GPIOA;
else {
gpioaddr = MCP23017_GPIOB;
p -= 8;
}
// read the current GPIO
WIRE.beginTransmission(MCP23017_ADDRESS | i2caddr);
wiresend(gpioaddr);
WIRE.endTransmission();
WIRE.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
return (wirerecv() >> p) & 0x1;
}
The Adafruit_MCP23017.h file is:
/***************************************************
This is a library for the MCP23017 i2c port expander
These displays use I2C to communicate, 2 pins are required to
interface
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#ifndef _Adafruit_MCP23017_H_
#define _Adafruit_MCP23017_H_
// Don't forget the Wire library
class Adafruit_MCP23017 {
public:
void begin(uint8_t addr);
void begin(void);
void pinMode(uint8_t p, uint8_t d);
void digitalWrite(uint8_t p, uint8_t d);
void pullUp(uint8_t p, uint8_t d);
uint8_t digitalRead(uint8_t p);
void writeGPIOAB(uint16_t);
uint16_t readGPIOAB();
private:
uint8_t i2caddr;
};
#define MCP23017_ADDRESS 0x20
// registers
#define MCP23017_IODIRA 0x00
#define MCP23017_IPOLA 0x02
#define MCP23017_GPINTENA 0x04
#define MCP23017_DEFVALA 0x06
#define MCP23017_INTCONA 0x08
#define MCP23017_IOCONA 0x0A
#define MCP23017_GPPUA 0x0C
#define MCP23017_INTFA 0x0E
#define MCP23017_INTCAPA 0x10
#define MCP23017_GPIOA 0x12
#define MCP23017_OLATA 0x14
#define MCP23017_IODIRB 0x01
#define MCP23017_IPOLB 0x03
#define MCP23017_GPINTENB 0x05
#define MCP23017_DEFVALB 0x07
#define MCP23017_INTCONB 0x09
#define MCP23017_IOCONB 0x0B
#define MCP23017_GPPUB 0x0D
#define MCP23017_INTFB 0x0F
#define MCP23017_INTCAPB 0x11
#define MCP23017_GPIOB 0x13
#define MCP23017_OLATB 0x15
#endif
The errors I get are:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 /tmp/build847613151344621352.tmp/Blink_Mcp23017.cpp -o /tmp/build847613151344621352.tmp/Blink_Mcp23017.cpp.o
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/TinyDebugSerial.h:31,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/WProgram.h:18,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Arduino.h:4,
from Blink_Mcp23017.ino:32:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:37:1: warning: "BIN" redefined
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotn85.h:38,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/io.h:284,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/interrupt.h:38,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/WProgram.h:8,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Arduino.h:4,
from Blink_Mcp23017.ino:32:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotnx5.h:55:1: warning: this is the location of the previous definition
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/USI_TWI_Master.cpp -o /tmp/build847613151344621352.tmp/TinyWireM_Digispark/USI_TWI_Master.cpp.o
/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/USI_TWI_Master.cpp:23:1: warning: "F_CPU" redefined
<command-line>: warning: this is the location of the previous definition
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark/TinyWireM.cpp -o /tmp/build847613151344621352.tmp/TinyWireM_Digispark/TinyWireM.cpp.o
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=attiny85 -DF_CPU=16500000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=104 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/TinyWireM_Digispark -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire -I/home/meissner/sketchbook/libraries/Adafruit_MCP23017 -I/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/utility /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp -o /tmp/build847613151344621352.tmp/Wire/Wire.cpp.o
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:26,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:37:1: warning: "BIN" redefined
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotn85.h:38,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/io.h:284,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/pgmspace.h:82,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:30,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Stream.h:24,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:26,
from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../avr/include/avr/iotnx5.h:55:1: warning: this is the location of the previous definition
In file included from /data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.cpp:29:
/data/shared/arduino/digispark-1.0.4-2013-10-10/libraries/Wire/Wire.h:61: error: conflicting return type specified for ‘virtual size_t TwoWire::write(const uint8_t*, size_t)’
/data/shared/arduino/digispark-1.0.4-2013-10-10/hardware/digispark/cores/tiny/Print.h:75: error: overriding ‘virtual void Print::write(const uint8_t*, size_t)’