aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boards.txt24
-rwxr-xr-xcores/arduino/HardwareSerial.cpp124
-rwxr-xr-xcores/arduino/HardwareSerial.h4
-rwxr-xr-xcores/arduino/wiring.h4
-rwxr-xr-xcores/arduino/wiring_analog.c2
-rw-r--r--libraries/Ethernet/Client.cpp16
-rw-r--r--libraries/Ethernet/keywords.txt30
-rw-r--r--libraries/Firmata/Firmata.cpp466
-rw-r--r--libraries/Firmata/Firmata.h72
-rw-r--r--libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde2
-rw-r--r--libraries/Firmata/examples/EchoString/EchoString.pde4
-rw-r--r--libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde217
-rw-r--r--libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde2
-rw-r--r--libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde2
-rw-r--r--libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde2
-rw-r--r--libraries/Firmata/examples/StandardFirmata/Makefile26
-rw-r--r--libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde313
-rwxr-xr-xlibraries/LiquidCrystal/LiquidCrystal.cpp297
-rwxr-xr-xlibraries/LiquidCrystal/LiquidCrystal.h93
-rw-r--r--libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.pde70
-rw-r--r--libraries/LiquidCrystal/examples/Blink/Blink.pde58
-rw-r--r--libraries/LiquidCrystal/examples/Cursor/Cursor.pde58
-rw-r--r--libraries/LiquidCrystal/examples/Display/Display.pde58
-rw-r--r--libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.pde58
-rw-r--r--libraries/LiquidCrystal/examples/Scroll/Scroll.pde83
-rw-r--r--libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.pde48
-rw-r--r--libraries/LiquidCrystal/examples/TextDirection/TextDirection.pde84
-rw-r--r--libraries/LiquidCrystal/examples/setCursor/setCursor.pde68
-rwxr-xr-xlibraries/LiquidCrystal/keywords.txt14
-rwxr-xr-xlibraries/Servo/Servo.cpp401
-rwxr-xr-xlibraries/Servo/Servo.h98
-rwxr-xr-xlibraries/Servo/keywords.txt14
-rw-r--r--libraries/Wire/utility/twi.c63
33 files changed, 2136 insertions, 739 deletions
diff --git a/boards.txt b/boards.txt
index 24ddfc0..4ae4ac9 100644
--- a/boards.txt
+++ b/boards.txt
@@ -1,6 +1,6 @@
##############################################################
-atmega328.name=Arduino Duemilanove w/ ATmega328
+atmega328.name=Arduino Duemilanove or Nano w/ ATmega328
atmega328.upload.protocol=stk500
atmega328.upload.maximum_size=30720
@@ -20,7 +20,7 @@ atmega328.build.core=arduino
##############################################################
-diecimila.name=Arduino Diecimila or Duemilanove w/ ATmega168
+diecimila.name=Arduino Diecimila, Duemilanove, or Nano w/ ATmega168
diecimila.upload.protocol=stk500
diecimila.upload.maximum_size=14336
@@ -80,26 +80,6 @@ mini.build.core=arduino
##############################################################
-nano.name=Arduino Nano
-
-nano.upload.protocol=stk500
-nano.upload.maximum_size=14336
-nano.upload.speed=19200
-
-nano.bootloader.low_fuses=0xff
-nano.bootloader.high_fuses=0xdd
-nano.bootloader.extended_fuses=0x00
-nano.bootloader.path=atmega
-nano.bootloader.file=ATmegaBOOT_168_diecimila.hex
-nano.bootloader.unlock_bits=0x3F
-nano.bootloader.lock_bits=0x0F
-
-nano.build.mcu=atmega168
-nano.build.f_cpu=16000000L
-nano.build.core=arduino
-
-##############################################################
-
bt.name=Arduino BT
bt.upload.protocol=stk500
diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp
index f8a959a..1af6a66 100755
--- a/cores/arduino/HardwareSerial.cpp
+++ b/cores/arduino/HardwareSerial.cpp
@@ -49,41 +49,41 @@ ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
- int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE;
-
- // if we should be storing the received character into the location
- // just before the tail (meaning that the head would advance to the
- // current location of the tail), we're about to overflow the buffer
- // and so we don't write the character or advance the head.
- if (i != rx_buffer->tail) {
- rx_buffer->buffer[rx_buffer->head] = c;
- rx_buffer->head = i;
- }
+ int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE;
+
+ // if we should be storing the received character into the location
+ // just before the tail (meaning that the head would advance to the
+ // current location of the tail), we're about to overflow the buffer
+ // and so we don't write the character or advance the head.
+ if (i != rx_buffer->tail) {
+ rx_buffer->buffer[rx_buffer->head] = c;
+ rx_buffer->head = i;
+ }
}
#if defined(__AVR_ATmega1280__)
SIGNAL(SIG_USART0_RECV)
{
- unsigned char c = UDR0;
+ unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
SIGNAL(SIG_USART1_RECV)
{
- unsigned char c = UDR1;
+ unsigned char c = UDR1;
store_char(c, &rx_buffer1);
}
SIGNAL(SIG_USART2_RECV)
{
- unsigned char c = UDR2;
+ unsigned char c = UDR2;
store_char(c, &rx_buffer2);
}
SIGNAL(SIG_USART3_RECV)
{
- unsigned char c = UDR3;
+ unsigned char c = UDR3;
store_char(c, &rx_buffer3);
}
@@ -96,9 +96,9 @@ SIGNAL(USART_RX_vect)
#endif
{
#if defined(__AVR_ATmega8__)
- unsigned char c = UDR;
+ unsigned char c = UDR;
#else
- unsigned char c = UDR0;
+ unsigned char c = UDR0;
#endif
store_char(c, &rx_buffer);
}
@@ -111,7 +111,7 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
- uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre)
+ uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
{
_rx_buffer = rx_buffer;
_ubrrh = ubrrh;
@@ -123,14 +123,43 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
_txen = txen;
_rxcie = rxcie;
_udre = udre;
+ _u2x = u2x;
}
// Public Methods //////////////////////////////////////////////////////////////
-void HardwareSerial::begin(long speed)
+void HardwareSerial::begin(long baud)
{
- *_ubrrh = ((F_CPU / 16 + speed / 2) / speed - 1) >> 8;
- *_ubrrl = ((F_CPU / 16 + speed / 2) / speed - 1);
+ uint16_t baud_setting;
+ bool use_u2x;
+
+ // U2X mode is needed for baud rates higher than (CPU Hz / 16)
+ if (baud > F_CPU / 16) {
+ use_u2x = true;
+ } else {
+ // figure out if U2X mode would allow for a better connection
+
+ // calculate the percent difference between the baud-rate specified and
+ // the real baud rate for both U2X and non-U2X mode (0-255 error percent)
+ uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
+ uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
+
+ // prefer non-U2X mode because it handles clock skew better
+ use_u2x = (nonu2x_baud_error > u2x_baud_error);
+ }
+
+ if (use_u2x) {
+ *_ucsra = 1 << _u2x;
+ baud_setting = (F_CPU / 4 / baud - 1) / 2;
+ } else {
+ *_ucsra = 0;
+ baud_setting = (F_CPU / 8 / baud - 1) / 2;
+ }
+
+ // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
+ *_ubrrh = baud_setting >> 8;
+ *_ubrrl = baud_setting;
+
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
@@ -138,54 +167,53 @@ void HardwareSerial::begin(long speed)
uint8_t HardwareSerial::available(void)
{
- return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
+ return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
}
int HardwareSerial::read(void)
{
- // if the head isn't ahead of the tail, we don't have any characters
- if (_rx_buffer->head == _rx_buffer->tail) {
- return -1;
- } else {
- unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
- _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
- return c;
- }
+ // if the head isn't ahead of the tail, we don't have any characters
+ if (_rx_buffer->head == _rx_buffer->tail) {
+ return -1;
+ } else {
+ unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
+ _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
+ return c;
+ }
}
void HardwareSerial::flush()
{
- // don't reverse this or there may be problems if the RX interrupt
- // occurs after reading the value of rx_buffer_head but before writing
- // the value to rx_buffer_tail; the previous value of rx_buffer_head
- // may be written to rx_buffer_tail, making it appear as if the buffer
- // don't reverse this or there may be problems if the RX interrupt
- // occurs after reading the value of rx_buffer_head but before writing
- // the value to rx_buffer_tail; the previous value of rx_buffer_head
- // may be written to rx_buffer_tail, making it appear as if the buffer
- // were full, not empty.
- _rx_buffer->head = _rx_buffer->tail;
+ // don't reverse this or there may be problems if the RX interrupt
+ // occurs after reading the value of rx_buffer_head but before writing
+ // the value to rx_buffer_tail; the previous value of rx_buffer_head
+ // may be written to rx_buffer_tail, making it appear as if the buffer
+ // don't reverse this or there may be problems if the RX interrupt
+ // occurs after reading the value of rx_buffer_head but before writing
+ // the value to rx_buffer_tail; the previous value of rx_buffer_head
+ // may be written to rx_buffer_tail, making it appear as if the buffer
+ // were full, not empty.
+ _rx_buffer->head = _rx_buffer->tail;
}
void HardwareSerial::write(uint8_t c)
{
- while (!((*_ucsra) & (1 << _udre)))
- ;
+ while (!((*_ucsra) & (1 << _udre)))
+ ;
- *_udr = c;
+ *_udr = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
#if defined(__AVR_ATmega8__)
-HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE);
+HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X);
#else
-HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0);
+HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#endif
#if defined(__AVR_ATmega1280__)
-HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1);
-HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2);
-HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3);
+HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1);
+HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2);
+HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3);
#endif
-
diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h
index 8610f5a..f975ccd 100755
--- a/cores/arduino/HardwareSerial.h
+++ b/cores/arduino/HardwareSerial.h
@@ -39,12 +39,13 @@ class HardwareSerial : public Print
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udre;
+ uint8_t _u2x;
public:
HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
- uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre);
+ uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
void begin(long);
uint8_t available(void);
int read(void);
@@ -62,4 +63,3 @@ extern HardwareSerial Serial3;
#endif
#endif
-
diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h
index 619e695..f0ba04c 100755
--- a/cores/arduino/wiring.h
+++ b/cores/arduino/wiring.h
@@ -86,8 +86,8 @@ extern "C"{
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
-#define lowByte(w) ((w) & 0xff)
-#define highByte(w) ((w) >> 8)
+#define lowByte(w) ((uint8_t) ((w) & 0xff))
+#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c
index 529ad52..782a0bd 100755
--- a/cores/arduino/wiring_analog.c
+++ b/cores/arduino/wiring_analog.c
@@ -42,7 +42,7 @@ int analogRead(uint8_t pin)
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
- ADMUX = (analog_reference << 6) | (pin & 0x07);
+ ADMUX = (analog_reference << 6) | (pin & 0x0f);
#if defined(__AVR_ATmega1280__)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/Client.cpp
index ebbb08d..0511c7b 100644
--- a/libraries/Ethernet/Client.cpp
+++ b/libraries/Ethernet/Client.cpp
@@ -113,13 +113,21 @@ void Client::stop() {
}
uint8_t Client::connected() {
- uint8_t s = status();
- return !(s == SOCK_LISTEN || s == SOCK_CLOSED || s == SOCK_FIN_WAIT ||
- (s == SOCK_CLOSE_WAIT && !available()));
+ if (_sock == 255) {
+ return 0;
+ } else {
+ uint8_t s = status();
+ return !(s == SOCK_LISTEN || s == SOCK_CLOSED || s == SOCK_FIN_WAIT ||
+ (s == SOCK_CLOSE_WAIT && !available()));
+ }
}
uint8_t Client::status() {
- return getSn_SR(_sock);
+ if (_sock == 255) {
+ return SOCK_CLOSED;
+ } else {
+ return getSn_SR(_sock);
+ }
}
// the next three functions are a hack so we can compare the client returned
diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt
new file mode 100644
index 0000000..ebc5793
--- /dev/null
+++ b/libraries/Ethernet/keywords.txt
@@ -0,0 +1,30 @@
+#######################################
+# Syntax Coloring Map For Ethernet
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+Ethernet KEYWORD1
+Client KEYWORD1
+Server KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+status KEYWORD2
+connect KEYWORD2
+write KEYWORD2
+available KEYWORD2
+read KEYWORD2
+flush KEYWORD2
+stop KEYWORD2
+connected KEYWORD2
+begin KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
diff --git a/libraries/Firmata/Firmata.cpp b/libraries/Firmata/Firmata.cpp
index 4e59d27..9a18615 100644
--- a/libraries/Firmata/Firmata.cpp
+++ b/libraries/Firmata/Firmata.cpp
@@ -29,18 +29,18 @@ extern "C" {
void sendValueAsTwo7bitBytes(int value)
{
- Serial.print(value & B01111111, BYTE); // LSB
- Serial.print(value >> 7 & B01111111, BYTE); // MSB
+ Serial.print(value & B01111111, BYTE); // LSB
+ Serial.print(value >> 7 & B01111111, BYTE); // MSB
}
void startSysex(void)
{
- Serial.print(START_SYSEX, BYTE);
+ Serial.print(START_SYSEX, BYTE);
}
void endSysex(void)
{
- Serial.print(END_SYSEX, BYTE);
+ Serial.print(END_SYSEX, BYTE);
}
//******************************************************************************
@@ -49,8 +49,8 @@ void endSysex(void)
FirmataClass::FirmataClass(void)
{
- firmwareVersionCount = 0;
- systemReset();
+ firmwareVersionCount = 0;
+ systemReset();
}
//******************************************************************************
@@ -60,83 +60,83 @@ FirmataClass::FirmataClass(void)
/* begin method for overriding default serial bitrate */
void FirmataClass::begin(void)
{
- Serial.begin(115200);
- blinkVersion();
- delay(300);
- printVersion();
+ Serial.begin(57600);
+ blinkVersion();
+ delay(300);
+ printVersion();
}
/* begin method for overriding default serial bitrate */
void FirmataClass::begin(long speed)
{
- blinkVersion();
+ blinkVersion();
#if defined(__AVR_ATmega128__) // Wiring
- Serial.begin((uint32_t)speed);
+ Serial.begin((uint32_t)speed);
#else
- Serial.begin(speed);
+ Serial.begin(speed);
#endif
- delay(300);
- printVersion();
- printFirmwareVersion();
+ delay(300);
+ printVersion();
+ printFirmwareVersion();
}
// output the protocol version message to the serial port
void FirmataClass::printVersion(void) {
- Serial.print(REPORT_VERSION, BYTE);
- Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
- Serial.print(FIRMATA_MINOR_VERSION, BYTE);
+ Serial.print(REPORT_VERSION, BYTE);
+ Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
+ Serial.print(FIRMATA_MINOR_VERSION, BYTE);
}
void FirmataClass::blinkVersion(void)
{
- // flash the pin with the protocol version
- pinMode(VERSION_BLINK_PIN,OUTPUT);
- pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400);
- delay(300);
- pin13strobe(2,1,4); // separator, a quick burst
- delay(300);
- pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
+ // flash the pin with the protocol version
+ pinMode(VERSION_BLINK_PIN,OUTPUT);
+ pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400);
+ delay(300);
+ pin13strobe(2,1,4); // separator, a quick burst
+ delay(300);
+ pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
}
void FirmataClass::printFirmwareVersion(void)
{
- byte i;
-
- if(firmwareVersionCount) { // make sure that the name has been set before reporting
- startSysex();
- Serial.print(REPORT_FIRMWARE, BYTE);
- Serial.print(firmwareVersionVector[0]); // major version number
- Serial.print(firmwareVersionVector[1]); // minor version number
- for(i=2; i<firmwareVersionCount; ++i) {
- sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
- }
- endSysex();
+ byte i;
+
+ if(firmwareVersionCount) { // make sure that the name has been set before reporting
+ startSysex();
+ Serial.print(REPORT_FIRMWARE, BYTE);
+ Serial.print(firmwareVersionVector[0]); // major version number
+ Serial.print(firmwareVersionVector[1]); // minor version number
+ for(i=2; i<firmwareVersionCount; ++i) {
+ sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
}
+ endSysex();
+ }
}
void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{
- const char *filename;
- char *extension;
-
-// parse out ".cpp" and "applet/" that comes from using __FILE__
- extension = strstr(name, ".cpp");
- filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
- // add two bytes for version numbers
- if(extension && filename) {
- firmwareVersionCount = extension - filename + 2;
- } else {
- firmwareVersionCount = strlen(name) + 2;
- filename = name;
- }
- firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
- firmwareVersionVector[firmwareVersionCount] = 0;
- firmwareVersionVector[0] = major;
- firmwareVersionVector[1] = minor;
- strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
-// alas, no snprintf on Arduino
-// snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
-// (char)major, (char)minor, firmwareVersionVector);
+ const char *filename;
+ char *extension;
+
+ // parse out ".cpp" and "applet/" that comes from using __FILE__
+ extension = strstr(name, ".cpp");
+ filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
+ // add two bytes for version numbers
+ if(extension && filename) {
+ firmwareVersionCount = extension - filename + 2;
+ } else {
+ firmwareVersionCount = strlen(name) + 2;
+ filename = name;
+ }
+ firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
+ firmwareVersionVector[firmwareVersionCount] = 0;
+ firmwareVersionVector[0] = major;
+ firmwareVersionVector[1] = minor;
+ strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
+ // alas, no snprintf on Arduino
+ // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
+ // (char)major, (char)minor, firmwareVersionVector);
}
//------------------------------------------------------------------------------
@@ -144,123 +144,123 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte
int FirmataClass::available(void)
{
- return Serial.available();
+ return Serial.available();
}
void FirmataClass::processSysexMessage(void)
{
- switch(storedInputData[0]) { //first byte in buffer is command
- case REPORT_FIRMWARE:
- printFirmwareVersion();
- break;
- case FIRMATA_STRING:
- if(currentStringCallback) {
- byte bufferLength = (sysexBytesRead - 1) / 2;
- char *buffer = (char*)malloc(bufferLength * sizeof(char));
- byte i = 1;
- byte j = 0;
- while(j < bufferLength) {
- buffer[j] = (char)storedInputData[i];
- i++;
- buffer[j] += (char)(storedInputData[i] << 7);
- i++;
- j++;
- }
- (*currentStringCallback)(buffer);
- }
- break;
- default:
- if(currentSysexCallback)
- (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
+ switch(storedInputData[0]) { //first byte in buffer is command
+ case REPORT_FIRMWARE:
+ printFirmwareVersion();
+ break;
+ case STRING_DATA:
+ if(currentStringCallback) {
+ byte bufferLength = (sysexBytesRead - 1) / 2;
+ char *buffer = (char*)malloc(bufferLength * sizeof(char));
+ byte i = 1;
+ byte j = 0;
+ while(j < bufferLength) {
+ buffer[j] = (char)storedInputData[i];
+ i++;
+ buffer[j] += (char)(storedInputData[i] << 7);
+ i++;
+ j++;
+ }
+ (*currentStringCallback)(buffer);
}
+ break;
+ default:
+ if(currentSysexCallback)
+ (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
+ }
}
void FirmataClass::processInput(void)
{
- int inputData = Serial.read(); // this is 'int' to handle -1 when no data
- int command;
+ int inputData = Serial.read(); // this is 'int' to handle -1 when no data
+ int command;
- // TODO make sure it handles -1 properly
-
- if (parsingSysex) {
- if(inputData == END_SYSEX) {
- //stop sysex byte
- parsingSysex = false;
- //fire off handler function
- processSysexMessage();
- } else {
- //normal data byte - add to buffer
- storedInputData[sysexBytesRead] = inputData;
- sysexBytesRead++;
- }
- } else if( (waitForData > 0) && (inputData < 128) ) {
- waitForData--;
- storedInputData[waitForData] = inputData;
- if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
- switch(executeMultiByteCommand) {
- case ANALOG_MESSAGE:
- if(currentAnalogCallback) {
- (*currentAnalogCallback)(multiByteChannel,
- (storedInputData[0] << 7)
- + storedInputData[1]);
- }
- break;
- case DIGITAL_MESSAGE:
- if(currentDigitalCallback) {
- (*currentDigitalCallback)(multiByteChannel,
- (storedInputData[0] << 7)
- + storedInputData[1]);
- }
- break;
- case SET_PIN_MODE:
- if(currentPinModeCallback)
- (*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
- break;
- case REPORT_ANALOG:
- if(currentReportAnalogCallback)
- (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
- break;
- case REPORT_DIGITAL:
- if(currentReportDigitalCallback)
- (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
- break;
- }
- executeMultiByteCommand = 0;
- }
+ // TODO make sure it handles -1 properly
+
+ if (parsingSysex) {
+ if(inputData == END_SYSEX) {
+ //stop sysex byte
+ parsingSysex = false;
+ //fire off handler function
+ processSysexMessage();
} else {
- // remove channel info from command byte if less than 0xF0
- if(inputData < 0xF0) {
- command = inputData & 0xF0;
- multiByteChannel = inputData & 0x0F;
- } else {
- command = inputData;
- // commands in the 0xF* range don't use channel data
+ //normal data byte - add to buffer
+ storedInputData[sysexBytesRead] = inputData;
+ sysexBytesRead++;
+ }
+ } else if( (waitForData > 0) && (inputData < 128) ) {
+ waitForData--;
+ storedInputData[waitForData] = inputData;
+ if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
+ switch(executeMultiByteCommand) {
+ case ANALOG_MESSAGE:
+ if(currentAnalogCallback) {
+ (*currentAnalogCallback)(multiByteChannel,
+ (storedInputData[0] << 7)
+ + storedInputData[1]);
}
- switch (command) {
- case ANALOG_MESSAGE:
- case DIGITAL_MESSAGE:
- case SET_PIN_MODE:
- waitForData = 2; // two data bytes needed
- executeMultiByteCommand = command;
- break;
- case REPORT_ANALOG:
- case REPORT_DIGITAL:
- waitForData = 1; // two data bytes needed
- executeMultiByteCommand = command;
- break;
- case START_SYSEX:
- parsingSysex = true;
- sysexBytesRead = 0;
- break;
- case SYSTEM_RESET:
- systemReset();
- break;
- case REPORT_VERSION:
- Firmata.printVersion();
- break;
+ break;
+ case DIGITAL_MESSAGE:
+ if(currentDigitalCallback) {
+ (*currentDigitalCallback)(multiByteChannel,
+ (storedInputData[0] << 7)
+ + storedInputData[1]);
}
+ break;
+ case SET_PIN_MODE:
+ if(currentPinModeCallback)
+ (*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
+ break;
+ case REPORT_ANALOG:
+ if(currentReportAnalogCallback)
+ (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
+ break;
+ case REPORT_DIGITAL:
+ if(currentReportDigitalCallback)
+ (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
+ break;
+ }
+ executeMultiByteCommand = 0;
+ }
+ } else {
+ // remove channel info from command byte if less than 0xF0
+ if(inputData < 0xF0) {
+ command = inputData & 0xF0;
+ multiByteChannel = inputData & 0x0F;
+ } else {
+ command = inputData;
+ // commands in the 0xF* range don't use channel data
}
+ switch (command) {
+ case ANALOG_MESSAGE:
+ case DIGITAL_MESSAGE:
+ case SET_PIN_MODE:
+ waitForData = 2; // two data bytes needed
+ executeMultiByteCommand = command;
+ break;
+ case REPORT_ANALOG:
+ case REPORT_DIGITAL:
+ waitForData = 1; // two data bytes needed
+ executeMultiByteCommand = command;
+ break;
+ case START_SYSEX:
+ parsingSysex = true;
+ sysexBytesRead = 0;
+ break;
+ case SYSTEM_RESET:
+ systemReset();
+ break;
+ case REPORT_VERSION:
+ Firmata.printVersion();
+ break;
+ }
+ }
}
//------------------------------------------------------------------------------
@@ -269,31 +269,31 @@ void FirmataClass::processInput(void)
// send an analog message
void FirmataClass::sendAnalog(byte pin, int value)
{
- // pin can only be 0-15, so chop higher bits
- Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE);
- sendValueAsTwo7bitBytes(value);
+ // pin can only be 0-15, so chop higher bits
+ Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE);
+ sendValueAsTwo7bitBytes(value);
}
// send a single digital pin in a digital message
void FirmataClass::sendDigital(byte pin, int value)
{
- /* TODO add single pin digital messages to the protocol, this needs to
- * track the last digital data sent so that it can be sure to change just
- * one bit in the packet. This is complicated by the fact that the
- * numbering of the pins will probably differ on Arduino, Wiring, and
- * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is
- * probably easier to send 8 bit ports for any board with more than 14
- * digital pins.
- */
-
- // TODO: the digital message should not be sent on the serial port every
- // time sendDigital() is called. Instead, it should add it to an int
- // which will be sent on a schedule. If a pin changes more than once
- // before the digital message is sent on the serial port, it should send a
- // digital message for each change.
-
-// if(value == 0)
-// sendDigitalPortPair();
+ /* TODO add single pin digital messages to the protocol, this needs to
+ * track the last digital data sent so that it can be sure to change just
+ * one bit in the packet. This is complicated by the fact that the
+ * numbering of the pins will probably differ on Arduino, Wiring, and
+ * other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is
+ * probably easier to send 8 bit ports for any board with more than 14
+ * digital pins.
+ */
+
+ // TODO: the digital message should not be sent on the serial port every
+ // time sendDigital() is called. Instead, it should add it to an int
+ // which will be sent on a schedule. If a pin changes more than once
+ // before the digital message is sent on the serial port, it should send a
+ // digital message for each change.
+
+ // if(value == 0)
+ // sendDigitalPortPair();
}
@@ -301,33 +301,33 @@ void FirmataClass::sendDigital(byte pin, int value)
// send an 8-bit port in a single digital message (protocol v2)
void FirmataClass::sendDigitalPort(byte portNumber, int portData)
{
- Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE);
- Serial.print(portData % 128, BYTE); // Tx bits 0-6
- Serial.print(portData >> 7, BYTE); // Tx bits 7-13
+ Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE);
+ Serial.print(portData % 128, BYTE); // Tx bits 0-6
+ Serial.print(portData >> 7, BYTE); // Tx bits 7-13
}
void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{
- byte i;
- startSysex();
- Serial.print(command, BYTE);
- for(i=0; i<bytec; i++) {
- sendValueAsTwo7bitBytes(bytev[i]);
- }
- endSysex();
+ byte i;
+ startSysex();
+ Serial.print(command, BYTE);
+ for(i=0; i<bytec; i++) {
+ sendValueAsTwo7bitBytes(bytev[i]);
+ }
+ endSysex();
}
void FirmataClass::sendString(byte command, const char* string)
{
- sendSysex(command, strlen(string), (byte *)string);
+ sendSysex(command, strlen(string), (byte *)string);
}
// send a string as the protocol string type
void FirmataClass::sendString(const char* string)
{
- sendString(FIRMATA_STRING, string);
+ sendString(STRING_DATA, string);
}
@@ -336,43 +336,43 @@ void FirmataClass::sendString(const char* string)
// generic callbacks
void FirmataClass::attach(byte command, callbackFunction newFunction)
{
- switch(command) {
- case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
- case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
- case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
- case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
- case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
- }
+ switch(command) {
+ case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
+ case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
+ case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
+ case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
+ case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
+ }
}
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{
- switch(command) {
- case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
- }
+ switch(command) {
+ case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
+ }
}
void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{
- switch(command) {
- case FIRMATA_STRING: currentStringCallback = newFunction; break;
- }
+ switch(command) {
+ case STRING_DATA: currentStringCallback = newFunction; break;
+ }
}
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{
- currentSysexCallback = newFunction;
+ currentSysexCallback = newFunction;
}
void FirmataClass::detach(byte command)
{
- switch(command) {
- case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
- case FIRMATA_STRING: currentStringCallback = NULL; break;
- case START_SYSEX: currentSysexCallback = NULL; break;
- default:
- attach(command, (callbackFunction)NULL);
- }
+ switch(command) {
+ case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
+ case STRING_DATA: currentStringCallback = NULL; break;
+ case START_SYSEX: currentSysexCallback = NULL; break;
+ default:
+ attach(command, (callbackFunction)NULL);
+ }
}
// sysex callbacks
@@ -402,24 +402,24 @@ void FirmataClass::detach(byte command)
// resets the system state upon a SYSTEM_RESET message from the host software
void FirmataClass::systemReset(void)
{
- byte i;
+ byte i;
- waitForData = 0; // this flag says the next serial input will be data
- executeMultiByteCommand = 0; // execute this after getting multi-byte data
- multiByteChannel = 0; // channel data for multiByteCommands
+ waitForData = 0; // this flag says the next serial input will be data
+ executeMultiByteCommand = 0; // execute this after getting multi-byte data
+ multiByteChannel = 0; // channel data for multiByteCommands
- for(i=0; i<MAX_DATA_BYTES; i++) {
- storedInputData[i] = 0;
- }
+ for(i=0; i<MAX_DATA_BYTES; i++) {
+ storedInputData[i] = 0;
+ }
- parsingSysex = false;
- sysexBytesRead = 0;
+ parsingSysex = false;
+ sysexBytesRead = 0;
- if(currentSystemResetCallback)
- (*currentSystemResetCallback)();
+ if(currentSystemResetCallback)
+ (*currentSystemResetCallback)();
- //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
+ //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
}
@@ -428,14 +428,14 @@ void FirmataClass::systemReset(void)
// used for flashing the pin for the version number
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{
- byte i;
- pinMode(VERSION_BLINK_PIN, OUTPUT);
- for(i=0; i<count; i++) {
- delay(offInterval);
- digitalWrite(VERSION_BLINK_PIN, HIGH);
- delay(onInterval);
- digitalWrite(VERSION_BLINK_PIN, LOW);
- }
+ byte i;
+ pinMode(VERSION_BLINK_PIN, OUTPUT);
+ for(i=0; i<count; i++) {
+ delay(offInterval);
+ digitalWrite(VERSION_BLINK_PIN, HIGH);
+ delay(onInterval);
+ digitalWrite(VERSION_BLINK_PIN, LOW);
+ }
}
diff --git a/libraries/Firmata/Firmata.h b/libraries/Firmata/Firmata.h
index a926462..2732fd6 100644
--- a/libraries/Firmata/Firmata.h
+++ b/libraries/Firmata/Firmata.h
@@ -22,8 +22,7 @@
* software can test whether it will be compatible with the currently
* installed firmware. */
#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes
-#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes
-#define VERSION_BLINK_PIN 13 // digital pin to blink version on
+#define FIRMATA_MINOR_VERSION 1 // for backwards compatible changes
#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages
@@ -42,12 +41,22 @@
#define END_SYSEX 0xF7 // end a MIDI Sysex message
// extended command set using sysex (0-127/0x00-0x7F)
-/* 0x00-0x0F reserved for custom commands */
+/* 0x00-0x0F reserved for user-defined commands */
#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq
-#define FIRMATA_STRING 0x71 // a string message with 14-bits per char
+#define STRING_DATA 0x71 // a string message with 14-bits per char
+#define SHIFT_DATA 0x75 // a bitstream to/from a shift register
+#define I2C_REQUEST 0x76 // send an I2C read/write request
+#define I2C_REPLY 0x77 // a reply to an I2C read request
+#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins
#define REPORT_FIRMWARE 0x79 // report name and version of the firmware
+#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop
#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages
+// these are DEPRECATED to make the naming more consistent
+#define FIRMATA_STRING 0x71 // same as STRING_DATA
+#define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST
+#define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY
+#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL
// pin modes
//#define INPUT 0x00 // defined in wiring.h
@@ -55,7 +64,8 @@
#define ANALOG 0x02 // analog pin in analogInput mode
#define PWM 0x03 // digital pin in PWM output mode
#define SERVO 0x04 // digital pin in Servo output mode
-
+#define SHIFT 0x05 // shiftIn/shiftOut mode
+#define I2C 0x06 // pin included in I2C setup
extern "C" {
// callback function types
@@ -146,21 +156,71 @@ extern FirmataClass Firmata;
#define TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog
#define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#elif defined(__AVR_ATmega8__) // old Arduinos
#define TOTAL_ANALOG_PINS 6
#define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog
#define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
+#elif defined(__AVR_ATmega1280__)// Arduino Mega
+#define TOTAL_ANALOG_PINS 16
+#define TOTAL_DIGITAL_PINS 70 // 54 digital + 16 analog
+#define TOTAL_PORTS 9 // total number of ports for the board
+#define ANALOG_PORT 8 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 54 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#elif defined(__AVR_ATmega128__)// Wiring
#define TOTAL_ANALOG_PINS 8
#define TOTAL_DIGITAL_PINS 51
+#define TOTAL_PORTS 7 // total number of ports for the board
+#define ANALOG_PORT 5 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 40 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
+#elif defined(__AVR_AT90USB162__) // Teensy
+#define TOTAL_ANALOG_PINS 0
+#define TOTAL_DIGITAL_PINS 21 // 21 digital + no analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 21 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 6 // digital pin to blink version on
+#elif defined(__AVR_ATmega32U4__) // Teensy
+#define TOTAL_ANALOG_PINS 12
+#define TOTAL_DIGITAL_PINS 25 // 11 digital + 12 analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 11 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 11 // digital pin to blink version on
+#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) // Teensy++
+#define TOTAL_ANALOG_PINS 8
+#define TOTAL_DIGITAL_PINS 46 // 38 digital + 8 analog
#define TOTAL_PORTS 6 // total number of ports for the board
-#define ANALOG_PORT 2 // port# of analog used as digital
+#define ANALOG_PORT 5 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 38 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 6 // digital pin to blink version on
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino
+#define TOTAL_ANALOG_PINS 8
+#define TOTAL_DIGITAL_PINS 32 // 24 digital + 8 analog
+#define TOTAL_PORTS 4 // total number of ports for the board
+#define ANALOG_PORT 3 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 24 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 0 // digital pin to blink version on
+#elif defined(__AVR_ATmega645__) // Illuminato
+#define TOTAL_ANALOG_PINS 6
+#define TOTAL_DIGITAL_PINS 42 // 36 digital + 6 analog
+#define TOTAL_PORTS 6 // total number of ports for the board
+#define ANALOG_PORT 4 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 36 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#else // anything else
#define TOTAL_ANALOG_PINS 6
#define TOTAL_DIGITAL_PINS 14
#define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital
+#define FIRST_ANALOG_PIN 14 // pin# corresponding to analog 0
+#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#endif
diff --git a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde
index fcd8e5e..ab83726 100644
--- a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde
+++ b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.pde
@@ -61,7 +61,7 @@ void setup()
servo9.attach(9);
servo10.attach(10);
- Firmata.begin();
+ Firmata.begin(57600);
}
/*==============================================================================
diff --git a/libraries/Firmata/examples/EchoString/EchoString.pde b/libraries/Firmata/examples/EchoString/EchoString.pde
index ed13ad8..6559ae1 100644
--- a/libraries/Firmata/examples/EchoString/EchoString.pde
+++ b/libraries/Firmata/examples/EchoString/EchoString.pde
@@ -25,9 +25,9 @@ void sysexCallback(byte command, byte argc, byte*argv)
void setup()
{
Firmata.setFirmwareVersion(0, 1);
- Firmata.attach(FIRMATA_STRING, stringCallback);
+ Firmata.attach(STRING_DATA, stringCallback);
Firmata.attach(START_SYSEX, sysexCallback);
- Firmata.begin();
+ Firmata.begin(57600);
}
void loop()
diff --git a/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde
new file mode 100644
index 0000000..796a8d5
--- /dev/null
+++ b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.pde
@@ -0,0 +1,217 @@
+/*
+ Copyright (C) 2009 Jeff Hoefs. All rights reserved.
+ Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See file LICENSE.txt for further informations on licensing terms.
+ */
+
+#include <Wire.h>
+#include <Firmata.h>
+
+
+#define I2C_WRITE B00000000
+#define I2C_READ B00001000
+#define I2C_READ_CONTINUOUSLY B00010000
+#define I2C_STOP_READING B00011000
+#define I2C_READ_WRITE_MODE_MASK B00011000
+
+#define MAX_QUERIES 8
+
+unsigned long currentMillis; // store the current value from millis()
+unsigned long nextExecuteMillis; // for comparison with currentMillis
+unsigned int samplingInterval = 32; // default sampling interval is 33ms
+unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom()
+unsigned int powerPinsEnabled = 0; // use as boolean to prevent enablePowerPins from being called more than once
+
+#define MINIMUM_SAMPLING_INTERVAL 10
+
+#define REGISTER_NOT_SPECIFIED -1
+
+struct i2c_device_info {
+ byte addr;
+ byte reg;
+ byte bytes;
+};
+
+i2c_device_info query[MAX_QUERIES];
+
+byte i2cRxData[32];
+boolean readingContinuously = false;
+byte queryIndex = 0;
+
+void readAndReportData(byte address, int theRegister, byte numBytes)
+{
+ if (theRegister != REGISTER_NOT_SPECIFIED) {
+ Wire.beginTransmission(address);
+ Wire.send((byte)theRegister);
+ Wire.endTransmission();
+ delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck
+ }
+ else {
+ theRegister = 0; // fill the register with a dummy value
+ }
+
+ Wire.requestFrom(address, numBytes);
+
+ // check to be sure correct number of bytes were returned by slave
+ if(numBytes == Wire.available()) {
+ i2cRxData[0] = address;
+ i2cRxData[1] = theRegister;
+ for (int i = 0; i < numBytes; i++) {
+ i2cRxData[2 + i] = Wire.receive();
+ }
+ // send slave address, register and received bytes
+ Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData);
+ }
+ else {
+ if(numBytes > Wire.available()) {
+ Firmata.sendString("I2C Read Error: Too many bytes received");
+ } else {
+ Firmata.sendString("I2C Read Error: Too few bytes received");
+ }
+ }
+
+}
+
+void sysexCallback(byte command, byte argc, byte *argv)
+{
+ byte mode;
+ byte slaveAddress;
+ byte slaveRegister;
+ byte data;
+ int delayTime;
+
+ if (command == I2C_REQUEST) {
+ mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
+ slaveAddress = argv[0];
+
+ switch(mode) {
+ case I2C_WRITE:
+ Wire.beginTransmission(slaveAddress);
+ for (byte i = 2; i < argc; i += 2) {
+ data = argv[i] + (argv[i + 1] << 7);
+ Wire.send(data);
+ }
+ Wire.endTransmission();
+ delayMicroseconds(70); // TODO is this needed?
+ break;
+ case I2C_READ:
+ if (argc == 6) {
+ // a slave register is specified
+ slaveRegister = argv[2] + (argv[3] << 7);
+ data = argv[4] + (argv[5] << 7); // bytes to read
+ readAndReportData(slaveAddress, (int)slaveRegister, data);
+ }
+ else {
+ // a slave register is NOT specified
+ data = argv[2] + (argv[3] << 7); // bytes to read
+ readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data);
+ }
+ break;
+ case I2C_READ_CONTINUOUSLY:
+ if ((queryIndex + 1) >= MAX_QUERIES) {
+ // too many queries, just ignore
+ Firmata.sendString("too many queries");
+ break;
+ }
+ query[queryIndex].addr = slaveAddress;
+ query[queryIndex].reg = argv[2] + (argv[3] << 7);
+ query[queryIndex].bytes = argv[4] + (argv[5] << 7);
+ readingContinuously = true;
+ queryIndex++;
+ break;
+ case I2C_STOP_READING:
+ readingContinuously = false;
+ queryIndex = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (command == SAMPLING_INTERVAL) {
+ samplingInterval = argv[0] + (argv[1] << 7);
+
+ if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
+ samplingInterval = MINIMUM_SAMPLING_INTERVAL;
+ }
+
+ samplingInterval -= 1;
+ Firmata.sendString("sampling interval");
+ }
+
+ else if (command == I2C_CONFIG) {
+ delayTime = (argv[4] + (argv[5] << 7)); // MSB
+ delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7)); // add LSB
+
+ if((argv[0] + (argv[1] << 7)) > 0) {
+ enablePowerPins(PORTC3, PORTC2);
+ }
+
+ if(delayTime > 0) {
+ i2cReadDelayTime = delayTime;
+ }
+
+ if(argc > 6) {
+ // If you extend I2C_Config, handle your data here
+ }
+
+ }
+}
+
+void systemResetCallback()
+{
+ readingContinuously = false;
+ queryIndex = 0;
+}
+
+/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */
+// Enables Pins A2 and A3 to be used as GND and Power
+// so that I2C devices can be plugged directly
+// into Arduino header (pins A2 - A5)
+static void enablePowerPins(byte pwrpin, byte gndpin)
+{
+ if(powerPinsEnabled == 0) {
+ DDRC |= _BV(pwrpin) | _BV(gndpin);
+ PORTC &=~ _BV(gndpin);
+ PORTC |= _BV(pwrpin);
+ powerPinsEnabled = 1;
+ Firmata.sendString("Power pins enabled");
+ delay(100);
+ }
+}
+
+void setup()
+{
+ Firmata.setFirmwareVersion(2, 0);
+
+ Firmata.attach(START_SYSEX, sysexCallback);
+ Firmata.attach(SYSTEM_RESET, systemResetCallback);
+
+ for (int i = 0; i < TOTAL_DIGITAL_PINS; ++i) {
+ pinMode(i, OUTPUT);
+ }
+
+ Firmata.begin(57600);
+ Wire.begin();
+}
+
+void loop()
+{
+ while (Firmata.available()) {
+ Firmata.processInput();
+ }
+
+ currentMillis = millis();
+ if (currentMillis > nextExecuteMillis) {
+ nextExecuteMillis = currentMillis + samplingInterval;
+
+ for (byte i = 0; i < queryIndex; i++) {
+ readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
+ }
+ }
+}
diff --git a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde
index a3c609c..fa48e2b 100644
--- a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde
+++ b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.pde
@@ -28,7 +28,7 @@ void setup()
servo9.attach(9);
servo10.attach(10);
- Firmata.begin();
+ Firmata.begin(57600);
}
void loop()
diff --git a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde
index 2950c01..430d0d0 100644
--- a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde
+++ b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde
@@ -16,7 +16,7 @@ void setup()
{
Firmata.setFirmwareVersion(0, 1);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
- Firmata.begin();
+ Firmata.begin(57600);
}
void loop()
diff --git a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde
index 1104a92..9c4e05d 100644
--- a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde
+++ b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde
@@ -45,7 +45,7 @@ void setup()
Firmata.setFirmwareVersion(0, 1);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
- Firmata.begin();
+ Firmata.begin(57600);
}
void loop()
diff --git a/libraries/Firmata/examples/StandardFirmata/Makefile b/libraries/Firmata/examples/StandardFirmata/Makefile
index 55ca8c2..835187a 100644
--- a/libraries/Firmata/examples/StandardFirmata/Makefile
+++ b/libraries/Firmata/examples/StandardFirmata/Makefile
@@ -50,14 +50,20 @@ TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
ARDUINO = /Applications/arduino
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
+ARDUINO_TOOLS = $(ARDUINO)/hardware/tools
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
-I$(ARDUINO_LIB_SRC)/EEPROM \
-I$(ARDUINO_LIB_SRC)/Firmata \
+ -I$(ARDUINO_LIB_SRC)/Matrix \
+ -I$(ARDUINO_LIB_SRC)/Servo \
+ -I$(ARDUINO_LIB_SRC)/Wire \
-I$(ARDUINO_LIB_SRC)
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
+ $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
+ $(ARDUINO_SRC)/Print.cpp \
$(ARDUINO_SRC)/WMath.cpp
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
@@ -106,12 +112,14 @@ AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE) -q -V
# Program settings
-CC = avr-gcc
-CXX = avr-g++
-OBJCOPY = avr-objcopy
-OBJDUMP = avr-objdump
-SIZE = avr-size
-NM = avr-nm
+ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin
+CC = $(ARDUINO_AVR_BIN)/avr-gcc
+CXX = $(ARDUINO_AVR_BIN)/avr-g++
+OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy
+OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump
+SIZE = $(ARDUINO_AVR_BIN)/avr-size
+NM = $(ARDUINO_AVR_BIN)/avr-nm
+#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
@@ -204,7 +212,8 @@ applet/$(TARGET).cpp: $(TARGET).pde
# Link: create ELF output file from object files.
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
- $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
+ $(CC) $(ALL_CFLAGS) $(OBJ) -lm --output $@ $(LDFLAGS)
+# $(CC) $(ALL_CFLAGS) $(OBJ) $(ARDUINO_TOOLS)/avr/avr/lib/avr5/crtm168.o --output $@ $(LDFLAGS)
pd_close_serial:
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
@@ -258,4 +267,7 @@ etags_MINGW:
# etags -a /usr/include/*.h /usr/include/sys/*.h
+path:
+ echo $(PATH)
+ echo $$PATH
diff --git a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde
index 4cc8539..16c8b87 100644
--- a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde
+++ b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.pde
@@ -1,21 +1,24 @@
/*
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms.
- */
+
+ formatted using the GNU C formatting and indenting
+*/
+
/*
- * TODO: add Servo support using setPinMode(pin, SERVO);
+ * TODO: add Servo support using setPinModeCallback(pin, SERVO);
* TODO: use Program Control to load stored profiles from EEPROM
*/
-#include <EEPROM.h>
#include <Firmata.h>
+#include <Servo.h>
/*==============================================================================
* GLOBAL VARIABLES
@@ -34,37 +37,45 @@ byte portStatus[TOTAL_PORTS];
/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis
+int samplingInterval = 19; // how often to run the main loop (in ms)
+Servo servos[2]; // the servo library can control servos on pins 9 and 10 only
/*==============================================================================
- * FUNCTIONS
+ * FUNCTIONS
*============================================================================*/
void outputPort(byte portNumber, byte portValue)
{
portValue = portValue &~ portStatus[portNumber];
if(previousPINs[portNumber] != portValue) {
- Firmata.sendDigitalPort(portNumber, portValue);
- previousPINs[portNumber] = portValue;
- Firmata.sendDigitalPort(portNumber, portValue);
- }
+ Firmata.sendDigitalPort(portNumber, portValue);
+ previousPINs[portNumber] = portValue;
+ Firmata.sendDigitalPort(portNumber, portValue);
+ }
}
/* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events
* to the Serial output queue using Serial.print() */
-void checkDigitalInputs(void)
+void checkDigitalInputs(void)
{
- byte i, tmp;
- for(i=0; i < TOTAL_PORTS; i++) {
- if(reportPINs[i]) {
- switch(i) {
- case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1
- case 1: outputPort(1, PINB); break;
- case ANALOG_PORT: outputPort(ANALOG_PORT, PINC); break;
- }
- }
+ byte i, tmp;
+ for(i=0; i < TOTAL_PORTS; i++) {
+ if(reportPINs[i]) {
+ switch(i) {
+ case 0:
+ outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
+ break;
+ case 1:
+ outputPort(1, PINB);
+ break;
+ case ANALOG_PORT:
+ outputPort(ANALOG_PORT, PINC);
+ break;
+ }
}
+ }
}
// -----------------------------------------------------------------------------
@@ -72,61 +83,88 @@ void checkDigitalInputs(void)
* two bit-arrays that track Digital I/O and PWM status
*/
void setPinModeCallback(byte pin, int mode) {
- byte port = 0;
- byte offset = 0;
-
- if (pin < 8) {
- port = 0;
- offset = 0;
- } else if (pin < 14) {
- port = 1;
- offset = 8;
- } else if (pin < 22) {
- port = 2;
- offset = 14;
- }
+ byte port = 0;
+ byte offset = 0;
- if(pin > 1) { // ignore RxTx (pins 0 and 1)
+ // TODO: abstract for different boards
+ if (pin < 8) {
+ port = 0;
+ offset = 0;
+ } else if (pin < 14) {
+ port = 1;
+ offset = 8;
+ } else if (pin < 22) {
+ port = 2;
+ offset = 14;
+ }
+
+ if(pin > 1) { // ignore RxTx (pins 0 and 1)
+ if(pin > 13)
+ reportAnalogCallback(pin - 14, mode == ANALOG ? 1 : 0); // turn on/off reporting
+ switch(mode) {
+ case ANALOG:
+ digitalWrite(pin, LOW); // disable internal pull-ups and fall thru to 'case INPUT:'
+ case INPUT:
+ pinStatus[pin] = mode;
+ pinMode(pin, INPUT);
+ portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
+ break;
+ case OUTPUT:
+ digitalWrite(pin, LOW); // disable PWM and fall thru to 'case PWM:'
+ case PWM:
+ pinStatus[pin] = mode;
+ pinMode(pin, OUTPUT);
+ portStatus[port] = portStatus[port] | (1 << (pin - offset));
+ break;
+ case SERVO:
+ if((pin == 9 || pin == 10))
pinStatus[pin] = mode;
- switch(mode) {
- case INPUT:
- pinMode(pin, INPUT);
- portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
- break;
- case OUTPUT:
- digitalWrite(pin, LOW); // disable PWM
- case PWM:
- pinMode(pin, OUTPUT);
- portStatus[port] = portStatus[port] | (1 << (pin - offset));
- break;
- //case ANALOG: // TODO figure this out
- default:
- Firmata.sendString("");
- }
- // TODO: save status to EEPROM here, if changed
+ else
+ Firmata.sendString("Servo only on pins 9 and 10");
+ break;
+ case I2C:
+ pinStatus[pin] = mode;
+ Firmata.sendString("I2C mode not yet supported");
+ break;
+ default:
+ Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
}
+ // TODO: save status to EEPROM here, if changed
+ }
}
void analogWriteCallback(byte pin, int value)
{
- setPinModeCallback(pin,PWM);
+ switch(pinStatus[pin]) {
+ case SERVO:
+ if(pin == 9) servos[0].write(value);
+ if(pin == 10) servos[1].write(value);
+ break;
+ case PWM:
analogWrite(pin, value);
+ break;
+ }
}
void digitalWriteCallback(byte port, int value)
{
- switch(port) {
- case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
- // 0xFF03 == B1111111100000011 0x03 == B00000011
- PORTD = (value &~ 0xFF03) | (PORTD & 0x03);
- break;
- case 1: // pins 8-13 (14,15 are disabled for the crystal)
- PORTB = (byte)value;
- break;
- case 2: // analog pins used as digital
- PORTC = (byte)value;
- break;
- }
+ switch(port) {
+ case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
+ // 0xFF03 == B1111111100000011 0x03 == B00000011
+ PORTD = (value &~ 0xFF03) | (PORTD & 0x03);
+ break;
+ case 1: // pins 8-13 (14,15 are disabled for the crystal)
+ PORTB = (byte)value;
+ break;
+ case 2: // analog pins used as digital
+ byte pin;
+ byte pinModeMask;
+ for(pin=0; pin<8; pin++)
+ if(pinStatus[pin] == OUTPUT)
+ pinModeMask += 1 << pin;
+ PORTC = (byte)value & pinModeMask;
+ break;
+ }
}
// -----------------------------------------------------------------------------
@@ -136,64 +174,93 @@ void digitalWriteCallback(byte port, int value)
//}
void reportAnalogCallback(byte pin, int value)
{
- if(value == 0) {
- analogInputsToReport = analogInputsToReport &~ (1 << pin);
- }
- else { // everything but 0 enables reporting of that pin
- analogInputsToReport = analogInputsToReport | (1 << pin);
- }
- // TODO: save status to EEPROM here, if changed
+ if(value == 0) {
+ analogInputsToReport = analogInputsToReport &~ (1 << pin);
+ }
+ else { // everything but 0 enables reporting of that pin
+ analogInputsToReport = analogInputsToReport | (1 << pin);
+ setPinModeCallback(pin, ANALOG);
+ }
+ // TODO: save status to EEPROM here, if changed
}
void reportDigitalCallback(byte port, int value)
{
- reportPINs[port] = (byte)value;
- if(port == ANALOG_PORT) // turn off analog reporting when used as digital
- analogInputsToReport = 0;
+ reportPINs[port] = (byte)value;
+ if(port == ANALOG_PORT) // turn off analog reporting when used as digital
+ analogInputsToReport = 0;
+}
+
+/*==============================================================================
+ * SYSEX-BASED commands
+ *============================================================================*/
+
+void sysexCallback(byte command, byte argc, byte *argv)
+{
+ switch(command) {
+ case SERVO_CONFIG:
+ if(argc > 4) {
+ // these vars are here for clarity, they'll optimized away by the compiler
+ byte pin = argv[0] - 9; // servos are pins 9 and 10, so offset for array
+ int minPulse = argv[1] + (argv[2] << 7);
+ int maxPulse = argv[3] + (argv[4] << 7);
+ servos[pin].attach(argv[0], minPulse, maxPulse);
+ // TODO does the Servo have to be detach()ed before reconfiguring?
+ setPinModeCallback(pin, SERVO);
+ }
+ break;
+ case SAMPLING_INTERVAL:
+ if (argc > 1)
+ samplingInterval = argv[0] + (argv[1] << 7);
+ else
+ Firmata.sendString("Not enough data");
+ break;
+ }
}
+
/*==============================================================================
* SETUP()
*============================================================================*/
void setup()
{
- byte i;
+ byte i;
- Firmata.setFirmwareVersion(2, 0);
+ Firmata.setFirmwareVersion(2, 1);
- Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
- Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
- Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
- Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
- Firmata.attach(SET_PIN_MODE, setPinModeCallback);
+ Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
+ Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
+ Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
+ Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
+ Firmata.attach(SET_PIN_MODE, setPinModeCallback);
+ Firmata.attach(START_SYSEX, sysexCallback);
- portStatus[0] = B00000011; // ignore Tx/RX pins
- portStatus[1] = B11000000; // ignore 14/15 pins
- portStatus[2] = B00000000;
+ portStatus[0] = B00000011; // ignore Tx/RX pins
+ portStatus[1] = B11000000; // ignore 14/15 pins
+ portStatus[2] = B00000000;
-// for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs
- for(i=0; i<14; ++i) {
- setPinModeCallback(i,OUTPUT);
- }
- // set all outputs to 0 to make sure internal pull-up resistors are off
- PORTB = 0; // pins 8-15
- PORTC = 0; // analog port
- PORTD = 0; // pins 0-7
-
- // TODO rethink the init, perhaps it should report analog on default
- for(i=0; i<TOTAL_PORTS; ++i) {
- reportPINs[i] = false;
- }
- // TODO: load state from EEPROM here
+ for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs
+ setPinModeCallback(i,OUTPUT);
+ }
+ // set all outputs to 0 to make sure internal pull-up resistors are off
+ PORTB = 0; // pins 8-15
+ PORTC = 0; // analog port
+ PORTD = 0; // pins 0-7
+
+ // TODO rethink the init, perhaps it should report analog on default
+ for(i=0; i<TOTAL_PORTS; ++i) {
+ reportPINs[i] = false;
+ }
+ // TODO: load state from EEPROM here
- /* send digital inputs here, if enabled, to set the initial state on the
- * host computer, since once in the loop(), this firmware will only send
- * digital data on change. */
- if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
- if(reportPINs[1]) outputPort(1, PINB);
- if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC);
+ /* send digital inputs here, if enabled, to set the initial state on the
+ * host computer, since once in the loop(), this firmware will only send
+ * digital data on change. */
+ if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
+ if(reportPINs[1]) outputPort(1, PINB);
+ if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC);
- Firmata.begin();
+ Firmata.begin(57600);
}
/*==============================================================================
@@ -201,26 +268,26 @@ void setup()
*============================================================================*/
void loop()
{
-/* DIGITALREAD - as fast as possible, check for changes and output them to the
- * FTDI buffer using Serial.print() */
- checkDigitalInputs();
- currentMillis = millis();
- if(currentMillis > nextExecuteMillis) {
- nextExecuteMillis = currentMillis + 19; // run this every 20ms
- /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
- * all serialReads at once, i.e. empty the buffer */
- while(Firmata.available())
- Firmata.processInput();
- /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
- * 60 bytes. use a timer to sending an event character every 4 ms to
- * trigger the buffer to dump. */
+ /* DIGITALREAD - as fast as possible, check for changes and output them to the
+ * FTDI buffer using Serial.print() */
+ checkDigitalInputs();
+ currentMillis = millis();
+ if(currentMillis > nextExecuteMillis) {
+ nextExecuteMillis = currentMillis + samplingInterval;
+ /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
+ * all serialReads at once, i.e. empty the buffer */
+ while(Firmata.available())
+ Firmata.processInput();
+ /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
+ * 60 bytes. use a timer to sending an event character every 4 ms to
+ * trigger the buffer to dump. */
- /* ANALOGREAD - right after the event character, do all of the
- * analogReads(). These only need to be done every 4ms. */
- for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
- if( analogInputsToReport & (1 << analogPin) ) {
- Firmata.sendAnalog(analogPin, analogRead(analogPin));
- }
- }
+ /* ANALOGREAD - right after the event character, do all of the
+ * analogReads(). These only need to be done every 4ms. */
+ for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
+ if( analogInputsToReport & (1 << analogPin) ) {
+ Firmata.sendAnalog(analogPin, analogRead(analogPin));
+ }
}
+ }
}
diff --git a/libraries/LiquidCrystal/LiquidCrystal.cpp b/libraries/LiquidCrystal/LiquidCrystal.cpp
index b5f2cd4..b66f107 100755
--- a/libraries/LiquidCrystal/LiquidCrystal.cpp
+++ b/libraries/LiquidCrystal/LiquidCrystal.cpp
@@ -25,10 +25,39 @@
// LiquidCrystal constructor is called).
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
- uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
- uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) :
- _four_bit_mode(0), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable)
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
+ init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
+{
+ init(0, rs, -1, enable, d0, d1, d2, d3, d4, d5, d6, d7);
+}
+
+LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
+{
+ init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
+{
+ init(1, rs, -1, enable, d0, d1, d2, d3, 0, 0, 0, 0);
+}
+
+void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
+{
+ _rs_pin = rs;
+ _rw_pin = rw;
+ _enable_pin = enable;
+
_data_pins[0] = d0;
_data_pins[1] = d1;
_data_pins[2] = d2;
@@ -37,92 +66,244 @@ LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
_data_pins[5] = d5;
_data_pins[6] = d6;
_data_pins[7] = d7;
-
+
pinMode(_rs_pin, OUTPUT);
- pinMode(_rw_pin, OUTPUT);
+ // we can save 1 pin by not using RW. Indicate by passing -1 instead of pin#
+ if (_rw_pin != -1) {
+ pinMode(_rw_pin, OUTPUT);
+ }
pinMode(_enable_pin, OUTPUT);
- for (int i = 0; i < 8; i++)
- pinMode(_data_pins[i], OUTPUT);
-
- command(0x38); // function set: 8 bits, 1 line, 5x8 dots
- command(0x0C); // display control: turn display on, cursor off, no blinking
- command(0x06); // entry mode set: increment automatically, display shift, right shift
- clear();
+ if (fourbitmode)
+ _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
+ else
+ _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
+
+ begin(16, 1);
}
-LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
- uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) :
- _four_bit_mode(1), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable)
-{
- _data_pins[0] = d0;
- _data_pins[1] = d1;
- _data_pins[2] = d2;
- _data_pins[3] = d3;
-
- pinMode(_rs_pin, OUTPUT);
- pinMode(_rw_pin, OUTPUT);
- pinMode(_enable_pin, OUTPUT);
+void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
+ if (lines > 1) {
+ _displayfunction |= LCD_2LINE;
+ }
+ _numlines = lines;
+ _currline = 0;
+
+ // for some 1 line displays you can select a 10 pixel high font
+ if ((dotsize != 0) && (lines == 1)) {
+ _displayfunction |= LCD_5x10DOTS;
+ }
+
+ // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
+ // according to datasheet, we need at least 40ms after power rises above 2.7V
+ // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
+ delayMicroseconds(50000);
+ // Now we pull both RS and R/W low to begin commands
+ digitalWrite(_rs_pin, LOW);
+ digitalWrite(_enable_pin, LOW);
+ if (_rw_pin != -1) {
+ digitalWrite(_rw_pin, LOW);
+ }
- for (int i = 0; i < 4; i++)
- pinMode(_data_pins[i], OUTPUT);
-
- command(0x28); // function set: 4 bits, 1 line, 5x8 dots
- command(0x0C); // display control: turn display on, cursor off, no blinking
- command(0x06); // entry mode set: increment automatically, display shift, right shift
+ //put the LCD into 4 bit or 8 bit mode
+ if (! (_displayfunction & LCD_8BITMODE)) {
+ // this is according to the hitachi HD44780 datasheet
+ // figure 24, pg 46
+
+ // we start in 8bit mode, try to set 4 bit mode
+ write4bits(0x03);
+ delayMicroseconds(4500); // wait min 4.1ms
+
+ // second try
+ write4bits(0x03);
+ delayMicroseconds(4500); // wait min 4.1ms
+
+ // third go!
+ write4bits(0x03);
+ delayMicroseconds(150);
+
+ // finally, set to 8-bit interface
+ write4bits(0x02);
+ } else {
+ // this is according to the hitachi HD44780 datasheet
+ // page 45 figure 23
+
+ // Send function set command sequence
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delayMicroseconds(4500); // wait more than 4.1ms
+
+ // second try
+ command(LCD_FUNCTIONSET | _displayfunction);
+ delayMicroseconds(150);
+
+ // third go
+ command(LCD_FUNCTIONSET | _displayfunction);
+ }
+
+ // finally, set # lines, font size, etc.
+ command(LCD_FUNCTIONSET | _displayfunction);
+
+ // turn the display on with no cursor or blinking default
+ _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+ display();
+
+ // clear it off
clear();
+
+ // Initialize to default text direction (for romance languages)
+ _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+ // set the entry mode
+ command(LCD_ENTRYMODESET | _displaymode);
+
}
+/********** high level commands, for the user! */
void LiquidCrystal::clear()
{
- command(0x01); // clear display, set cursor position to zero
- delayMicroseconds(2000);
+ command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
+ delayMicroseconds(2000); // this command takes a long time!
}
void LiquidCrystal::home()
{
- command(0x02); // set cursor position to zero
- delayMicroseconds(2000);
+ command(LCD_RETURNHOME); // set cursor position to zero
+ delayMicroseconds(2000); // this command takes a long time!
}
-void LiquidCrystal::setCursor(int col, int row)
+void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
- command(0x80 | (col + row_offsets[row]));
+ if ( row > _numlines ) {
+ row = _numlines-1; // we count rows starting w/0
+ }
+
+ command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+}
+
+// Turn the display on/off (quickly)
+void LiquidCrystal::noDisplay() {
+ _displaycontrol &= ~LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::display() {
+ _displaycontrol |= LCD_DISPLAYON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turns the underline cursor on/off
+void LiquidCrystal::noCursor() {
+ _displaycontrol &= ~LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::cursor() {
+ _displaycontrol |= LCD_CURSORON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// Turn on and off the blinking cursor
+void LiquidCrystal::noBlink() {
+ _displaycontrol &= ~LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+void LiquidCrystal::blink() {
+ _displaycontrol |= LCD_BLINKON;
+ command(LCD_DISPLAYCONTROL | _displaycontrol);
+}
+
+// These commands scroll the display without changing the RAM
+void LiquidCrystal::scrollDisplayLeft(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
+}
+void LiquidCrystal::scrollDisplayRight(void) {
+ command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
+}
+
+// This is for text that flows Left to Right
+void LiquidCrystal::leftToRight(void) {
+ _displaymode |= LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This is for text that flows Right to Left
+void LiquidCrystal::rightToLeft(void) {
+ _displaymode &= ~LCD_ENTRYLEFT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// This will 'right justify' text from the cursor
+void LiquidCrystal::autoscroll(void) {
+ _displaymode |= LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
}
-void LiquidCrystal::command(uint8_t value) {
+// This will 'left justify' text from the cursor
+void LiquidCrystal::noAutoscroll(void) {
+ _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
+ command(LCD_ENTRYMODESET | _displaymode);
+}
+
+// Allows us to fill the first 8 CGRAM locations
+// with custom characters
+void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
+ location &= 0x7; // we only have 8 locations 0-7
+ command(LCD_SETCGRAMADDR | (location << 3));
+ for (int i=0; i<8; i++) {
+ write(charmap[i]);
+ }
+}
+
+/*********** mid level commands, for sending data/cmds */
+
+inline void LiquidCrystal::command(uint8_t value) {
send(value, LOW);
}
-void LiquidCrystal::write(uint8_t value) {
+inline void LiquidCrystal::write(uint8_t value) {
send(value, HIGH);
}
+/************ low level data pushing commands **********/
+
+// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin, mode);
- digitalWrite(_rw_pin, LOW);
-
- if (_four_bit_mode) {
- for (int i = 0; i < 4; i++) {
- digitalWrite(_data_pins[i], (value >> (i + 4)) & 0x01);
- }
-
- digitalWrite(_enable_pin, HIGH);
- digitalWrite(_enable_pin, LOW);
-
- for (int i = 0; i < 4; i++) {
- digitalWrite(_data_pins[i], (value >> i) & 0x01);
- }
- digitalWrite(_enable_pin, HIGH);
- digitalWrite(_enable_pin, LOW);
+ // if there is a RW pin indicated, set it low to Write
+ if (_rw_pin != -1) {
+ digitalWrite(_rw_pin, LOW);
+ }
+
+ if (_displayfunction & LCD_8BITMODE) {
+ write8bits(value);
} else {
- for (int i = 0; i < 8; i++) {
- digitalWrite(_data_pins[i], (value >> i) & 0x01);
- }
+ write4bits(value>>4);
+ write4bits(value);
+ }
+}
+
+void LiquidCrystal::pulseEnable(void) {
+ digitalWrite(_enable_pin, LOW);
+ delayMicroseconds(1);
+ digitalWrite(_enable_pin, HIGH);
+ delayMicroseconds(1); // enable pulse must be >450ns
+ digitalWrite(_enable_pin, LOW);
+ delayMicroseconds(100); // commands need > 37us to settle
+}
- digitalWrite(_enable_pin, HIGH);
- digitalWrite(_enable_pin, LOW);
+void LiquidCrystal::write4bits(uint8_t value) {
+ for (int i = 0; i < 4; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
+
+ pulseEnable();
+}
+
+void LiquidCrystal::write8bits(uint8_t value) {
+ for (int i = 0; i < 8; i++) {
+ pinMode(_data_pins[i], OUTPUT);
+ digitalWrite(_data_pins[i], (value >> i) & 0x01);
+ }
+
+ pulseEnable();
}
diff --git a/libraries/LiquidCrystal/LiquidCrystal.h b/libraries/LiquidCrystal/LiquidCrystal.h
index a5edc5f..f66ec1b 100755
--- a/libraries/LiquidCrystal/LiquidCrystal.h
+++ b/libraries/LiquidCrystal/LiquidCrystal.h
@@ -4,28 +4,101 @@
#include <inttypes.h>
#include "Print.h"
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
class LiquidCrystal : public Print {
public:
- LiquidCrystal(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
- LiquidCrystal(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t,
- uint8_t, uint8_t, uint8_t, uint8_t);
+ LiquidCrystal(uint8_t rs, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
+ LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
+ LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
+ LiquidCrystal(uint8_t rs, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
+
+ void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
+ uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
+ uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
+
+ void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
+
void clear();
void home();
- void setCursor(int, int);
- /*
- void shiftDisplayLeft();
- void shiftDisplayRight();
- */
+
+ void noDisplay();
+ void display();
+ void noBlink();
+ void blink();
+ void noCursor();
+ void cursor();
+ void scrollDisplayLeft();
+ void scrollDisplayRight();
+ void leftToRight();
+ void rightToLeft();
+ void autoscroll();
+ void noAutoscroll();
+
+ void createChar(uint8_t, uint8_t[]);
+ void setCursor(uint8_t, uint8_t);
virtual void write(uint8_t);
void command(uint8_t);
private:
void send(uint8_t, uint8_t);
-
- uint8_t _four_bit_mode;
+ void write4bits(uint8_t);
+ void write8bits(uint8_t);
+ void pulseEnable();
+
uint8_t _rs_pin; // LOW: command. HIGH: character.
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
uint8_t _enable_pin; // activated by a HIGH pulse.
uint8_t _data_pins[8];
+
+ uint8_t _displayfunction;
+ uint8_t _displaycontrol;
+ uint8_t _displaymode;
+
+ uint8_t _initialized;
+
+ uint8_t _numlines,_currline;
};
#endif
diff --git a/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.pde b/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.pde
new file mode 100644
index 0000000..bf33743
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.pde
@@ -0,0 +1,70 @@
+/*
+ LiquidCrystal Library - Autoscroll
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch demonstrates the use of the autoscroll()
+ and noAutoscroll() functions to make new text scroll or not.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of columns and rows:
+ lcd.begin(16,2);
+}
+
+void loop() {
+ // set the cursor to (0,0):
+ lcd.setCursor(0, 0);
+ // print from 0 to 9:
+ for (int thisChar = 0; thisChar < 10; thisChar++) {
+ lcd.print(thisChar);
+ delay(500);
+ }
+
+ // set the cursor to (16,1):
+ lcd.setCursor(16,1);
+ // set the display to automatically scroll:
+ lcd.autoscroll();
+ // print from 0 to 9:
+ for (int thisChar = 0; thisChar < 10; thisChar++) {
+ lcd.print(thisChar);
+ delay(500);
+ }
+ // turn off automatic scrolling
+ lcd.noAutoscroll();
+
+ // clear screen for the next loop:
+ lcd.clear();
+}
+
diff --git a/libraries/LiquidCrystal/examples/Blink/Blink.pde b/libraries/LiquidCrystal/examples/Blink/Blink.pde
new file mode 100644
index 0000000..83c79b4
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/Blink/Blink.pde
@@ -0,0 +1,58 @@
+/*
+ LiquidCrystal Library - Blink
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints "Hello World!" to the LCD and makes the
+ cursor block blink.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ // Print a message to the LCD.
+ lcd.print("hello, world!");
+}
+
+void loop() {
+ // Turn off the blinking cursor:
+ lcd.noBlink();
+ delay(3000);
+ // Turn on the blinking cursor:
+ lcd.blink();
+ delay(3000);
+}
+
+
diff --git a/libraries/LiquidCrystal/examples/Cursor/Cursor.pde b/libraries/LiquidCrystal/examples/Cursor/Cursor.pde
new file mode 100644
index 0000000..c0273f4
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/Cursor/Cursor.pde
@@ -0,0 +1,58 @@
+/*
+ LiquidCrystal Library - Cursor
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints "Hello World!" to the LCD and
+ uses the cursor() and noCursor() methods to turn
+ on and off the cursor.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ // Print a message to the LCD.
+ lcd.print("hello, world!");
+}
+
+void loop() {
+ // Turn off the cursor:
+ lcd.noCursor();
+ delay(500);
+ // Turn on the cursor:
+ lcd.cursor();
+ delay(500);
+}
+
diff --git a/libraries/LiquidCrystal/examples/Display/Display.pde b/libraries/LiquidCrystal/examples/Display/Display.pde
new file mode 100644
index 0000000..b430539
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/Display/Display.pde
@@ -0,0 +1,58 @@
+/*
+ LiquidCrystal Library - display() and noDisplay()
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints "Hello World!" to the LCD and uses the
+ display() and noDisplay() functions to turn on and off
+ the display.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ // Print a message to the LCD.
+ lcd.print("hello, world!");
+}
+
+void loop() {
+ // Turn off the display:
+ lcd.noDisplay();
+ delay(500);
+ // Turn on the display:
+ lcd.display();
+ delay(500);
+}
+
diff --git a/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.pde b/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.pde
index 2f244d0..76cd746 100644
--- a/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.pde
+++ b/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.pde
@@ -1,18 +1,56 @@
+/*
+ LiquidCrystal Library - Hello World
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints "Hello World!" to the LCD
+ and shows the time.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
#include <LiquidCrystal.h>
-// LiquidCrystal display with:
-// rs on pin 12
-// rw on pin 11
-// enable on pin 10
-// d4, d5, d6, d7 on pins 5, 4, 3, 2
-LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
-void setup()
-{
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("hello, world!");
}
-void loop()
-{
+void loop() {
+ // set the cursor to column 0, line 1
+ // (note: line 1 is the second row, since counting begins with 0):
+ lcd.setCursor(0, 1);
+ // print the number of seconds since reset:
+ lcd.print(millis()/1000);
}
+
diff --git a/libraries/LiquidCrystal/examples/Scroll/Scroll.pde b/libraries/LiquidCrystal/examples/Scroll/Scroll.pde
new file mode 100644
index 0000000..9276553
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/Scroll/Scroll.pde
@@ -0,0 +1,83 @@
+/*
+ LiquidCrystal Library - scrollDisplayLeft() and scrollDisplayRight()
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints "Hello World!" to the LCD and uses the
+ scrollDisplayLeft() and scrollDisplayRight() methods to scroll
+ the text.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ //lcd.setCursor(0,7);
+ // Print a message to the LCD.
+ lcd.print("hello, world!");
+ delay(1000);
+}
+
+void loop() {
+ // scroll 13 positions (string length) to the left
+ // to move it offscreen left:
+ for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
+ // scroll one position left:
+ lcd.scrollDisplayLeft();
+ // wait a bit:
+ delay(150);
+ }
+
+ // scroll 29 positions (string length + display length) to the right
+ // to move it offscreen right:
+ for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
+ // scroll one position right:
+ lcd.scrollDisplayRight();
+ // wait a bit:
+ delay(150);
+ }
+
+ // scroll 16 positions (display length + string length) to the left
+ // to move it back to center:
+ for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
+ // scroll one position left:
+ lcd.scrollDisplayLeft();
+ // wait a bit:
+ delay(150);
+ }
+
+ // delay at the end of the full loop:
+ delay(1000);
+
+}
+
diff --git a/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.pde b/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.pde
index 0c4ce35..a094c24 100644
--- a/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.pde
+++ b/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.pde
@@ -1,19 +1,47 @@
/*
- * Displays text sent over the serial port (e.g. from the Serial Monitor) on
- * an attached LCD.
+ LiquidCrystal Library - Serial Input
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch displays text sent over the serial port
+ (e.g. from the Serial Monitor) on an attached LCD.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
*/
+// include the library code:
#include <LiquidCrystal.h>
-// LiquidCrystal display with:
-// rs on pin 12
-// rw on pin 11
-// enable on pin 10
-// d4, d5, d6, d7 on pins 5, 4, 3, 2
-LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
-void setup()
-{
+void setup(){
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ // initialize the serial communications:
Serial.begin(9600);
}
diff --git a/libraries/LiquidCrystal/examples/TextDirection/TextDirection.pde b/libraries/LiquidCrystal/examples/TextDirection/TextDirection.pde
new file mode 100644
index 0000000..725eb0d
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/TextDirection/TextDirection.pde
@@ -0,0 +1,84 @@
+ /*
+ LiquidCrystal Library - TextDirection
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch demonstrates how to use leftToRight() and rightToLeft()
+ to move the cursor.
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+int thisChar = 'a';
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(16, 2);
+ // turn on the cursor:
+ lcd.cursor();
+ Serial.begin(9600);
+}
+
+void loop() {
+ // reverse directions at 'm':
+ if (thisChar == 'm') {
+ // go right for the next letter
+ lcd.rightToLeft();
+ }
+ // reverse again at 's':
+ if (thisChar == 's') {
+ // go left for the next letter
+ lcd.leftToRight();
+ }
+ // reset at 'z':
+ if (thisChar > 'z') {
+ // go to (0,0):
+ lcd.home();
+ // start again at 0
+ thisChar = 'a';
+ }
+ // print the character
+ lcd.print(thisChar, BYTE);
+ // wait a second:
+ delay(1000);
+ // increment the letter:
+ thisChar++;
+}
+
+
+
+
+
+
+
+
diff --git a/libraries/LiquidCrystal/examples/setCursor/setCursor.pde b/libraries/LiquidCrystal/examples/setCursor/setCursor.pde
new file mode 100644
index 0000000..edd2e77
--- /dev/null
+++ b/libraries/LiquidCrystal/examples/setCursor/setCursor.pde
@@ -0,0 +1,68 @@
+/*
+ LiquidCrystal Library - setCursor
+
+ Demonstrates the use a 16x2 LCD display. The LiquidCrystal
+ library works with all LCD displays that are compatible with the
+ Hitachi HD44780 driver. There are many of them out there, and you
+ can usually tell them by the 16-pin interface.
+
+ This sketch prints to all the positions of the LCD using the
+ setCursor(0 method:
+
+ The circuit:
+ * LCD RS pin to digital pin 12
+ * LCD Enable pin to digital pin 11
+ * LCD D4 pin to digital pin 5
+ * LCD D5 pin to digital pin 4
+ * LCD D6 pin to digital pin 3
+ * LCD D7 pin to digital pin 2
+ * 10K resistor:
+ * ends to +5V and ground
+ * wiper to LCD VO pin (pin 3)
+
+ Library originally added 18 Apr 2008
+ by David A. Mellis
+ library modified 5 Jul 2009
+ by Limor Fried (http://www.ladyada.net)
+ example added 9 Jul 2009
+ by Tom Igoe
+ modified 25 July 2009
+ by David A. Mellis
+
+ http://www.arduino.cc/en/Tutorial/LiquidCrystal
+ */
+
+// include the library code:
+#include <LiquidCrystal.h>
+
+// these constants won't change. But you can change the size of
+// your LCD using them:
+const int numRows = 2;
+const int numCols = 16;
+
+// initialize the library with the numbers of the interface pins
+LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
+
+void setup() {
+ // set up the LCD's number of rows and columns:
+ lcd.begin(numRows, numCols);
+}
+
+void loop() {
+ // loop from ASCII 'a' to ASCII 'z':
+ for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {
+ // loop over the columns:
+ for (int thisCol = 0; thisCol < numRows; thisCol++) {
+ // loop over the rows:
+ for (int thisRow = 0; thisRow < numCols; thisRow++) {
+ // set the cursor position:
+ lcd.setCursor(thisRow,thisCol);
+ // print the letter:
+ lcd.print(thisLetter, BYTE);
+ delay(200);
+ }
+ }
+ }
+}
+
+
diff --git a/libraries/LiquidCrystal/keywords.txt b/libraries/LiquidCrystal/keywords.txt
index 367ab1f..132845c 100755
--- a/libraries/LiquidCrystal/keywords.txt
+++ b/libraries/LiquidCrystal/keywords.txt
@@ -12,10 +12,24 @@ LiquidCrystal KEYWORD1
# Methods and Functions (KEYWORD2)
#######################################
+begin KEYWORD2
clear KEYWORD2
home KEYWORD2
print KEYWORD2
setCursor KEYWORD2
+cursor KEYWORD2
+noCursor KEYWORD2
+blink KEYWORD2
+noBlink KEYWORD2
+display KEYWORD2
+noDisplay KEYWORD2
+autoscroll KEYWORD2
+noAutoscroll KEYWORD2
+leftToRight KEYWORD2
+rightToLeft KEYWORD2
+scrollDisplayLeft KEYWORD2
+scrollDisplayRight KEYWORD2
+createChar KEYWORD2
#######################################
# Constants (LITERAL1)
diff --git a/libraries/Servo/Servo.cpp b/libraries/Servo/Servo.cpp
index 8578fef..9f58d64 100755
--- a/libraries/Servo/Servo.cpp
+++ b/libraries/Servo/Servo.cpp
@@ -1,133 +1,268 @@
-#include <avr/interrupt.h>
-#include <wiring.h>
-#include <Servo.h>
-
-/*
- Servo.h - Hardware Servo Timer Library
- Author: Jim Studt, jim@federated.com
- Copyright (c) 2007 David A. Mellis. All right reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-
-uint8_t Servo::attached9 = 0;
-uint8_t Servo::attached10 = 0;
-
-void Servo::seizeTimer1()
-{
- uint8_t oldSREG = SREG;
-
- cli();
- TCCR1A = _BV(WGM11); /* Fast PWM, ICR1 is top */
- TCCR1B = _BV(WGM13) | _BV(WGM12) /* Fast PWM, ICR1 is top */
- | _BV(CS11) /* div 8 clock prescaler */
- ;
- OCR1A = 3000;
- OCR1B = 3000;
- ICR1 = clockCyclesPerMicrosecond()*(20000L/8); // 20000 uS is a bit fast for the refresh, 20ms, but
- // it keeps us from overflowing ICR1 at 20MHz clocks
- // That "/8" at the end is the prescaler.
-#if defined(__AVR_ATmega8__)
- TIMSK &= ~(_BV(TICIE1) | _BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) );
-#else
- TIMSK1 &= ~(_BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) );
-#endif
-
- SREG = oldSREG; // undo cli()
-}
-
-void Servo::releaseTimer1() {}
-
-#define NO_ANGLE (0xff)
-
-Servo::Servo() : pin(0), angle(NO_ANGLE) {}
-
-uint8_t Servo::attach(int pinArg)
-{
- return attach(pinArg, 544, 2400);
-}
-
-uint8_t Servo::attach(int pinArg, int min, int max)
-{
- if (pinArg != 9 && pinArg != 10) return 0;
-
- min16 = min / 16;
- max16 = max / 16;
-
- pin = pinArg;
- angle = NO_ANGLE;
- digitalWrite(pin, LOW);
- pinMode(pin, OUTPUT);
-
- if (!attached9 && !attached10) seizeTimer1();
-
- if (pin == 9) {
- attached9 = 1;
- TCCR1A = (TCCR1A & ~_BV(COM1A0)) | _BV(COM1A1);
- }
-
- if (pin == 10) {
- attached10 = 1;
- TCCR1A = (TCCR1A & ~_BV(COM1B0)) | _BV(COM1B1);
- }
- return 1;
-}
-
-void Servo::detach()
-{
- // muck with timer flags
- if (pin == 9) {
- attached9 = 0;
- TCCR1A = TCCR1A & ~_BV(COM1A0) & ~_BV(COM1A1);
- pinMode(pin, INPUT);
- }
-
- if (pin == 10) {
- attached10 = 0;
- TCCR1A = TCCR1A & ~_BV(COM1B0) & ~_BV(COM1B1);
- pinMode(pin, INPUT);
- }
-
- if (!attached9 && !attached10) releaseTimer1();
-}
-
-void Servo::write(int angleArg)
-{
- uint16_t p;
-
- if (angleArg < 0) angleArg = 0;
- if (angleArg > 180) angleArg = 180;
- angle = angleArg;
-
- // bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
- // That 8L on the end is the TCNT1 prescaler, it will need to change if the clock's prescaler changes,
- // but then there will likely be an overflow problem, so it will have to be handled by a human.
- p = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/8L;
- if (pin == 9) OCR1A = p;
- if (pin == 10) OCR1B = p;
-}
-
-uint8_t Servo::read()
-{
- return angle;
-}
-
-uint8_t Servo::attached()
-{
- if (pin == 9 && attached9) return 1;
- if (pin == 10 && attached10) return 1;
- return 0;
-}
+/*
+ Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
+ Copyright (c) 2009 Michael Margolis. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+
+ A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
+ The servos are pulsed in the background using the value most recently written using the write() method
+
+ Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
+ Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
+
+ The methods are:
+
+ Servo - Class for manipulating servo motors connected to Arduino pins.
+
+ attach(pin ) - Attaches a servo motor to an i/o pin.
+ attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
+ default min is 544, max is 2400
+
+ write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
+ writeMicroseconds() - Sets the servo pulse width in microseconds
+ read() - Gets the last written servo pulse width as an angle between 0 and 180.
+ readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
+ attached() - Returns true if there is a servo attached.
+ detach() - Stops an attached servos from pulsing its i/o pin.
+
+*/
+
+#include <avr/interrupt.h>
+#include <WProgram.h>
+
+
+#include "Servo.h"
+
+#define TICKS_PER_uS (clockCyclesPerMicrosecond() / 8) // number of timer ticks per microsecond with prescale of 8
+
+#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
+#define TRIM_DURATION (SERVOS_PER_TIMER/2) // compensation ticks to trim adjust for digitalWrite delays
+
+#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
+
+static servo_t servos[MAX_SERVOS]; // static array of servo structures
+static volatile int8_t Channel[NBR_TIMERS]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
+#if defined(__AVR_ATmega1280__)
+typedef enum { _timer5, _timer1, _timer3, _timer4 } servoTimer_t; // this is the sequence for timer utilization on mega
+#else
+typedef enum { _timer1 } servoTimer_t; // this is the sequence for timer utilization on other controllers
+#endif
+
+uint8_t ServoCount = 0; // the total number of attached servos
+
+// convenience macros
+#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((servoTimer_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
+#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
+#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
+#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
+
+#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
+#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
+
+/************ static functions common to all instances ***********************/
+
+static inline void handle_interrupts(servoTimer_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
+{
+ if( Channel[timer] < 0 )
+ *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
+ else{
+ if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
+ digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
+ }
+
+ Channel[timer]++; // increment to the next channel
+ if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
+ *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
+ if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
+ digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
+ }
+ else {
+ // finished all channels so wait for the refresh period to expire before starting over
+ if( (unsigned)*TCNTn < (((unsigned int)REFRESH_INTERVAL * TICKS_PER_uS) + 4) ) // allow a few ticks to ensure the next OCR1A not missed
+ *OCRnA = (unsigned int)REFRESH_INTERVAL * TICKS_PER_uS;
+ else
+ *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
+ Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
+ }
+}
+
+SIGNAL (TIMER1_COMPA_vect)
+{
+ handle_interrupts(_timer1, &TCNT1, &OCR1A);
+}
+
+#if defined(__AVR_ATmega1280__)
+SIGNAL (TIMER3_COMPA_vect)
+{
+ handle_interrupts(_timer3, &TCNT3, &OCR3A);
+}
+SIGNAL (TIMER4_COMPA_vect)
+{
+ handle_interrupts(_timer4, &TCNT4, &OCR4A);
+}
+SIGNAL (TIMER5_COMPA_vect)
+{
+ handle_interrupts(_timer5, &TCNT5, &OCR5A);
+}
+#endif
+
+static void initISR(servoTimer_t timer)
+{
+ if(timer == _timer1) {
+ TCCR1A = 0; // normal counting mode
+ TCCR1B = _BV(CS11); // set prescaler of 8
+ TCNT1 = 0; // clear the timer count
+#if defined(__AVR_ATmega8__)
+ TIFR |= _BV(OCF1A); // clear any pending interrupts;
+ TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
+#else
+ TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
+ TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
+#endif
+ }
+#if defined(__AVR_ATmega1280__)
+ else if(timer == _timer3) {
+ TCCR3A = 0; // normal counting mode
+ TCCR3B = _BV(CS31); // set prescaler of 8
+ TCNT3 = 0; // clear the timer count
+ TIFR3 = _BV(OCF3A); // clear any pending interrupts;
+ TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
+ }
+ else if(timer == _timer4) {
+ TCCR4A = 0; // normal counting mode
+ TCCR4B = _BV(CS41); // set prescaler of 8
+ TCNT4 = 0; // clear the timer count
+ TIFR4 = _BV(OCF4A); // clear any pending interrupts;
+ TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
+ }
+ else if(timer == _timer5) {
+ TCCR5A = 0; // normal counting mode
+ TCCR5B = _BV(CS51); // set prescaler of 8
+ TCNT5 = 0; // clear the timer count
+ TIFR5 = _BV(OCF5A); // clear any pending interrupts;
+ TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt
+ }
+#endif
+}
+
+static boolean isTimerActive(servoTimer_t timer)
+{
+ // returns true if any servo is active on this timer
+ for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
+ if(SERVO(timer,channel).Pin.isActive == true)
+ return true;
+ }
+ return false;
+}
+
+
+/****************** end of static functions ******************************/
+
+Servo::Servo()
+{
+ if( ServoCount < MAX_SERVOS) {
+ this->servoIndex = ServoCount++; // assign a servo index to this instance
+ servos[this->servoIndex].ticks = DEFAULT_PULSE_WIDTH * TICKS_PER_uS; // store default values
+ }
+ else
+ this->servoIndex = INVALID_SERVO ; // too many servos
+}
+
+uint8_t Servo::attach(int pin)
+{
+ return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
+}
+
+uint8_t Servo::attach(int pin, int min, int max)
+{
+ if(this->servoIndex < MAX_SERVOS ) {
+ pinMode( pin, OUTPUT) ; // set servo pin to output
+ servos[this->servoIndex].Pin.nbr = pin;
+ // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
+ this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
+ this->max = (MAX_PULSE_WIDTH - max)/4;
+ // initialize the timer if it has not already been initialized
+ servoTimer_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
+ if(isTimerActive(timer) == false)
+ initISR(timer);
+ servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
+ }
+ return this->servoIndex ;
+}
+
+void Servo::detach()
+{
+ servos[this->servoIndex].Pin.isActive = false;
+
+#ifdef FREE_TIMERS
+ if(isTimerActive(SERVO_INDEX_TO_TIMER(servoIndex)) == false) {
+ ;// call to unimplimented function in wiring.c to re-init timer (set timer back to PWM mode) TODO?
+ }
+#endif
+}
+
+void Servo::write(int value)
+{
+ if(value < MIN_PULSE_WIDTH)
+ { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
+ if(value < 0) value = 0;
+ if(value > 180) value = 180;
+ value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
+ }
+ this->writeMicroseconds(value);
+}
+
+void Servo::writeMicroseconds(int value)
+{
+ // calculate and store the values for the given channel
+ byte channel = this->servoIndex;
+ if( (channel >= 0) && (channel < MAX_SERVOS) ) // ensure channel is valid
+ {
+ if( value < SERVO_MIN() ) // ensure pulse width is valid
+ value = SERVO_MIN();
+ else if( value > SERVO_MAX() )
+ value = SERVO_MAX();
+
+ value = (value-TRIM_DURATION) * TICKS_PER_uS; // convert to ticks after compensating for interrupt overhead
+ uint8_t oldSREG = SREG;
+ cli();
+ servos[channel].ticks = value;
+ SREG = oldSREG;
+ }
+}
+
+int Servo::read() // return the value as degrees
+{
+ return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
+}
+
+int Servo::readMicroseconds()
+{
+ unsigned int pulsewidth;
+ if( this->servoIndex != INVALID_SERVO )
+ pulsewidth = (servos[this->servoIndex].ticks / TICKS_PER_uS) + TRIM_DURATION ;
+ else
+ pulsewidth = 0;
+
+ return pulsewidth;
+}
+
+bool Servo::attached()
+{
+ return servos[this->servoIndex].Pin.isActive ;
+}
diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h
index 0b0e8db..9a25c65 100755
--- a/libraries/Servo/Servo.h
+++ b/libraries/Servo/Servo.h
@@ -1,10 +1,6 @@
-#ifndef Servo_h
-#define Servo_h
-
/*
- Servo.h - Hardware Servo Timer Library
- Author: Jim Studt, jim@federated.com
- Copyright (c) 2007 David A. Mellis. All right reserved.
+ Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
+ Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -21,32 +17,76 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/*
+
+ A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
+ The servos are pulsed in the background using the value most recently written using the write() method
+
+ Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
+ Timers are siezed as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
+
+ The methods are:
+
+ Servo - Class for manipulating servo motors connected to Arduino pins.
+
+ attach(pin ) - Attaches a servo motor to an i/o pin.
+ attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
+ default min is 544, max is 2400
+
+ write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
+ writeMicroseconds() - Sets the servo pulse width in microseconds
+ read() - Gets the last written servo pulse width as an angle between 0 and 180.
+ readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
+ attached() - Returns true if there is a servo attached.
+ detach() - Stops an attached servos from pulsing its i/o pin.
+ */
+
+#ifndef Servo_h
+#define Servo_h
+
#include <inttypes.h>
+#define Servo_VERSION 2 // software version of this library
+
+#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
+#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
+#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
+#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
+
+#if defined(__AVR_ATmega1280__)
+#define MAX_SERVOS 48 // the maximum number of servos (valid range is from 1 to 48)
+#else
+#define MAX_SERVOS 12 // this library supports up to 12 on a standard Arduino
+#endif
+
+#define INVALID_SERVO 255 // flag indicating an invalid servo index
+
+typedef struct {
+ uint8_t nbr :6 ; // a pin number from 0 to 63
+ uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false
+} ServoPin_t ;
+
+typedef struct {
+ ServoPin_t Pin;
+ unsigned int ticks;
+} servo_t;
+
class Servo
{
- private:
- uint8_t pin;
- uint8_t angle; // in degrees
- uint8_t min16; // minimum pulse, 16uS units (default is 34)
- uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
- static void seizeTimer1();
- static void releaseTimer1();
- static uint8_t attached9;
- static uint8_t attached10;
- public:
- Servo();
- uint8_t attach(int);
- // pulse length for 0 degrees in microseconds, 544uS default
- // pulse length for 180 degrees in microseconds, 2400uS default
- uint8_t attach(int, int, int);
- // attach to a pin, sets pinMode, returns 0 on failure, won't
- // position the servo until a subsequent write() happens
- // Only works for 9 and 10.
- void detach();
- void write(int); // specify the angle in degrees, 0 to 180
- uint8_t read();
- uint8_t attached();
+public:
+ Servo();
+ uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
+ uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
+ void detach();
+ void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
+ void writeMicroseconds(int value); // Write pulse width in microseconds
+ int read(); // returns current pulse width as an angle between 0 and 180 degrees
+ int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
+ bool attached(); // return true if this servo is attached, otherwise false
+private:
+ uint8_t servoIndex; // index into the channel data for this servo
+ int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH
+ int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
};
-#endif
+#endif \ No newline at end of file
diff --git a/libraries/Servo/keywords.txt b/libraries/Servo/keywords.txt
index 918c46a..ca5ba79 100755
--- a/libraries/Servo/keywords.txt
+++ b/libraries/Servo/keywords.txt
@@ -6,16 +6,18 @@
# Datatypes (KEYWORD1)
#######################################
-Servo KEYWORD1
+Servo KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
-attach KEYWORD2
-detach KEYWORD2
-write KEYWORD2
-read KEYWORD2
-attached KEYWORD2
+attach KEYWORD2
+detach KEYWORD2
+write KEYWORD2
+read KEYWORD2
+attached KEYWORD2
+writeMicroseconds KEYWORD2
+readMicroseconds KEYWORD2
#######################################
# Constants (LITERAL1)
diff --git a/libraries/Wire/utility/twi.c b/libraries/Wire/utility/twi.c
index 82a25c0..2ad2a71 100644
--- a/libraries/Wire/utility/twi.c
+++ b/libraries/Wire/utility/twi.c
@@ -87,9 +87,9 @@ void twi_init(void)
It is 72 for a 16mhz Wiring board with 100kHz TWI */
// enable twi module, acks, and twi interrupt
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
- // allocate buffers
+ // allocate buffers
twi_masterBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t));
twi_txBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t));
twi_rxBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t));
@@ -135,29 +135,34 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
- twi_masterBufferLength = length;
+ twi_masterBufferLength = length-1; // This is not intuitive, read on...
+ // On receive, the previously configured ACK/NACK setting is transmitted in
+ // response to the received byte before the interrupt is signalled.
+ // Therefor we must actually set NACK when the _next_ to last byte is
+ // received, causing that NACK to be sent in response to receiving the last
+ // expected byte of data.
// build sla+w, slave device address + w bit
twi_slarw = TW_READ;
- twi_slarw |= address << 1;
+ twi_slarw |= address << 1;
// send start condition
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
- // wait for read operation to complete
- while(TWI_MRX == twi_state){
- continue;
- }
+ // wait for read operation to complete
+ while(TWI_MRX == twi_state){
+ continue;
+ }
if (twi_masterBufferIndex < length)
- length = twi_masterBufferIndex;
+ length = twi_masterBufferIndex;
// copy twi buffer to data
for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[i];
}
- return length;
+ return length;
}
/*
@@ -202,24 +207,24 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
// build sla+w, slave device address + w bit
twi_slarw = TW_WRITE;
- twi_slarw |= address << 1;
+ twi_slarw |= address << 1;
// send start condition
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
- // wait for write operation to complete
- while(wait && (TWI_MTX == twi_state)){
- continue;
- }
-
- if (twi_error == 0xFF)
- return 0; // success
- else if (twi_error == TW_MT_SLA_NACK)
- return 2; // error: address send, nack received
- else if (twi_error == TW_MT_DATA_NACK)
- return 3; // error: data send, nack received
- else
- return 4; // other twi error
+ // wait for write operation to complete
+ while(wait && (TWI_MTX == twi_state)){
+ continue;
+ }
+
+ if (twi_error == 0xFF)
+ return 0; // success
+ else if (twi_error == TW_MT_SLA_NACK)
+ return 2; // error: address send, nack received
+ else if (twi_error == TW_MT_DATA_NACK)
+ return 3; // error: data send, nack received
+ else
+ return 4; // other twi error
}
/*
@@ -285,9 +290,9 @@ void twi_attachSlaveTxEvent( void (*function)(void) )
*/
void twi_reply(uint8_t ack)
{
- // transmit master read ready signal, with or without ack
- if(ack){
- TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
+ // transmit master read ready signal, with or without ack
+ if(ack){
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
}else{
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
}