root / arduino-1.0 / libraries / Firmata / examples / I2CFirmata / I2CFirmata.ino @ 58d82c77
History | View | Annotate | Download (6.09 KB)
1 |
/* |
---|---|
2 |
* Firmata is a generic protocol for communicating with microcontrollers |
3 |
* from software on a host computer. It is intended to work with |
4 |
* any host computer software package. |
5 |
* |
6 |
* To download a host software package, please clink on the following link |
7 |
* to open the download page in your default browser. |
8 |
* |
9 |
* http://firmata.org/wiki/Download |
10 |
*/ |
11 |
|
12 |
/* |
13 |
Copyright (C) 2009 Jeff Hoefs. All rights reserved. |
14 |
Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. |
15 |
|
16 |
This library is free software; you can redistribute it and/or |
17 |
modify it under the terms of the GNU Lesser General Public |
18 |
License as published by the Free Software Foundation; either |
19 |
version 2.1 of the License, or (at your option) any later version. |
20 |
|
21 |
See file LICENSE.txt for further informations on licensing terms. |
22 |
*/ |
23 |
|
24 |
#include <Wire.h> |
25 |
#include <Firmata.h> |
26 |
|
27 |
|
28 |
#define I2C_WRITE B00000000 |
29 |
#define I2C_READ B00001000 |
30 |
#define I2C_READ_CONTINUOUSLY B00010000 |
31 |
#define I2C_STOP_READING B00011000 |
32 |
#define I2C_READ_WRITE_MODE_MASK B00011000 |
33 |
|
34 |
#define MAX_QUERIES 8 |
35 |
|
36 |
unsigned long currentMillis; // store the current value from millis() |
37 |
unsigned long previousMillis; // for comparison with currentMillis |
38 |
unsigned int samplingInterval = 32; // default sampling interval is 33ms |
39 |
unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() |
40 |
unsigned int powerPinsEnabled = 0; // use as boolean to prevent enablePowerPins from being called more than once |
41 |
|
42 |
#define MINIMUM_SAMPLING_INTERVAL 10 |
43 |
|
44 |
#define REGISTER_NOT_SPECIFIED -1 |
45 |
|
46 |
struct i2c_device_info { |
47 |
byte addr; |
48 |
byte reg; |
49 |
byte bytes; |
50 |
}; |
51 |
|
52 |
i2c_device_info query[MAX_QUERIES]; |
53 |
|
54 |
byte i2cRxData[32]; |
55 |
boolean readingContinuously = false; |
56 |
byte queryIndex = 0; |
57 |
|
58 |
void readAndReportData(byte address, int theRegister, byte numBytes) |
59 |
{ |
60 |
if (theRegister != REGISTER_NOT_SPECIFIED) { |
61 |
Wire.beginTransmission(address); |
62 |
Wire.write((byte)theRegister); |
63 |
Wire.endTransmission(); |
64 |
delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck |
65 |
} |
66 |
else { |
67 |
theRegister = 0; // fill the register with a dummy value |
68 |
} |
69 |
|
70 |
Wire.requestFrom(address, numBytes); |
71 |
|
72 |
// check to be sure correct number of bytes were returned by slave |
73 |
if(numBytes == Wire.available()) { |
74 |
i2cRxData[0] = address; |
75 |
i2cRxData[1] = theRegister; |
76 |
for (int i = 0; i < numBytes; i++) { |
77 |
i2cRxData[2 + i] = Wire.read(); |
78 |
} |
79 |
// send slave address, register and received bytes |
80 |
Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData); |
81 |
} |
82 |
else { |
83 |
if(numBytes > Wire.available()) { |
84 |
Firmata.sendString("I2C Read Error: Too many bytes received"); |
85 |
} else { |
86 |
Firmata.sendString("I2C Read Error: Too few bytes received"); |
87 |
} |
88 |
} |
89 |
|
90 |
} |
91 |
|
92 |
void sysexCallback(byte command, byte argc, byte *argv) |
93 |
{ |
94 |
byte mode; |
95 |
byte slaveAddress; |
96 |
byte slaveRegister; |
97 |
byte data; |
98 |
int delayTime; |
99 |
|
100 |
if (command == I2C_REQUEST) { |
101 |
mode = argv[1] & I2C_READ_WRITE_MODE_MASK; |
102 |
slaveAddress = argv[0]; |
103 |
|
104 |
switch(mode) { |
105 |
case I2C_WRITE: |
106 |
Wire.beginTransmission(slaveAddress); |
107 |
for (byte i = 2; i < argc; i += 2) { |
108 |
data = argv[i] + (argv[i + 1] << 7); |
109 |
Wire.write(data); |
110 |
} |
111 |
Wire.endTransmission(); |
112 |
delayMicroseconds(70); // TODO is this needed? |
113 |
break; |
114 |
case I2C_READ: |
115 |
if (argc == 6) { |
116 |
// a slave register is specified |
117 |
slaveRegister = argv[2] + (argv[3] << 7); |
118 |
data = argv[4] + (argv[5] << 7); // bytes to read |
119 |
readAndReportData(slaveAddress, (int)slaveRegister, data); |
120 |
} |
121 |
else { |
122 |
// a slave register is NOT specified |
123 |
data = argv[2] + (argv[3] << 7); // bytes to read |
124 |
readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); |
125 |
} |
126 |
break; |
127 |
case I2C_READ_CONTINUOUSLY: |
128 |
if ((queryIndex + 1) >= MAX_QUERIES) { |
129 |
// too many queries, just ignore |
130 |
Firmata.sendString("too many queries"); |
131 |
break; |
132 |
} |
133 |
query[queryIndex].addr = slaveAddress; |
134 |
query[queryIndex].reg = argv[2] + (argv[3] << 7); |
135 |
query[queryIndex].bytes = argv[4] + (argv[5] << 7); |
136 |
readingContinuously = true; |
137 |
queryIndex++; |
138 |
break; |
139 |
case I2C_STOP_READING: |
140 |
readingContinuously = false; |
141 |
queryIndex = 0; |
142 |
break; |
143 |
default: |
144 |
break; |
145 |
} |
146 |
} |
147 |
else if (command == SAMPLING_INTERVAL) { |
148 |
samplingInterval = argv[0] + (argv[1] << 7); |
149 |
|
150 |
if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { |
151 |
samplingInterval = MINIMUM_SAMPLING_INTERVAL; |
152 |
} |
153 |
|
154 |
samplingInterval -= 1; |
155 |
Firmata.sendString("sampling interval"); |
156 |
} |
157 |
|
158 |
else if (command == I2C_CONFIG) { |
159 |
delayTime = (argv[4] + (argv[5] << 7)); // MSB |
160 |
delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7)); // add LSB |
161 |
|
162 |
if((argv[0] + (argv[1] << 7)) > 0) { |
163 |
enablePowerPins(PORTC3, PORTC2); |
164 |
} |
165 |
|
166 |
if(delayTime > 0) { |
167 |
i2cReadDelayTime = delayTime; |
168 |
} |
169 |
|
170 |
if(argc > 6) { |
171 |
// If you extend I2C_Config, handle your data here |
172 |
} |
173 |
|
174 |
} |
175 |
} |
176 |
|
177 |
void systemResetCallback() |
178 |
{ |
179 |
readingContinuously = false; |
180 |
queryIndex = 0; |
181 |
} |
182 |
|
183 |
/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */ |
184 |
// Enables Pins A2 and A3 to be used as GND and Power |
185 |
// so that I2C devices can be plugged directly |
186 |
// into Arduino header (pins A2 - A5) |
187 |
static void enablePowerPins(byte pwrpin, byte gndpin) |
188 |
{ |
189 |
if(powerPinsEnabled == 0) { |
190 |
DDRC |= _BV(pwrpin) | _BV(gndpin); |
191 |
PORTC &=~ _BV(gndpin); |
192 |
PORTC |= _BV(pwrpin); |
193 |
powerPinsEnabled = 1; |
194 |
Firmata.sendString("Power pins enabled"); |
195 |
delay(100); |
196 |
} |
197 |
} |
198 |
|
199 |
void setup() |
200 |
{ |
201 |
Firmata.setFirmwareVersion(2, 0); |
202 |
|
203 |
Firmata.attach(START_SYSEX, sysexCallback); |
204 |
Firmata.attach(SYSTEM_RESET, systemResetCallback); |
205 |
|
206 |
for (int i = 0; i < TOTAL_PINS; ++i) { |
207 |
pinMode(i, OUTPUT); |
208 |
} |
209 |
|
210 |
Firmata.begin(57600); |
211 |
Wire.begin(); |
212 |
} |
213 |
|
214 |
void loop() |
215 |
{ |
216 |
while (Firmata.available()) { |
217 |
Firmata.processInput(); |
218 |
} |
219 |
|
220 |
currentMillis = millis(); |
221 |
if (currentMillis - previousMillis > samplingInterval) { |
222 |
previousMillis += samplingInterval; |
223 |
|
224 |
for (byte i = 0; i < queryIndex; i++) { |
225 |
readAndReportData(query[i].addr, query[i].reg, query[i].bytes); |
226 |
} |
227 |
} |
228 |
} |