Moving the processing-5503 branch (used for Arduino 0017) into the trunk.

This commit is contained in:
David A. Mellis 2009-08-15 14:48:42 +00:00
commit 50f77c7210
33 changed files with 2132 additions and 735 deletions

View File

@ -1,6 +1,6 @@
############################################################## ##############################################################
atmega328.name=Arduino Duemilanove w/ ATmega328 atmega328.name=Arduino Duemilanove or Nano w/ ATmega328
atmega328.upload.protocol=stk500 atmega328.upload.protocol=stk500
atmega328.upload.maximum_size=30720 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.protocol=stk500
diecimila.upload.maximum_size=14336 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.name=Arduino BT
bt.upload.protocol=stk500 bt.upload.protocol=stk500

View File

@ -49,41 +49,41 @@ ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
inline void store_char(unsigned char c, ring_buffer *rx_buffer) inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{ {
int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE; int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location // if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the // just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer // current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head. // and so we don't write the character or advance the head.
if (i != rx_buffer->tail) { if (i != rx_buffer->tail) {
rx_buffer->buffer[rx_buffer->head] = c; rx_buffer->buffer[rx_buffer->head] = c;
rx_buffer->head = i; rx_buffer->head = i;
} }
} }
#if defined(__AVR_ATmega1280__) #if defined(__AVR_ATmega1280__)
SIGNAL(SIG_USART0_RECV) SIGNAL(SIG_USART0_RECV)
{ {
unsigned char c = UDR0; unsigned char c = UDR0;
store_char(c, &rx_buffer); store_char(c, &rx_buffer);
} }
SIGNAL(SIG_USART1_RECV) SIGNAL(SIG_USART1_RECV)
{ {
unsigned char c = UDR1; unsigned char c = UDR1;
store_char(c, &rx_buffer1); store_char(c, &rx_buffer1);
} }
SIGNAL(SIG_USART2_RECV) SIGNAL(SIG_USART2_RECV)
{ {
unsigned char c = UDR2; unsigned char c = UDR2;
store_char(c, &rx_buffer2); store_char(c, &rx_buffer2);
} }
SIGNAL(SIG_USART3_RECV) SIGNAL(SIG_USART3_RECV)
{ {
unsigned char c = UDR3; unsigned char c = UDR3;
store_char(c, &rx_buffer3); store_char(c, &rx_buffer3);
} }
@ -96,9 +96,9 @@ SIGNAL(USART_RX_vect)
#endif #endif
{ {
#if defined(__AVR_ATmega8__) #if defined(__AVR_ATmega8__)
unsigned char c = UDR; unsigned char c = UDR;
#else #else
unsigned char c = UDR0; unsigned char c = UDR0;
#endif #endif
store_char(c, &rx_buffer); 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 *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb, volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr, 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; _rx_buffer = rx_buffer;
_ubrrh = ubrrh; _ubrrh = ubrrh;
@ -123,14 +123,43 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
_txen = txen; _txen = txen;
_rxcie = rxcie; _rxcie = rxcie;
_udre = udre; _udre = udre;
_u2x = u2x;
} }
// Public Methods ////////////////////////////////////////////////////////////// // Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long speed) void HardwareSerial::begin(long baud)
{ {
*_ubrrh = ((F_CPU / 16 + speed / 2) / speed - 1) >> 8; uint16_t baud_setting;
*_ubrrl = ((F_CPU / 16 + speed / 2) / speed - 1); 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, _rxen);
sbi(*_ucsrb, _txen); sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie); sbi(*_ucsrb, _rxcie);
@ -138,54 +167,53 @@ void HardwareSerial::begin(long speed)
uint8_t HardwareSerial::available(void) 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) int HardwareSerial::read(void)
{ {
// if the head isn't ahead of the tail, we don't have any characters // if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) { if (_rx_buffer->head == _rx_buffer->tail) {
return -1; return -1;
} else { } else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE; _rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
return c; return c;
} }
} }
void HardwareSerial::flush() void HardwareSerial::flush()
{ {
// don't reverse this or there may be problems if the RX interrupt // 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 // 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 // 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 // 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 // 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 // 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 // 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 // may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty. // were full, not empty.
_rx_buffer->head = _rx_buffer->tail; _rx_buffer->head = _rx_buffer->tail;
} }
void HardwareSerial::write(uint8_t c) void HardwareSerial::write(uint8_t c)
{ {
while (!((*_ucsra) & (1 << _udre))) while (!((*_ucsra) & (1 << _udre)))
; ;
*_udr = c; *_udr = c;
} }
// Preinstantiate Objects ////////////////////////////////////////////////////// // Preinstantiate Objects //////////////////////////////////////////////////////
#if defined(__AVR_ATmega8__) #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 #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 #endif
#if defined(__AVR_ATmega1280__) #if defined(__AVR_ATmega1280__)
HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1); 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); 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); HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3);
#endif #endif

View File

@ -39,12 +39,13 @@ class HardwareSerial : public Print
uint8_t _txen; uint8_t _txen;
uint8_t _rxcie; uint8_t _rxcie;
uint8_t _udre; uint8_t _udre;
uint8_t _u2x;
public: public:
HardwareSerial(ring_buffer *rx_buffer, HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl, volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb, volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr, 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); void begin(long);
uint8_t available(void); uint8_t available(void);
int read(void); int read(void);
@ -62,4 +63,3 @@ extern HardwareSerial Serial3;
#endif #endif
#endif #endif

View File

@ -86,8 +86,8 @@ extern "C"{
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
#define lowByte(w) ((w) & 0xff) #define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((w) >> 8) #define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitSet(value, bit) ((value) |= (1UL << (bit)))

View File

@ -42,7 +42,7 @@ int analogRead(uint8_t pin)
// set the analog reference (high two bits of ADMUX) and select the // set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result) // channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default). // to 0 (the default).
ADMUX = (analog_reference << 6) | (pin & 0x07); ADMUX = (analog_reference << 6) | (pin & 0x0f);
#if defined(__AVR_ATmega1280__) #if defined(__AVR_ATmega1280__)
// the MUX5 bit of ADCSRB selects whether we're reading from channels // the MUX5 bit of ADCSRB selects whether we're reading from channels

View File

@ -113,13 +113,21 @@ void Client::stop() {
} }
uint8_t Client::connected() { uint8_t Client::connected() {
uint8_t s = status(); if (_sock == 255) {
return !(s == SOCK_LISTEN || s == SOCK_CLOSED || s == SOCK_FIN_WAIT || return 0;
(s == SOCK_CLOSE_WAIT && !available())); } 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() { 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 // the next three functions are a hack so we can compare the client returned

View File

@ -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)
#######################################

View File

@ -29,18 +29,18 @@ extern "C" {
void sendValueAsTwo7bitBytes(int value) void sendValueAsTwo7bitBytes(int value)
{ {
Serial.print(value & B01111111, BYTE); // LSB Serial.print(value & B01111111, BYTE); // LSB
Serial.print(value >> 7 & B01111111, BYTE); // MSB Serial.print(value >> 7 & B01111111, BYTE); // MSB
} }
void startSysex(void) void startSysex(void)
{ {
Serial.print(START_SYSEX, BYTE); Serial.print(START_SYSEX, BYTE);
} }
void endSysex(void) void endSysex(void)
{ {
Serial.print(END_SYSEX, BYTE); Serial.print(END_SYSEX, BYTE);
} }
//****************************************************************************** //******************************************************************************
@ -49,8 +49,8 @@ void endSysex(void)
FirmataClass::FirmataClass(void) FirmataClass::FirmataClass(void)
{ {
firmwareVersionCount = 0; firmwareVersionCount = 0;
systemReset(); systemReset();
} }
//****************************************************************************** //******************************************************************************
@ -60,83 +60,83 @@ FirmataClass::FirmataClass(void)
/* begin method for overriding default serial bitrate */ /* begin method for overriding default serial bitrate */
void FirmataClass::begin(void) void FirmataClass::begin(void)
{ {
Serial.begin(115200); Serial.begin(57600);
blinkVersion(); blinkVersion();
delay(300); delay(300);
printVersion(); printVersion();
} }
/* begin method for overriding default serial bitrate */ /* begin method for overriding default serial bitrate */
void FirmataClass::begin(long speed) void FirmataClass::begin(long speed)
{ {
blinkVersion(); blinkVersion();
#if defined(__AVR_ATmega128__) // Wiring #if defined(__AVR_ATmega128__) // Wiring
Serial.begin((uint32_t)speed); Serial.begin((uint32_t)speed);
#else #else
Serial.begin(speed); Serial.begin(speed);
#endif #endif
delay(300); delay(300);
printVersion(); printVersion();
printFirmwareVersion(); printFirmwareVersion();
} }
// output the protocol version message to the serial port // output the protocol version message to the serial port
void FirmataClass::printVersion(void) { void FirmataClass::printVersion(void) {
Serial.print(REPORT_VERSION, BYTE); Serial.print(REPORT_VERSION, BYTE);
Serial.print(FIRMATA_MAJOR_VERSION, BYTE); Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
Serial.print(FIRMATA_MINOR_VERSION, BYTE); Serial.print(FIRMATA_MINOR_VERSION, BYTE);
} }
void FirmataClass::blinkVersion(void) void FirmataClass::blinkVersion(void)
{ {
// flash the pin with the protocol version // flash the pin with the protocol version
pinMode(VERSION_BLINK_PIN,OUTPUT); pinMode(VERSION_BLINK_PIN,OUTPUT);
pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400);
delay(300); delay(300);
pin13strobe(2,1,4); // separator, a quick burst pin13strobe(2,1,4); // separator, a quick burst
delay(300); delay(300);
pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
} }
void FirmataClass::printFirmwareVersion(void) void FirmataClass::printFirmwareVersion(void)
{ {
byte i; byte i;
if(firmwareVersionCount) { // make sure that the name has been set before reporting if(firmwareVersionCount) { // make sure that the name has been set before reporting
startSysex(); startSysex();
Serial.print(REPORT_FIRMWARE, BYTE); Serial.print(REPORT_FIRMWARE, BYTE);
Serial.print(firmwareVersionVector[0]); // major version number Serial.print(firmwareVersionVector[0]); // major version number
Serial.print(firmwareVersionVector[1]); // minor version number Serial.print(firmwareVersionVector[1]); // minor version number
for(i=2; i<firmwareVersionCount; ++i) { for(i=2; i<firmwareVersionCount; ++i) {
sendValueAsTwo7bitBytes(firmwareVersionVector[i]); sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
}
endSysex();
} }
endSysex();
}
} }
void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
{ {
const char *filename; const char *filename;
char *extension; char *extension;
// parse out ".cpp" and "applet/" that comes from using __FILE__ // parse out ".cpp" and "applet/" that comes from using __FILE__
extension = strstr(name, ".cpp"); extension = strstr(name, ".cpp");
filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
// add two bytes for version numbers // add two bytes for version numbers
if(extension && filename) { if(extension && filename) {
firmwareVersionCount = extension - filename + 2; firmwareVersionCount = extension - filename + 2;
} else { } else {
firmwareVersionCount = strlen(name) + 2; firmwareVersionCount = strlen(name) + 2;
filename = name; filename = name;
} }
firmwareVersionVector = (byte *) malloc(firmwareVersionCount); firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
firmwareVersionVector[firmwareVersionCount] = 0; firmwareVersionVector[firmwareVersionCount] = 0;
firmwareVersionVector[0] = major; firmwareVersionVector[0] = major;
firmwareVersionVector[1] = minor; firmwareVersionVector[1] = minor;
strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
// alas, no snprintf on Arduino // alas, no snprintf on Arduino
// snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s", // snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
// (char)major, (char)minor, firmwareVersionVector); // (char)major, (char)minor, firmwareVersionVector);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -144,123 +144,123 @@ void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte
int FirmataClass::available(void) int FirmataClass::available(void)
{ {
return Serial.available(); return Serial.available();
} }
void FirmataClass::processSysexMessage(void) void FirmataClass::processSysexMessage(void)
{ {
switch(storedInputData[0]) { //first byte in buffer is command switch(storedInputData[0]) { //first byte in buffer is command
case REPORT_FIRMWARE: case REPORT_FIRMWARE:
printFirmwareVersion(); printFirmwareVersion();
break; break;
case FIRMATA_STRING: case STRING_DATA:
if(currentStringCallback) { if(currentStringCallback) {
byte bufferLength = (sysexBytesRead - 1) / 2; byte bufferLength = (sysexBytesRead - 1) / 2;
char *buffer = (char*)malloc(bufferLength * sizeof(char)); char *buffer = (char*)malloc(bufferLength * sizeof(char));
byte i = 1; byte i = 1;
byte j = 0; byte j = 0;
while(j < bufferLength) { while(j < bufferLength) {
buffer[j] = (char)storedInputData[i]; buffer[j] = (char)storedInputData[i];
i++; i++;
buffer[j] += (char)(storedInputData[i] << 7); buffer[j] += (char)(storedInputData[i] << 7);
i++; i++;
j++; j++;
} }
(*currentStringCallback)(buffer); (*currentStringCallback)(buffer);
}
break;
default:
if(currentSysexCallback)
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
} }
break;
default:
if(currentSysexCallback)
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
}
} }
void FirmataClass::processInput(void) void FirmataClass::processInput(void)
{ {
int inputData = Serial.read(); // this is 'int' to handle -1 when no data int inputData = Serial.read(); // this is 'int' to handle -1 when no data
int command; int command;
// TODO make sure it handles -1 properly // TODO make sure it handles -1 properly
if (parsingSysex) { if (parsingSysex) {
if(inputData == END_SYSEX) { if(inputData == END_SYSEX) {
//stop sysex byte //stop sysex byte
parsingSysex = false; parsingSysex = false;
//fire off handler function //fire off handler function
processSysexMessage(); 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;
}
} else { } else {
// remove channel info from command byte if less than 0xF0 //normal data byte - add to buffer
if(inputData < 0xF0) { storedInputData[sysexBytesRead] = inputData;
command = inputData & 0xF0; sysexBytesRead++;
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;
}
} }
} 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;
}
} 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 // send an analog message
void FirmataClass::sendAnalog(byte pin, int value) void FirmataClass::sendAnalog(byte pin, int value)
{ {
// pin can only be 0-15, so chop higher bits // pin can only be 0-15, so chop higher bits
Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE); Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE);
sendValueAsTwo7bitBytes(value); sendValueAsTwo7bitBytes(value);
} }
// send a single digital pin in a digital message // send a single digital pin in a digital message
void FirmataClass::sendDigital(byte pin, int value) void FirmataClass::sendDigital(byte pin, int value)
{ {
/* TODO add single pin digital messages to the protocol, this needs to /* 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 * 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 * one bit in the packet. This is complicated by the fact that the
* numbering of the pins will probably differ on Arduino, Wiring, and * 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 * 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 * probably easier to send 8 bit ports for any board with more than 14
* digital pins. * digital pins.
*/ */
// TODO: the digital message should not be sent on the serial port every // 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 // 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 // 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 // before the digital message is sent on the serial port, it should send a
// digital message for each change. // digital message for each change.
// if(value == 0) // if(value == 0)
// sendDigitalPortPair(); // sendDigitalPortPair();
} }
@ -301,33 +301,33 @@ void FirmataClass::sendDigital(byte pin, int value)
// send an 8-bit port in a single digital message (protocol v2) // send an 8-bit port in a single digital message (protocol v2)
void FirmataClass::sendDigitalPort(byte portNumber, int portData) void FirmataClass::sendDigitalPort(byte portNumber, int portData)
{ {
Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE); Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE);
Serial.print(portData % 128, BYTE); // Tx bits 0-6 Serial.print(portData % 128, BYTE); // Tx bits 0-6
Serial.print(portData >> 7, BYTE); // Tx bits 7-13 Serial.print(portData >> 7, BYTE); // Tx bits 7-13
} }
void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
{ {
byte i; byte i;
startSysex(); startSysex();
Serial.print(command, BYTE); Serial.print(command, BYTE);
for(i=0; i<bytec; i++) { for(i=0; i<bytec; i++) {
sendValueAsTwo7bitBytes(bytev[i]); sendValueAsTwo7bitBytes(bytev[i]);
} }
endSysex(); endSysex();
} }
void FirmataClass::sendString(byte command, const char* string) 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 // send a string as the protocol string type
void FirmataClass::sendString(const char* string) 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 // generic callbacks
void FirmataClass::attach(byte command, callbackFunction newFunction) void FirmataClass::attach(byte command, callbackFunction newFunction)
{ {
switch(command) { switch(command) {
case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
case SET_PIN_MODE: currentPinModeCallback = newFunction; break; case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
{ {
switch(command) { switch(command) {
case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, stringCallbackFunction newFunction) void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
{ {
switch(command) { switch(command) {
case FIRMATA_STRING: currentStringCallback = newFunction; break; case STRING_DATA: currentStringCallback = newFunction; break;
} }
} }
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
{ {
currentSysexCallback = newFunction; currentSysexCallback = newFunction;
} }
void FirmataClass::detach(byte command) void FirmataClass::detach(byte command)
{ {
switch(command) { switch(command) {
case SYSTEM_RESET: currentSystemResetCallback = NULL; break; case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
case FIRMATA_STRING: currentStringCallback = NULL; break; case STRING_DATA: currentStringCallback = NULL; break;
case START_SYSEX: currentSysexCallback = NULL; break; case START_SYSEX: currentSysexCallback = NULL; break;
default: default:
attach(command, (callbackFunction)NULL); attach(command, (callbackFunction)NULL);
} }
} }
// sysex callbacks // sysex callbacks
@ -402,24 +402,24 @@ void FirmataClass::detach(byte command)
// resets the system state upon a SYSTEM_RESET message from the host software // resets the system state upon a SYSTEM_RESET message from the host software
void FirmataClass::systemReset(void) void FirmataClass::systemReset(void)
{ {
byte i; byte i;
waitForData = 0; // this flag says the next serial input will be data waitForData = 0; // this flag says the next serial input will be data
executeMultiByteCommand = 0; // execute this after getting multi-byte data executeMultiByteCommand = 0; // execute this after getting multi-byte data
multiByteChannel = 0; // channel data for multiByteCommands multiByteChannel = 0; // channel data for multiByteCommands
for(i=0; i<MAX_DATA_BYTES; i++) { for(i=0; i<MAX_DATA_BYTES; i++) {
storedInputData[i] = 0; storedInputData[i] = 0;
} }
parsingSysex = false; parsingSysex = false;
sysexBytesRead = 0; sysexBytesRead = 0;
if(currentSystemResetCallback) if(currentSystemResetCallback)
(*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 // used for flashing the pin for the version number
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval) void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
{ {
byte i; byte i;
pinMode(VERSION_BLINK_PIN, OUTPUT); pinMode(VERSION_BLINK_PIN, OUTPUT);
for(i=0; i<count; i++) { for(i=0; i<count; i++) {
delay(offInterval); delay(offInterval);
digitalWrite(VERSION_BLINK_PIN, HIGH); digitalWrite(VERSION_BLINK_PIN, HIGH);
delay(onInterval); delay(onInterval);
digitalWrite(VERSION_BLINK_PIN, LOW); digitalWrite(VERSION_BLINK_PIN, LOW);
} }
} }

View File

@ -22,8 +22,7 @@
* software can test whether it will be compatible with the currently * software can test whether it will be compatible with the currently
* installed firmware. */ * installed firmware. */
#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes #define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes
#define FIRMATA_MINOR_VERSION 0 // for backwards compatible changes #define FIRMATA_MINOR_VERSION 1 // for backwards compatible changes
#define VERSION_BLINK_PIN 13 // digital pin to blink version on
#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages #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 #define END_SYSEX 0xF7 // end a MIDI Sysex message
// extended command set using sysex (0-127/0x00-0x7F) // 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 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 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_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
#define SYSEX_REALTIME 0x7F // MIDI Reserved for 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 // pin modes
//#define INPUT 0x00 // defined in wiring.h //#define INPUT 0x00 // defined in wiring.h
@ -55,7 +64,8 @@
#define ANALOG 0x02 // analog pin in analogInput mode #define ANALOG 0x02 // analog pin in analogInput mode
#define PWM 0x03 // digital pin in PWM output mode #define PWM 0x03 // digital pin in PWM output mode
#define SERVO 0x04 // digital pin in Servo 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" { extern "C" {
// callback function types // callback function types
@ -146,21 +156,71 @@ extern FirmataClass Firmata;
#define TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog #define TOTAL_DIGITAL_PINS 22 // 14 digital + 8 analog
#define TOTAL_PORTS 3 // total number of ports for the board #define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital #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 #elif defined(__AVR_ATmega8__) // old Arduinos
#define TOTAL_ANALOG_PINS 6 #define TOTAL_ANALOG_PINS 6
#define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog #define TOTAL_DIGITAL_PINS 20 // 14 digital + 6 analog
#define TOTAL_PORTS 3 // total number of ports for the board #define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital #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 #elif defined(__AVR_ATmega128__)// Wiring
#define TOTAL_ANALOG_PINS 8 #define TOTAL_ANALOG_PINS 8
#define TOTAL_DIGITAL_PINS 51 #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 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 #else // anything else
#define TOTAL_ANALOG_PINS 6 #define TOTAL_ANALOG_PINS 6
#define TOTAL_DIGITAL_PINS 14 #define TOTAL_DIGITAL_PINS 14
#define TOTAL_PORTS 3 // total number of ports for the board #define TOTAL_PORTS 3 // total number of ports for the board
#define ANALOG_PORT 2 // port# of analog used as digital #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 #endif

View File

@ -61,7 +61,7 @@ void setup()
servo9.attach(9); servo9.attach(9);
servo10.attach(10); servo10.attach(10);
Firmata.begin(); Firmata.begin(57600);
} }
/*============================================================================== /*==============================================================================

View File

@ -25,9 +25,9 @@ void sysexCallback(byte command, byte argc, byte*argv)
void setup() void setup()
{ {
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(FIRMATA_STRING, stringCallback); Firmata.attach(STRING_DATA, stringCallback);
Firmata.attach(START_SYSEX, sysexCallback); Firmata.attach(START_SYSEX, sysexCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -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);
}
}
}

View File

@ -28,7 +28,7 @@ void setup()
servo9.attach(9); servo9.attach(9);
servo10.attach(10); servo10.attach(10);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -16,7 +16,7 @@ void setup()
{ {
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -45,7 +45,7 @@ void setup()
Firmata.setFirmwareVersion(0, 1); Firmata.setFirmwareVersion(0, 1);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.begin(); Firmata.begin(57600);
} }
void loop() void loop()

View File

@ -50,14 +50,20 @@ TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
ARDUINO = /Applications/arduino ARDUINO = /Applications/arduino
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
ARDUINO_TOOLS = $(ARDUINO)/hardware/tools
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
-I$(ARDUINO_LIB_SRC)/EEPROM \ -I$(ARDUINO_LIB_SRC)/EEPROM \
-I$(ARDUINO_LIB_SRC)/Firmata \ -I$(ARDUINO_LIB_SRC)/Firmata \
-I$(ARDUINO_LIB_SRC)/Matrix \
-I$(ARDUINO_LIB_SRC)/Servo \
-I$(ARDUINO_LIB_SRC)/Wire \
-I$(ARDUINO_LIB_SRC) -I$(ARDUINO_LIB_SRC)
SRC = $(wildcard $(ARDUINO_SRC)/*.c) SRC = $(wildcard $(ARDUINO_SRC)/*.c)
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
$(ARDUINO_SRC)/Print.cpp \
$(ARDUINO_SRC)/WMath.cpp $(ARDUINO_SRC)/WMath.cpp
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) 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 -b $(UPLOAD_RATE) -q -V
# Program settings # Program settings
CC = avr-gcc ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin
CXX = avr-g++ CC = $(ARDUINO_AVR_BIN)/avr-gcc
OBJCOPY = avr-objcopy CXX = $(ARDUINO_AVR_BIN)/avr-g++
OBJDUMP = avr-objdump OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy
SIZE = avr-size OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump
NM = avr-nm SIZE = $(ARDUINO_AVR_BIN)/avr-size
NM = $(ARDUINO_AVR_BIN)/avr-nm
#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude
AVRDUDE = avrdude AVRDUDE = avrdude
REMOVE = rm -f REMOVE = rm -f
MV = mv -f MV = mv -f
@ -204,7 +212,8 @@ applet/$(TARGET).cpp: $(TARGET).pde
# Link: create ELF output file from object files. # Link: create ELF output file from object files.
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) 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: pd_close_serial:
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true 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 # etags -a /usr/include/*.h /usr/include/sys/*.h
path:
echo $(PATH)
echo $$PATH

View File

@ -1,21 +1,24 @@
/* /*
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
See file LICENSE.txt for further informations on licensing terms. 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 * TODO: use Program Control to load stored profiles from EEPROM
*/ */
#include <EEPROM.h>
#include <Firmata.h> #include <Firmata.h>
#include <Servo.h>
/*============================================================================== /*==============================================================================
* GLOBAL VARIABLES * GLOBAL VARIABLES
@ -34,37 +37,45 @@ byte portStatus[TOTAL_PORTS];
/* timer variables */ /* timer variables */
unsigned long currentMillis; // store the current value from millis() unsigned long currentMillis; // store the current value from millis()
unsigned long nextExecuteMillis; // for comparison with currentMillis 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) void outputPort(byte portNumber, byte portValue)
{ {
portValue = portValue &~ portStatus[portNumber]; portValue = portValue &~ portStatus[portNumber];
if(previousPINs[portNumber] != portValue) { if(previousPINs[portNumber] != portValue) {
Firmata.sendDigitalPort(portNumber, portValue); Firmata.sendDigitalPort(portNumber, portValue);
previousPINs[portNumber] = portValue; previousPINs[portNumber] = portValue;
Firmata.sendDigitalPort(portNumber, portValue); Firmata.sendDigitalPort(portNumber, portValue);
} }
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* check all the active digital inputs for change of state, then add any events * check all the active digital inputs for change of state, then add any events
* to the Serial output queue using Serial.print() */ * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void) void checkDigitalInputs(void)
{ {
byte i, tmp; byte i, tmp;
for(i=0; i < TOTAL_PORTS; i++) { for(i=0; i < TOTAL_PORTS; i++) {
if(reportPINs[i]) { if(reportPINs[i]) {
switch(i) { switch(i) {
case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 case 0:
case 1: outputPort(1, PINB); break; outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
case ANALOG_PORT: outputPort(ANALOG_PORT, PINC); break; 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 * two bit-arrays that track Digital I/O and PWM status
*/ */
void setPinModeCallback(byte pin, int mode) { void setPinModeCallback(byte pin, int mode) {
byte port = 0; byte port = 0;
byte offset = 0; byte offset = 0;
if (pin < 8) { // TODO: abstract for different boards
port = 0; if (pin < 8) {
offset = 0; port = 0;
} else if (pin < 14) { offset = 0;
port = 1; } else if (pin < 14) {
offset = 8; port = 1;
} else if (pin < 22) { offset = 8;
port = 2; } else if (pin < 22) {
offset = 14; port = 2;
} offset = 14;
}
if(pin > 1) { // ignore RxTx (pins 0 and 1)
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; pinStatus[pin] = mode;
switch(mode) { else
case INPUT: Firmata.sendString("Servo only on pins 9 and 10");
pinMode(pin, INPUT); break;
portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); case I2C:
break; pinStatus[pin] = mode;
case OUTPUT: Firmata.sendString("I2C mode not yet supported");
digitalWrite(pin, LOW); // disable PWM break;
case PWM: default:
pinMode(pin, OUTPUT); Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
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
} }
// TODO: save status to EEPROM here, if changed
}
} }
void analogWriteCallback(byte pin, int value) 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); analogWrite(pin, value);
break;
}
} }
void digitalWriteCallback(byte port, int value) void digitalWriteCallback(byte port, int value)
{ {
switch(port) { switch(port) {
case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
// 0xFF03 == B1111111100000011 0x03 == B00000011 // 0xFF03 == B1111111100000011 0x03 == B00000011
PORTD = (value &~ 0xFF03) | (PORTD & 0x03); PORTD = (value &~ 0xFF03) | (PORTD & 0x03);
break; break;
case 1: // pins 8-13 (14,15 are disabled for the crystal) case 1: // pins 8-13 (14,15 are disabled for the crystal)
PORTB = (byte)value; PORTB = (byte)value;
break; break;
case 2: // analog pins used as digital case 2: // analog pins used as digital
PORTC = (byte)value; byte pin;
break; 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) void reportAnalogCallback(byte pin, int value)
{ {
if(value == 0) { if(value == 0) {
analogInputsToReport = analogInputsToReport &~ (1 << pin); analogInputsToReport = analogInputsToReport &~ (1 << pin);
} }
else { // everything but 0 enables reporting of that pin else { // everything but 0 enables reporting of that pin
analogInputsToReport = analogInputsToReport | (1 << pin); analogInputsToReport = analogInputsToReport | (1 << pin);
} setPinModeCallback(pin, ANALOG);
// TODO: save status to EEPROM here, if changed }
// TODO: save status to EEPROM here, if changed
} }
void reportDigitalCallback(byte port, int value) void reportDigitalCallback(byte port, int value)
{ {
reportPINs[port] = (byte)value; reportPINs[port] = (byte)value;
if(port == ANALOG_PORT) // turn off analog reporting when used as digital if(port == ANALOG_PORT) // turn off analog reporting when used as digital
analogInputsToReport = 0; 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() * SETUP()
*============================================================================*/ *============================================================================*/
void setup() void setup()
{ {
byte i; byte i;
Firmata.setFirmwareVersion(2, 0); Firmata.setFirmwareVersion(2, 1);
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
Firmata.attach(REPORT_ANALOG, reportAnalogCallback); Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
Firmata.attach(SET_PIN_MODE, setPinModeCallback); Firmata.attach(SET_PIN_MODE, setPinModeCallback);
Firmata.attach(START_SYSEX, sysexCallback);
portStatus[0] = B00000011; // ignore Tx/RX pins portStatus[0] = B00000011; // ignore Tx/RX pins
portStatus[1] = B11000000; // ignore 14/15 pins portStatus[1] = B11000000; // ignore 14/15 pins
portStatus[2] = B00000000; portStatus[2] = B00000000;
// for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs
for(i=0; i<14; ++i) { setPinModeCallback(i,OUTPUT);
setPinModeCallback(i,OUTPUT); }
} // set all outputs to 0 to make sure internal pull-up resistors are off
// set all outputs to 0 to make sure internal pull-up resistors are off PORTB = 0; // pins 8-15
PORTB = 0; // pins 8-15 PORTC = 0; // analog port
PORTC = 0; // analog port PORTD = 0; // pins 0-7
PORTD = 0; // pins 0-7
// TODO rethink the init, perhaps it should report analog on default // TODO rethink the init, perhaps it should report analog on default
for(i=0; i<TOTAL_PORTS; ++i) { for(i=0; i<TOTAL_PORTS; ++i) {
reportPINs[i] = false; reportPINs[i] = false;
} }
// TODO: load state from EEPROM here // TODO: load state from EEPROM here
/* send digital inputs here, if enabled, to set the initial state on the /* 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 * host computer, since once in the loop(), this firmware will only send
* digital data on change. */ * digital data on change. */
if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
if(reportPINs[1]) outputPort(1, PINB); if(reportPINs[1]) outputPort(1, PINB);
if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC); if(reportPINs[ANALOG_PORT]) outputPort(ANALOG_PORT, PINC);
Firmata.begin(); Firmata.begin(57600);
} }
/*============================================================================== /*==============================================================================
@ -201,26 +268,26 @@ void setup()
*============================================================================*/ *============================================================================*/
void loop() void loop()
{ {
/* DIGITALREAD - as fast as possible, check for changes and output them to the /* DIGITALREAD - as fast as possible, check for changes and output them to the
* FTDI buffer using Serial.print() */ * FTDI buffer using Serial.print() */
checkDigitalInputs(); checkDigitalInputs();
currentMillis = millis(); currentMillis = millis();
if(currentMillis > nextExecuteMillis) { if(currentMillis > nextExecuteMillis) {
nextExecuteMillis = currentMillis + 19; // run this every 20ms nextExecuteMillis = currentMillis + samplingInterval;
/* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
* all serialReads at once, i.e. empty the buffer */ * all serialReads at once, i.e. empty the buffer */
while(Firmata.available()) while(Firmata.available())
Firmata.processInput(); Firmata.processInput();
/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over /* 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 * 60 bytes. use a timer to sending an event character every 4 ms to
* trigger the buffer to dump. */ * trigger the buffer to dump. */
/* ANALOGREAD - right after the event character, do all of the /* ANALOGREAD - right after the event character, do all of the
* analogReads(). These only need to be done every 4ms. */ * analogReads(). These only need to be done every 4ms. */
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
if( analogInputsToReport & (1 << analogPin) ) { if( analogInputsToReport & (1 << analogPin) ) {
Firmata.sendAnalog(analogPin, analogRead(analogPin)); Firmata.sendAnalog(analogPin, analogRead(analogPin));
} }
}
} }
}
} }

View File

@ -25,10 +25,39 @@
// LiquidCrystal constructor is called). // LiquidCrystal constructor is called).
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, 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 d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) : 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)
{ {
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[0] = d0;
_data_pins[1] = d1; _data_pins[1] = d1;
_data_pins[2] = d2; _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[5] = d5;
_data_pins[6] = d6; _data_pins[6] = d6;
_data_pins[7] = d7; _data_pins[7] = d7;
pinMode(_rs_pin, OUTPUT); 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); pinMode(_enable_pin, OUTPUT);
for (int i = 0; i < 8; i++) if (fourbitmode)
pinMode(_data_pins[i], OUTPUT); _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
else
command(0x38); // function set: 8 bits, 1 line, 5x8 dots _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
command(0x0C); // display control: turn display on, cursor off, no blinking
command(0x06); // entry mode set: increment automatically, display shift, right shift begin(16, 1);
clear();
} }
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) : if (lines > 1) {
_four_bit_mode(1), _rs_pin(rs), _rw_pin(rw), _enable_pin(enable) _displayfunction |= LCD_2LINE;
{ }
_data_pins[0] = d0; _numlines = lines;
_data_pins[1] = d1; _currline = 0;
_data_pins[2] = d2;
_data_pins[3] = d3; // 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);
}
pinMode(_rs_pin, OUTPUT); //put the LCD into 4 bit or 8 bit mode
pinMode(_rw_pin, OUTPUT); if (! (_displayfunction & LCD_8BITMODE)) {
pinMode(_enable_pin, OUTPUT); // this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
for (int i = 0; i < 4; i++)
pinMode(_data_pins[i], OUTPUT); // we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
command(0x28); // function set: 4 bits, 1 line, 5x8 dots delayMicroseconds(4500); // wait min 4.1ms
command(0x0C); // display control: turn display on, cursor off, no blinking
command(0x06); // entry mode set: increment automatically, display shift, right shift // 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(); 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() void LiquidCrystal::clear()
{ {
command(0x01); // clear display, set cursor position to zero command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); delayMicroseconds(2000); // this command takes a long time!
} }
void LiquidCrystal::home() void LiquidCrystal::home()
{ {
command(0x02); // set cursor position to zero command(LCD_RETURNHOME); // set cursor position to zero
delayMicroseconds(2000); 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 }; 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]));
} }
void LiquidCrystal::command(uint8_t value) { // 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);
}
// 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); send(value, LOW);
} }
void LiquidCrystal::write(uint8_t value) { inline void LiquidCrystal::write(uint8_t value) {
send(value, HIGH); 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) { void LiquidCrystal::send(uint8_t value, uint8_t mode) {
digitalWrite(_rs_pin, mode); digitalWrite(_rs_pin, mode);
digitalWrite(_rw_pin, LOW);
if (_four_bit_mode) { // if there is a RW pin indicated, set it low to Write
for (int i = 0; i < 4; i++) { if (_rw_pin != -1) {
digitalWrite(_data_pins[i], (value >> (i + 4)) & 0x01); digitalWrite(_rw_pin, LOW);
} }
digitalWrite(_enable_pin, HIGH); if (_displayfunction & LCD_8BITMODE) {
digitalWrite(_enable_pin, LOW); write8bits(value);
for (int i = 0; i < 4; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
}
digitalWrite(_enable_pin, HIGH);
digitalWrite(_enable_pin, LOW);
} else { } else {
for (int i = 0; i < 8; i++) { write4bits(value>>4);
digitalWrite(_data_pins[i], (value >> i) & 0x01); write4bits(value);
}
digitalWrite(_enable_pin, HIGH);
digitalWrite(_enable_pin, LOW);
} }
} }
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
}
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();
}

View File

@ -4,28 +4,101 @@
#include <inttypes.h> #include <inttypes.h>
#include "Print.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 { class LiquidCrystal : public Print {
public: public:
LiquidCrystal(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); LiquidCrystal(uint8_t rs, uint8_t enable,
LiquidCrystal(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t, uint8_t, uint8_t, uint8_t); 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 clear();
void home(); void home();
void setCursor(int, int);
/* void noDisplay();
void shiftDisplayLeft(); void display();
void shiftDisplayRight(); 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); virtual void write(uint8_t);
void command(uint8_t); void command(uint8_t);
private: private:
void send(uint8_t, uint8_t); void send(uint8_t, uint8_t);
void write4bits(uint8_t);
uint8_t _four_bit_mode; void write8bits(uint8_t);
void pulseEnable();
uint8_t _rs_pin; // LOW: command. HIGH: character. uint8_t _rs_pin; // LOW: command. HIGH: character.
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD. uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
uint8_t _enable_pin; // activated by a HIGH pulse. uint8_t _enable_pin; // activated by a HIGH pulse.
uint8_t _data_pins[8]; uint8_t _data_pins[8];
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines,_currline;
}; };
#endif #endif

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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> #include <LiquidCrystal.h>
// LiquidCrystal display with: // initialize the library with the numbers of the interface pins
// rs on pin 12 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// 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);
void setup() void setup() {
{ // set up the LCD's number of rows and columns:
lcd.begin(16, 2);
// Print a message to the LCD. // Print a message to the LCD.
lcd.print("hello, world!"); 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);
} }

View File

@ -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);
}

View File

@ -1,19 +1,47 @@
/* /*
* Displays text sent over the serial port (e.g. from the Serial Monitor) on LiquidCrystal Library - Serial Input
* an attached LCD.
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> #include <LiquidCrystal.h>
// LiquidCrystal display with: // initialize the library with the numbers of the interface pins
// rs on pin 12 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// 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);
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); Serial.begin(9600);
} }

View File

@ -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++;
}

View File

@ -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);
}
}
}
}

View File

@ -12,10 +12,24 @@ LiquidCrystal KEYWORD1
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
begin KEYWORD2
clear KEYWORD2 clear KEYWORD2
home KEYWORD2 home KEYWORD2
print KEYWORD2 print KEYWORD2
setCursor 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) # Constants (LITERAL1)

View File

@ -1,133 +1,268 @@
#include <avr/interrupt.h> /*
#include <wiring.h> Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
#include <Servo.h> Copyright (c) 2009 Michael Margolis. All right reserved.
/* This library is free software; you can redistribute it and/or
Servo.h - Hardware Servo Timer Library modify it under the terms of the GNU Lesser General Public
Author: Jim Studt, jim@federated.com License as published by the Free Software Foundation; either
Copyright (c) 2007 David A. Mellis. All right reserved. version 2.1 of the License, or (at your option) any later version.
This library is free software; you can redistribute it and/or This library is distributed in the hope that it will be useful,
modify it under the terms of the GNU Lesser General Public but WITHOUT ANY WARRANTY; without even the implied warranty of
License as published by the Free Software Foundation; either MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
version 2.1 of the License, or (at your option) any later version. Lesser General Public License for more details.
This library is distributed in the hope that it will be useful, You should have received a copy of the GNU Lesser General Public
but WITHOUT ANY WARRANTY; without even the implied warranty of License along with this library; if not, write to the Free Software
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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.
uint8_t Servo::attached9 = 0; Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
uint8_t Servo::attached10 = 0;
The methods are:
void Servo::seizeTimer1()
{ Servo - Class for manipulating servo motors connected to Arduino pins.
uint8_t oldSREG = SREG;
attach(pin ) - Attaches a servo motor to an i/o pin.
cli(); attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
TCCR1A = _BV(WGM11); /* Fast PWM, ICR1 is top */ default min is 544, max is 2400
TCCR1B = _BV(WGM13) | _BV(WGM12) /* Fast PWM, ICR1 is top */
| _BV(CS11) /* div 8 clock prescaler */ 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
OCR1A = 3000; read() - Gets the last written servo pulse width as an angle between 0 and 180.
OCR1B = 3000; readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
ICR1 = clockCyclesPerMicrosecond()*(20000L/8); // 20000 uS is a bit fast for the refresh, 20ms, but attached() - Returns true if there is a servo attached.
// it keeps us from overflowing ICR1 at 20MHz clocks detach() - Stops an attached servos from pulsing its i/o pin.
// That "/8" at the end is the prescaler.
#if defined(__AVR_ATmega8__) */
TIMSK &= ~(_BV(TICIE1) | _BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) );
#else #include <avr/interrupt.h>
TIMSK1 &= ~(_BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) ); #include <WProgram.h>
#endif
SREG = oldSREG; // undo cli() #include "Servo.h"
}
#define TICKS_PER_uS (clockCyclesPerMicrosecond() / 8) // number of timer ticks per microsecond with prescale of 8
void Servo::releaseTimer1() {}
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
#define NO_ANGLE (0xff) #define TRIM_DURATION (SERVOS_PER_TIMER/2) // compensation ticks to trim adjust for digitalWrite delays
Servo::Servo() : pin(0), angle(NO_ANGLE) {} #define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
uint8_t Servo::attach(int pinArg) 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)
return attach(pinArg, 544, 2400); #if defined(__AVR_ATmega1280__)
} typedef enum { _timer5, _timer1, _timer3, _timer4 } servoTimer_t; // this is the sequence for timer utilization on mega
#else
uint8_t Servo::attach(int pinArg, int min, int max) typedef enum { _timer1 } servoTimer_t; // this is the sequence for timer utilization on other controllers
{ #endif
if (pinArg != 9 && pinArg != 10) return 0;
uint8_t ServoCount = 0; // the total number of attached servos
min16 = min / 16;
max16 = max / 16; // convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((servoTimer_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
pin = pinArg; #define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
angle = NO_ANGLE; #define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
digitalWrite(pin, LOW); #define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
pinMode(pin, OUTPUT);
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
if (!attached9 && !attached10) seizeTimer1(); #define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
if (pin == 9) { /************ static functions common to all instances ***********************/
attached9 = 1;
TCCR1A = (TCCR1A & ~_BV(COM1A0)) | _BV(COM1A1); static inline void handle_interrupts(servoTimer_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
} {
if( Channel[timer] < 0 )
if (pin == 10) { *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
attached10 = 1; else{
TCCR1A = (TCCR1A & ~_BV(COM1B0)) | _BV(COM1B1); 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
return 1; }
}
Channel[timer]++; // increment to the next channel
void Servo::detach() if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
{ *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
// muck with timer flags if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
if (pin == 9) { digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
attached9 = 0; }
TCCR1A = TCCR1A & ~_BV(COM1A0) & ~_BV(COM1A1); else {
pinMode(pin, INPUT); // 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;
if (pin == 10) { else
attached10 = 0; *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
TCCR1A = TCCR1A & ~_BV(COM1B0) & ~_BV(COM1B1); Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
pinMode(pin, INPUT); }
} }
if (!attached9 && !attached10) releaseTimer1(); SIGNAL (TIMER1_COMPA_vect)
} {
handle_interrupts(_timer1, &TCNT1, &OCR1A);
void Servo::write(int angleArg) }
{
uint16_t p; #if defined(__AVR_ATmega1280__)
SIGNAL (TIMER3_COMPA_vect)
if (angleArg < 0) angleArg = 0; {
if (angleArg > 180) angleArg = 180; handle_interrupts(_timer3, &TCNT3, &OCR3A);
angle = angleArg; }
SIGNAL (TIMER4_COMPA_vect)
// 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, handle_interrupts(_timer4, &TCNT4, &OCR4A);
// 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; SIGNAL (TIMER5_COMPA_vect)
if (pin == 9) OCR1A = p; {
if (pin == 10) OCR1B = p; handle_interrupts(_timer5, &TCNT5, &OCR5A);
} }
#endif
uint8_t Servo::read()
{ static void initISR(servoTimer_t timer)
return angle; {
} if(timer == _timer1) {
TCCR1A = 0; // normal counting mode
uint8_t Servo::attached() TCCR1B = _BV(CS11); // set prescaler of 8
{ TCNT1 = 0; // clear the timer count
if (pin == 9 && attached9) return 1; #if defined(__AVR_ATmega8__)
if (pin == 10 && attached10) return 1; TIFR |= _BV(OCF1A); // clear any pending interrupts;
return 0; 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 ;
}

View File

@ -1,10 +1,6 @@
#ifndef Servo_h
#define Servo_h
/* /*
Servo.h - Hardware Servo Timer Library Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Author: Jim Studt, jim@federated.com Copyright (c) 2009 Michael Margolis. All right reserved.
Copyright (c) 2007 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public 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 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> #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 class Servo
{ {
private: public:
uint8_t pin; Servo();
uint8_t angle; // in degrees 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 min16; // minimum pulse, 16uS units (default is 34) uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150) void detach();
static void seizeTimer1(); void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
static void releaseTimer1(); void writeMicroseconds(int value); // Write pulse width in microseconds
static uint8_t attached9; int read(); // returns current pulse width as an angle between 0 and 180 degrees
static uint8_t attached10; int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
public: bool attached(); // return true if this servo is attached, otherwise false
Servo(); private:
uint8_t attach(int); uint8_t servoIndex; // index into the channel data for this servo
// pulse length for 0 degrees in microseconds, 544uS default int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH
// pulse length for 180 degrees in microseconds, 2400uS default int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
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();
}; };
#endif #endif

View File

@ -6,16 +6,18 @@
# Datatypes (KEYWORD1) # Datatypes (KEYWORD1)
####################################### #######################################
Servo KEYWORD1 Servo KEYWORD1
####################################### #######################################
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
attach KEYWORD2 attach KEYWORD2
detach KEYWORD2 detach KEYWORD2
write KEYWORD2 write KEYWORD2
read KEYWORD2 read KEYWORD2
attached KEYWORD2 attached KEYWORD2
writeMicroseconds KEYWORD2
readMicroseconds KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)

View File

@ -87,9 +87,9 @@ void twi_init(void)
It is 72 for a 16mhz Wiring board with 100kHz TWI */ It is 72 for a 16mhz Wiring board with 100kHz TWI */
// enable twi module, acks, and twi interrupt // 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_masterBuffer = (uint8_t*) calloc(TWI_BUFFER_LENGTH, sizeof(uint8_t));
twi_txBuffer = (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)); 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 // initialize buffer iteration vars
twi_masterBufferIndex = 0; 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 // build sla+w, slave device address + w bit
twi_slarw = TW_READ; twi_slarw = TW_READ;
twi_slarw |= address << 1; twi_slarw |= address << 1;
// send start condition // 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 // wait for read operation to complete
while(TWI_MRX == twi_state){ while(TWI_MRX == twi_state){
continue; continue;
} }
if (twi_masterBufferIndex < length) if (twi_masterBufferIndex < length)
length = twi_masterBufferIndex; length = twi_masterBufferIndex;
// copy twi buffer to data // copy twi buffer to data
for(i = 0; i < length; ++i){ for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[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 // build sla+w, slave device address + w bit
twi_slarw = TW_WRITE; twi_slarw = TW_WRITE;
twi_slarw |= address << 1; twi_slarw |= address << 1;
// send start condition // 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 // wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){ while(wait && (TWI_MTX == twi_state)){
continue; continue;
} }
if (twi_error == 0xFF) if (twi_error == 0xFF)
return 0; // success return 0; // success
else if (twi_error == TW_MT_SLA_NACK) else if (twi_error == TW_MT_SLA_NACK)
return 2; // error: address send, nack received return 2; // error: address send, nack received
else if (twi_error == TW_MT_DATA_NACK) else if (twi_error == TW_MT_DATA_NACK)
return 3; // error: data send, nack received return 3; // error: data send, nack received
else else
return 4; // other twi error return 4; // other twi error
} }
/* /*
@ -285,9 +290,9 @@ void twi_attachSlaveTxEvent( void (*function)(void) )
*/ */
void twi_reply(uint8_t ack) void twi_reply(uint8_t ack)
{ {
// transmit master read ready signal, with or without ack // transmit master read ready signal, with or without ack
if(ack){ if(ack){
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
}else{ }else{
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
} }