Jump to content
43oh

roger430

Members
  • Content Count

    21
  • Joined

  • Last visited

Reputation Activity

  1. Like
    roger430 reacted to RobG in Large LCD Module   
    Pictured below is a similar (HD44104 based) display (or what's left of it ) As you can see, there are only shift registers on the board. Probably not worth the effort, but could be used for a project: MSP430F/16k RAM based LCD driver board with -18V supply.
     

  2. Like
    roger430 reacted to oPossum in Large LCD Module   
    It has four Sanyo LC79401 LCD drivers that can drive 80 columns, so maybe 320 pixel horizontal resolution.
    It has three Sanyo LC79300 LCD drivers that can drive 80 rows, so maybe 240 pixel vertical resolution.
    Those Sanyo chips are basically just shift registers with outputs specifically for LCD drive. The display has to be constantly refreshed by an external LCD controller or maybe a MCU. That would require 9600 bytes for frame buffer and a good chunk of MPU time.
     
    This may be the pinout...
    1 Vo
    2 Vee
    3 D3 to 79401
    4 D2 to 79401
    5 D1 to 79401
    6 D0 to 79401
    7 Gnd
    8 +5
    9 CL2 to 79401
    10 CL1 to 79430
    11 FLM (DIOB0)
    12 LED K
    13 LED A
    14 NC
     
    The Epson S1D13305 controller may work with this LCD. Getting one of these controller chips may be difficult.
  3. Like
    roger430 got a reaction from oPossum in Simple temperature display project   
    I know, I know, not another temperature project . This one is a little different in that it is very simple and uses readily available and inexpensive components. A $1.99 display from Electronic Goldmine: http://www.goldmine-elec-products.com/p ... ber=G15318
    or even cheaper at $1.85 from All Electronics: http://www.allelectronics.com/make-a-st ... LCD/1.html
    a $4.29 breadboard power supply that provides both 5.0vdc and 3.3vdc using and ordinary 9 - 12 vdc wall wart:
    http://www.ebay.com/itm/Perfect-High-Qu ... 3f0f10117f
    and a 74HC595N 8 bit shift register at a quantity of 5 for as low as $1.85 including shipping from Ebay.
    I started this project to learn more about ADC and the '595 8 bit shift register. Along the way I learned about integer to ascii conversion (necessary for displaying the temperature value). It was also just plain fun working with the LCD display.
     

    ' alt='>'>
     
    The schematic:

    ' alt='>'>
     
    Here's the code:

    //****************************************************************************** // A simple temperature display project utilizing a $1.99 surplus LCD display module, // a 74HC595N serial/parallel chip, TI Launchpad with an MSP430G2231 installed and a $4.29 // power supply from Ebay that provides 5vdc and 3.3vdc from a wall wart. // Code to obtain the temperature came directly from TI's example files, itoa function from // Google group comp.lang.c and display routines from RobG's "Using 3 wires to control // parallel LCD display with timotet's adaptation for the Wintek 1x24 char LCD display. // //R.G. Rioux - October, 2011 // // MSP430G2x31 Demo - ADC10, Sample A10 Temp and Convert to oC and oF // Description: A single sample is made on A10 with reference to internal // 1.5V Vref. Software sets ADC10SC to start sample and conversion - ADC10SC // automatically cleared at EOC. ADC10 internal oscillator/4 times sample // (64x) and conversion. In Mainloop MSP430 waits in LPM0 to save power until // ADC10 conversion complete, ADC10_ISR will force exit from any LPMx in // Mainloop on reti. Temperaure in oC stored in IntDegC, oF in IntDegF. // Uncalibrated temperature measured from device to device will vary with // slope and offset - please see datasheet. // ACLK = n/a, MCLK = SMCLK = default DCO ~1.2MHz, ADC10CLK = ADC10OSC/4 // // D. Dang // Texas Instruments Inc. // October 2010 // // MSP430G2x31 // ----------------- // /|\| XIN|- // | | | // --|RST XOUT|- // | | // |A10 | // ENABLE<--|P1.4 P1.6|-->DATA // CLOCK<--|P1.5 | _____ // | P1.7|-->RESET (for Wintek 1x24 Char Display) // // Built with CCS Version 4.2.4.00033 // R.G. Rioux October 2011 //****************************************************************************** #include "msp430g2231.h" #include #include //------------------------------------------------------------------------------ // Display related definitions //------------------------------------------------------------------------------ #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define initDisplay() sendInstruction(0x1C); sendInstruction(0x14); sendInstruction(0x28); sendInstruction(0x4F); sendInstruction(0xE0) #define clearDisplay() sendInstruction(0x01); sendInstruction(0xE3); _delay_cycles(2000) #define DATAPIN BIT6 // P1.6 #define CLOCKPIN BIT5 // P1.5 #define ENABLEPIN BIT4 // P1.4 #define RESETPIN BIT7 // P1.7 //------------------------------------------------------------------------------ // Display related functions and variables //------------------------------------------------------------------------------ void send(char data, char registerSelect); void sendStr(char data[], int length); void reset(void); char charIndex = 0; char bitCounter = 0; //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ char buffer[4]; long temp; long IntDegF; long IntDegC; //------------------------------------------------------------------------------ // itoa functions //------------------------------------------------------------------------------ static char *i2a(unsigned i, char *a, unsigned r); char *itoa(int i, char *a, int r); // main void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT _delay_cycles(100000); // Wait for display to settle DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1DIR |= ENABLEPIN + CLOCKPIN + DATAPIN + RESETPIN; // sets ENABLEPIN,CLOCKPIN,DATAPIN and RESETPIN to outputs P1OUT &= ~(CLOCKPIN + DATAPIN + RESETPIN); // sets CLOCKPIN,RESETPIN and DATAPIN low P1OUT |= ENABLEPIN; ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; __enable_interrupt(); // Enable interrupts. TACCR0 = 30; // Delay to allow Ref to settle TACCTL0 |= CCIE; // Compare-mode interrupt. TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode. LPM0; // Wait for delay. TACCTL0 &= ~CCIE; // Disable timer Interrupt __disable_interrupt(); reset(); // reset Wintek 1x24 LCD display initDisplay(); // initialize display sendStr("Temperature:", 12); while(1) { ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled // oF = ((A10/1024)*1500mV)-923mV)*1/1.97mV = A10*761/1024 - 468 temp = ADC10MEM; IntDegF = ((temp - 630) * 761) / 1024; // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278 temp = ADC10MEM; IntDegC = ((temp - 673) * 423) / 1024; sendInstruction(0xF2); // position cursor itoa (IntDegF, buffer, 10); // convert to ascii chars sendStr(buffer, strlen(buffer)); send(0xB0, 1); sendStr("F", 1); sendInstruction(0xF7); // position cursor itoa(IntDegC, buffer, 10); sendStr(buffer, strlen(buffer)); send(0xB0, 1); sendStr("C", 1); } } // ADC10 interrupt service routine #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR) } #pragma vector=TIMERA0_VECTOR __interrupt void ta0_isr(void) { TACTL = 0; LPM0_EXIT; // Exit LPM0 on return } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; _delay_cycles(3000); P1OUT |= ENABLEPIN; _delay_cycles(10000); P1OUT &= ~ENABLEPIN; } void sendStr(char string[], int size) { int charIndex = 0; while(charIndex < size) { sendData(string[charIndex]); charIndex++; } } void reset() { P1OUT &= ~RESETPIN; // RESETPIN low _delay_cycles(10000); P1OUT |= RESETPIN; } /* ** The following two functions together make up an itoa() ** implementation. Function i2a() is a 'private' function ** called by the public itoa() function. ** ** itoa() takes three arguments: ** 1) the integer to be converted, ** 2) a pointer to a character conversion buffer, ** 3) the radix for the conversion ** which can range between 2 and 36 inclusive ** range errors on the radix default it to base10 ** Code from Google group comp.lang.c */ static char *i2a(unsigned i, char *a, unsigned r) { if (i/r > 0) a = i2a(i/r,a,r); *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; return a+1; } char *itoa(int i, char *a, int r) { if ((r < 2) || (r > 36)) r = 10; if (i < 0) { *a = '-'; *i2a(-(unsigned)i,a+1,r) = 0; } else *i2a(i,a,r) = 0; return a; }
  4. Like
    roger430 reacted to oPossum in Using the internal temperature sensor   
    TI has some sample code for the internal temperature sensor, but it does not explain how to scale the ADC reading to useful units of degrees. Here is a step-by-step explanation of how to do the scaling with integer math for degrees C, K and F. There is also sample code to display the temperature on a Nokia 5110 LCD.

     
    The data sheet (SLAU144) has this formula for converting temperature in degrees Celsius to voltage.
    V = 0.00355 * C + 0.986

    What we need is a formula for converting voltage to temperature.
     
    Rewrite the data sheet fomula with temperature on the left
    0.00355 * C + 0.986 = V
     
    Divide both sides by 0.00355
    C + 277.75 = V / 0.00355
     
    Subtract 277.75 from both sides
    C = V / 0.00355 - 277.75
     
    Now we have a formula for converting voltage to temperature.
     
    The data sheet has this formula for converting voltage to ADC value, once again the opposite of what we neeed.

    For Vref- == 0
    A = 1023 * V / Vref
     
    Swap sides
    1023 * V / Vref = A
     
    Multiply by Vref
    1023 * V = A * Vref
     
    Divide by 1023
    V = A * Vref / 1023
     
    For a 1.5V reference
    V = A * 1.5 / 1023
     
    Simplify
    V = A * 0.0014663
     
    Substitute ADC conversion forumula for voltage in the temperature conversion formula.
    C = A * 0.0014663 / 0.00355 - 277.75
     
    Simplify
    C = A * 0.413 - 277.75
     
    Now we have a formula to convert ADC reading to temperature.
    It uses real numbers, so floating point math is required for good precision.
    Floating point is slow and requires more flash, so let's use integer math instead.
    Multiply by 65536 (2^16) and then divide by the same.
    C = (A * 27069 - 18202393) / 65536
     
    Use a right shift instead of divide. This will become a move of high word to low word.
    C = (A * 27069 - 18202393) >> 16
     
    Add 0.5 * 65536 to impove rounding.
    C = (A * 27069 - 18202393 + 32768) >> 16
     
    Simplify.
    C = (A * 27069 - 18169625) >> 16
     
    So that is how to go from ADC to degrees Celsius.
     
     
    To convert degrees C to degees K.
    K = C + 273.15
     
    Applied to ADC to degrees C conversion formula.
    K = (A * 27069 - 18169625) >> 16 - 273.15
     
    Implement with integer math by multiplying by 65536
    K = (A * 27069 - 18169625 - 17,901,158) >> 16
     
    Simplify.
    K = (A * 27069 - 268467) >> 16
     
    To convert degrees C to degrees F.
    F = C * 9 / 5 + 32
     
    Applied to voltage to degrees C conversion forumula
    F = (V / 0.00355 - 277.75) * 9 / 5 + 32
     
    Multiply by 9
    F = (V / 0.0003944 - 2499.75) / 5 + 32
     
    Divide by 5
    F = (V / 0.0019722 - 499.95) + 32
     
    Add 32
    F = V / 0.0019722 - 467.95
     
    Substitute ADC to voltage forumula
    F = A * 0.0014663 / 0.0019722 - 467.95
     
    Simplifiy
    F = A * 0.7435 - 467.95
     
    Convert to integer
    F = (A * 48724 - 30667156) >> 16
     
    Improve rounding
    F = (A * 48724 - 30667156 + 32768) >> 16
     
    Simplify
    F = (A * 48724 - 30634388) >> 16
     
    So now we have three formulas to convert ADC reading to degrees C, K and F using fast and compact integer math.
    C = (A * 27069 - 18169625) >> 16
    K = (A * 27069 - 268467) >> 16
    F = (A * 48724 - 30634388) >> 16
     
    Using the ADC value, rather than a different temperature scale, will ensure greatest precision for each temperature scale.
     
    main.c

    #include #include #include "lcd.h" #define ADC_SLEEP // Sleep during ADC conversion //#define SHOW_ADC // Show ADC raw and ADC millivolts // Print integer from -999 to 9999 using 12 x 16 font void print_int(int i, const unsigned y) { if(i < -999 || i > 9999) return; const unsigned neg = i < 0; if(neg) i = -i; div_t d; d.quot = i; unsigned x = 48; do { d = div(d.quot, 10); pd12(d.rem, x -= 12, y); } while(d.quot); if(neg) pd12(14, x -= 12, y); while(x) pd12(10, x -= 12, y); } // Print integer from 0 to 9999 vertically using 6 x 8 font void print_v(int i, unsigned x) { unsigned y = 4; unsigned c; if(i < 0 || i > 9999) return; div_t d; d.quot = i; do { d = div(d.quot, 10); c = d.rem + '0'; lcd_print((char *)&c, x, --y); } while(d.quot); c = ' '; while(y) lcd_print((char *)&c, x, --y); } void main(void) { unsigned adc; // ADC value int c, k, f; // Temperature in degrees C, K, and F unsigned mv; // ADC reading in millivolts // WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset // lcd_init(); // Initialize LCD lcd_clear(0); // pd12(15, 48, 0); // Degrees pd12(17, 59, 0); // F pd12(15, 48, 2); // Degrees pd12(16, 58, 2); // C pd12(15, 48, 4); // Degrees pd12(18, 59, 4); // K #ifdef SHOW_ADC // lcd_print("Am", 72, 4); // AD / mV lcd_print("DV", 72, 5); // #endif // // ADC10CTL0 = 0; // Configure ADC ADC10CTL1 = INCH_10 | ADC10DIV_3; // ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE; //ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE | REF2_5V; #ifdef ADC_SLEEP // ADC10CTL0 |= ADC10IE; // Enable ADC conversion complete interrupt #endif // // for(; { // for-ever #ifdef ADC_SLEEP // ADC10CTL0 |= (ENC | ADC10SC); // Begin ADC conversion __bis_SR_register(LPM0_bits + GIE); // Sleep until conversion complete #else // ADC10CTL0 &= ~ADC10IFG; // Clear conversion complete flag ADC10CTL0 |= (ENC | ADC10SC); // Begin ADC conversion while(!(ADC10CTL0 & ADC10IFG)); // Wait for conversion to complete #endif // // adc = ADC10MEM; // Read ADC // // Convert to temperature c = ((27069L * adc) - 18169625L) >> 16; // Vref = 1.5V //c = ((45115L * adc) - 18169625L) >> 16; // Vref = 2.5V // k = ((27069L * adc) - 268467L) >> 16; // Vref = 1.5V //k = ((45115L * adc) - 268467L) >> 16; // Vref = 2.5V // f = ((48724L * adc) - 30634388L) >> 16; // Vref = 1.5V //f = ((81206L * adc) - 30634388L) >> 16; // Vref = 2.5V // // Convert to millivolts mv = (96094L * adc + 32768) >> 16; // Vref = 1.5V //mv = (160156L * adc + 32768) >> 16; // Vref = 2.5V // // Display on LCD print_int(f, 0); // Degrees F print_int(c, 2); // Degrees C print_int(k, 4); // Degrees K // #ifdef SHOW_ADC // print_v(adc, 72); // ADC print_v(mv, 78); // ADC millivolts #endif // // //__delay_cycles(100000); // } // } #pragma vector = ADC10_VECTOR // ADC conversion complete interrupt __interrupt void ADC10_ISR(void) // { // __bic_SR_register_on_exit(LPM0_bits); // Wakeup main code } //
     
    lcd.h

    typedef enum { lcd_command = 0, // Array of one or more commands lcd_data = 1, // Array of one or more bytes of data lcd_data_repeat = 2 // One byte of data repeated } lcd_cmd_type; void lcd_send(const unsigned char *cmd, unsigned len, const lcd_cmd_type type); void lcd_home(void); void lcd_pos(unsigned char x, unsigned char y); void lcd_clear(unsigned char x); void lcd_init(void); void lcd_print(char *s, unsigned x, unsigned y); void pd12(unsigned n, unsigned x, unsigned y);
     
    lcd.c

    #include #include "lcd.h" //static const unsigned TXD = BIT1; static const unsigned RXD = BIT2; static const unsigned SWITCH = BIT3; static const unsigned LCD_CLK = BIT5; static const unsigned LCD_BACKLIGHT = BIT6; static const unsigned LCD_DATA = BIT7; static const unsigned LCD_DC = BIT0; // PORT2 static const unsigned LCD_CE = BIT1; // PORT2 void lcd_send(const unsigned char *cmd, unsigned len, const lcd_cmd_type type) { register unsigned mask; P2OUT &= ~LCD_CE; do { mask = 0x0080; do { if(*cmd & mask) { P1OUT &= ~LCD_CLK; P1OUT |= LCD_DATA; } else { P1OUT &= ~(LCD_CLK | LCD_DATA); } P1OUT |= LCD_CLK; mask >>= 1; } while(!(mask & 1)); if(!type) P2OUT &= ~LCD_DC; if(*cmd & mask) { P1OUT &= ~LCD_CLK; P1OUT |= LCD_DATA; } else { P1OUT &= ~(LCD_CLK | LCD_DATA); } P1OUT |= LCD_CLK; P2OUT |= LCD_DC; if(!(type & 2)) ++cmd; } while(--len); P2OUT |= LCD_CE; } static const unsigned char home[] = { 0x40, 0x80 }; void lcd_home(void) { lcd_send(home, sizeof(home), lcd_command); } void lcd_pos(unsigned char x, unsigned char y) { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 | y; lcd_send(c, sizeof(c), lcd_command); } void lcd_clear(unsigned char x) { lcd_home(); lcd_send(&x, 504, lcd_data_repeat); lcd_home(); } void lcd_init(void) { static const unsigned char init[] = { 0x20 + 0x01, // function set - extended instructions enabled //0x80 + 64, // set vop (contrast) 0 - 127 0x80 + 66, // set vop (contrast) 0 - 127 0x04 + 0x02, // temperature control 0x10 + 0x03, // set bias system 0x20 + 0x00, // function set - chip active, horizontal addressing, basic instructions 0x08 + 0x04 // display control - normal mode }; P1REN = RXD | SWITCH; P1DIR = LCD_CLK | LCD_BACKLIGHT | LCD_DATA; P1OUT = LCD_CLK | RXD | SWITCH | LCD_BACKLIGHT; P2REN = 0; P2DIR = LCD_DC | LCD_CE; P2OUT = LCD_CE; __delay_cycles(20000); P2OUT |= LCD_DC; __delay_cycles(20000); lcd_send(init, sizeof(init), lcd_command); } static const unsigned char font6x8[96][5] = { 0x00, 0x00, 0x00, 0x00, 0x00, // 20 32 0x00, 0x00, 0x5F, 0x00, 0x00, // 21 33 ! 0x00, 0x07, 0x00, 0x07, 0x00, // 22 34 " 0x14, 0x7F, 0x14, 0x7F, 0x14, // 23 35 # 0x24, 0x2A, 0x7F, 0x2A, 0x12, // 24 36 $ 0x23, 0x13, 0x08, 0x64, 0x62, // 25 37 % 0x36, 0x49, 0x56, 0x20, 0x50, // 26 38 & 0x00, 0x08, 0x07, 0x03, 0x00, // 27 39 ' 0x00, 0x1C, 0x22, 0x41, 0x00, // 28 40 ( 0x00, 0x41, 0x22, 0x1C, 0x00, // 29 41 ) 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // 2A 42 * 0x08, 0x08, 0x3E, 0x08, 0x08, // 2B 43 + 0x00, 0x40, 0x38, 0x18, 0x00, // 2C 44 , 0x08, 0x08, 0x08, 0x08, 0x08, // 2D 45 - 0x00, 0x00, 0x60, 0x60, 0x00, // 2E 46 . 0x20, 0x10, 0x08, 0x04, 0x02, // 2F 47 / 0x3E, 0x51, 0x49, 0x45, 0x3E, // 30 48 0 0x00, 0x42, 0x7F, 0x40, 0x00, // 31 49 1 0x42, 0x61, 0x51, 0x49, 0x46, // 32 50 2 0x21, 0x41, 0x49, 0x4D, 0x33, // 33 51 3 0x18, 0x14, 0x12, 0x7F, 0x10, // 34 52 4 0x27, 0x45, 0x45, 0x45, 0x39, // 35 53 5 0x3C, 0x4A, 0x49, 0x49, 0x30, // 36 54 6 0x41, 0x21, 0x11, 0x09, 0x07, // 37 55 7 0x36, 0x49, 0x49, 0x49, 0x36, // 38 56 8 0x06, 0x49, 0x49, 0x29, 0x1E, // 39 57 9 0x00, 0x00, 0x14, 0x00, 0x00, // 3A 58 : 0x00, 0x00, 0x40, 0x34, 0x00, // 3B 59 ; 0x00, 0x08, 0x14, 0x22, 0x41, // 3C 60 < 0x14, 0x14, 0x14, 0x14, 0x14, // 3D 61 = 0x00, 0x41, 0x22, 0x14, 0x08, // 3E 62 > 0x02, 0x01, 0x51, 0x09, 0x06, // 3F 63 ? 0x3E, 0x41, 0x5D, 0x59, 0x4E, // 40 64 @ 0x7C, 0x12, 0x11, 0x12, 0x7C, // 41 65 A 0x7F, 0x49, 0x49, 0x49, 0x36, // 42 66 B 0x3E, 0x41, 0x41, 0x41, 0x22, // 43 67 C 0x7F, 0x41, 0x41, 0x41, 0x3E, // 44 68 D 0x7F, 0x49, 0x49, 0x49, 0x41, // 45 69 E 0x7F, 0x09, 0x09, 0x09, 0x01, // 46 70 F 0x3E, 0x41, 0x49, 0x49, 0x7A, // 47 71 G 0x7F, 0x08, 0x08, 0x08, 0x7F, // 48 72 H 0x00, 0x41, 0x7F, 0x41, 0x00, // 49 73 I 0x20, 0x40, 0x41, 0x3F, 0x01, // 4A 74 J 0x7F, 0x08, 0x14, 0x22, 0x41, // 4B 75 K 0x7F, 0x40, 0x40, 0x40, 0x40, // 4C 76 L 0x7F, 0x02, 0x1C, 0x02, 0x7F, // 4D 77 M 0x7F, 0x04, 0x08, 0x10, 0x7F, // 4E 78 N 0x3E, 0x41, 0x41, 0x41, 0x3E, // 4F 79 O 0x7F, 0x09, 0x09, 0x09, 0x06, // 50 80 P 0x3E, 0x41, 0x51, 0x21, 0x5E, // 51 81 Q 0x7F, 0x09, 0x19, 0x29, 0x46, // 52 82 R 0x26, 0x49, 0x49, 0x49, 0x32, // 53 83 S 0x01, 0x01, 0x7F, 0x01, 0x01, // 54 84 T 0x3F, 0x40, 0x40, 0x40, 0x3F, // 55 85 U 0x1F, 0x20, 0x40, 0x20, 0x1F, // 56 86 V 0x3F, 0x40, 0x38, 0x40, 0x3F, // 57 87 W 0x63, 0x14, 0x08, 0x14, 0x63, // 58 88 X 0x03, 0x04, 0x78, 0x04, 0x03, // 59 89 Y 0x61, 0x51, 0x49, 0x45, 0x43, // 5A 90 Z 0x00, 0x7F, 0x41, 0x41, 0x41, // 5B 91 [ 0x02, 0x04, 0x08, 0x10, 0x20, // 5C 92 '\' 0x00, 0x41, 0x41, 0x41, 0x7F, // 5D 93 ] 0x04, 0x02, 0x01, 0x02, 0x04, // 5E 94 ^ 0x80, 0x80, 0x80, 0x80, 0x80, // 5F 95 _ 0x00, 0x03, 0x07, 0x08, 0x00, // 60 96 ' 0x20, 0x54, 0x54, 0x54, 0x78, // 61 97 a 0x7F, 0x28, 0x44, 0x44, 0x38, // 62 98 b 0x38, 0x44, 0x44, 0x44, 0x28, // 63 99 c 0x38, 0x44, 0x44, 0x28, 0x7F, // 64 100 d 0x38, 0x54, 0x54, 0x54, 0x18, // 65 101 e 0x00, 0x08, 0x7E, 0x09, 0x02, // 66 102 f 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // 67 103 g 0x7F, 0x08, 0x04, 0x04, 0x78, // 68 104 h 0x00, 0x44, 0x7D, 0x40, 0x00, // 69 105 i 0x00, 0x20, 0x40, 0x40, 0x3D, // 6A 106 j 0x00, 0x7F, 0x10, 0x28, 0x44, // 6B 107 k 0x00, 0x41, 0x7F, 0x40, 0x00, // 6C 108 l 0x7C, 0x04, 0x78, 0x04, 0x78, // 6D 109 m 0x7C, 0x08, 0x04, 0x04, 0x78, // 6E 110 n 0x38, 0x44, 0x44, 0x44, 0x38, // 6F 111 o 0xFC, 0x18, 0x24, 0x24, 0x18, // 70 112 p 0x18, 0x24, 0x24, 0x18, 0xFC, // 71 113 q 0x7C, 0x08, 0x04, 0x04, 0x08, // 72 114 r 0x48, 0x54, 0x54, 0x54, 0x24, // 73 115 s 0x04, 0x04, 0x3F, 0x44, 0x24, // 74 116 t 0x3C, 0x40, 0x40, 0x20, 0x7C, // 75 117 u 0x1C, 0x20, 0x40, 0x20, 0x1C, // 76 118 v 0x3C, 0x40, 0x30, 0x40, 0x3C, // 77 119 w 0x44, 0x28, 0x10, 0x28, 0x44, // 78 120 x 0x4C, 0x90, 0x90, 0x90, 0x7C, // 79 121 y 0x44, 0x64, 0x54, 0x4C, 0x44, // 7A 122 z 0x00, 0x08, 0x36, 0x41, 0x00, // 7B 123 { 0x00, 0x00, 0x77, 0x00, 0x00, // 7C 124 | 0x00, 0x41, 0x36, 0x08, 0x00, // 7D 125 } 0x02, 0x01, 0x02, 0x04, 0x02, // 7E 126 ~ 0x00, 0x06, 0x09, 0x09, 0x06, // 7F 127 degrees }; void lcd_print(char *s, unsigned x, unsigned y) { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 | y; lcd_send(c, sizeof(c), lcd_command); while(*s) { lcd_send(&font6x8[*s - 32][0], 5, lcd_data); lcd_send(&font6x8[0][0], 1, lcd_data); ++s; } } static const unsigned char num11x16[19][11 * 2] = { 0x00,0xF0,0xFC,0xFE,0x06,0x02,0x06,0xFE,0xFC,0xF0,0x00, // 0 0x00,0x07,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x07,0x00, 0x00,0x00,0x08,0x0C,0xFC,0xFE,0xFE,0x00,0x00,0x00,0x00, // 1 0x00,0x20,0x20,0x20,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x00, 0x00,0x0C,0x0E,0x06,0x02,0x02,0x86,0xFE,0x7C,0x38,0x00, // 2 0x00,0x30,0x38,0x3C,0x36,0x33,0x31,0x30,0x30,0x38,0x00, 0x00,0x0C,0x0E,0x86,0x82,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 3 0x00,0x18,0x38,0x30,0x20,0x20,0x31,0x3F,0x1F,0x0E,0x00, 0x00,0x00,0xC0,0x20,0x18,0x04,0xFE,0xFE,0xFE,0x00,0x00, // 4 0x00,0x03,0x02,0x02,0x02,0x22,0x3F,0x3F,0x3F,0x22,0x02, 0x00,0x00,0x7E,0x7E,0x46,0x46,0xC6,0xC6,0x86,0x00,0x00, // 5 0x00,0x18,0x38,0x30,0x20,0x20,0x30,0x3F,0x1F,0x0F,0x00, 0x00,0xC0,0xF0,0xF8,0xFC,0x4C,0xC6,0xC2,0x82,0x00,0x00, // 6 0x00,0x0F,0x1F,0x3F,0x30,0x20,0x30,0x3F,0x1F,0x0F,0x00, 0x00,0x06,0x06,0x06,0x06,0x06,0xC6,0xF6,0x3E,0x0E,0x00, // 7 0x00,0x00,0x00,0x30,0x3C,0x0F,0x03,0x00,0x00,0x00,0x00, 0x00,0x38,0x7C,0xFE,0xC6,0x82,0xC6,0xFE,0x7C,0x38,0x00, // 8 0x00,0x0E,0x1F,0x3F,0x31,0x20,0x31,0x3F,0x1F,0x0E,0x00, 0x00,0x78,0xFC,0xFE,0x86,0x02,0x86,0xFE,0xFC,0xF8,0x00, // 9 0x00,0x00,0x00,0x21,0x21,0x31,0x1D,0x1F,0x0F,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x70,0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // : 0x00,0x0E,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // . 0x00,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x00,0x00,0x00,0x00, // / 0x00,0x30,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // - 0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x00,0x18,0x3C,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, // 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xF0,0xF8,0x0C,0x06,0x02,0x02,0x02,0x02,0x0E,0x0C,0x00, // C 0x03,0x07,0x0C,0x18,0x10,0x10,0x10,0x10,0x1C,0x0C,0x00, 0xFE,0xFE,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00, // F 0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFE,0xFE,0x40,0xE0,0xB0,0x18,0x0C,0x06,0x02,0x00,0x00, // K 0x1F,0x1F,0x00,0x00,0x01,0x03,0x06,0x0C,0x18,0x10,0x00 }; void pd12(unsigned n, unsigned x, unsigned y) { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 + y; lcd_send(c, 2, lcd_command); lcd_send(num11x16[n], 11, lcd_data); c[1] = 0x41 + y; lcd_send(c, 2, lcd_command); lcd_send(num11x16[n] + 11, 11, lcd_data); }
  5. Like
    roger430 got a reaction from anissof in PCF8566 & MSP430G   
    Does anyone on this board have any experience in using the PCF8566 to drive glass LCD displays? It uses I2C for communications with a Master. I'm getting acknowledgments back from the PCF8566 after selecting its address and also from sending a command to it, however, subsequent data bytes display incorrectly. Any help would be greatly appreciated.
     
    Thanks,
    Roger430
  6. Like
    roger430 got a reaction from anissof in PCF8566 & MSP430G   
    Well here it is in all its glory! If only I could find a use for it. . .
    The toughest part was trying to figure out the configuration of the Raw LCD display. This one happened to have 4 back planes and used only 2 pins for each character for a total of 20 pins. It has a few graphics and a low battery indicator. It also has a small 7 segment character in the upper right hand corner as seen in the photo. The PCF8566 plays nicely with the MSP420G2231 and works very well with 3.3v.
     

     

     
    and here is the code:
     

    //****************************************************************************** // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes // // Description: I2C Master communicates with I2C Slave using // the USI. Master data should increment from 0x55 with each transmitted byte // and Master determines the number of bytes recieved, set by // the Number_of_Bytes value. LED off for address or data Ack; // LED on for address or data NAck. // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz // // // ***THIS IS THE MASTER CODE*** // // Slave Master // (msp430g2x21_usi_15.c) // MSP430G2x21/G2x31 MSP430G2x21/G2x31 // ----------------- ----------------- // /|\| XIN|- /|\| XIN|- // | | | | | | // --|RST XOUT|- --|RST XOUT|- // | | | | // LED <-|P1.0 | | | // | | | P1.0|-> LED // | SDA/P1.7|------->|P1.6/SDA | // | SCL/P1.6|<-------|P1.7/SCL | // // Note: internal pull-ups are used in this example for SDA & SCL // // D. Dang // Texas Instruments Inc. // October 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 //****************************************************************************** #include #define number_of_bytes 10 // How many bytes? void Master_Transmit(void); //void Master_Recieve(void); void Setup_USI_Master_TX(void); //void Setup_USI_Master_RX(void); // First two bytes are PCF8566 commands static char MST_Data[10] = {0xC8, 0x00, 0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xBE, 0x00}; //character segment map char SLV_Addr = 0x7C; int I2C_State = 0; int Bytecount = 0; int Transmit = 0; // State variable void Data_TX (void); void main(void) { volatile unsigned int i; // Use volatile to prevent removal WDTCTL = WDTPW + WDTHOLD; // Stop watchdog if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased // do not load, trap CPU!! } BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0 P1REN |= 0xC0; // P1.6 & P1.7 Pullups P1DIR = 0xFF; // Unused pins as outputs P2OUT = 0; P2DIR = 0xFF; while(1) { Master_Transmit(); //_NOP(); // Used for IAR } } /****************************************************** // USI interrupt service routine // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14 ******************************************************/ #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave P1OUT |= 0x01; // LED on: sequence start Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; if (Transmit == 1){ USISRL = 0x7C; // Address is 0x48 << 1 bit + 0 (rw) } if (Transmit == 0){ USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit // + 1 for Read } USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; // Turn on LED: error } else { // Ack received, TX data to slave... USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack //Bytecount++; P1OUT &= ~0x01; // Turn off LED break; } case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; USICNT |= 0x01; } // set count=1 to trigger next state else{ P1OUT &= ~0x01; // Turn off LED Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag } void Data_TX (void){ USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack Bytecount++; } void Setup_USI_Master_TX (void) { _DINT(); Bytecount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } void Master_Transmit(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication LPM0; // CPU off, await USI interrupt __delay_cycles(10000); // Delay between comm cycles }
  7. Like
    roger430 got a reaction from pine in PCF8566 & MSP430G   
    Well here it is in all its glory! If only I could find a use for it. . .
    The toughest part was trying to figure out the configuration of the Raw LCD display. This one happened to have 4 back planes and used only 2 pins for each character for a total of 20 pins. It has a few graphics and a low battery indicator. It also has a small 7 segment character in the upper right hand corner as seen in the photo. The PCF8566 plays nicely with the MSP420G2231 and works very well with 3.3v.
     

     

     
    and here is the code:
     

    //****************************************************************************** // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes // // Description: I2C Master communicates with I2C Slave using // the USI. Master data should increment from 0x55 with each transmitted byte // and Master determines the number of bytes recieved, set by // the Number_of_Bytes value. LED off for address or data Ack; // LED on for address or data NAck. // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz // // // ***THIS IS THE MASTER CODE*** // // Slave Master // (msp430g2x21_usi_15.c) // MSP430G2x21/G2x31 MSP430G2x21/G2x31 // ----------------- ----------------- // /|\| XIN|- /|\| XIN|- // | | | | | | // --|RST XOUT|- --|RST XOUT|- // | | | | // LED <-|P1.0 | | | // | | | P1.0|-> LED // | SDA/P1.7|------->|P1.6/SDA | // | SCL/P1.6|<-------|P1.7/SCL | // // Note: internal pull-ups are used in this example for SDA & SCL // // D. Dang // Texas Instruments Inc. // October 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 //****************************************************************************** #include #define number_of_bytes 10 // How many bytes? void Master_Transmit(void); //void Master_Recieve(void); void Setup_USI_Master_TX(void); //void Setup_USI_Master_RX(void); // First two bytes are PCF8566 commands static char MST_Data[10] = {0xC8, 0x00, 0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xBE, 0x00}; //character segment map char SLV_Addr = 0x7C; int I2C_State = 0; int Bytecount = 0; int Transmit = 0; // State variable void Data_TX (void); void main(void) { volatile unsigned int i; // Use volatile to prevent removal WDTCTL = WDTPW + WDTHOLD; // Stop watchdog if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased // do not load, trap CPU!! } BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0 P1REN |= 0xC0; // P1.6 & P1.7 Pullups P1DIR = 0xFF; // Unused pins as outputs P2OUT = 0; P2DIR = 0xFF; while(1) { Master_Transmit(); //_NOP(); // Used for IAR } } /****************************************************** // USI interrupt service routine // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14 ******************************************************/ #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave P1OUT |= 0x01; // LED on: sequence start Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; if (Transmit == 1){ USISRL = 0x7C; // Address is 0x48 << 1 bit + 0 (rw) } if (Transmit == 0){ USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit // + 1 for Read } USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; // Turn on LED: error } else { // Ack received, TX data to slave... USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack //Bytecount++; P1OUT &= ~0x01; // Turn off LED break; } case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; USICNT |= 0x01; } // set count=1 to trigger next state else{ P1OUT &= ~0x01; // Turn off LED Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag } void Data_TX (void){ USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack Bytecount++; } void Setup_USI_Master_TX (void) { _DINT(); Bytecount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } void Master_Transmit(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication LPM0; // CPU off, await USI interrupt __delay_cycles(10000); // Delay between comm cycles }
  8. Like
    roger430 got a reaction from oPossum in PCF8566 & MSP430G   
    Well here it is in all its glory! If only I could find a use for it. . .
    The toughest part was trying to figure out the configuration of the Raw LCD display. This one happened to have 4 back planes and used only 2 pins for each character for a total of 20 pins. It has a few graphics and a low battery indicator. It also has a small 7 segment character in the upper right hand corner as seen in the photo. The PCF8566 plays nicely with the MSP420G2231 and works very well with 3.3v.
     

     

     
    and here is the code:
     

    //****************************************************************************** // MSP430G2x21/G2x31 Demo - I2C Master Transmitter / Reciever, multiple bytes // // Description: I2C Master communicates with I2C Slave using // the USI. Master data should increment from 0x55 with each transmitted byte // and Master determines the number of bytes recieved, set by // the Number_of_Bytes value. LED off for address or data Ack; // LED on for address or data NAck. // ACLK = n/a, MCLK = SMCLK = Calibrated 1MHz // // // ***THIS IS THE MASTER CODE*** // // Slave Master // (msp430g2x21_usi_15.c) // MSP430G2x21/G2x31 MSP430G2x21/G2x31 // ----------------- ----------------- // /|\| XIN|- /|\| XIN|- // | | | | | | // --|RST XOUT|- --|RST XOUT|- // | | | | // LED <-|P1.0 | | | // | | | P1.0|-> LED // | SDA/P1.7|------->|P1.6/SDA | // | SCL/P1.6|<-------|P1.7/SCL | // // Note: internal pull-ups are used in this example for SDA & SCL // // D. Dang // Texas Instruments Inc. // October 2010 // Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10 //****************************************************************************** #include #define number_of_bytes 10 // How many bytes? void Master_Transmit(void); //void Master_Recieve(void); void Setup_USI_Master_TX(void); //void Setup_USI_Master_RX(void); // First two bytes are PCF8566 commands static char MST_Data[10] = {0xC8, 0x00, 0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xBE, 0x00}; //character segment map char SLV_Addr = 0x7C; int I2C_State = 0; int Bytecount = 0; int Transmit = 0; // State variable void Data_TX (void); void main(void) { volatile unsigned int i; // Use volatile to prevent removal WDTCTL = WDTPW + WDTHOLD; // Stop watchdog if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF) { while(1); // If calibration constants erased // do not load, trap CPU!! } BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0 P1REN |= 0xC0; // P1.6 & P1.7 Pullups P1DIR = 0xFF; // Unused pins as outputs P2OUT = 0; P2DIR = 0xFF; while(1) { Master_Transmit(); //_NOP(); // Used for IAR } } /****************************************************** // USI interrupt service routine // Data Transmit : state 0 -> 2 -> 4 -> 10 -> 12 -> 14 ******************************************************/ #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave P1OUT |= 0x01; // LED on: sequence start Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; if (Transmit == 1){ USISRL = 0x7C; // Address is 0x48 << 1 bit + 0 (rw) } if (Transmit == 0){ USISRL = 0x91; // 0x91 Address is 0x48 << 1 bit // + 1 for Read } USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; // Turn on LED: error } else { // Ack received, TX data to slave... USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack //Bytecount++; P1OUT &= ~0x01; // Turn off LED break; } case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop P1OUT |= 0x01; USICNT |= 0x01; } // set count=1 to trigger next state else{ P1OUT &= ~0x01; // Turn off LED Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag } void Data_TX (void){ USISRL = MST_Data[bytecount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack Bytecount++; } void Setup_USI_Master_TX (void) { _DINT(); Bytecount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_7+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } void Master_Transmit(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication LPM0; // CPU off, await USI interrupt __delay_cycles(10000); // Delay between comm cycles }
  9. Like
    roger430 got a reaction from timotet in Simple temperature display project   
    I know, I know, not another temperature project . This one is a little different in that it is very simple and uses readily available and inexpensive components. A $1.99 display from Electronic Goldmine: http://www.goldmine-elec-products.com/p ... ber=G15318
    or even cheaper at $1.85 from All Electronics: http://www.allelectronics.com/make-a-st ... LCD/1.html
    a $4.29 breadboard power supply that provides both 5.0vdc and 3.3vdc using and ordinary 9 - 12 vdc wall wart:
    http://www.ebay.com/itm/Perfect-High-Qu ... 3f0f10117f
    and a 74HC595N 8 bit shift register at a quantity of 5 for as low as $1.85 including shipping from Ebay.
    I started this project to learn more about ADC and the '595 8 bit shift register. Along the way I learned about integer to ascii conversion (necessary for displaying the temperature value). It was also just plain fun working with the LCD display.
     

    ' alt='>'>
     
    The schematic:

    ' alt='>'>
     
    Here's the code:

    //****************************************************************************** // A simple temperature display project utilizing a $1.99 surplus LCD display module, // a 74HC595N serial/parallel chip, TI Launchpad with an MSP430G2231 installed and a $4.29 // power supply from Ebay that provides 5vdc and 3.3vdc from a wall wart. // Code to obtain the temperature came directly from TI's example files, itoa function from // Google group comp.lang.c and display routines from RobG's "Using 3 wires to control // parallel LCD display with timotet's adaptation for the Wintek 1x24 char LCD display. // //R.G. Rioux - October, 2011 // // MSP430G2x31 Demo - ADC10, Sample A10 Temp and Convert to oC and oF // Description: A single sample is made on A10 with reference to internal // 1.5V Vref. Software sets ADC10SC to start sample and conversion - ADC10SC // automatically cleared at EOC. ADC10 internal oscillator/4 times sample // (64x) and conversion. In Mainloop MSP430 waits in LPM0 to save power until // ADC10 conversion complete, ADC10_ISR will force exit from any LPMx in // Mainloop on reti. Temperaure in oC stored in IntDegC, oF in IntDegF. // Uncalibrated temperature measured from device to device will vary with // slope and offset - please see datasheet. // ACLK = n/a, MCLK = SMCLK = default DCO ~1.2MHz, ADC10CLK = ADC10OSC/4 // // D. Dang // Texas Instruments Inc. // October 2010 // // MSP430G2x31 // ----------------- // /|\| XIN|- // | | | // --|RST XOUT|- // | | // |A10 | // ENABLE<--|P1.4 P1.6|-->DATA // CLOCK<--|P1.5 | _____ // | P1.7|-->RESET (for Wintek 1x24 Char Display) // // Built with CCS Version 4.2.4.00033 // R.G. Rioux October 2011 //****************************************************************************** #include "msp430g2231.h" #include #include //------------------------------------------------------------------------------ // Display related definitions //------------------------------------------------------------------------------ #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define initDisplay() sendInstruction(0x1C); sendInstruction(0x14); sendInstruction(0x28); sendInstruction(0x4F); sendInstruction(0xE0) #define clearDisplay() sendInstruction(0x01); sendInstruction(0xE3); _delay_cycles(2000) #define DATAPIN BIT6 // P1.6 #define CLOCKPIN BIT5 // P1.5 #define ENABLEPIN BIT4 // P1.4 #define RESETPIN BIT7 // P1.7 //------------------------------------------------------------------------------ // Display related functions and variables //------------------------------------------------------------------------------ void send(char data, char registerSelect); void sendStr(char data[], int length); void reset(void); char charIndex = 0; char bitCounter = 0; //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ char buffer[4]; long temp; long IntDegF; long IntDegC; //------------------------------------------------------------------------------ // itoa functions //------------------------------------------------------------------------------ static char *i2a(unsigned i, char *a, unsigned r); char *itoa(int i, char *a, int r); // main void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT _delay_cycles(100000); // Wait for display to settle DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1DIR |= ENABLEPIN + CLOCKPIN + DATAPIN + RESETPIN; // sets ENABLEPIN,CLOCKPIN,DATAPIN and RESETPIN to outputs P1OUT &= ~(CLOCKPIN + DATAPIN + RESETPIN); // sets CLOCKPIN,RESETPIN and DATAPIN low P1OUT |= ENABLEPIN; ADC10CTL1 = INCH_10 + ADC10DIV_3; // Temp Sensor ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE; __enable_interrupt(); // Enable interrupts. TACCR0 = 30; // Delay to allow Ref to settle TACCTL0 |= CCIE; // Compare-mode interrupt. TACTL = TASSEL_2 | MC_1; // TACLK = SMCLK, Up mode. LPM0; // Wait for delay. TACCTL0 &= ~CCIE; // Disable timer Interrupt __disable_interrupt(); reset(); // reset Wintek 1x24 LCD display initDisplay(); // initialize display sendStr("Temperature:", 12); while(1) { ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled // oF = ((A10/1024)*1500mV)-923mV)*1/1.97mV = A10*761/1024 - 468 temp = ADC10MEM; IntDegF = ((temp - 630) * 761) / 1024; // oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278 temp = ADC10MEM; IntDegC = ((temp - 673) * 423) / 1024; sendInstruction(0xF2); // position cursor itoa (IntDegF, buffer, 10); // convert to ascii chars sendStr(buffer, strlen(buffer)); send(0xB0, 1); sendStr("F", 1); sendInstruction(0xF7); // position cursor itoa(IntDegC, buffer, 10); sendStr(buffer, strlen(buffer)); send(0xB0, 1); sendStr("C", 1); } } // ADC10 interrupt service routine #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR) } #pragma vector=TIMERA0_VECTOR __interrupt void ta0_isr(void) { TACTL = 0; LPM0_EXIT; // Exit LPM0 on return } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; _delay_cycles(3000); P1OUT |= ENABLEPIN; _delay_cycles(10000); P1OUT &= ~ENABLEPIN; } void sendStr(char string[], int size) { int charIndex = 0; while(charIndex < size) { sendData(string[charIndex]); charIndex++; } } void reset() { P1OUT &= ~RESETPIN; // RESETPIN low _delay_cycles(10000); P1OUT |= RESETPIN; } /* ** The following two functions together make up an itoa() ** implementation. Function i2a() is a 'private' function ** called by the public itoa() function. ** ** itoa() takes three arguments: ** 1) the integer to be converted, ** 2) a pointer to a character conversion buffer, ** 3) the radix for the conversion ** which can range between 2 and 36 inclusive ** range errors on the radix default it to base10 ** Code from Google group comp.lang.c */ static char *i2a(unsigned i, char *a, unsigned r) { if (i/r > 0) a = i2a(i/r,a,r); *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r]; return a+1; } char *itoa(int i, char *a, int r) { if ((r < 2) || (r > 36)) r = 10; if (i < 0) { *a = '-'; *i2a(-(unsigned)i,a+1,r) = 0; } else *i2a(i,a,r) = 0; return a; }
  10. Like
    roger430 reacted to timotet in Using 3 wires to control parallel LCD display   
    So Ive managed to get RobG's code to work on the Wintek 1 x 24 Character LCD Display Module that I got awhile ago from
    Electronic Goldmine for $1.99.
     
    Here's the link: http://www.goldmine-elec-products.com/p ... ber=G15318
     
    There are only 2 cons so far:
    1 It takes 5v to power the display.
    2 It takes 4 wires instead of 3. ( you have to toggle the reset pin on the display.)
     
    logic seems to work fine at the 3.6v the msp430 puts out.
     


     
    here's the code:

    /* hex instructions for display setup 0x1C == LCD power control PW 0x14 == Display on/off DO 0x28 == Display Control sets lines ect. DC 0x4F == Contrast Set CN 0xE0 == DDRAM address set DA */ #include "msp430g2452.h" #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define clearDisplay() sendInstruction(0x01); _delay_cycles(2000) #define DATAPIN BIT6 #define CLOCKPIN BIT5 #define ENABLEPIN BIT4 #define RESETPIN BIT7 void send(char data, char registerSelect); void sendDataArray(char data[], char length); //void resetPin(unsigned int bit); void initDisplay(void); char charIndex = 0; char bitCounter = 0; const char message1[8] = {0x34,0x33,0x6F,0x68,0x2E,0x63,0x6F,0x6D}; char message2[11] = {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xA4}; const char message3[16] = {0x34,0x2D,0x70,0x69,0x6E,0x20,0x73,0x65,0x72,0x69,0x61,0x6C,0x20,0x4C,0x43,0x44}; char message4[12] = {0x54,0x68,0x61,0x6E,0x6B,0x73,0x20,0xAE,0x6F,0x62,0x47,0x21}; void main(void) { WDTCTL = WDTPW + WDTHOLD; _delay_cycles(100000); P1DIR |= ENABLEPIN + CLOCKPIN + DATAPIN + RESETPIN; // sets ENABLEPIN,CLOCKPIN,DATAPIN and RESETPIN to outputs P1OUT &= ~(CLOCKPIN + DATAPIN + RESETPIN); // sets CLOCKPIN,RESETPIN and DATAPIN low P1OUT |= ENABLEPIN; // sets ENABLEPIN high initDisplay(); // initiate display while(1) { // send const message using sendDataArray clearDisplay(); sendDataArray((char *)message1, 8); _delay_cycles(3000000); // send message using sendDataArray clearDisplay(); sendDataArray(message2, 11); _delay_cycles(3000000); // send message one char at the time clearDisplay(); charIndex = 0; while(charIndex < 16) { sendData(message3[charIndex]); charIndex++; } _delay_cycles(3000000); // send message using sendDataArray clearDisplay(); sendDataArray(message4, 12); _delay_cycles(3000000); } } void sendDataArray(char data[], char length) { charIndex = 0; while(charIndex < length) { sendData(data[charIndex]); charIndex++; } } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; _delay_cycles(3000); P1OUT |= ENABLEPIN; _delay_cycles(10000); P1OUT &= ~ENABLEPIN; } void initDisplay(void) { P1OUT &= ~RESETPIN; // RESETPIN low _delay_cycles(10000); P1OUT |= RESETPIN; //RESETPIN high sendInstruction(0x1C); //PW sendInstruction(0x14); //DO 0x14 sendInstruction(0x28); //DC 0x28 sendInstruction(0x4F); //CN 0x4F sendInstruction(0xE0); //DA //sendInstruction(0x72); //SC //sendInstruction(0xC); //CR }
  11. Like
    roger430 reacted to nuetron in Using 3 wires to control parallel LCD display   
    Hey Rob, I modified your sendDataArray(), thought this might help:

    void sendStr(char string[], char size) { int charIndex = 0; sendInstruction(0x80); // First line while(charIndex < size) { if(charIndex == (size / 2)) // half sendInstruction(0xC0); // Second line sendData(string[charIndex]); charIndex++; } }
    This mod can print a 32-char string on a 16x2 display, while making sure all of the string is visible.
    It can also be used for a 16x1 (logical 8x2), 20x2, and other small ones. It will, however, need slight changes for displays with more than two lines.
     
    Hope this is useful!
     
    BTW: this was written in C++
  12. Like
    roger430 reacted to RobG in Using 3 wires to control parallel LCD display   
    I have seen this done other ways, but I didn't want to deal with 7 pins, or 4 bits, etc., so I did it my way.
    You send 8 bits to shift register, then set data out to whatever RS should be, and finally pulse E, that simple.
    I will add my code later, once I clean it up.
    BTW, if you are interested, the display is LMB162 and was purchased from ebay for $7.99 with free S/H to US of A (it took a week to get to NC.)
    It requires 3.3V Vcc with 5V BL, that's why I like it (well, I don't like the fact that I need separate power for BL.)
     


     

     
    My next step is to reduce number of required pins to 2 by adding missing pulse detector (555 I think will do well here.)

  13. Like
    roger430 reacted to NatureTM in Generating random numbers.   
    I was looking for example code for RF2500 last night and came across some TI code for using the ADC as a random number generator. The function was in assembly, so I rewrote it in C:
     

    bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; }
     
    Pin 1.5 is floating unconnected, and is measured by the adc. The LSB is used as the random bit. There's a twist though. Pin 1.4 is also floating unconnected, and is used as Vref+, so the top end of the range is floating as well. I thought that was pretty clever. Nice, TI!
     
    I wrote a few console programs to help me visualize the randomness. It turned out the generator was biased toward producing 0's. This function used with the previous function seemed to remove the bias:
     

    bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } }
     
    To test for bias, I displayed a meandering line in a serial console. If I get more 0's than 1's, the line should slowly skew to the left or right:
     

    #include "msp430g2231.h" #include "config.h" #include "softserial.h" #include #define CONSOLE_WIDTH 80 bool getRandomBit(); bool get0BiasRandomBit(); void main(){ int linePositon = CONSOLE_WIDTH / 2; char cursorPosition; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTHOLD; // Stop WDT SoftSerial_init(); _enable_interrupts(); while(1){ for(cursorPosition = 0; cursorPosition < linePositon; cursorPosition++) SoftSerial_xmit('8'); SoftSerial_xmit(' '); cursorPosition++; while(cursorPosition < CONSOLE_WIDTH){ SoftSerial_xmit('8'); cursorPosition++; } if(get0BiasRandomBit()) linePositon++; else linePositon--; if(linePositon < 0) linePositon = CONSOLE_WIDTH + linePositon; else if(linePositon >= CONSOLE_WIDTH - 1) linePositon = linePositon - CONSOLE_WIDTH; } } bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } } bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; }
     
    and some example output from this code:

     
    This sends a comma-separated list of random ints to the console:

    #include "msp430g2231.h" #include "config.h" #include "softserial.h" #include #include int adcGenRand16(); void reverse(char s[]); void itoa(int n, char s[]); void txString(char string[]); bool getRandomBit(); bool get0BiasRandomBit(); void main(){ int random; char string[7]; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTHOLD; // Stop WDT SoftSerial_init(); _enable_interrupts(); while(1){ random = adcGenRand16(); itoa(random, string); txString(string); } } void txString(char string[]){ int iString = 0; while(string[iString] != 0){ SoftSerial_xmit(string[iString]); iString++; } SoftSerial_xmit(','); SoftSerial_xmit(' '); } bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } } bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; } int adcGenRand16(){ char bit; unsigned int random; for(bit = 0; bit < 16; bit++){ random <<= 1; random |= get0BiasRandomBit(); } return random; } /* itoa: convert n to characters in s */ void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) /* record sign */ n = -n; /* make n positive */ i = 0; do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); } /* reverse: reverse string s in place */ void reverse(char s[]) { int i, j; char c; for (i = 0, j = strlen(s)-1; i c = s[i]; s[i] = s[j]; s[j] = c; } }
     

     
    I guess I got a little sidetracked from my original purpose of getting started with the RF2500, but I had fun.
  14. Like
    roger430 got a reaction from xmob in [ ENDED ] Aug-Sep 2011 - 43oh Project of the Month Contest   
    Magic Eight Ball
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch an animated "<>" and look at the answer in the LCD display. The random seed code is adapted from a translation of TI assembler code to C by NatureTM in the "Code Vault" section of this forum. I used the same LCD Display and code that is used in the "Using 3 wires to control parallel LCD display" by RobG. I had to use different ports for the display to accommodate the random number generator code.
    This project won't change the world, however, it keeps kids busy for a while. :D
     
    ** Added delay toward beginning of main(void) to allow settling of MSP430. Prior to this change the reset button had to
    be pressed to start the program.
     
    Here are some pictures as well as the schematic and code:
     

     

     

     

    //****************************************************************************** // Magic Eight Ball Project // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To use, press S1, "Magic Eight Ball v0.03 - READY" should appear on the LCD display. // Ask your question, press S2, watch "<>" animation and an answer will appear // in the LCD display. // // 08/14/11 Improved randomness of answers. Used NatureTM's code from the 43oh // forum to generate a random seed. Requires that P1.4 and P1.5 be in the Input // mode (floating). Thanks NatureTM! // // 09/17/11 Adapted output to LCD Display. Modified code from 43oh forum "Using // 3 wires to control parallel LCD display" by RobG. Thanks Robg! Also modified // nuetron's code modification to break long lines up. Thanks nuetron! // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> Pin 6 of Display (E) // | P1.7|--------> Pin 1&2 of 74HC164 (AB) // | CCI0A/RXD/P1.2|--------> Pin 8 of 74HC164 (CLK) // // R.G. Rioux // September 2011 // Built with CCS Version 4.2.4.00033 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() #include // strlen() //------------------------------------------------------------------------------ // Display related definitions //------------------------------------------------------------------------------ #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define initDisplay() sendInstruction(0x3C); sendInstruction(0x0C); clearDisplay(); sendInstruction(0x06) #define clearDisplay() sendInstruction(0x01); _delay_cycles(2000) #define DATAPIN BIT7 // P1.7 #define CLOCKPIN BIT2 // P1.2 #define ENABLEPIN BIT1 // P1.1 #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Display related functions and variables //------------------------------------------------------------------------------ void send(char data, char registerSelect); void sendStr(char data[], int length); char charIndex = 0; char bitCounter = 0; //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int seed; unsigned int randnum = 0; int i; int j; // indexes char msgflag = 0; // Used comma in string as a delimiter to break string up into two lines static char *answer[11] = { "Yes,in due time.", "My sources say,no.", "Definitely not.", "Yes.", "Probably.", "I have my,doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!", "Are you kidding?" }; // <> animation array static char *anim[8] = { " <> ", " < > ", " < > ", " < > ", " < > ", " < > ", " < > ", "< >" }; int getRandomBit(); int length = 0; int lFlag = 0; // line flag //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer _delay_cycles(100000); DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT &= ~(CLOCKPIN + DATAPIN); P1OUT &= ~(BIT0 + BIT6); P1OUT |= ENABLEPIN; // Set all pins to output except BUTTON, P1.4 and P1.5 P1DIR = 0xFF & ~(BUTTON + BIT4 + BIT5); P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); initDisplay(); sendStr("Magic Eight Ball,v0.03 - READY", 30); srand(getRandomBit()); //Random number generator seed while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { for (i=1;i<=5;i++) // Waste time display animated "<>" { clearDisplay(); for (j=0;j<8;j++){ sendStr(anim[j],16); __delay_cycles(150000); } lFlag ^= 1; } clearDisplay(); lFlag = 0; sendStr(answer[randnum], strlen(answer[randnum])); // Send message msgflag = 0; // Reset message flag } } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 11; // random number 0 to 10 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } int getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM; } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; P1OUT |= ENABLEPIN; } void sendStr(char string[], int size) { int charIndex = 0; lFlag == 0 ? sendInstruction(0x80) : sendInstruction(0xC0); // Select line while(charIndex < size) { // If "," appears in string use line 2 if (string[charIndex] == 0x2C) { sendInstruction(0xC0); // Second line charIndex++; // Bypass displaying comma } sendData(string[charIndex]); charIndex++; } } //------------------------------------------------------------------------------
  15. Like
    roger430 got a reaction from RobG in [ ENDED ] Aug-Sep 2011 - 43oh Project of the Month Contest   
    Magic Eight Ball
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch an animated "<>" and look at the answer in the LCD display. The random seed code is adapted from a translation of TI assembler code to C by NatureTM in the "Code Vault" section of this forum. I used the same LCD Display and code that is used in the "Using 3 wires to control parallel LCD display" by RobG. I had to use different ports for the display to accommodate the random number generator code.
    This project won't change the world, however, it keeps kids busy for a while. :D
     
    ** Added delay toward beginning of main(void) to allow settling of MSP430. Prior to this change the reset button had to
    be pressed to start the program.
     
    Here are some pictures as well as the schematic and code:
     

     

     

     

    //****************************************************************************** // Magic Eight Ball Project // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To use, press S1, "Magic Eight Ball v0.03 - READY" should appear on the LCD display. // Ask your question, press S2, watch "<>" animation and an answer will appear // in the LCD display. // // 08/14/11 Improved randomness of answers. Used NatureTM's code from the 43oh // forum to generate a random seed. Requires that P1.4 and P1.5 be in the Input // mode (floating). Thanks NatureTM! // // 09/17/11 Adapted output to LCD Display. Modified code from 43oh forum "Using // 3 wires to control parallel LCD display" by RobG. Thanks Robg! Also modified // nuetron's code modification to break long lines up. Thanks nuetron! // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> Pin 6 of Display (E) // | P1.7|--------> Pin 1&2 of 74HC164 (AB) // | CCI0A/RXD/P1.2|--------> Pin 8 of 74HC164 (CLK) // // R.G. Rioux // September 2011 // Built with CCS Version 4.2.4.00033 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() #include // strlen() //------------------------------------------------------------------------------ // Display related definitions //------------------------------------------------------------------------------ #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define initDisplay() sendInstruction(0x3C); sendInstruction(0x0C); clearDisplay(); sendInstruction(0x06) #define clearDisplay() sendInstruction(0x01); _delay_cycles(2000) #define DATAPIN BIT7 // P1.7 #define CLOCKPIN BIT2 // P1.2 #define ENABLEPIN BIT1 // P1.1 #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Display related functions and variables //------------------------------------------------------------------------------ void send(char data, char registerSelect); void sendStr(char data[], int length); char charIndex = 0; char bitCounter = 0; //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int seed; unsigned int randnum = 0; int i; int j; // indexes char msgflag = 0; // Used comma in string as a delimiter to break string up into two lines static char *answer[11] = { "Yes,in due time.", "My sources say,no.", "Definitely not.", "Yes.", "Probably.", "I have my,doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!", "Are you kidding?" }; // <> animation array static char *anim[8] = { " <> ", " < > ", " < > ", " < > ", " < > ", " < > ", " < > ", "< >" }; int getRandomBit(); int length = 0; int lFlag = 0; // line flag //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer _delay_cycles(100000); DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT &= ~(CLOCKPIN + DATAPIN); P1OUT &= ~(BIT0 + BIT6); P1OUT |= ENABLEPIN; // Set all pins to output except BUTTON, P1.4 and P1.5 P1DIR = 0xFF & ~(BUTTON + BIT4 + BIT5); P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); initDisplay(); sendStr("Magic Eight Ball,v0.03 - READY", 30); srand(getRandomBit()); //Random number generator seed while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { for (i=1;i<=5;i++) // Waste time display animated "<>" { clearDisplay(); for (j=0;j<8;j++){ sendStr(anim[j],16); __delay_cycles(150000); } lFlag ^= 1; } clearDisplay(); lFlag = 0; sendStr(answer[randnum], strlen(answer[randnum])); // Send message msgflag = 0; // Reset message flag } } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 11; // random number 0 to 10 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } int getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM; } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; P1OUT |= ENABLEPIN; } void sendStr(char string[], int size) { int charIndex = 0; lFlag == 0 ? sendInstruction(0x80) : sendInstruction(0xC0); // Select line while(charIndex < size) { // If "," appears in string use line 2 if (string[charIndex] == 0x2C) { sendInstruction(0xC0); // Second line charIndex++; // Bypass displaying comma } sendData(string[charIndex]); charIndex++; } } //------------------------------------------------------------------------------
  16. Like
    roger430 got a reaction from bluehash in Magic Eight Ball   
    Magic Eight Ball Part II
    I decided to update this project by adding code to generate a random seed for the random number generator. This gives a little better randomness to the answers. I also added a LCD display as pictured below. The random seed code is adapted from a translation of TI assembler code to C from NatureTM in the "Code Vault" section of this forum. I used the same LCD Display that is used in the "Using 3 wires to control parallel LCD display" by RobG. I had to use different ports to accommodate the random number generator code.
    This project won't change the world, however, it kept kids busy for a while.
     
    ** Added delay toward beginning of main(void) to allow settling of MSP430. Prior to this change the reset button had to
    be pressed to start the program.
     

     

     

     

    //****************************************************************************** // Magic Eight Ball Project // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To use, press S1, "Magic Eight Ball v0.03 - READY" should appear on the LCD display. // Ask your question, press S2, watch "<>" animation and an answer will appear // in the LCD display. // // 08/14/11 Improved randomness of answers. Used NatureTM's code from the 43oh // forum to generate a random seed. Requires that P1.4 and P1.5 be in the Input // mode (floating). Thanks NatureTM! // // 09/17/11 Adapted output to LCD Display. Modified code from 43oh forum "Using // 3 wires to control parallel LCD display" by RobG. Thanks Robg! Also modified // nuetron's code modification to break long lines up. Thanks nuetron! // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> Pin 6 of Display (E) // | P1.7|--------> Pin 1&2 of 74HC164 (AB) // | CCI0A/RXD/P1.2|--------> Pin 8 of 74HC164 (CLK) // // R.G. Rioux // September 2011 // Built with CCS Version 4.2.4.00033 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() #include // strlen() //------------------------------------------------------------------------------ // Display related definitions //------------------------------------------------------------------------------ #define sendData(data) send(data, 1) #define sendInstruction(data) send(data, 0) #define initDisplay() sendInstruction(0x3C); sendInstruction(0x0C); clearDisplay(); sendInstruction(0x06) #define clearDisplay() sendInstruction(0x01); _delay_cycles(2000) #define DATAPIN BIT7 // P1.7 #define CLOCKPIN BIT2 // P1.2 #define ENABLEPIN BIT1 // P1.1 #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Display related functions and variables //------------------------------------------------------------------------------ void send(char data, char registerSelect); void sendStr(char data[], int length); char charIndex = 0; char bitCounter = 0; //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int seed; unsigned int randnum = 0; int i; int j; // indexes char msgflag = 0; // Used comma in string as a delimiter to break string up into two lines static char *answer[11] = { "Yes,in due time.", "My sources say,no.", "Definitely not.", "Yes.", "Probably.", "I have my,doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!", "Are you kidding?" }; // <> animation array static char *anim[8] = { " <> ", " < > ", " < > ", " < > ", " < > ", " < > ", " < > ", "< >" }; int getRandomBit(); int length = 0; int lFlag = 0; // line flag //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer _delay_cycles(100000); DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT &= ~(CLOCKPIN + DATAPIN); P1OUT &= ~(BIT0 + BIT6); P1OUT |= ENABLEPIN; // Set all pins to output except BUTTON, P1.4 and P1.5 P1DIR = 0xFF & ~(BUTTON + BIT4 + BIT5); P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); initDisplay(); sendStr("Magic Eight Ball,v0.03 - READY", 30); srand(getRandomBit()); //Random number generator seed while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { for (i=1;i<=5;i++) // Waste time display animated "<>" { clearDisplay(); for (j=0;j<8;j++){ sendStr(anim[j],16); __delay_cycles(150000); } lFlag ^= 1; } clearDisplay(); lFlag = 0; sendStr(answer[randnum], strlen(answer[randnum])); // Send message msgflag = 0; // Reset message flag } } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 11; // random number 0 to 10 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } int getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM; } void send(char data, char registerSelect) { bitCounter = 0; while(bitCounter < 8) { (data & BIT7) ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); data <<= 1; P1OUT |= CLOCKPIN; P1OUT &= ~CLOCKPIN; bitCounter++; } registerSelect ? (P1OUT |= DATAPIN) : (P1OUT &= ~DATAPIN); P1OUT &= ~ENABLEPIN; P1OUT |= ENABLEPIN; } void sendStr(char string[], int size) { int charIndex = 0; lFlag == 0 ? sendInstruction(0x80) : sendInstruction(0xC0); // Select line while(charIndex < size) { // If "," appears in string use line 2 if (string[charIndex] == 0x2C) { sendInstruction(0xC0); // Second line charIndex++; // Bypass displaying comma } sendData(string[charIndex]); charIndex++; } } //------------------------------------------------------------------------------
  17. Like
    roger430 got a reaction from jsolarski in Magic Eight Ball   
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch the blinking lights and look at the answer in a terminal program such as "minicom" in Linux or "putty.exe" in WinXP/Vista/Win7. You have to configure your comm program to read what ever port the Launchpad uses (for my Linux box it is /dev/ttyACM0 and for my Windows 7 box it was COM5 - the options are 9600,8,N,1 no flow control). I imagine a serial LCD device could be used, however, I don't have one. If anyone tries this project with a serial LCD display, please let me know how it works. I'm sure my code could be cleaned up to be more efficient, however, as I said I'm learning! The device pulls about 75-80 uA when it's waiting for a button press in LPM0 mode. Here is the code:
     

    //****************************************************************************** // Magic Eight Ball Project // UART code taken from msp430g2xx1_ta_uart9600.c example file. // (D. Dang, Texas Instuments Inc.) // MSP430G2xx1 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo, 32kHz ACLK // ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO // //* An external watch crystal is required on XIN XOUT for ACLK *// // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To operate, simply connect Launchpad to PC USB port and fire up a comm program // such as "minicom" in Linux or "putty.exe" in Windows XP/Vista/7. (Be sure to // configure your comm program for whatever comm port the Launchpad uses.) // Press S1 (Reset) on Launchpad. "Magic Eight Ball Ready" should appear in // terminal window. // Ask your question, press S2, watch the blinking lights and answer will appear // in the terminal window. // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> // | | 9600 8N1 // | CCI0A/RXD/P1.2|<-------- // // R.G. Rioux // July 2011 // Built with CCS Version 4.2.3.00004 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (1000000 / (9600 * 2)) #define UART_TBIT (1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for full-duplex UART communication //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int randnum = 0; int i; char msgflag = 0; static char *answer[10] = { "Yes, in due time.", "My sources say no.", "Definitely not.", "Yes.", "Probably.", "I have my doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!" }; //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD; // Timer function for TXD pin P1DIR = 0xFF & ~BUTTON; // Set all pins but BUTTON to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("Magic Eight Ball v0.01\r\n"); TimerA_UART_print("READY.\r\n"); while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { P1OUT |= BIT6; for (i=1;i<=25;i++) { P1OUT ^= BIT0 + BIT6; // Flash LEDs __delay_cycles(100000); } P1OUT &= ~(BIT0 + BIT6); TimerA_UART_print(answer[randnum]); // Send message TimerA_UART_print("\r\n"); // Send CRLF msgflag = 0; // Reset message flag } } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ void TimerA_UART_init(void) { TACCTL0 = OUT; // Set TXD Idle as Mark = '1' TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got TX'd TACCR0 = TAR; // Current state of TA counter TACCR0 += UART_TBIT; // One bit time till first bit TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int txData = byte; // Load global variable txData |= 0x100; // Add mark stop bit to TXData txData <<= 1; // Add space start bit } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to CCRx if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 10; // random number 0 to 9 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } //------------------------------------------------------------------------------
  18. Like
    roger430 got a reaction from SouLSLayeR in Magic Eight Ball   
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch the blinking lights and look at the answer in a terminal program such as "minicom" in Linux or "putty.exe" in WinXP/Vista/Win7. You have to configure your comm program to read what ever port the Launchpad uses (for my Linux box it is /dev/ttyACM0 and for my Windows 7 box it was COM5 - the options are 9600,8,N,1 no flow control). I imagine a serial LCD device could be used, however, I don't have one. If anyone tries this project with a serial LCD display, please let me know how it works. I'm sure my code could be cleaned up to be more efficient, however, as I said I'm learning! The device pulls about 75-80 uA when it's waiting for a button press in LPM0 mode. Here is the code:
     

    //****************************************************************************** // Magic Eight Ball Project // UART code taken from msp430g2xx1_ta_uart9600.c example file. // (D. Dang, Texas Instuments Inc.) // MSP430G2xx1 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo, 32kHz ACLK // ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO // //* An external watch crystal is required on XIN XOUT for ACLK *// // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To operate, simply connect Launchpad to PC USB port and fire up a comm program // such as "minicom" in Linux or "putty.exe" in Windows XP/Vista/7. (Be sure to // configure your comm program for whatever comm port the Launchpad uses.) // Press S1 (Reset) on Launchpad. "Magic Eight Ball Ready" should appear in // terminal window. // Ask your question, press S2, watch the blinking lights and answer will appear // in the terminal window. // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> // | | 9600 8N1 // | CCI0A/RXD/P1.2|<-------- // // R.G. Rioux // July 2011 // Built with CCS Version 4.2.3.00004 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (1000000 / (9600 * 2)) #define UART_TBIT (1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for full-duplex UART communication //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int randnum = 0; int i; char msgflag = 0; static char *answer[10] = { "Yes, in due time.", "My sources say no.", "Definitely not.", "Yes.", "Probably.", "I have my doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!" }; //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD; // Timer function for TXD pin P1DIR = 0xFF & ~BUTTON; // Set all pins but BUTTON to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("Magic Eight Ball v0.01\r\n"); TimerA_UART_print("READY.\r\n"); while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { P1OUT |= BIT6; for (i=1;i<=25;i++) { P1OUT ^= BIT0 + BIT6; // Flash LEDs __delay_cycles(100000); } P1OUT &= ~(BIT0 + BIT6); TimerA_UART_print(answer[randnum]); // Send message TimerA_UART_print("\r\n"); // Send CRLF msgflag = 0; // Reset message flag } } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ void TimerA_UART_init(void) { TACCTL0 = OUT; // Set TXD Idle as Mark = '1' TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got TX'd TACCR0 = TAR; // Current state of TA counter TACCR0 += UART_TBIT; // One bit time till first bit TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int txData = byte; // Load global variable txData |= 0x100; // Add mark stop bit to TXData txData <<= 1; // Add space start bit } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to CCRx if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 10; // random number 0 to 9 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } //------------------------------------------------------------------------------
  19. Like
    roger430 got a reaction from bluehash in Magic Eight Ball   
    Here's my first attempt at having the TI Launchpad do something a little more than flashing LEDs. I used this project to learn more about the MSP430 interrupts, GPIO, low power mode and timers. It operates similar to the old "Magic Eight Ball" in that you ask a question, press S2 (P1.3) on the Launchpad, watch the blinking lights and look at the answer in a terminal program such as "minicom" in Linux or "putty.exe" in WinXP/Vista/Win7. You have to configure your comm program to read what ever port the Launchpad uses (for my Linux box it is /dev/ttyACM0 and for my Windows 7 box it was COM5 - the options are 9600,8,N,1 no flow control). I imagine a serial LCD device could be used, however, I don't have one. If anyone tries this project with a serial LCD display, please let me know how it works. I'm sure my code could be cleaned up to be more efficient, however, as I said I'm learning! The device pulls about 75-80 uA when it's waiting for a button press in LPM0 mode. Here is the code:
     

    //****************************************************************************** // Magic Eight Ball Project // UART code taken from msp430g2xx1_ta_uart9600.c example file. // (D. Dang, Texas Instuments Inc.) // MSP430G2xx1 Demo - Timer_A, Ultra-Low Pwr UART 9600 Echo, 32kHz ACLK // ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO // //* An external watch crystal is required on XIN XOUT for ACLK *// // // Description: Simple Magic Eight Ball adaptation utilizing the MSP430 Launchpad. // To operate, simply connect Launchpad to PC USB port and fire up a comm program // such as "minicom" in Linux or "putty.exe" in Windows XP/Vista/7. (Be sure to // configure your comm program for whatever comm port the Launchpad uses.) // Press S1 (Reset) on Launchpad. "Magic Eight Ball Ready" should appear in // terminal window. // Ask your question, press S2, watch the blinking lights and answer will appear // in the terminal window. // // MSP430G2xx1 // ----------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // <---|P1.3 Switch | // | CCI0B/TXD/P1.1|--------> // | | 9600 8N1 // | CCI0A/RXD/P1.2|<-------- // // R.G. Rioux // July 2011 // Built with CCS Version 4.2.3.00004 //****************************************************************************** #include "msp430g2231.h" #include // rand() & srand() //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define UART_TXD 0x02 // TXD on P1.1 (Timer0_A.OUT0) #define UART_RXD 0x04 // RXD on P1.2 (Timer0_A.CCI1A) #define BUTTON BIT3 // Button on P1.3 //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 (1000000 / (9600 * 2)) #define UART_TBIT (1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for full-duplex UART communication //------------------------------------------------------------------------------ unsigned int txData; // UART internal variable for TX unsigned char rxBuffer; // Received UART character //------------------------------------------------------------------------------ // Global variables in program //------------------------------------------------------------------------------ unsigned int randnum = 0; int i; char msgflag = 0; static char *answer[10] = { "Yes, in due time.", "My sources say no.", "Definitely not.", "Yes.", "Probably.", "I have my doubts.", "Who knows?", "Looking good!", "Go for it!", "Forget about it!" }; //------------------------------------------------------------------------------ // Function prototypes //------------------------------------------------------------------------------ void TimerA_UART_init(void); void TimerA_UART_tx(unsigned char byte); void TimerA_UART_print(char *string); //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer DCOCTL = 0x00; // Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_TXD; // Timer function for TXD pin P1DIR = 0xFF & ~BUTTON; // Set all pins but BUTTON to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; P1IE |= BUTTON; //P1.3 interrupt enabled P1IFG = 0x00; //Clear all interrupt flags __enable_interrupt(); TimerA_UART_init(); // Start Timer_A UART TimerA_UART_print("Magic Eight Ball v0.01\r\n"); TimerA_UART_print("READY.\r\n"); while (1) { _bis_SR_register(LPM0_bits + GIE); if (msgflag == 1) { P1OUT |= BIT6; for (i=1;i<=25;i++) { P1OUT ^= BIT0 + BIT6; // Flash LEDs __delay_cycles(100000); } P1OUT &= ~(BIT0 + BIT6); TimerA_UART_print(answer[randnum]); // Send message TimerA_UART_print("\r\n"); // Send CRLF msgflag = 0; // Reset message flag } } } //------------------------------------------------------------------------------ // Function configures Timer_A for full-duplex UART operation //------------------------------------------------------------------------------ void TimerA_UART_init(void) { TACCTL0 = OUT; // Set TXD Idle as Mark = '1' TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode } //------------------------------------------------------------------------------ // Outputs one byte using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_tx(unsigned char byte) { while (TACCTL0 & CCIE); // Ensure last char got TX'd TACCR0 = TAR; // Current state of TA counter TACCR0 += UART_TBIT; // One bit time till first bit TACCTL0 = OUTMOD0 + CCIE; // Set TXD on EQU0, Int txData = byte; // Load global variable txData |= 0x100; // Add mark stop bit to TXData txData <<= 1; // Add space start bit } //------------------------------------------------------------------------------ // Prints a string over using the Timer_A UART //------------------------------------------------------------------------------ void TimerA_UART_print(char *string) { while (*string) { TimerA_UART_tx(*string++); } } //------------------------------------------------------------------------------ // Timer_A UART - Transmit Interrupt Handler //------------------------------------------------------------------------------ #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A0_ISR(void) { static unsigned char txBitCnt = 10; TACCR0 += UART_TBIT; // Add Offset to CCRx if (txBitCnt == 0) { // All bits TXed? TACCTL0 &= ~CCIE; // All bits TXed, disable interrupt txBitCnt = 10; // Re-load bit counter } else { if (txData & 0x01) { TACCTL0 &= ~OUTMOD2; // TX Mark '1' } else { TACCTL0 |= OUTMOD2; // TX Space '0' } txData >>= 1; txBitCnt--; } } // Switch interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { randnum = rand() % 10; // random number 0 to 9 // Not very random, however, adequate for // this project. msgflag = 1; // message flag P1IFG &= ~BUTTON; // reset interrupt flag _bic_SR_register_on_exit(LPM0_bits); } //------------------------------------------------------------------------------
×
×
  • Create New...