diff options
Diffstat (limited to 'msp430/libraries')
55 files changed, 5629 insertions, 0 deletions
diff --git a/msp430/libraries/IRremote/IRremote.cpp b/msp430/libraries/IRremote/IRremote.cpp new file mode 100644 index 0000000..18d0209 --- /dev/null +++ b/msp430/libraries/IRremote/IRremote.cpp @@ -0,0 +1,758 @@ +/* + * IRremote + * Version 0.11 August, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html + * + * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#include "IRremote.h" +#include "IRremoteInt.h" + +volatile irparams_t irparams; + +// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging. +// To use them, set DEBUG in IRremoteInt.h +// Normally macros are used for efficiency + +int MATCH(int measured, int desired) { + #ifdef DEBUG + Serial.print("Testing: "); + Serial.print(TICKS_LOW(desired), DEC); + Serial.print(" <= "); + Serial.print(measured, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired), DEC); + #endif + return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired); +} + +int MATCH_MARK(int measured_ticks, int desired_us) { + #ifdef DEBUG + Serial.print("Testing mark "); + Serial.print(measured_ticks * USECPERTICK, DEC); + Serial.print(" vs "); + Serial.print(desired_us, DEC); + Serial.print(": "); + Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); // SH 071112 + -> - + Serial.print(" <= "); + Serial.print(measured_ticks, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC); + #endif + return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS); // SH 071112 + -> - in TICKS_LOW +} + +int MATCH_SPACE(int measured_ticks, int desired_us) { + #ifdef DEBUG + Serial.print("Testing space "); + Serial.print(measured_ticks * USECPERTICK, DEC); + Serial.print(" vs "); + Serial.print(desired_us, DEC); + Serial.print(": "); + Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC); + Serial.print(" <= "); + Serial.print(measured_ticks, DEC); + Serial.print(" <= "); + Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC); // SH 071112 - -> + + #endif + return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS); // SH 071112 - -> + in TICKS_HIGH +} + +// Soojin Han: this function is for serial debug interface +void debug_print(const char *data) +{ + #ifdef DEBUG + delay(100); + Serial.println(data); + #endif +} + +void IRsend::sendNEC(unsigned long data, int nbits) +{ + enableIROut(38); + mark(NEC_HDR_MARK); + space(NEC_HDR_SPACE); + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + mark(NEC_BIT_MARK); + space(NEC_ONE_SPACE); + } + else { + mark(NEC_BIT_MARK); + space(NEC_ZERO_SPACE); + } + data <<= 1; + } + mark(NEC_BIT_MARK); + space(0); +} + +void IRsend::sendSony(unsigned long data, int nbits) { + enableIROut(40); + mark(SONY_HDR_MARK); + space(SONY_HDR_SPACE); + data = data << (32 - nbits); + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + mark(SONY_ONE_MARK); + space(SONY_HDR_SPACE); + } + else { + mark(SONY_ZERO_MARK); + space(SONY_HDR_SPACE); + } + data <<= 1; + } +} + +void IRsend::sendRaw(unsigned int buf[], int len, int hz) +{ + enableIROut(hz); + for (int i = 0; i < len; i++) { + if (i & 1) { + space(buf[i]); + } + else { + mark(buf[i]); + } + } + space(0); // Just to be sure +} + +// Note: first bit must be a one (start bit) +void IRsend::sendRC5(unsigned long data, int nbits) +{ + enableIROut(36); + data = data << (32 - nbits); + mark(RC5_T1); // First start bit + space(RC5_T1); // Second start bit + mark(RC5_T1); // Second start bit + for (int i = 0; i < nbits; i++) { + if (data & TOPBIT) { + space(RC5_T1); // 1 is space, then mark + mark(RC5_T1); + } + else { + mark(RC5_T1); + space(RC5_T1); + } + data <<= 1; + } + space(0); // Turn off at end +} + +// Caller needs to take care of flipping the toggle bit +void IRsend::sendRC6(unsigned long data, int nbits) +{ + enableIROut(36); + data = data << (32 - nbits); + mark(RC6_HDR_MARK); + space(RC6_HDR_SPACE); + mark(RC6_T1); // start bit + space(RC6_T1); + int t; + for (int i = 0; i < nbits; i++) { + if (i == 3) { + // double-wide trailer bit + t = 2 * RC6_T1; + } + else { + t = RC6_T1; + } + if (data & TOPBIT) { + mark(t); + space(t); + } + else { + space(t); + mark(t); + } + + data <<= 1; + } + space(0); // Turn off at end +} + + +void IRsend::mark(int time) { + // Sends an IR mark for the specified number of microseconds. + // The mark output is modulated at the PWM frequency. + TIMER_ENABLE_PWM; // Set SMCLK, Up mode + delayMicroseconds(time); +} + +/* Leave pin off for time (given in microseconds) */ +void IRsend::space(int time) { + // Sends an IR space for the specified number of microseconds. + // A space is no output, so the PWM output is disabled. + TIMER_DISABLE_PWM; // Set SMCLK, Stop mode + delayMicroseconds(time); +} + +// TODO: update the comments below + +void IRsend::enableIROut(int khz) { + // Enables IR output. The khz value controls the modulation frequency in kilohertz. + // The IR output will be on pin 3 (OC2B). + // This routine is designed for 36-40KHz; if you use it for other values, it's up to you + // to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) + // TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B + // controlling the duty cycle. + // There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) + // To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. + // A few hours staring at the ATmega documentation and this will all make sense. + // See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. + + + // Disable the Timer_A Interrupt (which is used for receiving IR) + TIMER_DISABLE_INTR; //Timer_A Overflow Interrupt + + TIMER_PIN_SELECT(); // P2.3 output and P2.3 option select (when TIMER_PWM_PIN is P2_3) + + pinMode(TIMER_PWM_PIN, OUTPUT); + digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low + + // TODO: update the comments below + + // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted + // WGM2 = 101: phase-correct PWM with OCRA as top + // CS2 = 000: no prescaling + // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. + TIMER_CONFIG_KHZ(khz); +} + +IRrecv::IRrecv(int recvpin) +{ + irparams.recvpin = recvpin; + irparams.blinkflag = 0; +} + +// initialization +void IRrecv::enableIRIn() { + _DINT(); // disable interrupts + // setup pulse clock timer interrupt + + //Prescale /8 (16M/8 = 0.5 microseconds per tick) + // Therefore, the timer interval can range from 0.5 to 128 microseconds + // depending on the reset value (255 to 0) + TIMER_CONFIG_NORMAL(); + + //Timer_A Overflow Interrupt Enable + TIMER_ENABLE_INTR; + + TIMER_RESET; + + _EINT(); // enable interrupts + + // initialize state machine variables + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; + + // set pin modes + pinMode(irparams.recvpin, INPUT); +} + +// enable/disable blinking of pin 13 on IR processing +void IRrecv::blink13(int blinkflag) +{ + irparams.blinkflag = blinkflag; + if (blinkflag) + pinMode(BLINKLED, OUTPUT); +} + +// TIMERA interrupt code to collect raw data. +// Widths of alternating SPACE, MARK are recorded in rawbuf. +// Recorded in ticks of 50 microseconds. +// rawlen counts the number of entries recorded so far. +// First entry is the SPACE between transmissions. +// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues. +// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts +__attribute__((interrupt(TIMER_INTR_NAME))) +void IRrecv::RecvIsr(void) +{ + TIMER_RESET; + //P2DIR |= BIT0 | BIT1 | BIT2; + // P2OUT ^= BIT2; + + uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); + + irparams.timer++; // One more 50us tick + if (irparams.rawlen >= RAWBUF) { + // Buffer overflow + irparams.rcvstate = STATE_STOP; + } + switch(irparams.rcvstate) { + case STATE_IDLE: // In the middle of a gap + //P2OUT |= BIT0; + //P2OUT &= ~BIT1; + //P2OUT &= ~BIT2; + + if (irdata == MARK) { + if (irparams.timer < GAP_TICKS) { + // Not big enough to be a gap. + irparams.timer = 0; + } + else { + // gap just ended, record duration and start recording transmission + irparams.rawlen = 0; + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_MARK; + } + } + break; + case STATE_MARK: // timing MARK + if (irdata == SPACE) { // MARK ended, record time + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_SPACE; + } + break; + case STATE_SPACE: // timing SPACE + if (irdata == MARK) { // SPACE just ended, record it + irparams.rawbuf[irparams.rawlen++] = irparams.timer; + irparams.timer = 0; + irparams.rcvstate = STATE_MARK; + } + else { // SPACE + if (irparams.timer > GAP_TICKS) { + // big SPACE, indicates gap between codes + // Mark current code as ready for processing + // Switch to STOP + // Don't reset timer; keep counting space width + irparams.rcvstate = STATE_STOP; + } + } + break; + case STATE_STOP: // waiting, measuring gap + if (irdata == MARK) { // reset gap timer + irparams.timer = 0; + } + break; + } + + if (irparams.blinkflag) { + if (irdata == MARK) { + BLINKLED_ON(); // turn pin 13 LED on + } + else { + BLINKLED_OFF(); // turn pin 13 LED off + } + } +} + +void IRrecv::resume() { + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; +} + + + +// Decodes the received IR message +// Returns 0 if no data ready, 1 if data ready. +// Results of decoding are stored in results +int IRrecv::decode(decode_results *results) { + results->rawbuf = irparams.rawbuf; + results->rawlen = irparams.rawlen; + + if (irparams.rcvstate != STATE_STOP) { + return ERR; + } + /* + #ifdef DEBUG + if (results->rawlen != 0){ + Serial.print("results->rawlen: "); + Serial.println(irparams.rawlen); + } + #endif + */ +#ifdef DEBUG + Serial.println("Attempting NEC decode"); +#endif + if (decodeNEC(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting Sony decode"); +#endif + if (decodeSony(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting RC5 decode"); +#endif + if (decodeRC5(results)) { + return DECODED; + } +#ifdef DEBUG + Serial.println("Attempting RC6 decode"); +#endif + if (decodeRC6(results)) { + return DECODED; + } + // decodeHash returns a hash on any input. + // Thus, it needs to be last in the list. + // If you add any decodes, add them before this. + if (decodeHash(results)) { + return DECODED; + } + // Throw away and start over + resume(); + debug_print("ERR in IRrecv::decode"); + return ERR; +} + +long IRrecv::decodeNEC(decode_results *results) { + long data = 0; + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) { + return ERR; + } + offset++; + // Check for repeat + if (irparams.rawlen == 4 && + MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) && + MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) { + results->bits = 0; + results->value = REPEAT; + results->decode_type = NEC; + return DECODED; + } + if (irparams.rawlen < 2 * NEC_BITS + 4) { + return ERR; + } + // Initial space + if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) { + return ERR; + } + offset++; + for (int i = 0; i < NEC_BITS; i++) { + if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) { + return ERR; + } + offset++; + if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) { + data = (data << 1) | 1; + } + else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) { + data <<= 1; + } + else { + return ERR; + } + offset++; + } + // Success + results->bits = NEC_BITS; + results->value = data; + results->decode_type = NEC; + return DECODED; +} + +long IRrecv::decodeSony(decode_results *results) { + long data = 0; + if (irparams.rawlen < 2 * SONY_BITS + 2) { + return ERR; + } + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) { + return ERR; + } + offset++; + + while (offset + 1 < irparams.rawlen) { + if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) { + break; + } + offset++; + if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) { + data = (data << 1) | 1; + } + else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) { + data <<= 1; + } + else { + return ERR; + } + offset++; + } + + // Success + results->bits = (offset - 1) / 2; + if (results->bits < 12) { + results->bits = 0; + return ERR; + } + results->value = data; + results->decode_type = SONY; + return DECODED; +} + +// Gets one undecoded level at a time from the raw buffer. +// The RC5/6 decoding is easier if the data is broken into time intervals. +// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1, +// successive calls to getRClevel will return MARK, MARK, SPACE. +// offset and used are updated to keep track of the current position. +// t1 is the time interval for a single bit in microseconds. +// Returns -1 for error (measured time interval is not a multiple of t1). +int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) { + if (*offset >= results->rawlen) { + // After end of recorded buffer, assume SPACE. + return SPACE; + } + int width = results->rawbuf[*offset]; + int val = ((*offset) % 2) ? MARK : SPACE; + int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS; + + int avail; + if (MATCH(width, t1 + correction)) { + avail = 1; + } + else if (MATCH(width, 2*t1 + correction)) { + avail = 2; + } + else if (MATCH(width, 3*t1 + correction)) { + avail = 3; + } + else { + return -1; + } + + (*used)++; + if (*used >= avail) { + *used = 0; + (*offset)++; + } +#ifdef DEBUG + if (val == MARK) { + Serial.println("MARK"); + } + else { + Serial.println("SPACE"); + } +#endif + return val; +} + +long IRrecv::decodeRC5(decode_results *results) { + if (irparams.rawlen < MIN_RC5_SAMPLES + 2) { + return ERR; + } + int offset = 1; // Skip gap space + long data = 0; + int used = 0; + // Get start bits + if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; + if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR; + if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR; + int nbits; + for (nbits = 0; offset < irparams.rawlen; nbits++) { + int levelA = getRClevel(results, &offset, &used, RC5_T1); + int levelB = getRClevel(results, &offset, &used, RC5_T1); + if (levelA == SPACE && levelB == MARK) { + // 1 bit + data = (data << 1) | 1; + } + else if (levelA == MARK && levelB == SPACE) { + // zero bit + data <<= 1; + } + else { + return ERR; + } + } + + // Success + results->bits = nbits; + results->value = data; + results->decode_type = RC5; + return DECODED; +} + +long IRrecv::decodeRC6(decode_results *results) { + if (results->rawlen < MIN_RC6_SAMPLES) { + return ERR; + } + int offset = 1; // Skip first space + // Initial mark + if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) { + return ERR; + } + offset++; + if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) { + return ERR; + } + offset++; + long data = 0; + int used = 0; + // Get start bit (1) + if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR; + if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR; + int nbits; + for (nbits = 0; offset < results->rawlen; nbits++) { + int levelA, levelB; // Next two levels + levelA = getRClevel(results, &offset, &used, RC6_T1); + if (nbits == 3) { + // T bit is double wide; make sure second half matches + if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR; + } + levelB = getRClevel(results, &offset, &used, RC6_T1); + if (nbits == 3) { + // T bit is double wide; make sure second half matches + if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR; + } + if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5 + // 1 bit + data = (data << 1) | 1; + } + else if (levelA == SPACE && levelB == MARK) { + // zero bit + data <<= 1; + } + else { + return ERR; // Error + } + } + // Success + results->bits = nbits; + results->value = data; + results->decode_type = RC6; + return DECODED; +} + +/* ----------------------------------------------------------------------- + * hashdecode - decode an arbitrary IR code. + * Instead of decoding using a standard encoding scheme + * (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value. + * + * The algorithm: look at the sequence of MARK signals, and see if each one + * is shorter (0), the same length (1), or longer (2) than the previous. + * Do the same with the SPACE signals. Hszh the resulting sequence of 0's, + * 1's, and 2's to a 32-bit value. This will give a unique value for each + * different code (probably), for most code systems. + * + * http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html + */ + +// Compare two tick values, returning 0 if newval is shorter, +// 1 if newval is equal, and 2 if newval is longer +// Use a tolerance of 20% +int IRrecv::compare(unsigned int oldval, unsigned int newval) { + if (newval < oldval * .8) { + return 0; + } + else if (oldval < newval * .8) { + return 2; + } + else { + return 1; + } +} + +// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param +#define FNV_PRIME_32 16777619 +#define FNV_BASIS_32 2166136261U + +/* Converts the raw code values into a 32-bit hash code. + * Hopefully this code is unique for each button. + * This isn't a "real" decoding, just an arbitrary value. + */ +long IRrecv::decodeHash(decode_results *results) { + // Require at least 6 samples to prevent triggering on noise + if (results->rawlen < 6) { + return ERR; + } + long hash = FNV_BASIS_32; + for (int i = 1; i+2 < results->rawlen; i++) { + int value = compare(results->rawbuf[i], results->rawbuf[i+2]); + // Add value into the hash + hash = (hash * FNV_PRIME_32) ^ value; + } + results->value = hash; + results->bits = 32; + results->decode_type = UNKNOWN; + return DECODED; +} + +/* Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand ) + +The Dish send function needs to be repeated 4 times, and the Sharp function +has the necessary repeat built in because of the need to invert the signal. + +Sharp protocol documentation: +http://www.sbprojects.com/knowledge/ir/sharp.htm + +Here are the LIRC files that I found that seem to match the remote codes +from the oscilloscope: + +Sharp LCD TV: +http://lirc.sourceforge.net/remotes/sharp/GA538WJSA + +DISH NETWORK (echostar 301): +http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx + +For the DISH codes, only send the last for characters of the hex. +i.e. use 0x1C10 instead of 0x0000000000001C10 which is listed in the +linked LIRC file. +*/ + +void IRsend::sendSharp(unsigned long data, int nbits) { + unsigned long invertdata = data ^ SHARP_TOGGLE_MASK; + enableIROut(38); + for (int i = 0; i < nbits; i++) { + if (data & 0x4000) { + mark(SHARP_BIT_MARK); + space(SHARP_ONE_SPACE); + } + else { + mark(SHARP_BIT_MARK); + space(SHARP_ZERO_SPACE); + } + data <<= 1; + } + + mark(SHARP_BIT_MARK); + space(SHARP_ZERO_SPACE); + delay(46); + for (int i = 0; i < nbits; i++) { + if (invertdata & 0x4000) { + mark(SHARP_BIT_MARK); + space(SHARP_ONE_SPACE); + } + else { + mark(SHARP_BIT_MARK); + space(SHARP_ZERO_SPACE); + } + invertdata <<= 1; + } + mark(SHARP_BIT_MARK); + space(SHARP_ZERO_SPACE); + delay(46); +} + +void IRsend::sendDISH(unsigned long data, int nbits) +{ + enableIROut(56); + mark(DISH_HDR_MARK); + space(DISH_HDR_SPACE); + for (int i = 0; i < nbits; i++) { + if (data & DISH_TOP_BIT) { + mark(DISH_BIT_MARK); + space(DISH_ONE_SPACE); + } + else { + mark(DISH_BIT_MARK); + space(DISH_ZERO_SPACE); + } + data <<= 1; + } +} + diff --git a/msp430/libraries/IRremote/IRremote.h b/msp430/libraries/IRremote/IRremote.h new file mode 100644 index 0000000..0a9f04f --- /dev/null +++ b/msp430/libraries/IRremote/IRremote.h @@ -0,0 +1,101 @@ +/* + * IRremote + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#ifndef IRremote_h +#define IRremote_h + +// The following are compile-time library options. +// If you change them, recompile the library. +// If DEBUG is defined, a lot of debugging output will be printed during decoding. +// TEST must be defined for the IRtest unittests to work. It will make some +// methods virtual, which will be slightly slower, which is why it is optional. +// #define DEBUG +// #define TEST + +// Results returned from the decoder +class decode_results { +public: + int decode_type; // NEC, SONY, RC5, UNKNOWN + unsigned long value; // Decoded value + int bits; // Number of bits in decoded value + volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks + int rawlen; // Number of records in rawbuf. +}; + +// Values for decode_type +#define NEC 1 +#define SONY 2 +#define RC5 3 +#define RC6 4 +#define DISH 5 +#define SHARP 6 +#define UNKNOWN -1 + +// Decoded value for NEC when a repeat code is received +#define REPEAT 0xffffffff + +// main class for receiving IR +class IRrecv +{ +public: + IRrecv(int recvpin); + void blink13(int blinkflag); + int decode(decode_results *results); + void enableIRIn(); + void resume(); +private: + // These are called by decode + int getRClevel(decode_results *results, int *offset, int *used, int t1); + long decodeNEC(decode_results *results); + long decodeSony(decode_results *results); + long decodeRC5(decode_results *results); + long decodeRC6(decode_results *results); + long decodeHash(decode_results *results); + int compare(unsigned int oldval, unsigned int newval); + static void RecvIsr(); +} +; + +// Only used for testing; can remove virtual for shorter code +#ifdef TEST +#define VIRTUAL virtual +#else +#define VIRTUAL +#endif + +class IRsend +{ +public: + IRsend() {} + void sendNEC(unsigned long data, int nbits); + void sendSony(unsigned long data, int nbits); + void sendRaw(unsigned int buf[], int len, int hz); + void sendRC5(unsigned long data, int nbits); + void sendRC6(unsigned long data, int nbits); + void sendDISH(unsigned long data, int nbits); + void sendSharp(unsigned long data, int nbits); + // private: + void enableIROut(int khz); + VIRTUAL void mark(int usec); + VIRTUAL void space(int usec); +} +; + +// Some useful constants + +#define USECPERTICK 50 +#define RAWBUF 76 // Length of raw duration buffer + +// Marks tend to be 100us too long, and spaces 100us too short +// when received due to sensor lag. +#define MARK_EXCESS 100 + +#endif diff --git a/msp430/libraries/IRremote/IRremoteInt.h b/msp430/libraries/IRremote/IRremoteInt.h new file mode 100644 index 0000000..15a6d85 --- /dev/null +++ b/msp430/libraries/IRremote/IRremoteInt.h @@ -0,0 +1,185 @@ +/* + * IRremote + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html + * + * Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers + * + * Interrupt code based on NECIRrcv by Joe Knapp + * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 + * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ + */ + +#ifndef IRremoteint_h +#define IRremoteint_h + +#include <Energia.h> + +// NOTE: launchpad with a M430G2553 + +#define IR_USE_TIMERA + +// Clock freq in kilohertz +// Defined because using F_CPU in TIMER_CONFIG_KHZ does not work. +// TIMER_CONFIG_KHZ does a calculation and using too large of a +// number causes overflow. +#define FOSC 16000 + +#ifdef F_CPU +#define SYSCLOCK F_CPU // main MSP430 clock +#else +#define SYSCLOCK 16000000 +#endif + +#define ERR 0 +#define DECODED 1 + +//#define DEBUG + +// TODO: edit these to match MSP430 + +// defines for setting and clearing register bits +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +// pulse parameters in usec +#define NEC_HDR_MARK 9000 +#define NEC_HDR_SPACE 4500 +#define NEC_BIT_MARK 560 +#define NEC_ONE_SPACE 1690 +#define NEC_ZERO_SPACE 560 +#define NEC_RPT_SPACE 2250 + +#define SONY_HDR_MARK 2400 +#define SONY_HDR_SPACE 600 +#define SONY_ONE_MARK 1200 +#define SONY_ZERO_MARK 600 +#define SONY_RPT_LENGTH 45000 + +#define RC5_T1 889 +#define RC5_RPT_LENGTH 46000 + +#define RC6_HDR_MARK 2666 +#define RC6_HDR_SPACE 889 +#define RC6_T1 444 +#define RC6_RPT_LENGTH 46000 + +#define SHARP_BIT_MARK 245 +#define SHARP_ONE_SPACE 1805 +#define SHARP_ZERO_SPACE 795 +#define SHARP_GAP 600000 +#define SHARP_TOGGLE_MASK 0x3FF +#define SHARP_RPT_SPACE 3000 + +#define DISH_HDR_MARK 400 +#define DISH_HDR_SPACE 6100 +#define DISH_BIT_MARK 400 +#define DISH_ONE_SPACE 1700 +#define DISH_ZERO_SPACE 2800 +#define DISH_RPT_SPACE 6200 +#define DISH_TOP_BIT 0x8000 + +#define SHARP_BITS 15 +#define DISH_BITS 16 + +#define TOLERANCE 25 // percent tolerance in measurements +#define LTOL (1.0 - TOLERANCE/100.) +#define UTOL (1.0 + TOLERANCE/100.) + +#define _GAP 5000 // Minimum map between transmissions +#define GAP_TICKS (_GAP/USECPERTICK) + +#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK)) +#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1)) + +#ifndef DEBUG +// SH 071112 this macros have a tolerance problem. +//#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us)) +//#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS) +//#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS) +// Debugging versions are in IRremote.cpp +#endif + +// receiver states +#define STATE_IDLE 2 +#define STATE_MARK 3 +#define STATE_SPACE 4 +#define STATE_STOP 5 + +// information for the interrupt handler +typedef struct { + uint8_t recvpin; // pin for IR data from detector + uint8_t rcvstate; // state machine + uint8_t blinkflag; // TRUE to enable blinking of GREEN_LED on IR processing + unsigned int timer; // state timer, counts 50uS ticks. + unsigned int rawbuf[RAWBUF]; // raw data + uint8_t rawlen; // counter of entries in rawbuf +} +irparams_t; + +// Defined in IRremote.cpp +extern volatile irparams_t irparams; + +// IR detector output is active low +#define MARK 0 +#define SPACE 1 + +#define TOPBIT 0x80000000 + +#define NEC_BITS 32 +#define SONY_BITS 12 +#define MIN_RC5_SAMPLES 11 +#define MIN_RC6_SAMPLES 1 + +#define TIMER_PWM_PIN P2_3 +// NOTE: TIMER_PIN_SELECT depends on TIMER_PWM_PIN +// P2DIR |= BIT3; // P2.3 output +// P2SEL |= BIT3; // P2.3 option select +#define TIMER_PIN_SELECT() ({ \ + P2DIR |= BIT3; \ + P2SEL |= BIT3; \ +}) + +// defines for Timer_A (16 bits) +// NOTE: Using A1 instead of A0 because A0 is used by Serial +#if defined(IR_USE_TIMERA) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TA1CTL = TASSEL_2 + MC_1) // SMCLK, Up mode +#define TIMER_DISABLE_PWM (TA1CTL = TASSEL_2 + MC_0) // SMCLK, Stop mode +#define TIMER_ENABLE_INTR ({ /*TA1CTL |= TAIE;*/ TA1CCTL0 |= CCIE;}) // SH 071112 +#define TIMER_DISABLE_INTR ({TA1CTL &= ~TAIE; TA1CCTL0 &= ~CCIE;}) +#define TIMER_INTR_NAME TIMER1_A0_VECTOR +#define TIMER_CONFIG_KHZ(val) ({ \ + TA1CCTL0 |= OUTMOD_4; \ + TA1CCR0 = FOSC/val/2; \ +}) + +// TODO: update TIMER_CONFIG_NORMAL +// need to alter the math? + +// TA1CCR0 = SYSCLOCK * USECPERTICK / 1000000; + +#define TIMER_CONFIG_NORMAL() ({ \ + TA1CTL = TASSEL_2 + MC_1; \ + TA1CCTL0 |= OUTMOD_4; \ + TA1CCR0 = SYSCLOCK * USECPERTICK / 1000000; \ + TA1R = 0; \ +}) +#endif + +#else // unknown timer +#error "Internal code configuration error, no known IR_USE_TIMER# defined\n" +#endif + +// defines for blinking the (Green) LED +// MSP430 launchpad also has RED_LED +#define GREEN_LED P1_0 +#define BLINKLED GREEN_LED +#define BLINKLED_ON() (digitalWrite(BLINKLED, HIGH)) +#define BLINKLED_OFF() (digitalWrite(BLINKLED, LOW)) + diff --git a/msp430/libraries/IRremote/LICENSE.txt b/msp430/libraries/IRremote/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/msp430/libraries/IRremote/LICENSE.txt @@ -0,0 +1,458 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/msp430/libraries/IRremote/examples/IRrecord/IRrecord.pde b/msp430/libraries/IRremote/examples/IRrecord/IRrecord.pde new file mode 100644 index 0000000..913d431 --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRrecord/IRrecord.pde @@ -0,0 +1,170 @@ +/* + * IRrecord: record and play back IR signals as a minimal + * An IR detector/demodulator must be connected to the input RECV_PIN. + * An IR LED must be connected to the output PWM pin 3. + * A button must be connected to the input BUTTON_PIN; this is the + * send button. + * A visible LED can be connected to STATUS_PIN to provide status. + * + * The logic is: + * If the button is pressed, send the IR code. + * If an IR code is received, record it. + * + * Version 0.11 September, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include <IRremote.h> + +int RECV_PIN = 11; +int BUTTON_PIN = 5; +int STATUS_PIN = 2; + +IRrecv irrecv(RECV_PIN); +IRsend irsend; + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver + pinMode(BUTTON_PIN, INPUT); + pinMode(STATUS_PIN, OUTPUT); +} + +// Storage for the recorded code +int codeType = -1; // The type of code +unsigned long codeValue; // The code value if not raw +unsigned int rawCodes[RAWBUF]; // The durations if raw +int codeLen; // The length of the code +int toggle = 0; // The RC5/6 toggle state + +// Stores the code for later playback +// Most of this code is just logging +void storeCode(void* v){ + decode_results *results = (decode_results *)v; +//void storeCode(decode_results *results) { + + codeType = results->decode_type; + int count = results->rawlen; + if (codeType == UNKNOWN) { + Serial.println("Received unknown code, saving as raw"); + codeLen = results->rawlen - 1; + // To store raw codes: + // Drop first value (gap) + // Convert from ticks to microseconds + // Tweak marks shorter, and spaces longer to cancel out IR receiver distortion + for (int i = 1; i <= codeLen; i++) { + if (i % 2) { + // Mark + rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS; + Serial.print(" m"); + } + else { + // Space + rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS; + Serial.print(" s"); + } + Serial.print(rawCodes[i - 1], DEC); + } + Serial.println(""); + } + else { + if (codeType == NEC) { + Serial.print("Received NEC: "); + if (results->value == REPEAT) { + // Don't record a NEC repeat value as that's useless. + Serial.println("repeat; ignoring."); + return; + } + } + else if (codeType == SONY) { + Serial.print("Received SONY: "); + } + else if (codeType == RC5) { + Serial.print("Received RC5: "); + } + else if (codeType == RC6) { + Serial.print("Received RC6: "); + } + else { + Serial.print("Unexpected codeType "); + Serial.print(codeType, DEC); + Serial.println(""); + } + Serial.println(results->value, HEX); + codeValue = results->value; + codeLen = results->bits; + } +} + +void sendCode(int repeat) { + if (codeType == NEC) { + if (repeat) { + irsend.sendNEC(REPEAT, codeLen); + Serial.println("Sent NEC repeat"); + } + else { + irsend.sendNEC(codeValue, codeLen); + Serial.print("Sent NEC "); + Serial.println(codeValue, HEX); + } + } + else if (codeType == SONY) { + irsend.sendSony(codeValue, codeLen); + Serial.print("Sent Sony "); + Serial.println(codeValue, HEX); + } + else if (codeType == RC5 || codeType == RC6) { + if (!repeat) { + // Flip the toggle bit for a new button press + toggle = 1 - toggle; + } + // Put the toggle bit into the code to send + codeValue = codeValue & ~(1 << (codeLen - 1)); + codeValue = codeValue | (toggle << (codeLen - 1)); + if (codeType == RC5) { + Serial.print("Sent RC5 "); + Serial.println(codeValue, HEX); + irsend.sendRC5(codeValue, codeLen); + } + else { + irsend.sendRC6(codeValue, codeLen); + Serial.print("Sent RC6 "); + Serial.println(codeValue, HEX); + } + } + else if (codeType == UNKNOWN /* i.e. raw */) { + // Assume 38 KHz + irsend.sendRaw(rawCodes, codeLen, 38); + Serial.println("Sent raw"); + } +} + +int lastButtonState; + +void loop() { + // If button pressed, send the code. + int buttonState = digitalRead(BUTTON_PIN); + if (lastButtonState == LOW && buttonState == HIGH) { + Serial.println("Released"); + irrecv.enableIRIn(); // Re-enable receiver + } + + if (buttonState==LOW) { + Serial.println("Pressed, sending"); + digitalWrite(STATUS_PIN, HIGH); + sendCode(lastButtonState == buttonState); + digitalWrite(STATUS_PIN, LOW); + delay(50); // Wait a bit between retransmissions + } + else if (irrecv.decode(&results)) { + digitalWrite(STATUS_PIN, HIGH); + storeCode(&results); + irrecv.resume(); // resume receiver + digitalWrite(STATUS_PIN, LOW); + } + lastButtonState = buttonState; +}
\ No newline at end of file diff --git a/msp430/libraries/IRremote/examples/IRrecvDemo/IRrecvDemo.pde b/msp430/libraries/IRremote/examples/IRrecvDemo/IRrecvDemo.pde new file mode 100644 index 0000000..14982d8 --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRrecvDemo/IRrecvDemo.pde @@ -0,0 +1,28 @@ +/* + * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include <IRremote.h> + +int RECV_PIN = 11; + +IRrecv irrecv(RECV_PIN); + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +void loop() { + if (irrecv.decode(&results)) { + Serial.println(results.value, HEX); + irrecv.resume(); // Receive the next value + } +}
diff --git a/msp430/libraries/IRremote/examples/IRrecvDump/IRrecvDump.pde b/msp430/libraries/IRremote/examples/IRrecvDump/IRrecvDump.pde new file mode 100644 index 0000000..61f200f --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRrecvDump/IRrecvDump.pde @@ -0,0 +1,74 @@ +/* + * IRremote: IRrecvDump - dump details of IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include <IRremote.h> + +int RECV_PIN = 11; + +IRrecv irrecv(RECV_PIN); + +decode_results results; + +void setup() +{ + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +// Dumps out the decode_results structure. +// Call this after IRrecv::decode() +// void * to work around compiler issue +void dump(void *v) { + decode_results *results = (decode_results *)v; +//void dump(decode_results *results) { + int count = results->rawlen; + if (results->decode_type == UNKNOWN) { + Serial.println("Could not decode message"); + } + else { + if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); + } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); + } + Serial.print("Raw ("); + Serial.print(count, DEC); + Serial.print("): "); + + for (int i = 0; i < count; i++) { + if ((i % 2) == 1) { + Serial.print(results->rawbuf[i]*USECPERTICK, DEC); + } + else { + Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); + } + Serial.print(" "); + } + Serial.println(""); +} + + +void loop() { + if (irrecv.decode(&results)) { + Serial.println(results.value, HEX); + dump(&results); + irrecv.resume(); // Receive the next value + } +}
diff --git a/msp430/libraries/IRremote/examples/IRrelay/IRrelay.pde b/msp430/libraries/IRremote/examples/IRrelay/IRrelay.pde new file mode 100644 index 0000000..170a184 --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRrelay/IRrelay.pde @@ -0,0 +1,85 @@ +/* + * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv + * An IR detector/demodulator must be connected to the input RECV_PIN. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include <IRremote.h> + +int RECV_PIN = 11; +int RELAY_PIN = 4; + +IRrecv irrecv(RECV_PIN); +decode_results results; + +// Dumps out the decode_results structure. +// Call this after IRrecv::decode() +// void * to work around compiler issue +void dump(void *v) { + decode_results *results = (decode_results *)v; +//void dump(decode_results *results) { + int count = results->rawlen; + if (results->decode_type == UNKNOWN) { + Serial.println("Could not decode message"); + } + else { + if (results->decode_type == NEC) { + Serial.print("Decoded NEC: "); + } + else if (results->decode_type == SONY) { + Serial.print("Decoded SONY: "); + } + else if (results->decode_type == RC5) { + Serial.print("Decoded RC5: "); + } + else if (results->decode_type == RC6) { + Serial.print("Decoded RC6: "); + } + Serial.print(results->value, HEX); + Serial.print(" ("); + Serial.print(results->bits, DEC); + Serial.println(" bits)"); + } + Serial.print("Raw ("); + Serial.print(count, DEC); + Serial.print("): "); + + for (int i = 0; i < count; i++) { + if ((i % 2) == 1) { + Serial.print(results->rawbuf[i]*USECPERTICK, DEC); + } + else { + Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); + } + Serial.print(" "); + } + Serial.println(""); +} + +void setup() +{ + pinMode(RELAY_PIN, OUTPUT); + pinMode(13, OUTPUT); + Serial.begin(9600); + irrecv.enableIRIn(); // Start the receiver +} + +int on = 0; +unsigned long last = millis(); + +void loop() { + if (irrecv.decode(&results)) { + // If it's been at least 1/4 second since the last + // IR received, toggle the relay + if (millis() - last > 250) { + on = !on; + digitalWrite(RELAY_PIN, on ? HIGH : LOW); + digitalWrite(13, on ? HIGH : LOW); + dump(&results); + } + last = millis(); + irrecv.resume(); // Receive the next value + } +}
diff --git a/msp430/libraries/IRremote/examples/IRsendDemo/IRsendDemo.pde b/msp430/libraries/IRremote/examples/IRsendDemo/IRsendDemo.pde new file mode 100644 index 0000000..d864c82 --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRsendDemo/IRsendDemo.pde @@ -0,0 +1,26 @@ +/* + * IRremote: IRsendDemo - demonstrates sending IR codes with IRsend + * An IR LED must be connected to Arduino PWM pin 3. + * Version 0.1 July, 2009 + * Copyright 2009 Ken Shirriff + * http://arcfn.com + */ + +#include <IRremote.h> + +IRsend irsend; + +void setup() +{ + Serial.begin(9600); +} + +void loop() { + if (Serial.read() != -1) { + for (int i = 0; i < 3; i++) { + irsend.sendSony(0xa90, 12); // Sony TV power code + delay(100); + } + } +} +
diff --git a/msp430/libraries/IRremote/examples/IRtest/IRtest.pde b/msp430/libraries/IRremote/examples/IRtest/IRtest.pde new file mode 100644 index 0000000..62743af --- /dev/null +++ b/msp430/libraries/IRremote/examples/IRtest/IRtest.pde @@ -0,0 +1,190 @@ +/*
+ * IRremote: IRtest unittest
+ * Version 0.1 July, 2009
+ * Copyright 2009 Ken Shirriff
+ * http://arcfn.com
+ *
+ * Note: to run these tests, edit IRremote/IRremote.h to add "#define TEST"
+ * You must then recompile the library by removing IRremote.o and restarting
+ * the arduino IDE.
+ */
+
+#include <IRremote.h>
+#include <IRremoteInt.h>
+
+// Dumps out the decode_results structure.
+// Call this after IRrecv::decode()
+// void * to work around compiler issue
+void dump(void *v) {
+ decode_results *results = (decode_results *)v;
+//void dump(decode_results *results) {
+ int count = results->rawlen;
+ if (results->decode_type == UNKNOWN) {
+ Serial.println("Could not decode message");
+ }
+ else {
+ if (results->decode_type == NEC) {
+ Serial.print("Decoded NEC: ");
+ }
+ else if (results->decode_type == SONY) {
+ Serial.print("Decoded SONY: ");
+ }
+ else if (results->decode_type == RC5) {
+ Serial.print("Decoded RC5: ");
+ }
+ else if (results->decode_type == RC6) {
+ Serial.print("Decoded RC6: ");
+ }
+ Serial.print(results->value, HEX);
+ Serial.print(" (");
+ Serial.print(results->bits, DEC);
+ Serial.println(" bits)");
+ }
+ Serial.print("Raw (");
+ Serial.print(count, DEC);
+ Serial.print("): ");
+
+ for (int i = 0; i < count; i++) {
+ if ((i % 2) == 1) {
+ Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
+ }
+ else {
+ Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
+ }
+ Serial.print(" ");
+ }
+ Serial.println("");
+}
+
+IRrecv irrecv(0);
+decode_results results;
+
+class IRsendDummy :
+public IRsend
+{
+public:
+ // For testing, just log the marks/spaces
+#define SENDLOG_LEN 128
+ int sendlog[SENDLOG_LEN];
+ int sendlogcnt;
+ IRsendDummy() :
+ IRsend() {
+ }
+ void reset() {
+ sendlogcnt = 0;
+ }
+ void mark(int time) {
+ sendlog[sendlogcnt] = time;
+ if (sendlogcnt < SENDLOG_LEN) sendlogcnt++;
+ }
+ void space(int time) {
+ sendlog[sendlogcnt] = -time;
+ if (sendlogcnt < SENDLOG_LEN) sendlogcnt++;
+ }
+ // Copies the dummy buf into the interrupt buf
+ void useDummyBuf() {
+ int last = SPACE;
+ irparams.rcvstate = STATE_STOP;
+ irparams.rawlen = 1; // Skip the gap
+ for (int i = 0 ; i < sendlogcnt; i++) {
+ if (sendlog[i] < 0) {
+ if (last == MARK) {
+ // New space
+ irparams.rawbuf[irparams.rawlen++] = (-sendlog[i] - MARK_EXCESS) / USECPERTICK;
+ last = SPACE;
+ }
+ else {
+ // More space
+ irparams.rawbuf[irparams.rawlen - 1] += -sendlog[i] / USECPERTICK;
+ }
+ }
+ else if (sendlog[i] > 0) {
+ if (last == SPACE) {
+ // New mark
+ irparams.rawbuf[irparams.rawlen++] = (sendlog[i] + MARK_EXCESS) / USECPERTICK;
+ last = MARK;
+ }
+ else {
+ // More mark
+ irparams.rawbuf[irparams.rawlen - 1] += sendlog[i] / USECPERTICK;
+ }
+ }
+ }
+ if (irparams.rawlen % 2) {
+ irparams.rawlen--; // Remove trailing space
+ }
+ }
+};
+
+IRsendDummy irsenddummy;
+
+void verify(unsigned long val, int bits, int type) {
+ irsenddummy.useDummyBuf();
+ irrecv.decode(&results);
+ Serial.print("Testing ");
+ Serial.print(val, HEX);
+ if (results.value == val && results.bits == bits && results.decode_type == type) {
+ Serial.println(": OK");
+ }
+ else {
+ Serial.println(": Error");
+ dump(&results);
+ }
+}
+
+void testNEC(unsigned long val, int bits) {
+ irsenddummy.reset();
+ irsenddummy.sendNEC(val, bits);
+ verify(val, bits, NEC);
+}
+void testSony(unsigned long val, int bits) {
+ irsenddummy.reset();
+ irsenddummy.sendSony(val, bits);
+ verify(val, bits, SONY);
+}
+void testRC5(unsigned long val, int bits) {
+ irsenddummy.reset();
+ irsenddummy.sendRC5(val, bits);
+ verify(val, bits, RC5);
+}
+void testRC6(unsigned long val, int bits) {
+ irsenddummy.reset();
+ irsenddummy.sendRC6(val, bits);
+ verify(val, bits, RC6);
+}
+
+void test() {
+ Serial.println("NEC tests");
+ testNEC(0x00000000, 32);
+ testNEC(0xffffffff, 32);
+ testNEC(0xaaaaaaaa, 32);
+ testNEC(0x55555555, 32);
+ testNEC(0x12345678, 32);
+ Serial.println("Sony tests");
+ testSony(0xfff, 12);
+ testSony(0x000, 12);
+ testSony(0xaaa, 12);
+ testSony(0x555, 12);
+ testSony(0x123, 12);
+ Serial.println("RC5 tests");
+ testRC5(0xfff, 12);
+ testRC5(0x000, 12);
+ testRC5(0xaaa, 12);
+ testRC5(0x555, 12);
+ testRC5(0x123, 12);
+ Serial.println("RC6 tests");
+ testRC6(0xfffff, 20);
+ testRC6(0x00000, 20);
+ testRC6(0xaaaaa, 20);
+ testRC6(0x55555, 20);
+ testRC6(0x12345, 20);
+}
+
+void setup()
+{
+ Serial.begin(9600);
+ test();
+}
+
+void loop() {
+}
diff --git a/msp430/libraries/IRremote/keywords.txt b/msp430/libraries/IRremote/keywords.txt new file mode 100644 index 0000000..7bf0f25 --- /dev/null +++ b/msp430/libraries/IRremote/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For IRremote +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +decode_results KEYWORD1 +IRrecv KEYWORD1 +IRsend KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +blink13 KEYWORD2 +decode KEYWORD2 +enableIRIn KEYWORD2 +resume KEYWORD2 +enableIROut KEYWORD2 +sendNEC KEYWORD2 +sendSony KEYWORD2 +sendRaw KEYWORD2 +sendRC5 KEYWORD2 +sendRC6 KEYWORD2 +# +####################################### +# Constants (LITERAL1) +####################################### + +NEC LITERAL1 +SONY LITERAL1 +RC5 LITERAL1 +RC6 LITERAL1 +UNKNOWN LITERAL1 +REPEAT LITERAL1 diff --git a/msp430/libraries/LiquidCrystal/LiquidCrystal.cpp b/msp430/libraries/LiquidCrystal/LiquidCrystal.cpp new file mode 100644 index 0000000..611113a --- /dev/null +++ b/msp430/libraries/LiquidCrystal/LiquidCrystal.cpp @@ -0,0 +1,309 @@ +#include "LiquidCrystal.h" + +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include "Arduino.h" + +// When the display powers up, it is configured as follows: +// +// 1. Display clear +// 2. Function set: +// DL = 1; 8-bit interface data +// N = 0; 1-line display +// F = 0; 5x8 dot character font +// 3. Display on/off control: +// D = 0; Display off +// C = 0; Cursor off +// B = 0; Blinking off +// 4. Entry mode set: +// I/D = 1; Increment by 1 +// S = 0; No shift +// +// Note, however, that resetting the Arduino doesn't reset the LCD, so we +// can't assume that its in that state when a sketch starts (and the +// LiquidCrystal constructor is called). + +LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) +{ + 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, 255, 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, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0); +} + +void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7) +{ + _rs_pin = rs; + _rw_pin = rw; + _enable_pin = enable; + + _data_pins[0] = d0; + _data_pins[1] = d1; + _data_pins[2] = d2; + _data_pins[3] = d3; + _data_pins[4] = d4; + _data_pins[5] = d5; + _data_pins[6] = d6; + _data_pins[7] = d7; + + pinMode(_rs_pin, OUTPUT); + // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin# + if (_rw_pin != 255) { + pinMode(_rw_pin, OUTPUT); + } + pinMode(_enable_pin, OUTPUT); + + if (fourbitmode) + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + else + _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; + +} + +void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + if (lines > 1) { + _displayfunction |= LCD_2LINE; + } + _numlines = lines; + _currline = 0; + + // for some 1 line displays you can select a 10 pixel high font + if ((dotsize != 0) && (lines == 1)) { + _displayfunction |= LCD_5x10DOTS; + } + + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40ms after power rises above 2.7V + // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 + delayMicroseconds(50000); + // Now we pull both RS and R/W low to begin commands + digitalWrite(_rs_pin, LOW); + digitalWrite(_enable_pin, LOW); + if (_rw_pin != 255) { + digitalWrite(_rw_pin, LOW); + } + + //put the LCD into 4 bit or 8 bit mode + if (! (_displayfunction & LCD_8BITMODE)) { + // this is according to the hitachi HD44780 datasheet + // figure 24, pg 46 + + // we start in 8bit mode, try to set 4 bit mode + write4bits(0x03); + delayMicroseconds(4500); // wait min 4.1ms + + // second try + write4bits(0x03); + delayMicroseconds(4500); // wait min 4.1ms + + // third go! + write4bits(0x03); + delayMicroseconds(150); + + // finally, set to 4-bit interface + write4bits(0x02); + } else { + // this is according to the hitachi HD44780 datasheet + // page 45 figure 23 + + // Send function set command sequence + command(LCD_FUNCTIONSET | _displayfunction); + delayMicroseconds(4500); // wait more than 4.1ms + + // second try + command(LCD_FUNCTIONSET | _displayfunction); + delayMicroseconds(150); + + // third go + command(LCD_FUNCTIONSET | _displayfunction); + } + + // finally, set # lines, font size, etc. + command(LCD_FUNCTIONSET | _displayfunction); + + // turn the display on with no cursor or blinking default + _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + display(); + + // clear it off + clear(); + + // Initialize to default text direction (for romance languages) + _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + // set the entry mode + command(LCD_ENTRYMODESET | _displaymode); + +} + +/********** high level commands, for the user! */ +void LiquidCrystal::clear() +{ + command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void LiquidCrystal::home() +{ + command(LCD_RETURNHOME); // set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void LiquidCrystal::setCursor(uint8_t col, uint8_t row) +{ + int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + if ( row >= _numlines ) { + row = _numlines-1; // we count rows starting w/0 + } + + command(LCD_SETDDRAMADDR | (col + row_offsets[row])); +} + +// Turn the display on/off (quickly) +void LiquidCrystal::noDisplay() { + _displaycontrol &= ~LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal::display() { + _displaycontrol |= LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void LiquidCrystal::noCursor() { + _displaycontrol &= ~LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal::cursor() { + _displaycontrol |= LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turn on and off the blinking cursor +void LiquidCrystal::noBlink() { + _displaycontrol &= ~LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal::blink() { + _displaycontrol |= LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void LiquidCrystal::scrollDisplayLeft(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} +void LiquidCrystal::scrollDisplayRight(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right +void LiquidCrystal::leftToRight(void) { + _displaymode |= LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void LiquidCrystal::rightToLeft(void) { + _displaymode &= ~LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void LiquidCrystal::autoscroll(void) { + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// 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); +} + +inline size_t LiquidCrystal::write(uint8_t value) { + send(value, HIGH); + return 1; // assume sucess +} + +/************ low level data pushing commands **********/ + +// write either command or data, with automatic 4/8-bit selection +void LiquidCrystal::send(uint8_t value, uint8_t mode) { + digitalWrite(_rs_pin, mode); + + // if there is a RW pin indicated, set it low to Write + if (_rw_pin != 255) { + digitalWrite(_rw_pin, LOW); + } + + if (_displayfunction & LCD_8BITMODE) { + write8bits(value); + } else { + write4bits(value>>4); + write4bits(value); + } +} + +void LiquidCrystal::pulseEnable(void) { + digitalWrite(_enable_pin, LOW); + delayMicroseconds(1); + digitalWrite(_enable_pin, HIGH); + delayMicroseconds(1); // enable pulse must be >450ns + digitalWrite(_enable_pin, LOW); + delayMicroseconds(100); // commands need > 37us to settle +} + +void LiquidCrystal::write4bits(uint8_t value) { + for (int i = 0; i < 4; i++) { + pinMode(_data_pins[i], OUTPUT); + digitalWrite(_data_pins[i], (value >> i) & 0x01); + } + + pulseEnable(); +} + +void LiquidCrystal::write8bits(uint8_t value) { + for (int i = 0; i < 8; i++) { + pinMode(_data_pins[i], OUTPUT); + digitalWrite(_data_pins[i], (value >> i) & 0x01); + } + + pulseEnable(); +} diff --git a/msp430/libraries/LiquidCrystal/LiquidCrystal.h b/msp430/libraries/LiquidCrystal/LiquidCrystal.h new file mode 100644 index 0000000..24ec5af --- /dev/null +++ b/msp430/libraries/LiquidCrystal/LiquidCrystal.h @@ -0,0 +1,106 @@ +#ifndef LiquidCrystal_h +#define LiquidCrystal_h + +#include <inttypes.h> +#include "Print.h" + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +class LiquidCrystal : public Print { +public: + LiquidCrystal(uint8_t rs, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); + LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); + LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + LiquidCrystal(uint8_t rs, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + + void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, + uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7); + + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS); + + void clear(); + void home(); + + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void leftToRight(); + void rightToLeft(); + void autoscroll(); + void noAutoscroll(); + + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); + virtual size_t write(uint8_t); + void command(uint8_t); + + using Print::write; +private: + void send(uint8_t, uint8_t); + void write4bits(uint8_t); + void write8bits(uint8_t); + void pulseEnable(); + + uint8_t _rs_pin; // LOW: command. HIGH: character. + uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD. + uint8_t _enable_pin; // activated by a HIGH pulse. + uint8_t _data_pins[8]; + + uint8_t _displayfunction; + uint8_t _displaycontrol; + uint8_t _displaymode; + + uint8_t _initialized; + + uint8_t _numlines,_currline; +}; + +#endif diff --git a/msp430/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.ino b/msp430/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.ino new file mode 100644 index 0000000..756d5b5 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/Autoscroll/Autoscroll.ino @@ -0,0 +1,83 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(16,2); +} + +void loop() { + // set the cursor to (0,0): + lcd.setCursor(0, 0); + // print from 0 to 9: + for (int thisChar = 0; thisChar < 10; thisChar++) { + lcd.print(thisChar); + delay(500); + } + + // set the cursor to (16,1): + lcd.setCursor(16,1); + // set the display to automatically scroll: + lcd.autoscroll(); + // print from 0 to 9: + for (int thisChar = 0; thisChar < 10; thisChar++) { + lcd.print(thisChar); + delay(500); + } + // turn off automatic scrolling + lcd.noAutoscroll(); + + // clear screen for the next loop: + lcd.clear(); +} + diff --git a/msp430/libraries/LiquidCrystal/examples/Blink/Blink.ino b/msp430/libraries/LiquidCrystal/examples/Blink/Blink.ino new file mode 100644 index 0000000..b0d2505 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/Blink/Blink.ino @@ -0,0 +1,71 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // Turn off the blinking cursor: + lcd.noBlink(); + delay(3000); + // Turn on the blinking cursor: + lcd.blink(); + delay(3000); +} + + diff --git a/msp430/libraries/LiquidCrystal/examples/Cursor/Cursor.ino b/msp430/libraries/LiquidCrystal/examples/Cursor/Cursor.ino new file mode 100644 index 0000000..8513ef7 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/Cursor/Cursor.ino @@ -0,0 +1,70 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // Turn off the cursor: + lcd.noCursor(); + delay(500); + // Turn on the cursor: + lcd.cursor(); + delay(500); +} + diff --git a/msp430/libraries/LiquidCrystal/examples/CustomCharacter/CustomCharacter.ino b/msp430/libraries/LiquidCrystal/examples/CustomCharacter/CustomCharacter.ino new file mode 100644 index 0000000..23fbe56 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/CustomCharacter/CustomCharacter.ino @@ -0,0 +1,147 @@ +/* + LiquidCrystal Library - Custom Characters + + Demonstrates how to add custom characters on an 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 "I <heart> Arduino!" and a little dancing man + to the LCD. + + The circuit: + ================================= + LCD pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + created21 Mar 2011 + by Tom Igoe + Based on Adafruit's example at + https://github.com/adafruit/SPI_VFD/blob/master/examples/createChar/createChar.pde + + This example code is in the public domain. + http://www.arduino.cc/en/Tutorial/LiquidCrystal + + Also useful: + http://icontexto.com/charactercreator/ + + */ + +// include the library code: +#include <LiquidCrystal.h> + +// initialize the library with the numbers of the interface pins +LiquidCrystal lcd(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +// make some custom characters: +byte heart[8] = { + 0b00000, + 0b01010, + 0b11111, + 0b11111, + 0b11111, + 0b01110, + 0b00100, + 0b00000 +}; + +byte smiley[8] = { + 0b00000, + 0b00000, + 0b01010, + 0b00000, + 0b00000, + 0b10001, + 0b01110, + 0b00000 +}; + +byte frownie[8] = { + 0b00000, + 0b00000, + 0b01010, + 0b00000, + 0b00000, + 0b00000, + 0b01110, + 0b10001 +}; + +byte armsDown[8] = { + 0b00100, + 0b01010, + 0b00100, + 0b00100, + 0b01110, + 0b10101, + 0b00100, + 0b01010 +}; + +byte armsUp[8] = { + 0b00100, + 0b01010, + 0b00100, + 0b10101, + 0b01110, + 0b00100, + 0b00100, + 0b01010 +}; +void setup() { + // create a new character + lcd.createChar(0, heart); + // create a new character + lcd.createChar(1, smiley); + // create a new character + lcd.createChar(2, frownie); + // create a new character + lcd.createChar(3, armsDown); + // create a new character + lcd.createChar(4, armsUp); + + // set up the lcd's number of columns and rows: + lcd.begin(16, 2); + // Print a message to the lcd. + lcd.print("I "); + lcd.write(0); + lcd.print(" Arduino! "); + lcd.write(1); + +} + +void loop() { + // read the potentiometer on A0: + int sensorReading = analogRead(A0); + // map the result to 200 - 1000: + int delayTime = map(sensorReading, 0, 1023, 200, 1000); + // set the cursor to the bottom row, 5th position: + lcd.setCursor(4, 1); + // draw the little man, arms down: + lcd.write(3); + delay(delayTime); + lcd.setCursor(4, 1); + // draw him arms up: + lcd.write(4); + delay(delayTime); +} + + + diff --git a/msp430/libraries/LiquidCrystal/examples/Display/Display.ino b/msp430/libraries/LiquidCrystal/examples/Display/Display.ino new file mode 100644 index 0000000..31289b4 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/Display/Display.ino @@ -0,0 +1,70 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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); + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // Turn off the display: + lcd.noDisplay(); + delay(500); + // Turn on the display: + lcd.display(); + delay(500); +} + diff --git a/msp430/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.ino b/msp430/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.ino new file mode 100644 index 0000000..f906cd4 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/HelloWorld/HelloWorld.ino @@ -0,0 +1,68 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + // Print a message to the LCD. + lcd.print("hello, world!"); +} + +void loop() { + // set the cursor to column 0, line 1 + // (note: line 1 is the second row, since counting begins with 0): + lcd.setCursor(0, 1); + // print the number of seconds since reset: + lcd.print(millis()/1000); +} + diff --git a/msp430/libraries/LiquidCrystal/examples/Scroll/Scroll.ino b/msp430/libraries/LiquidCrystal/examples/Scroll/Scroll.ino new file mode 100644 index 0000000..0da976d --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/Scroll/Scroll.ino @@ -0,0 +1,95 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + // Print a message to the LCD. + lcd.print("hello, world!"); + delay(1000); +} + +void loop() { + // scroll 13 positions (string length) to the left + // to move it offscreen left: + for (int positionCounter = 0; positionCounter < 13; positionCounter++) { + // scroll one position left: + lcd.scrollDisplayLeft(); + // wait a bit: + delay(150); + } + + // scroll 29 positions (string length + display length) to the right + // to move it offscreen right: + for (int positionCounter = 0; positionCounter < 29; positionCounter++) { + // scroll one position right: + lcd.scrollDisplayRight(); + // wait a bit: + delay(150); + } + + // scroll 16 positions (display length + string length) to the left + // to move it back to center: + for (int positionCounter = 0; positionCounter < 16; positionCounter++) { + // scroll one position left: + lcd.scrollDisplayLeft(); + // wait a bit: + delay(150); + } + + // delay at the end of the full loop: + delay(1000); + +} + diff --git a/msp430/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.ino b/msp430/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.ino new file mode 100644 index 0000000..f76d23d --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/SerialDisplay/SerialDisplay.ino @@ -0,0 +1,87 @@ +/* + LiquidCrystal Library - Serial Input + + Demonstrates the use a 16x2 LCD display. The LiquidCrystal + library works with all LCD displays that are compatible with the + Hitachi HD44780 driver. There are many of them out there, and you + can usually tell them by the 16-pin interface. + + This sketch displays text sent over the serial port + (e.g. from the Serial Monitor) on an attached LCD. + + The circuit: + ================================= + LCD pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 + * LCD R/W pin to ground + * 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup(){ + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + // initialize the serial communications: + Serial.begin(9600); +} + +void loop() +{ + // when characters arrive over the serial port... + if (Serial.available()) { + // wait a bit for the entire message to arrive + delay(100); + // clear the screen + lcd.clear(); + // read all the available characters + while (Serial.available() > 0) { + // display each character to the LCD + lcd.write(Serial.read()); + } + } +} diff --git a/msp430/libraries/LiquidCrystal/examples/TextDirection/TextDirection.ino b/msp430/libraries/LiquidCrystal/examples/TextDirection/TextDirection.ino new file mode 100644 index 0000000..9114197 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/TextDirection/TextDirection.ino @@ -0,0 +1,97 @@ + /* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +int thisChar = 'a'; + +void setup() { + // set up the LCD's number of columns and rows: + 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.write(thisChar); + // wait a second: + delay(1000); + // increment the letter: + thisChar++; +} + + + + + + + + diff --git a/msp430/libraries/LiquidCrystal/examples/setCursor/setCursor.ino b/msp430/libraries/LiquidCrystal/examples/setCursor/setCursor.ino new file mode 100644 index 0000000..131e810 --- /dev/null +++ b/msp430/libraries/LiquidCrystal/examples/setCursor/setCursor.ino @@ -0,0 +1,81 @@ +/* + 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 pin Connect to + --------------------------------- + 01 - GND GND, pot + 02 - VCC +5V, pot + 03 - Contrast Pot wiper + 04 - RS Pin8 (P2.0) + 05 - R/W GND + 06 - EN Pin9 (P2.1) + 07 - DB0 GND + 08 - DB1 GND + 09 - DB2 GND + 10 - DB3 GND + 11 - DB4 Pin10 (P2.2) + 12 - DB5 Pin11 (P2.3) + 13 - DB6 Pin12 (P2.4) + 14 - DB7 Pin13 (P2.5) + 15 - BL+ +5V + 16 - BL- GND + ================================= + + 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 22 Nov 2010 + by Tom Igoe + + This example code is in the public domain. + + 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(P2_0, P2_1, P2_2, P2_3, P2_4, P2_5); + +void setup() { + // set up the LCD's number of columns and rows: + lcd.begin(numCols,numRows); +} + +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.write(thisLetter); + delay(200); + } + } + } +} + + diff --git a/msp430/libraries/LiquidCrystal/keywords.txt b/msp430/libraries/LiquidCrystal/keywords.txt new file mode 100644 index 0000000..132845c --- /dev/null +++ b/msp430/libraries/LiquidCrystal/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For LiquidCrystal +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +LiquidCrystal KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +clear KEYWORD2 +home KEYWORD2 +print KEYWORD2 +setCursor KEYWORD2 +cursor KEYWORD2 +noCursor KEYWORD2 +blink KEYWORD2 +noBlink KEYWORD2 +display KEYWORD2 +noDisplay KEYWORD2 +autoscroll KEYWORD2 +noAutoscroll KEYWORD2 +leftToRight KEYWORD2 +rightToLeft KEYWORD2 +scrollDisplayLeft KEYWORD2 +scrollDisplayRight KEYWORD2 +createChar KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/msp430/libraries/MspFlash/MspFlash.cpp b/msp430/libraries/MspFlash/MspFlash.cpp new file mode 100644 index 0000000..3495e62 --- /dev/null +++ b/msp430/libraries/MspFlash/MspFlash.cpp @@ -0,0 +1,62 @@ +/* + MspFlash.h - Read/Write flash memory library for MSP430 Energia + Copyright (c) 2012 Peter Brier. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "MspFlash.h" +#include <msp430.h> +#include <Energia.h> + +// The Flash clock must be between 200 and 400 kHz to operate correctly +// TODO: calculate correct devider (0..64) depending on clock frequenct (F_CPU) +// Now we set F_CPU/64 is 250khz at F_CPU = 16MHz + +#define FLASHCLOCK FSSEL1+((F_CPU/400000L) & 63); // SCLK + +// erase flash, make sure pointer is in the segment you wish to erase, otherwise you may erase you program or some data +void MspFlashClass::erase(unsigned char *flash) +{ + disableWatchDog(); // Disable WDT + FCTL2 = FWKEY+FLASHCLOCK; // SMCLK/2 + FCTL3 = FWKEY; // Clear LOCK + FCTL1 = FWKEY+ERASE; //Enable segment erase + *flash = 0; // Dummy write, erase Segment + FCTL3 = FWKEY+LOCK; // Done, set LOCK + enableWatchDog(); // Enable WDT +} + +// load from memory, at segment boundary +void MspFlashClass::read(unsigned char *flash, unsigned char *dest, int len) +{ + while(len--) + *(dest++) = *(flash++); +} + +// save in to flash (at segment boundary) +void MspFlashClass::write(unsigned char *flash, unsigned char *src, int len) +{ + disableWatchDog(); // Disable WDT + FCTL2 = FWKEY+FLASHCLOCK; // SMCLK/2 + FCTL3 = FWKEY; // Clear LOCK + FCTL1 = FWKEY+WRT; // Enable write + while(len--) // Copy data + *(flash++) = *(src++); + FCTL1 = FWKEY; //Done. Clear WRT + FCTL3 = FWKEY+LOCK; // Set LOCK + enableWatchDog(); // Enable WDT +} + +MspFlashClass Flash; diff --git a/msp430/libraries/MspFlash/MspFlash.h b/msp430/libraries/MspFlash/MspFlash.h new file mode 100644 index 0000000..afa131c --- /dev/null +++ b/msp430/libraries/MspFlash/MspFlash.h @@ -0,0 +1,83 @@ +/* + MspFlash.h - Read/Write flash memory library for MSP430 Energia + Copyright (c) 2012 Peter Brier. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Provide access to the MSP430 flash memory controller. + All flash memory can be read, erased and written (except SEGMENT_A, the LOCK bits are not in the code, for a good reason). + Flash can only be erased per 512 byte segments (except the 4 special information segments, they are 64 bytes in size) + + The same flash locations can be written multiple times with new values, but flash bits can only be reset (from 1 to 0) and cannot + change to a 1 (you need to flash erase the whole segment) + + functions: + ~~~~~~~~~~ + erase(): Erase a flash segment, all bytes in the segment will read 0xFF after an erase + + read(): Read flash locations (actually just a proxy for memcpy) + + write(): Write flash locations (actually just a proxy for memcpy), the same location can be written multiple times, + but once a bit is reset, you cannot set it with a subsequent write, you need to flash the complete segment to do so. + + NOTE: you are flashing the program memory, you can modify EVERYTHING (program and data) this is usually not what you want. + Be carefull when flashing data. You may use SEG_B to SEG_D for normal use, they should not be filled by the compiler with code + or static data. If you wish to use main memory without wasting any space, you need to inform the linker NOT to use the required + segments. This is done in the linker script (this is not for the faint of heart). + + An alternative approach is to allocate a static variable with a size of AT LEAST 2 SEGMENTS in your program. + This makes sure there is at least ONE COMPLETE SEGMENT in this static variable, so there is no colleteral damage when you flash this + area. You need to find the pointer to the start of the next segment. There is a macro define to do this: SEGPTR(x) + A example that makes 2 segments available for flashing by allocating 3 segments of constant data: + + static const unsigned char flash[3*512] = {0}; + + Flash segments: |...SEGMENT-0...|...SEGMENT-1...|...SEGMENT-2...|...SEGMENT-3...|...SEGMENT-4...|...SEGMENT-5...| + Program output: |Program code.......|flash[3*512***********************************]|Other data.................| + Available segments: |-------------------------------|+++++++++++++++|+++++++++++++++|-------------------------------| + + +*/ + +#ifndef MSP_FLASH_h +#define MSP_FLASH_h + +#define SEGMENT_SIZE 512 // main segment size (smallest flasheable area) +#define INFO_SIZE 64 // information flah sizes (SEG_A to SEG_D) + +// segment addresses of 64 byte segments +#define SEGMENT_D ((unsigned char*)0x1000) +#define SEGMENT_C ((unsigned char*)0x1000+64) +#define SEGMENT_B ((unsigned char*)0x1000+128) +// #define SEGMENT_A ((unsigned char*)0x1000+192) // NOTE: Contains chip calibarion data, do not change or erase (the protection bit should prevent this happening) + +// Segment start addresses of 512 byte segments 0..63 (depending on device flash size) +#define SEGMENT(x) ( (unsigned char*) 0xFFFF - (x)*SEG_SIZE ) + +// return segment pointer inside variable. Note: return start of NEXT segment +#define SEGPTR(x) ( (unsigned char *) (((unsigned short)(&x)+512) & 0xFE00) ) + +class MspFlashClass +{ + public: + void erase(unsigned char *flash); + void read(unsigned char *flash, unsigned char *dest, int len); + void write(unsigned char *flash, unsigned char *src, int len); +}; + +extern MspFlashClass Flash; + +#endif // MSP_FLASH_h +
diff --git a/msp430/libraries/MspFlash/examples/flash_readwrite/flash_readwrite.ino b/msp430/libraries/MspFlash/examples/flash_readwrite/flash_readwrite.ino new file mode 100644 index 0000000..70f3674 --- /dev/null +++ b/msp430/libraries/MspFlash/examples/flash_readwrite/flash_readwrite.ino @@ -0,0 +1,151 @@ +/* + flas_readwrite.h - Read/Write flash memory library example for MSP430 Energia + Copyright (c) 2012 Peter Brier. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Provide access to the MSP430 flash memory controller. + All flash memory can be read, erased and written (except SEGMENT_A, the LOCK bits are not in the code, for a good reason). + Flash can only be erased per 512 byte segments (except the 4 special information segments, they are 64 bytes in size) + + The same flash locations can be written multiple times with new values, but flash bits can only be reset (from 1 to 0) and cannot + change to a 1 (you need to flash erase the whole segment) + + functions: + ~~~~~~~~~~ + erase(): Erase a flash segment, all bytes in the segment will read 0xFF after an erase + + read(): Read flash locations (actually just a proxy for memcpy) + + write(): Write flash locations (actually just a proxy for memcpy), the same location can be written multiple times, + but once a bit is reset, you cannot set it with a subsequent write, you need to flash the complete segment to do so. + + constants: + ~~~~~~~~~~ + SEGMENT_A // pointer to 64 byte flash segments + SEGMENT_B + SEGMENT_C + SEGMENT_D + + Macros: + ~~~~~~~ + SEGPTR(x) // Return pointer to first complete segment inside variable + SEGMENT(n) // Return pointer to start of segment n (n=0..63) + + + NOTE: you are flashing the program memory, you can modify EVERYTHING (program, data) this is usually not what you want. + Be carefull when flashing data. You may use SEG_B to SEG_D for normal use, they should not be filled by the compiler + If you wish to use main memory, you need to inform the linker NOT to use the segments you wish to use in the linker script + (this is not for the faint of heart). + + An alternative approach is to allocate a static variable with a size of AT LEAST 2 SEGMENTS in your program. + This makes sure there is at least ONE COMPLETE SEGMENT in this static variable, so there is no colleteral damage when you flash this + area. You need to find the pointer to the start of the next segment. There is a macro define to do this: SEGPTR(x) + A example that makes 2 segments available for flashing by allocating 3 segments of constant data: + + + Using the example: + ~~~~~~~~~~~~~~~~~~ + + On the launchpad; put the two UART jumpers in HARDWARE SERIAL position (horizontal position) and use the terminal window to connect + to the board (9600baud). + + 'e' Erase the flash segment + 'w' Write "Hello World" to the flash + 'r' Read the contents of the flash, and print as byte values and characters. stop at the first NULL byte + + - When you program the launchpad and read the flash, a single "0" character should be read (mem contains zero values) + Writing the flash before you have erased it is not possible (you cannot program OFF bits to ON bits) + - When you erase the flash, 0xFF values will be read back + - When you write the flash, "Hello World" will be read back + + +*/ + +#include "MspFlash.h" + + +// Two options to use for flash: One of the info flash segments, or a part of the program memory +// either define a bit of constant program memory, and pass a pointer to the start of a segment to the flash functions, + +//*** Option 1: use program memory, uncomment these lines and you have 512 bytes of flash available (1024 bytes allocated) **** +//const unsigned char data[2*SEGMENT_SIZE] = {0}; +//#define flash SEGPTR(data) +// + +//*** Option 2: use one of the 64 byte info segments, uncomment this line. Use SEGMENT_B, SEGMENT_C or SEGMENT_D (each 64 bytes, 192 bytes in total) +#define flash SEGMENT_D +// + + +void setup() +{ + // put your setup code here, to run once: + Serial.begin(9600); +} + +void loop() { + // put your main code here, to run repeatedly: + if ( Serial.available() ) + { + switch ( Serial.read() ) + { + case 'e': doErase(); break; + case 'r': doRead(); break; + case 'w': doWrite(); break; + case 10: + case 13: break; + default: doHelp(); + } + } +} + +void doRead() +{ + unsigned char p = 0; + int i=0; + Serial.println("Read:"); + do + { + Flash.read(flash+i, &p, 1); + Serial.write(p); + Serial.print(":"); + Serial.println(p); + } while ( p && (i++ < 16) ); + Serial.println("."); +} + + +void doErase() +{ + Serial.println("Erase"); + Flash.erase(flash); + Serial.println("Done."); +} + +void doWrite() +{ + Serial.println("Write"); + Flash.write(flash, (unsigned char*) "Hello World!" ,13); + Serial.println("Done."); +} + +void doHelp() +{ + int div = (F_CPU/400000L) & 63; + Serial.println("flash test: e, r, w"); + Serial.println(F_CPU); + Serial.println(div); +} diff --git a/msp430/libraries/MspFlash/keywords.txt b/msp430/libraries/MspFlash/keywords.txt new file mode 100644 index 0000000..72b8fc2 --- /dev/null +++ b/msp430/libraries/MspFlash/keywords.txt @@ -0,0 +1,29 @@ +#######################################
+# Syntax Coloring Map
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+Flash KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+erase KEYWORD2
+read KEYWORD2
+write KEYWORD2
+
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+SEGMENT KEYWORD2
+SEGMENT_A LITERAL1
+SEGMENT_B LITERAL1
+SEGMENT_C LITERAL1
+SEGMENT_D LITERAL1
+SEG_SIZE LITERAL1
+INFO_SIZE LITERAL1
+SEGPTR KEYWORD2
\ No newline at end of file diff --git a/msp430/libraries/SPI/SPI.cpp b/msp430/libraries/SPI/SPI.cpp new file mode 100644 index 0000000..bcb7323 --- /dev/null +++ b/msp430/libraries/SPI/SPI.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + * + * 2012-04-29 rick@kimballsoftware.com - added msp430 support. + * + */ + +#include <Energia.h> + +#include "SPI.h" + +SPIClass SPI; + +void SPIClass::begin() +{ + spi_initialize(); +} + +void SPIClass::end() +{ + spi_disable(); +} + +void SPIClass::setBitOrder(uint8_t bitOrder) +{ + spi_set_bitorder(bitOrder); +} + +void SPIClass::setDataMode(uint8_t mode) +{ + spi_set_datamode(mode); +} + +void SPIClass::setClockDivider(uint8_t rate) +{ + spi_set_divisor(rate); +} diff --git a/msp430/libraries/SPI/SPI.h b/msp430/libraries/SPI/SPI.h new file mode 100644 index 0000000..28b47eb --- /dev/null +++ b/msp430/libraries/SPI/SPI.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + * + * 2012-04-29 rick@kimballsoftware.com - added msp430 support. + * + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include <Energia.h> +#include <inttypes.h> + +#if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USI__) +#include "utility/spi_430.h" +#endif + +#define SPI_MODE0 0 +#define SPI_MODE1 1 +#define SPI_MODE2 2 +#define SPI_MODE3 4 + +class SPIClass { +public: + inline static uint8_t transfer(uint8_t _data); + + // SPI Configuration methods + + static void begin(); // Default + static void end(); + + static void setBitOrder(uint8_t); + static void setDataMode(uint8_t); + static void setClockDivider(uint8_t); + + inline static void attachInterrupt(); + inline static void detachInterrupt(); +}; + +extern SPIClass SPI; + +uint8_t SPIClass::transfer(uint8_t _data) { + return spi_send(_data); +} + +void SPIClass::attachInterrupt() { + /* undocumented in Arduino 1.0 */ +} + +void SPIClass::detachInterrupt() { + /* undocumented in Arduino 1.0 */ +} + +#endif diff --git a/msp430/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/msp430/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..66568ea --- /dev/null +++ b/msp430/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,146 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 8 + MOSI: pin 14/15 + MISO: pin 15/14 * need to level convert this + SCK: pin 7 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + + modified 2 May 2012 + Rick Kimball - changed pin # for msp430 + + */ + +// the sensor communicates using SPI, so include the library: +#include <SPI.h> + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; // 3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; // 16 least significant bits of pressure +const int TEMPERATURE = 0x21; // 16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 9; // P2.1 +const int chipSelectPin = 8; // P2.0 + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initialize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} diff --git a/msp430/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/msp430/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 0000000..d808a68 --- /dev/null +++ b/msp430/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,73 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 8 (SS pin) P2.0 + * SDI - to digital pin 14/15 (MOSI pin USI/USCI) P1.6/P1.7 + * CLK - to digital pin 7 (SCK pin) P1.5 + + created 10 Aug 2010 + by Tom Igoe + + modified 2 May 2012 - changed SS pin + by Rick Kimball + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// include the SPI library: +#include <SPI.h> + +// set pin 8 as the slave select for the digital pot: +const int slaveSelectPin = SS; + +void setup() { + // set the slaveSelectPin as an output: + pinMode (slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +int digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin,LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin,HIGH); +}
\ No newline at end of file diff --git a/msp430/libraries/SPI/keywords.txt b/msp430/libraries/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/msp430/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1
\ No newline at end of file diff --git a/msp430/libraries/SPI/utility/spi_430.h b/msp430/libraries/SPI/utility/spi_430.h new file mode 100644 index 0000000..262759a --- /dev/null +++ b/msp430/libraries/SPI/utility/spi_430.h @@ -0,0 +1,50 @@ +/*
+ * spi_430.h - common function declarations for different SPI implementations
+ *
+ * Copyright (c) 2012 by Rick Kimball <rick@kimballsoftware.com>
+ * spi abstraction api for msp430
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _SPI_430_H_
+#define _SPI_430_H_
+
+#if defined(__MSP430_HAS_USCI__)
+
+#define SPI_CLOCK_DIV1 1
+#define SPI_CLOCK_DIV2 2
+#define SPI_CLOCK_DIV4 4
+#define SPI_CLOCK_DIV8 8
+#define SPI_CLOCK_DIV16 16
+#define SPI_CLOCK_DIV32 32
+#define SPI_CLOCK_DIV64 64
+#define SPI_CLOCK_DIV128 128
+
+#elif defined(__MSP430_HAS_USI__)
+
+#define SPI_CLOCK_DIV1 0
+#define SPI_CLOCK_DIV2 USIDIV_1
+#define SPI_CLOCK_DIV4 USIDIV_2
+#define SPI_CLOCK_DIV8 USIDIV_3
+#define SPI_CLOCK_DIV16 USIDIV_4
+#define SPI_CLOCK_DIV32 USIDIV_5
+#define SPI_CLOCK_DIV64 USIDIV_6
+#define SPI_CLOCK_DIV128 USIDIV_7
+
+#else
+ #error "SPI not supported by hardware on this chip"
+#endif
+
+void spi_initialize(void);
+void spi_disable(void);
+uint8_t spi_send(const uint8_t);
+void spi_set_bitorder(const uint8_t);
+void spi_set_datamode(const uint8_t);
+void spi_set_divisor(const uint16_t clkdivider);
+
+#endif /*_SPI_430_H_*/
diff --git a/msp430/libraries/SPI/utility/usci_spi.cpp b/msp430/libraries/SPI/utility/usci_spi.cpp new file mode 100644 index 0000000..25d7157 --- /dev/null +++ b/msp430/libraries/SPI/utility/usci_spi.cpp @@ -0,0 +1,133 @@ +/**
+ * File: usci_spi.c - msp430 USCI SPI implementation
+ *
+ * Copyright (c) 2012 by Rick Kimball <rick@kimballsoftware.com>
+ * spi abstraction api for msp430
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <msp430.h>
+#include <stdint.h>
+#include "spi_430.h"
+
+#ifdef __MSP430_HAS_USCI__
+
+/**
+ * USCI flags for various the SPI MODEs
+ *
+ * Note: The msp430 UCCKPL tracks the CPOL value. However,
+ * the UCCKPH flag is inverted when compared to the CPHA
+ * value described in Motorola documentation.
+ */
+
+#define SPI_MODE_0 (UCCKPH) /* CPOL=0 CPHA=0 */
+#define SPI_MODE_1 (0) /* CPOL=0 CPHA=1 */
+#define SPI_MODE_2 (UCCKPL | UCCKPH) /* CPOL=1 CPHA=0 */
+#define SPI_MODE_3 (UCCKPL) /* CPOL=1 CPHA=1 */
+
+#define SPI_MODE_MASK (UCCKPL | UCCKPH)
+
+/**
+ * spi_initialize() - Configure USCI UCB0 for SPI mode
+ *
+ * P2.0 - CS (active low)
+ * P1.5 - SCLK
+ * P1.6 - MISO aka SOMI
+ * P1.7 - MOSI aka SIMO
+ *
+ */
+void spi_initialize(void)
+{
+ UCB0CTL1 = UCSWRST | UCSSEL_2; // Put USCI in reset mode, source USCI clock from SMCLK
+ UCB0CTL0 = SPI_MODE_0 | UCMSB | UCSYNC | UCMST; // Use SPI MODE 0 - CPOL=0 CPHA=0
+
+ P1OUT |= (BIT5 | BIT7); // SPI output pins low
+ P1SEL |= BIT5 | BIT6 | BIT7; // configure P1.5, P1.6, P1.7 for USCI
+ P1SEL2 |= BIT5 | BIT6 | BIT7; // more required SPI configuration
+
+ UCB0BR0 = SPI_CLOCK_DIV4 & 0xFF; // set initial speed to 4MHz
+ UCB0BR1 = (SPI_CLOCK_DIV4 >> 8 ) & 0xFF;
+
+ UCB0CTL1 &= ~UCSWRST; // release USCI for operation
+}
+
+/**
+ * spi_disable() - put USCI into reset mode
+ */
+void spi_disable(void)
+{
+ UCB0CTL1 |= UCSWRST; // Put USCI in reset mode
+}
+
+/**
+ * spi_send() - send a byte and recv response
+ */
+uint8_t spi_send(const uint8_t _data)
+{
+ while (!(UC0IFG & UCB0TXIFG))
+ ; // wait for previous tx to complete
+
+ UCB0TXBUF = _data; // setting TXBUF clears the TXIFG flag
+
+ while (!(UC0IFG & UCB0RXIFG))
+ ; // wait for an rx character?
+
+ return UCB0RXBUF; // reading clears RXIFG flag
+}
+
+/***SPI_MODE_0
+ * spi_set_divisor() - set new clock divider for USCI
+ *
+ * USCI speed is based on the SMCLK divided by BR0 and BR1
+ *
+ */
+void spi_set_divisor(const uint16_t clkdiv)
+{
+ UCB0CTL1 |= UCSWRST; // go into reset state
+ UCB0BR0 = clkdiv & 0xFF;
+ UCB0BR1 = (clkdiv >> 8 ) & 0xFF;
+ UCB0CTL1 &= ~UCSWRST; // release for operation
+}
+
+/**
+ * spi_set_bitorder(LSBFIRST=0 | MSBFIRST=1)
+ */
+void spi_set_bitorder(const uint8_t order)
+{
+ UCB0CTL1 |= UCSWRST; // go into reset state
+ UCB0CTL0 = (UCB0CTL0 & ~UCMSB) | ((order == 1 /*MSBFIRST*/) ? UCMSB : 0); /* MSBFIRST = 1 */
+ UCB0CTL1 &= ~UCSWRST; // release for operation
+}
+
+/**
+ * spi_set_datamode() - mode 0 - 3
+ */
+void spi_set_datamode(const uint8_t mode)
+{
+ UCB0CTL1 |= UCSWRST; // go into reset state
+ switch(mode) {
+ case 0: /* SPI_MODE0 */
+ UCB0CTL0 = (UCB0CTL0 & ~SPI_MODE_MASK) | SPI_MODE_0;
+ break;
+ case 1: /* SPI_MODE1 */
+ UCB0CTL0 = (UCB0CTL0 & ~SPI_MODE_MASK) | SPI_MODE_1;
+ break;
+ case 2: /* SPI_MODE2 */
+ UCB0CTL0 = (UCB0CTL0 & ~SPI_MODE_MASK) | SPI_MODE_2;
+ break;
+ case 4: /* SPI_MODE3 */
+ UCB0CTL0 = (UCB0CTL0 & ~SPI_MODE_MASK) | SPI_MODE_3;
+ break;
+ default:
+ break;
+ }
+ UCB0CTL1 &= ~UCSWRST; // release for operation
+}
+#else
+ //#error "Error! This device doesn't have a USCI peripheral"
+#endif
diff --git a/msp430/libraries/SPI/utility/usi_spi.cpp b/msp430/libraries/SPI/utility/usi_spi.cpp new file mode 100644 index 0000000..a03fd6a --- /dev/null +++ b/msp430/libraries/SPI/utility/usi_spi.cpp @@ -0,0 +1,164 @@ +/**
+ * File: usi_spi.c - msp430 USI SPI implementation
+ *
+ * Copyright (c) 2012 by Rick Kimball <rick@kimballsoftware.com>
+ * spi abstraction api for msp430
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ *
+ * 07-14-2012 - rick@kimballsoftware.com
+ * Fixed MODE2/MODE3 phase problems. Added logic to deal with USI5 errata.
+ */
+
+#include <msp430.h>
+#include <stdint.h>
+#include "spi_430.h"
+
+#ifdef __MSP430_HAS_USI__
+/**
+ * USI flags for various the SPI MODEs
+ *
+ * Note: The msp430 USICKPL tracks the CPOL value. However,
+ * the USICKPH flag is inverted when compared to the CPHA
+ * value described in Motorola documentation.
+ */
+#define SPI_DIV_MASK (USIDIV0 | USIDIV1 | USIDIV2)
+#define SPI_LSBMSB_MASK (USILSB)
+
+/* deal with USI5 errata see: document slaz061b */
+enum USI5 {
+ USI5_NO_ADJUST=0,
+ USI5_ADJUST=1,
+ USI5_SENT=2,
+};
+static enum USI5 bResetAdjust;
+
+/**
+ * spi_initialize() - Configure USI for SPI mode
+ *
+ * P2.0 - CS (active low)
+ * P1.5 - SCLK
+ * P1.6 - MOSI aka SIMO
+ * P1.7 - MISO aka SOMI
+ */
+
+void spi_initialize(void)
+{
+ USICTL0 |= USISWRST; // put USI in reset mode, source USI clock from SMCLK
+ USICTL0 |= USIPE5 | USIPE6 | USIPE7 | USIMST | USIOE;
+ USICKCTL |= USIDIV_2 | USISSEL_2; // default speed 4MHz 16MHz/4
+ USICTL1 = USICKPH; // SPI_MODE_0
+
+ P1OUT |= BIT5 | BIT6; // SPI OUTPUT PINS LOW
+ P1DIR = (P1DIR & ~BIT7) | BIT5 | BIT6; // configure P1.5, P1.6, P1.7 for USI
+
+ USICTL0 &= ~USISWRST; // release USI for operation
+
+ bResetAdjust = USI5_ADJUST;
+}
+
+void spi_disable(void) {
+ USICTL0 |= USISWRST; // put USI in reset mode
+}
+
+/**
+ * spi_send() - send a byte and recv response
+ */
+uint8_t spi_send(const uint8_t _data)
+{
+ USISRL = _data;
+
+ // SPI master generates one additional clock after module reset if USICKPH is set.
+ if ( bResetAdjust == USI5_ADJUST ) {
+ USICNT=7; // adjust first time send
+ bResetAdjust = USI5_SENT;
+ }
+ else {
+ USICNT = 8;
+ }
+
+ while (!(USICTL1 & USIIFG)) {
+ ; // wait for an USICNT to decrement to 0
+ }
+
+ return USISRL; // reading clears RXIFG flag
+}
+
+/**
+ * spi_set_divisor() - set new clock divider for USI
+ *
+ * There are a fixed set of valid values for clock divisors
+ * see the slau144 for details. DIV by 2/4/8 .. 128
+ */
+
+void spi_set_divisor(const uint16_t clkdiv)
+{
+ USICTL0 |= USISWRST; // put USI in reset mode
+ USICKCTL = (USICKCTL & ~SPI_DIV_MASK) | clkdiv;
+ USICTL0 &= ~USISWRST; // release for operation
+}
+
+/**
+ * spi_set_bitorder (enum LSBFIRST=0|MSBFIRST=1)
+ *
+ * Note: this should use the LSBFIRST/MSBFIRST defines however
+ * it doesn't to allow this code to compile without Energia.
+ *
+ */
+void spi_set_bitorder(const uint8_t order)
+{
+ USICTL0 |= USISWRST; // put USI in reset mode
+ USICTL0 = (USICTL0 & ~SPI_LSBMSB_MASK) | ((order == 1 /*MSBFIRST*/) ? 0 : USILSB); /* MSBFIRST = 1 */
+ USICTL0 &= ~USISWRST; // release for operation
+}
+
+/**
+ * spi_set_datamode() - Motorola SPI Mode 0 ... 3
+ *
+ * mode is really an enum SPI_MODE0 ... SPI_MODE3 as defined in
+ * the Energia header file.
+ */
+void spi_set_datamode(const uint8_t mode)
+{
+ USICTL0 |= USISWRST; // put USI in reset mode while we make changes
+ switch(mode) {
+ case 0: /* SPI_MODE0 */
+ USICKCTL &= ~USICKPL; /* CPOL=0 */
+ USICTL1 |= USICKPH; /* CPHA=0 */
+ break;
+
+ case 1: /* SPI_MODE1 */
+ USICKCTL &= ~USICKPL; /* CPOL=0 */
+ USICTL1 &= ~USICKPH; /* CPHA=1 */
+ break;
+
+ case 2: /* SPI_MODE2 */
+ USICKCTL |= USICKPL; /* CPOL=1 */
+ USICTL1 |= USICKPH; /* CPHA=0 */
+ break;
+
+ case 4: /* SPI_MODE3 */
+ USICKCTL |= USICKPL; /* CPOL=1 */
+ USICTL1 &= ~USICKPH; /* CPHA=1 */
+ break;
+
+ default:
+ break;
+ }
+ USICTL0 &= ~USISWRST; // release for operation
+
+ if ( USICTL1 & USICKPH ) {
+ if ( bResetAdjust != USI5_SENT ) {
+ bResetAdjust = USI5_ADJUST;
+ }
+ }
+ else {
+ bResetAdjust = USI5_NO_ADJUST;
+ }
+}
+#else
+ //#warning "Error! This device doesn't have a USI peripheral"
+#endif
diff --git a/msp430/libraries/Servo/Servo.cpp b/msp430/libraries/Servo/Servo.cpp new file mode 100644 index 0000000..8853dd9 --- /dev/null +++ b/msp430/libraries/Servo/Servo.cpp @@ -0,0 +1,207 @@ +/*
+ Servo.cpp - Interrupt driven Servo library for MSP430
+ Copyright (c) 2012 Petr Baudis. All right reserved.
+ Modified by Peter Brier 26-6-2012: Fixed timing/IRQ problem
+
+ Derived from:
+ Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
+ Copyright (c) 2009 Michael Margolis. All right reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "Energia.h"
+#include "Servo.h"
+
+#define F_TIMER (F_CPU/8L)
+#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to timer ticks (assumes prescale of 8)
+#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
+
+#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
+
+
+#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
+#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
+
+
+/************ static functions and data structures common to all instances ***********************/
+
+
+static servo_t servos[MAX_SERVOS]; // static array of servo structures
+static unsigned int ServoCount = 0; // the total number of attached servos
+
+static volatile int counter = 0; // Servo counter; -1 before first servo starts being serviced
+static volatile unsigned int totalWait = 0; // Total amount waited so far in the current period; after all servos, wait for the rest of REFRESH_INTERVAL
+
+#ifndef TIMERA0_VECTOR
+#define TIMERA0_VECTOR TIMER0_A0_VECTOR
+#endif /* TIMER0_A0_VECTOR */
+
+// Timer A0 interrupt service routine
+static void
+Timer_A(void)
+{
+ static unsigned long wait;
+ if (counter >= 0) {
+ /* Turn pulse off. */
+ digitalWrite(servos[counter].Pin.nbr, LOW);
+ }
+
+ /* Service next servo, while skipping any inactive servo records. */
+ do {
+ counter++;
+ } while (!servos[counter].Pin.isActive && counter < ServoCount);
+
+ // Counter range is 0-ServoCount, the last count is used to complete the REFRESH_INTERVAL
+ if (counter < ServoCount) {
+ /* Turn pulse on for the next servo. */
+ digitalWrite(servos[counter].Pin.nbr, HIGH);
+ /* And hold! */
+ totalWait += servos[counter].ticks;
+ CCR0 = servos[counter].ticks;
+ } else {
+ /* Wait for the remaining of REFRESH_INTERVAL. */
+ wait = usToTicks(REFRESH_INTERVAL) - totalWait;
+ totalWait = 0;
+ CCR0 = (wait < 1000 ? 1000 : wait);
+ counter = -1;
+ }
+}
+
+// Timer A0 interrupt service routine
+__attribute__((interrupt(TIMERA0_VECTOR)))
+static void
+Timer_A_int(void)
+{
+ Timer_A();
+}
+
+static boolean isTimerActive(void)
+{
+ // returns true if any servo is active
+ for(int i = 0; i < MAX_SERVOS; i++)
+ if (servos[i].Pin.isActive == true)
+ return true;
+ return false;
+}
+
+static void enableTimer(void)
+{
+ counter = -1;
+ totalWait = 0;
+
+ Timer_A(); // enable first servo
+
+ CCTL0 = CCIE; // CCR0 interrupt enabled
+ TACTL = TASSEL_2 + MC_1 + ID_3; // prescale SMCLK/8, upmode
+}
+
+static void disableTimer(void)
+{
+ // disable interrupt
+ CCTL0 = 0;
+ CCR0 = 0;
+}
+
+
+/****************** end of static functions ******************************/
+
+Servo::Servo()
+{
+ if( ServoCount < MAX_SERVOS) {
+ this->servoIndex = ServoCount++; // assign a servo index to this instance
+ servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // 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;
+
+ boolean timer_active = isTimerActive();
+ servos[this->servoIndex].Pin.isActive = true;
+ if (!timer_active)
+ enableTimer();
+ }
+ return this->servoIndex ;
+}
+
+void Servo::detach()
+{
+ servos[this->servoIndex].Pin.isActive = false;
+ if (!isTimerActive())
+ disableTimer();
+}
+
+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 < 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;
+ value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
+ servos[channel].ticks = value; // this is atomic on a 16bit uC, no need to disable Interrupts
+ }
+}
+
+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 = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
+ else
+ pulsewidth = 0;
+
+ return pulsewidth;
+}
+
+bool Servo::attached()
+{
+ return servos[this->servoIndex].Pin.isActive ;
+}
diff --git a/msp430/libraries/Servo/Servo.h b/msp430/libraries/Servo/Servo.h new file mode 100644 index 0000000..27a6a31 --- /dev/null +++ b/msp430/libraries/Servo/Servo.h @@ -0,0 +1,83 @@ +/* + Servo.h - Interrupt driven Servo library for MSP430 + Copyright (c) 2012 Petr Baudis. All right reserved. + Modified by Peter Brier 26-6-2012: Fixed timing/IRQ problem + + Derived from: + Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 + Copyright (c) 2009 Michael Margolis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef Servo_H +#define Servo_H + +#include <inttypes.h> + +/* + This version attempts to be compatible with the Arduino Servo library, + but supports only a single timer. So do not add too many servos. :-) + */ + +/* + Note that the Servo uses TIMER0_A, which cannot be used for other + purposes, e.g. for TimerSerial. + + XXX: Also, some pins reused by TIMER0_A may be affected by this + library, but I do not understand the datasheet enough regarding this. + Most likely, you should avoid PWM on pin 2? (And other stuff too?) + */ + +#define Servo_VERSION 2 // software version of this library + +#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo [uS] +#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo [uS] +#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached +#define REFRESH_INTERVAL 20000 // servos refresh period in microseconds + +#define MAX_SERVOS 8 + +#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 +{ +public: + Servo(); + uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure + uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes. + void detach(); + void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds + void writeMicroseconds(int value); // Write pulse width in microseconds + int read(); // returns current pulse width as an angle between 0 and 180 degrees + int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release) + bool attached(); // return true if this servo is attached, otherwise false +private: + uint8_t servoIndex; // index into the channel data for this servo + int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH + int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH +}; + +#endif diff --git a/msp430/libraries/Servo/examples/Knob/Knob.ino b/msp430/libraries/Servo/examples/Knob/Knob.ino new file mode 100644 index 0000000..886e107 --- /dev/null +++ b/msp430/libraries/Servo/examples/Knob/Knob.ino @@ -0,0 +1,22 @@ +// Controlling a servo position using a potentiometer (variable resistor) +// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott> + +#include <Servo.h> + +Servo myservo; // create servo object to control a servo + +int potpin = 0; // analog pin used to connect the potentiometer +int val; // variable to read the value from the analog pin + +void setup() +{ + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + +void loop() +{ + val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023) + val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180) + myservo.write(val); // sets the servo position according to the scaled value + delay(15); // waits for the servo to get there +} diff --git a/msp430/libraries/Servo/examples/Sweep/Sweep.ino b/msp430/libraries/Servo/examples/Sweep/Sweep.ino new file mode 100644 index 0000000..fb326e7 --- /dev/null +++ b/msp430/libraries/Servo/examples/Sweep/Sweep.ino @@ -0,0 +1,31 @@ +// Sweep +// by BARRAGAN <http://barraganstudio.com> +// This example code is in the public domain. + + +#include <Servo.h> + +Servo myservo; // create servo object to control a servo + // a maximum of eight servo objects can be created + +int pos = 0; // variable to store the servo position + +void setup() +{ + myservo.attach(9); // attaches the servo on pin 9 to the servo object +} + + +void loop() +{ + for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees + { // in steps of 1 degree + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } + for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees + { + myservo.write(pos); // tell servo to go to position in variable 'pos' + delay(15); // waits 15ms for the servo to reach the position + } +} diff --git a/msp430/libraries/Servo/keywords.txt b/msp430/libraries/Servo/keywords.txt new file mode 100644 index 0000000..ca5ba79 --- /dev/null +++ b/msp430/libraries/Servo/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map Servo +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Servo KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +read KEYWORD2 +attached KEYWORD2 +writeMicroseconds KEYWORD2 +readMicroseconds KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/msp430/libraries/Stepper/Stepper.cpp b/msp430/libraries/Stepper/Stepper.cpp new file mode 100644 index 0000000..5d6b5e5 --- /dev/null +++ b/msp430/libraries/Stepper/Stepper.cpp @@ -0,0 +1,220 @@ +/* + Stepper.cpp - - Stepper library for Wiring/Arduino - Version 0.4 + + Original library (0.1) by Tom Igoe. + Two-wire modifications (0.2) by Sebastian Gassner + Combination version (0.3) by Tom Igoe and David Mellis + Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley + + Drives a unipolar or bipolar stepper motor using 2 wires or 4 wires + + When wiring multiple stepper motors to a microcontroller, + you quickly run out of output pins, with each motor requiring 4 connections. + + By making use of the fact that at any time two of the four motor + coils are the inverse of the other two, the number of + control connections can be reduced from 4 to 2. + + A slightly modified circuit around a Darlington transistor array or an L293 H-bridge + connects to only 2 microcontroler pins, inverts the signals received, + and delivers the 4 (2 plus 2 inverted ones) output signals required + for driving a stepper motor. + + The sequence of control signals for 4 control wires is as follows: + + Step C0 C1 C2 C3 + 1 1 0 1 0 + 2 0 1 1 0 + 3 0 1 0 1 + 4 1 0 0 1 + + The sequence of controls signals for 2 control wires is as follows + (columns C1 and C2 from above): + + Step C0 C1 + 1 0 1 + 2 1 1 + 3 1 0 + 4 0 0 + + The circuits can be found at + +http://www.arduino.cc/en/Tutorial/Stepper + + + */ + + +#include "Arduino.h" +#include "Stepper.h" + +/* + * two-wire constructor. + * Sets which wires should control the motor. + */ +Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2) +{ + this->step_number = 0; // which step the motor is on + this->speed = 0; // the motor speed, in revolutions per minute + this->direction = 0; // motor direction + this->last_step_time = 0; // time stamp in ms of the last step taken + this->number_of_steps = number_of_steps; // total number of steps for this motor + + // Arduino pins for the motor control connection: + this->motor_pin_1 = motor_pin_1; + this->motor_pin_2 = motor_pin_2; + + // setup the pins on the microcontroller: + pinMode(this->motor_pin_1, OUTPUT); + pinMode(this->motor_pin_2, OUTPUT); + + // When there are only 2 pins, set the other two to 0: + this->motor_pin_3 = 0; + this->motor_pin_4 = 0; + + // pin_count is used by the stepMotor() method: + this->pin_count = 2; +} + + +/* + * constructor for four-pin version + * Sets which wires should control the motor. + */ + +Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4) +{ + this->step_number = 0; // which step the motor is on + this->speed = 0; // the motor speed, in revolutions per minute + this->direction = 0; // motor direction + this->last_step_time = 0; // time stamp in ms of the last step taken + this->number_of_steps = number_of_steps; // total number of steps for this motor + + // Arduino pins for the motor control connection: + this->motor_pin_1 = motor_pin_1; + this->motor_pin_2 = motor_pin_2; + this->motor_pin_3 = motor_pin_3; + this->motor_pin_4 = motor_pin_4; + + // setup the pins on the microcontroller: + pinMode(this->motor_pin_1, OUTPUT); + pinMode(this->motor_pin_2, OUTPUT); + pinMode(this->motor_pin_3, OUTPUT); + pinMode(this->motor_pin_4, OUTPUT); + + // pin_count is used by the stepMotor() method: + this->pin_count = 4; +} + +/* + Sets the speed in revs per minute + +*/ +void Stepper::setSpeed(long whatSpeed) +{ + this->step_delay = 60L * 1000L / this->number_of_steps / whatSpeed; +} + +/* + Moves the motor steps_to_move steps. If the number is negative, + the motor moves in the reverse direction. + */ +void Stepper::step(int steps_to_move) +{ + int steps_left = abs(steps_to_move); // how many steps to take + + // determine direction based on whether steps_to_mode is + or -: + if (steps_to_move > 0) {this->direction = 1;} + if (steps_to_move < 0) {this->direction = 0;} + + + // decrement the number of steps, moving one step each time: + while(steps_left > 0) { + // move only if the appropriate delay has passed: + if (millis() - this->last_step_time >= this->step_delay) { + // get the timeStamp of when you stepped: + this->last_step_time = millis(); + // increment or decrement the step number, + // depending on direction: + if (this->direction == 1) { + this->step_number++; + if (this->step_number == this->number_of_steps) { + this->step_number = 0; + } + } + else { + if (this->step_number == 0) { + this->step_number = this->number_of_steps; + } + this->step_number--; + } + // decrement the steps left: + steps_left--; + // step the motor to step number 0, 1, 2, or 3: + stepMotor(this->step_number % 4); + } + } +} + +/* + * Moves the motor forward or backwards. + */ +void Stepper::stepMotor(int thisStep) +{ + if (this->pin_count == 2) { + switch (thisStep) { + case 0: /* 01 */ + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, HIGH); + break; + case 1: /* 11 */ + digitalWrite(motor_pin_1, HIGH); + digitalWrite(motor_pin_2, HIGH); + break; + case 2: /* 10 */ + digitalWrite(motor_pin_1, HIGH); + digitalWrite(motor_pin_2, LOW); + break; + case 3: /* 00 */ + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, LOW); + break; + } + } + if (this->pin_count == 4) { + switch (thisStep) { + case 0: // 1010 + digitalWrite(motor_pin_1, HIGH); + digitalWrite(motor_pin_2, LOW); + digitalWrite(motor_pin_3, HIGH); + digitalWrite(motor_pin_4, LOW); + break; + case 1: // 0110 + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, HIGH); + digitalWrite(motor_pin_3, HIGH); + digitalWrite(motor_pin_4, LOW); + break; + case 2: //0101 + digitalWrite(motor_pin_1, LOW); + digitalWrite(motor_pin_2, HIGH); + digitalWrite(motor_pin_3, LOW); + digitalWrite(motor_pin_4, HIGH); + break; + case 3: //1001 + digitalWrite(motor_pin_1, HIGH); + digitalWrite(motor_pin_2, LOW); + digitalWrite(motor_pin_3, LOW); + digitalWrite(motor_pin_4, HIGH); + break; + } + } +} + +/* + version() returns the version of the library: +*/ +int Stepper::version(void) +{ + return 4; +} diff --git a/msp430/libraries/Stepper/Stepper.h b/msp430/libraries/Stepper/Stepper.h new file mode 100644 index 0000000..4094aee --- /dev/null +++ b/msp430/libraries/Stepper/Stepper.h @@ -0,0 +1,83 @@ +/* + Stepper.h - - Stepper library for Wiring/Arduino - Version 0.4 + + Original library (0.1) by Tom Igoe. + Two-wire modifications (0.2) by Sebastian Gassner + Combination version (0.3) by Tom Igoe and David Mellis + Bug fix for four-wire (0.4) by Tom Igoe, bug fix from Noah Shibley + + Drives a unipolar or bipolar stepper motor using 2 wires or 4 wires + + When wiring multiple stepper motors to a microcontroller, + you quickly run out of output pins, with each motor requiring 4 connections. + + By making use of the fact that at any time two of the four motor + coils are the inverse of the other two, the number of + control connections can be reduced from 4 to 2. + + A slightly modified circuit around a Darlington transistor array or an L293 H-bridge + connects to only 2 microcontroler pins, inverts the signals received, + and delivers the 4 (2 plus 2 inverted ones) output signals required + for driving a stepper motor. + + The sequence of control signals for 4 control wires is as follows: + + Step C0 C1 C2 C3 + 1 1 0 1 0 + 2 0 1 1 0 + 3 0 1 0 1 + 4 1 0 0 1 + + The sequence of controls signals for 2 control wires is as follows + (columns C1 and C2 from above): + + Step C0 C1 + 1 0 1 + 2 1 1 + 3 1 0 + 4 0 0 + + The circuits can be found at + http://www.arduino.cc/en/Tutorial/Stepper +*/ + +// ensure this library description is only included once +#ifndef Stepper_h +#define Stepper_h + +// library interface description +class Stepper { + public: + // constructors: + Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2); + Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4); + + // speed setter method: + void setSpeed(long whatSpeed); + + // mover method: + void step(int number_of_steps); + + int version(void); + + private: + void stepMotor(int this_step); + + int direction; // Direction of rotation + int speed; // Speed in RPMs + unsigned long step_delay; // delay between steps, in ms, based on speed + int number_of_steps; // total number of steps this motor can take + int pin_count; // whether you're driving the motor with 2 or 4 pins + int step_number; // which step the motor is on + + // motor pin numbers: + int motor_pin_1; + int motor_pin_2; + int motor_pin_3; + int motor_pin_4; + + long last_step_time; // time stamp in ms of when the last step was taken +}; + +#endif + diff --git a/msp430/libraries/Stepper/examples/MotorKnob/MotorKnob.ino b/msp430/libraries/Stepper/examples/MotorKnob/MotorKnob.ino new file mode 100644 index 0000000..d428186 --- /dev/null +++ b/msp430/libraries/Stepper/examples/MotorKnob/MotorKnob.ino @@ -0,0 +1,41 @@ +/* + * MotorKnob + * + * A stepper motor follows the turns of a potentiometer + * (or other sensor) on analog input 0. + * + * http://www.arduino.cc/en/Reference/Stepper + * This example code is in the public domain. + */ + +#include <Stepper.h> + +// change this to the number of steps on your motor +#define STEPS 100 + +// create an instance of the stepper class, specifying +// the number of steps of the motor and the pins it's +// attached to +Stepper stepper(STEPS, 8, 9, 10, 11); + +// the previous reading from the analog input +int previous = 0; + +void setup() +{ + // set the speed of the motor to 30 RPMs + stepper.setSpeed(30); +} + +void loop() +{ + // get the sensor value + int val = analogRead(0); + + // move a number of steps equal to the change in the + // sensor reading + stepper.step(val - previous); + + // remember the previous value of the sensor + previous = val; +}
\ No newline at end of file diff --git a/msp430/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino b/msp430/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino new file mode 100644 index 0000000..2dbb57d --- /dev/null +++ b/msp430/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino @@ -0,0 +1,44 @@ + +/* + Stepper Motor Control - one revolution + + This program drives a unipolar or bipolar stepper motor. + The motor is attached to digital pins 8 - 11 of the Arduino. + + The motor should revolve one revolution in one direction, then + one revolution in the other direction. + + + Created 11 Mar. 2007 + Modified 30 Nov. 2009 + by Tom Igoe + + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution + // for your motor + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11); + +void setup() { + // set the speed at 60 rpm: + myStepper.setSpeed(60); + // initialize the serial port: + Serial.begin(9600); +} + +void loop() { + // step one revolution in one direction: + Serial.println("clockwise"); + myStepper.step(stepsPerRevolution); + delay(500); + + // step one revolution in the other direction: + Serial.println("counterclockwise"); + myStepper.step(-stepsPerRevolution); + delay(500); +} + diff --git a/msp430/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino b/msp430/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino new file mode 100644 index 0000000..36d3299 --- /dev/null +++ b/msp430/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino @@ -0,0 +1,44 @@ + +/* + Stepper Motor Control - one step at a time + + This program drives a unipolar or bipolar stepper motor. + The motor is attached to digital pins 8 - 11 of the Arduino. + + The motor will step one step at a time, very slowly. You can use this to + test that you've got the four wires of your stepper wired to the correct + pins. If wired correctly, all steps should be in the same direction. + + Use this also to count the number of steps per revolution of your motor, + if you don't know it. Then plug that number into the oneRevolution + example to see if you got it right. + + Created 30 Nov. 2009 + by Tom Igoe + + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution + // for your motor + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11); + +int stepCount = 0; // number of steps the motor has taken + +void setup() { + // initialize the serial port: + Serial.begin(9600); +} + +void loop() { + // step one step: + myStepper.step(1); + Serial.print("steps:" ); + Serial.println(stepCount); + stepCount++; + delay(500); +} + diff --git a/msp430/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino b/msp430/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino new file mode 100644 index 0000000..dbd0f7f --- /dev/null +++ b/msp430/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino @@ -0,0 +1,49 @@ + +/* + Stepper Motor Control - speed control + + This program drives a unipolar or bipolar stepper motor. + The motor is attached to digital pins 8 - 11 of the Arduino. + A potentiometer is connected to analog input 0. + + The motor will rotate in a clockwise direction. The higher the potentiometer value, + the faster the motor speed. Because setSpeed() sets the delay between steps, + you may notice the motor is less responsive to changes in the sensor value at + low speeds. + + Created 30 Nov. 2009 + Modified 28 Oct 2010 + by Tom Igoe + + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution +// for your motor + + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11); + +int stepCount = 0; // number of steps the motor has taken + +void setup() { + // initialize the serial port: + Serial.begin(9600); +} + +void loop() { + // read the sensor value: + int sensorReading = analogRead(A0); + // map it to a range from 0 to 100: + int motorSpeed = map(sensorReading, 0, 1023, 0, 100); + // set the motor speed: + if (motorSpeed > 0) { + myStepper.setSpeed(motorSpeed); + // step 1/100 of a revolution: + myStepper.step(stepsPerRevolution/100); + } +} + + diff --git a/msp430/libraries/Stepper/keywords.txt b/msp430/libraries/Stepper/keywords.txt new file mode 100644 index 0000000..19a0fad --- /dev/null +++ b/msp430/libraries/Stepper/keywords.txt @@ -0,0 +1,28 @@ +####################################### +# Syntax Coloring Map For Test +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Stepper KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +step KEYWORD2 +setSpeed KEYWORD2 +version KEYWORD2 + +###################################### +# Instances (KEYWORD2) +####################################### +direction KEYWORD2 +speed KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/msp430/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino b/msp430/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino new file mode 100644 index 0000000..9c41c18 --- /dev/null +++ b/msp430/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -0,0 +1,87 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder +// by Nicholas Zambetti <http://www.zambetti.com> +// and James Tichenor <http://www.jamestichenor.net> + +// Demonstrates use of the Wire library reading data from the +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial communication at 9600bps +} + +int reading = 0; + +void loop() +{ + // step 1: instruct sensor to read echoes + Wire.beginTransmission(112); // transmit to device #112 (0x70) + // the address specified in the datasheet is 224 (0xE0) + // but i2c adressing uses the high 7 bits so it's 112 + Wire.write(byte(0x00)); // sets register pointer to the command register (0x00) + Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50) + // use 0x51 for centimeters + // use 0x52 for ping microseconds + Wire.endTransmission(); // stop transmitting + + // step 2: wait for readings to happen + delay(70); // datasheet suggests at least 65 milliseconds + + // step 3: instruct sensor to return a particular echo reading + Wire.beginTransmission(112); // transmit to device #112 + Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02) + Wire.endTransmission(); // stop transmitting + + // step 4: request reading from sensor + Wire.requestFrom(112, 2); // request 2 bytes from slave device #112 + + // step 5: receive reading from sensor + if(2 <= Wire.available()) // if two bytes were received + { + reading = Wire.read(); // receive high byte (overwrites previous reading) + reading = reading << 8; // shift high byte to be high 8 bits + reading |= Wire.read(); // receive low byte as lower 8 bits + Serial.println(reading); // print the reading + } + + delay(250); // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA0)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xAA)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(byte(0xA5)); + Wire.endTransmission(); + + Wire.beginTransmission(oldAddress); + Wire.write(byte(0x00)); + Wire.write(newAddress); + Wire.endTransmission(); +} + +*/ diff --git a/msp430/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino b/msp430/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino new file mode 100644 index 0000000..38da1c5 --- /dev/null +++ b/msp430/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino @@ -0,0 +1,39 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti <http://www.zambetti.com> +// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/> + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() +{ + Wire.beginTransmission(44); // transmit to device #44 (0x2c) + // device address is specified in datasheet + Wire.write(byte(0x00)); // sends instruction byte + Wire.write(val); // sends potentiometer value byte + Wire.endTransmission(); // stop transmitting + + val++; // increment value + if(val == 64) // if reached 64th position (max) + { + val = 0; // start over from lowest value + } + delay(500); +} + diff --git a/msp430/libraries/Wire/examples/master_reader/master_reader.ino b/msp430/libraries/Wire/examples/master_reader/master_reader.ino new file mode 100644 index 0000000..4124d7d --- /dev/null +++ b/msp430/libraries/Wire/examples/master_reader/master_reader.ino @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial for output +} + +void loop() +{ + Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 + + while(Wire.available()) // slave may send less than requested + { + char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + + delay(500); +} diff --git a/msp430/libraries/Wire/examples/master_writer/master_writer.ino b/msp430/libraries/Wire/examples/master_writer/master_writer.ino new file mode 100644 index 0000000..ccaa036 --- /dev/null +++ b/msp430/libraries/Wire/examples/master_writer/master_writer.ino @@ -0,0 +1,31 @@ +// Wire Master Writer +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() +{ + Wire.beginTransmission(4); // transmit to device #4 + Wire.write("x is "); // sends five bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} diff --git a/msp430/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/msp430/libraries/Wire/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 0000000..60dd4bd --- /dev/null +++ b/msp430/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,38 @@ +// Wire Slave Receiver +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(4); // join i2c bus with address #4 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) +{ + while(1 < Wire.available()) // loop through all but the last + { + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} diff --git a/msp430/libraries/Wire/examples/slave_sender/slave_sender.ino b/msp430/libraries/Wire/examples/slave_sender/slave_sender.ino new file mode 100644 index 0000000..d3b238a --- /dev/null +++ b/msp430/libraries/Wire/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ + Wire.begin(2); // join i2c bus with address #2 + Wire.onRequest(requestEvent); // register event +} + +void loop() +{ + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ + Wire.write("hello "); // respond with message of 6 bytes + // as expected by master +} diff --git a/msp430/libraries/Wire/keywords.txt b/msp430/libraries/Wire/keywords.txt new file mode 100644 index 0000000..12f129b --- /dev/null +++ b/msp430/libraries/Wire/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +send KEYWORD2 +receive KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + |
