Jump to content


Popular Content

Showing content with the highest reputation on 02/04/2012 in Posts

  1. 3 points
    I wanted to try out myself how well solar energy really works. Toward this aim I built a solar collector system for waterheating. A small boiler with a heat exchanger is used for heat storage and a ordinary heating pump for the water circulation. Temperature is measured at the collector, at the entrance and outlet of the heat exchanger and inside the heat storage boiler. As a controller for the pump I used an MSP430 launchpad. There were several problems I had to solve. First, temperature must be measured with a resolution of at least 1 degree. My preferred temperature sensor would have been a Pt100. This sensors are accurate and linear, but not very sensitive. With a 8 bit AD converter, a resolution of not more than 4 degree is possible, not good enough. Therefore I was forced to use NTC sensors. These are more sensitive, but not very accurate and the resistance changes with temperature not linearly, but exponentially. When I tried this out, I had to realize that the exponential function of C uses too much memory. Therefore, I had to find a replacement and I used a rational approximation that uses much less space and works satisfactorily accurate. Further, as the NTC sensors are not accurate enough, I had to measure the value of each and correct by software. To supervise the working of the controller I transmit the temperature values, the state of the pump and what action is taken to a PC that can be connected to the launchpad. This is actually not needed for the working of the controller, but it is nice to have a mean to see what is going on. Here is how the program works: After initialization we enter an infinite loop, that does the actual work. - First all 4 temperature values are measured. According to these values we decide what to do. - If the boiler temp is too high, we switch the pump of for security reasons. - If the pump is off and the collector temp is higher than the boiler temp by some margin and the collector temp is above some minimal value, we switch the pump on. - If the pump is on, we compare the entry and outlet temp of the heat exchanger. If these differ less than some value, that is, practically no heat is put into the boiler, we switch the pump off. - Finally we toggle a LED every 1 sec to indicate that the controller is working and wait 1 minute before we start the next cycle. To make the temperature measurement more reliable, I measure the temp 8 times and take the average. To minimize current consumption I put the CPU to sleep during wait. This controller now works for more than half an year to my full satisfaction. I get approx. 0.75 kW / m^2 heating power on a sunny day. I only regret, that we do not have more sunny days here in Switzerland. And here is the program that uses up nearly every bit of the 2K memory: ======================================================= /* Solar collector controller * Daniel Huber 1.7.2011 daniel_huber@sunrise.ch * * Measures Pin 1.3,1.4,1.5,1.7 with average * Calculates temperatures from measured values * If boiler temp too high -> do nothing * If collector temp > boiler+ TDelCol switch on pump, wait 1 min. * If temp of heatexchanger input < heat exchanger output+TDelEx switch off pump, repeat * send values to RS232 */ #include "msp430g2231.h" #include "stdbool.h" #include "stdlib.h" #include "math.h" #include "string.h" #define Tcm 110 // max temp at collector #define Tcmin 30 // min temp at collector #define Tbm 90 // max temp at boiler #define TDelCol 5 // min. temp between Collector and Boiler #define TDelEx 2 // min. temp between heat exchanger in and out #define TXD BIT1 // TXD on P1.1 #define Bit_time 104 // 9600 Baud, SMCLK=1MHz (1MHz/ 9600)=104 #define LEDR BIT0 // LED red #define LEDG BIT6 // LED green #define CHCOLLECT INCH_4 // measure channel collector #define CHHEATEXIN INCH_5 // measure channel heat exchanger #define CHHEATEXOUT INCH_3 // measure channel heat exchanger #define CHBOILER INCH_7 // measure channel boiler // pump on/off #define PumpOn {P1OUT |= BIT0;PumpOnFl=true; } #define PumpOff {P1OUT &= ~BIT0;PumpOnFl=false; } unsigned char BitCnt; // Bit count, used when transmitting byte unsigned int TXByte; // value sent over UART when Transmit() is called int i,j; // 'for' loop variable int TCol,TExIn,TExOut,TBoiler,channel; // Measured ADC Value bool PumpOnFl; // pump on flag unsigned int ADCValue; // aux. value to return value from interrupt short state; // state variable char msg[3]; float cor,R; // Function Definitions void Transmit(); //transmits a byte int Single_Measure(); //measures with avarage void Single_Measure0(); //measure single value void TransmitRecord(/*int TCol,int TExIn,int TExOut,int TBoiler,bool PumpOnFl*/); // transmit one record void delay1(); //delays 1 sec int P2T(int P); // ADC value to degree void main(void) { WDTCTL = WDTPW + WDTHOLD+WDTCNTCL; // Stop WDT: PWD,Hold, Counter Reset BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz // BCSCTL3 |= LFXT1S1; // sets LFXT1Sx to 0b10, VLO mode, bit not set-> 32KHz BCSCTL3 |= XCAP_2; // set 10pF for cristal oscillator P1SEL |= TXD; // Connect TXD to timer pin P1DIR |= TXD | LEDR | LEDG; // use TX PumpOff; // Pump off state=1; __bis_SR_register(GIE); // interrupts enabled while(1){ msg[0]='\0'; // empty string cor=1.01*10.12;channel=CHCOLLECT; //correction factor: TCol=P2T(Single_Measure()); // collector temp cor=1*10.32;channel=CHHEATEXIN; TExIn=P2T(Single_Measure()); // heat exchanger in temp cor=0.89*10.21;channel=CHHEATEXOUT; // 0.937 takes care of R20 difference TExOut=3+P2T(Single_Measure()); // heat exchanger out temp, correct for NTC tolerance cor=1*10.32;channel=CHBOILER; TBoiler=P2T(Single_Measure());// boiler temp if (TBoiler > Tbm && state!=0) {PumpOff;state=0;strcat(msg,"st00");} switch(state){ case(0): if(TBoiler case(1): if((TCol>TBoiler+TDelCol) && TCol>=Tcmin) {PumpOn; state=2;strcat(msg,"12");} break; case(2): if(TExIn } TransmitRecord(); for(i=1;i<60;i++){ P1OUT ^= LEDG; // toggle LED at P1.6 delay1(); } } } // transmit one record void TransmitRecord(){ unsigned int k; i=0; while(i>=0){ switch(i){ case(0): k='SS'; break; case(1): k='tt'; break; case(2): k=TCol; break; case(3): k=TExIn; break; case(4): k=TExOut; break; case(5): k=TBoiler; break; case(6): if(PumpOnFl)k=1; else k=0; break; case(7): if (strlen(msg)>0){k=256*msg[1]+msg[0]; break;} else {i++;} case(8): k='EE'; break; case(9): {k='nn'; i=-2;} }; TXByte = (k & 0x00FF); // Set TXByte Transmit(); // Send TXByte = k >> 8; // Set TXByte to the upper 8 bits TXByte = TXByte & 0x00FF; Transmit(); i++; } } // averaged single measurement int Single_Measure(/*int channel*/){ int ADCAvg = 0; for (i = 0; i < 8; i++){ // add up values Single_Measure0(channel); ADCAvg += ADCValue; } ADCAvg >>= 3; // divide by 8 return ADCAvg; } /** * Reads ADC channel once, using AVCC as reference. **/ void Single_Measure0(/*int channel*/) { ADC10CTL0 &= ~ENC; // Disable ADC ADC10CTL0 = ADC10SHT_3 + ADC10ON + ADC10IE; // 64 clock ticks, ADC On, enable ADC interrupt ADC10CTL1 = ADC10SSEL_3 +channel; // Set 'chan', SMCLK __delay_cycles(1000); ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversion _BIS_SR(CPUOFF + GIE); // sleep CPU } /** * Transmits the value currently in TXByte. The function waits till it is * finished transmiting before it returns. **/ void Transmit() { TXByte |= 0x100; // Add stop bit to TXByte (which is logical 1) TXByte = TXByte << 1; // Add start bit (which is logical 0) BitCnt = 0xA; // Load Bit counter, 8 bits + ST/SP CCTL0 = OUT; // TXD Idle as Mark TACTL = TASSEL_2 + MC_2; // SMCLK, continuous mode CCR0 = TAR; // Initialize compare register CCR0 += Bit_time; // Set time till first bit CCTL0 = CCIS0 + OUTMOD0 + CCIE; // Set signal, intial value, enable interrupts while ( CCTL0 & CCIE ); // Wait for previous TX completion } /** * ADC interrupt routine. Pulls CPU out of sleep mode. **/ #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { ADCValue = ADC10MEM; // Saves measured value. __bic_SR_register_on_exit(CPUOFF); // Enable CPU so the main while loop continues } /** * Timer interrupt routine. This handles transmitting and receiving bytes. **/ #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { CCR0 += Bit_time; // Add Offset to CCR0 if ( BitCnt == 0) // If all bits TXed { TACTL = TASSEL_2; // SMCLK, timer off (for power consumption) CCTL0 &= ~ CCIE ; // Disable interrupt } else { CCTL0 |= OUTMOD2; // Set TX bit to 0 if (TXByte & 0x01) CCTL0 &= ~ OUTMOD2; // If it should be 1, set it to 1 TXByte = TXByte >> 1; BitCnt --; } } /** * function to get temperature from measured ADC value **/ int P2T(int P){ #define P0 0x3FF R=cor*P/(P0-P); return( (159.444F+R*(29.4008F-0.21077F * R))/(1+R*(0.59504F+0.0155797F * R)) ); } //put CPU to sleep for 1 sec void delay1(){ IE1 |= WDTIE; // Watchdog Interrupt Enable WDTCTL = WDTPW+WDTTMSEL+WDTSSEL; // Passwd(WDTPW), Counter-Mode //Intervall(WDTTMSEL),Timer= "0"(WDTCNTCL), //SourceClk=ACLCK(WDTSSEL),Sel:00=Clk/32768 01=Clk/8192 10:Clk/512 11=Clk/64 _BIS_SR(LPM3_bits + GIE); // put CPU to sleep LPM1_bits } // delay interrupt routine, wakes up CPU #pragma vector=WDT_VECTOR __interrupt void WATCHDOG_ISR (void){ // interrupt routine for delay WDTCTL = WDTPW + WDTHOLD+WDTCNTCL; //Password(WDTPW), //Watchdog stop(WDTHOLD),Counter=0, this resets register(exeption: hold bit) // IE1 &= ~WDTIE; // Watchdog Interrupt Disable __bic_SR_register_on_exit(LPM3_bits); // clear LPM3 bits so the main while loop continues } ========================================================
  2. 3 points

    Nokia 5110 C++ Template Class

    This is a C++ template for the Nokia 5100 that uses software SPI. Inspired by Rickta59's GPIO template Using C++ templates allow the compiler to make decisions at compile time that would normally occur (repeatedly) at execution time. This results in smaller and faster code. They also are type safe and compatible with source level debugging (unlike macros). Software SPI is used to make the code very portable to the entire MSP430 family and allow flexible pin assignment. Four wiring schemes are supported. This is the syntax for creating an instance of the template. Nokia5110< \ // Template name P1OUT, // Output port for clock and data BIT0, // Clock pin bitmask BIT1, // Data pin bitmask P1OUT, // Output port for DC (data/command), use PNONE if DC line is not used BIT2, // DC pin bitmask (or clock stretch cycles if DC line is not used) P1OUT, // Output port for CE (chip enable), use PNONE if CE line is not used BIT3, // CE pin bitmask 10000> \ // Reset cycle count lcd; // Object name The class template namespace nokia5110 { unsigned char PNONE; 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; template struct Nokia5110 { void write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type = lcd_data); void reset(void); void init(void); void vert(void); void home(void); void pos(unsigned char x, unsigned char y); void clear(unsigned char x = 0); void bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h); inline void bitmap(const unsigned char *bmp, signed char x, signed char y) { bitmap(bmp + 2, x, y, bmp[0], bmp[1]); }; void print(char c); inline void print(unsigned char x, unsigned char y, char c) { pos(x, y); print(c); }; void print(char *s); inline void print(unsigned char x, unsigned char y, char *s) { pos(x, y); print(s); }; void printv(unsigned char x, unsigned char y, char *s); }; template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type) { register unsigned mask; if(&_EP != &PNONE) _EP &= ~_CE; do { mask = 0x0080; do { if(*cmd & mask) { _SP |= _DATA; _SP &= ~_CLK; } else { _SP &= ~(_CLK | _DATA); } _SP |= _CLK; mask >>= 1; } while(!(mask & 1)); if(&_CP == &PNONE) { __delay_cycles(_DC); } else { if(!type) _CP &= ~_DC; } if(*cmd & mask) { _SP |= _DATA; _SP &= ~_CLK; } else { _SP &= ~(_CLK | _DATA); } _SP |= _CLK; if(&_CP != &PNONE) _CP |= _DC; if(!(type & 2)) ++cmd; } while(--len); if(&_EP != &PNONE) _EP |= _CE; } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::reset(void) { // --- Set initial state of CLK, DC and CE as needed // * = output used for reset if(&_CP == &PNONE) { if(&_EP != &PNONE) { // CLK*, DATA, CE _EP |= _CE; } // else // CLK*, DATA } else { if(&_EP != &PNONE) { // CLK, DATA, DC*, CE if(&_SP == &_EP) { _SP |= (_CLK | _CE); } else { _SP |= _CLK; _EP |= _CE; } } // else // CLK, DATA, DC* } // --- Reset pulse on CLK or DC as needed if(&_CP == &PNONE) { // No DC port, use CLK to reset _SP &= ~_CLK; __delay_cycles(_RST); _SP |= _CLK; } else { // Use DC to reset _CP &= ~_DC; __delay_cycles(_RST); _CP |= _DC; } __delay_cycles(_RST); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::init(void) { static const unsigned char init[] = { 0x20 | 0x01, // Function set - extended instructions enabled //0x80 | 64, // Set vop (contrast) 0 - 127 0x80 | 70, // Higher contrast improves animation 0x04 | 2, // Temperature control 0x10 | 3, // Set bias system 0x20 | 0x00, // Function set - chip active, horizontal addressing, basic instructions 0x08 | 0x04 // Display control - normal mode }; write(init, sizeof(init), lcd_command); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::vert(void) { static const unsigned char v[] = { 0x20 | 0x02, // Function set - chip active, vertical addressing, basic instructions }; write(v, sizeof(v), lcd_command); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::home(void) { static const unsigned char home[] = { 0x40, 0x80 }; write(home, sizeof(home), lcd_command); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::pos(unsigned char x, unsigned char y) { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 | y; write(c, sizeof(c), lcd_command); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::clear(unsigned char x) { home(); write(&x, 504, lcd_data_repeat); home(); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h) { unsigned char c[2]; unsigned char ww; if(x < 0) { ww = w + x; bmp -= x; x = 0; } else if(x + w >= 84) { ww = (84 - x); } else { ww = w; } c[0] = 0x80 | x; c[1] = 0x40 | y; while(h--) { write(c, sizeof(c), lcd_command); ++c[1]; write(bmp, ww); bmp += w; } } static const unsigned char font[96][5] = { 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x5F, 0x00, 0x00, // ! 0x00, 0x07, 0x00, 0x07, 0x00, // " 0x14, 0x7F, 0x14, 0x7F, 0x14, // # 0x24, 0x2A, 0x7F, 0x2A, 0x12, // $ 0x23, 0x13, 0x08, 0x64, 0x62, // % 0x36, 0x49, 0x56, 0x20, 0x50, // & 0x00, 0x08, 0x07, 0x03, 0x00, // ' 0x00, 0x1C, 0x22, 0x41, 0x00, // ( 0x00, 0x41, 0x22, 0x1C, 0x00, // ) 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // * 0x08, 0x08, 0x3E, 0x08, 0x08, // + 0x00, 0x40, 0x38, 0x18, 0x00, // , 0x08, 0x08, 0x08, 0x08, 0x08, // - 0x00, 0x00, 0x60, 0x60, 0x00, // . 0x20, 0x10, 0x08, 0x04, 0x02, // / 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 0x42, 0x61, 0x51, 0x49, 0x46, // 2 0x21, 0x41, 0x49, 0x4D, 0x33, // 3 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 0x27, 0x45, 0x45, 0x45, 0x39, // 5 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 0x41, 0x21, 0x11, 0x09, 0x07, // 7 0x36, 0x49, 0x49, 0x49, 0x36, // 8 0x06, 0x49, 0x49, 0x29, 0x1E, // 9 0x00, 0x00, 0x14, 0x00, 0x00, // : 0x00, 0x00, 0x40, 0x34, 0x00, // ; 0x00, 0x08, 0x14, 0x22, 0x41, // < 0x14, 0x14, 0x14, 0x14, 0x14, // = 0x00, 0x41, 0x22, 0x14, 0x08, // > 0x02, 0x01, 0x51, 0x09, 0x06, // ? 0x3E, 0x41, 0x5D, 0x59, 0x4E, // @ 0x7C, 0x12, 0x11, 0x12, 0x7C, // A 0x7F, 0x49, 0x49, 0x49, 0x36, // B 0x3E, 0x41, 0x41, 0x41, 0x22, // C 0x7F, 0x41, 0x41, 0x41, 0x3E, // D 0x7F, 0x49, 0x49, 0x49, 0x41, // E 0x7F, 0x09, 0x09, 0x09, 0x01, // F 0x3E, 0x41, 0x49, 0x49, 0x7A, // G 0x7F, 0x08, 0x08, 0x08, 0x7F, // H 0x00, 0x41, 0x7F, 0x41, 0x00, // I 0x20, 0x40, 0x41, 0x3F, 0x01, // J 0x7F, 0x08, 0x14, 0x22, 0x41, // K 0x7F, 0x40, 0x40, 0x40, 0x40, // L 0x7F, 0x02, 0x1C, 0x02, 0x7F, // M 0x7F, 0x04, 0x08, 0x10, 0x7F, // N 0x3E, 0x41, 0x41, 0x41, 0x3E, // O 0x7F, 0x09, 0x09, 0x09, 0x06, // P 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q 0x7F, 0x09, 0x19, 0x29, 0x46, // R 0x26, 0x49, 0x49, 0x49, 0x32, // S 0x01, 0x01, 0x7F, 0x01, 0x01, // T 0x3F, 0x40, 0x40, 0x40, 0x3F, // U 0x1F, 0x20, 0x40, 0x20, 0x1F, // V 0x3F, 0x40, 0x38, 0x40, 0x3F, // W 0x63, 0x14, 0x08, 0x14, 0x63, // X 0x03, 0x04, 0x78, 0x04, 0x03, // Y 0x61, 0x51, 0x49, 0x45, 0x43, // Z 0x00, 0x7F, 0x41, 0x41, 0x41, // [ 0x02, 0x04, 0x08, 0x10, 0x20, // '\' 0x00, 0x41, 0x41, 0x41, 0x7F, // ] 0x04, 0x02, 0x01, 0x02, 0x04, // ^ 0x80, 0x80, 0x80, 0x80, 0x80, // _ 0x00, 0x03, 0x07, 0x08, 0x00, // ' 0x20, 0x54, 0x54, 0x54, 0x78, // a 0x7F, 0x28, 0x44, 0x44, 0x38, // b 0x38, 0x44, 0x44, 0x44, 0x28, // c 0x38, 0x44, 0x44, 0x28, 0x7F, // d 0x38, 0x54, 0x54, 0x54, 0x18, // e 0x00, 0x08, 0x7E, 0x09, 0x02, // f 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g 0x7F, 0x08, 0x04, 0x04, 0x78, // h 0x00, 0x44, 0x7D, 0x40, 0x00, // i 0x00, 0x20, 0x40, 0x40, 0x3D, // j 0x00, 0x7F, 0x10, 0x28, 0x44, // k 0x00, 0x41, 0x7F, 0x40, 0x00, // l 0x7C, 0x04, 0x78, 0x04, 0x78, // m 0x7C, 0x08, 0x04, 0x04, 0x78, // n 0x38, 0x44, 0x44, 0x44, 0x38, // o 0xFC, 0x18, 0x24, 0x24, 0x18, // p 0x18, 0x24, 0x24, 0x18, 0xFC, // q 0x7C, 0x08, 0x04, 0x04, 0x08, // r 0x48, 0x54, 0x54, 0x54, 0x24, // s 0x04, 0x04, 0x3F, 0x44, 0x24, // t 0x3C, 0x40, 0x40, 0x20, 0x7C, // u 0x1C, 0x20, 0x40, 0x20, 0x1C, // v 0x3C, 0x40, 0x30, 0x40, 0x3C, // w 0x44, 0x28, 0x10, 0x28, 0x44, // x 0x4C, 0x90, 0x90, 0x90, 0x7C, // y 0x44, 0x64, 0x54, 0x4C, 0x44, // z 0x00, 0x08, 0x36, 0x41, 0x00, // { 0x00, 0x00, 0x77, 0x00, 0x00, // | 0x00, 0x41, 0x36, 0x08, 0x00, // } 0x02, 0x01, 0x02, 0x04, 0x02, // ~ 0x00, 0x06, 0x09, 0x09, 0x06, // degrees }; template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::print(char c) { write(&font[c - 32][0], 5); write(&font[0][0], 1); } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::print(char *s) { while(*s) { write(&font[*s - 32][0], 5); write(&font[0][0], 1); ++s; } } template void Nokia5110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RST>::printv(unsigned char x, unsigned char y, char *s) { while(*s) { pos(x, y); ++y; write(&font[*s - 32][0], 5); write(&font[0][0], 1); ++s; } } } // namespace Test code #include "msp430g2553.h" #include "nokia5110tl.h" using namespace nokia5110; static const unsigned char ti[] = { 48, 48 / 8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC, 0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0xF0, 0xF0,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFC,0xFC,0x3C,0x80,0xFC,0xFD, 0xFD,0xFD,0x3D,0x81,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC, 0xFC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0x00, 0x00,0x1C,0x7C,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC,0xFC, 0xFC,0xFC,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xF7,0xF0,0xF0,0x00,0xF0,0xFF,0xFF,0xFF, 0xFF,0x0F,0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xF0,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x3F,0x7F,0xFF, 0xFF,0xFF,0xFF,0xFF,0x7F,0x3F,0x3F,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0x1F,0x00,0x1E,0x1F,0x1F,0x1F,0x1F, 0x01,0x1E,0x1F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x7F,0x7F,0x3F,0x3F,0x3F,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x03, 0x0F,0x3F,0xFF,0xFE,0xFE,0xFE,0xFC,0xFC,0xFC,0xFC, 0xFC,0xFC,0xFC,0x7F,0x1F,0x07,0x03,0x03,0x01,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01,0x07,0x0F,0x0F,0x1F,0x1F,0x3F, 0x3F,0x3F,0x3F,0x1C,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; static const unsigned char g0[] = { 40, 40 / 8, 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x20,0x10,0x20, 0x20,0x40,0x80,0x80,0x00,0x00,0xE0,0x1E,0x02,0x02, 0x0C,0x30,0xC0,0x80,0x40,0x20,0x20,0x10,0x08,0x08, 0xD0,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xC0,0x40,0x40,0x40,0x40,0x40,0x43,0x6C,0x10, 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E, 0x11,0x10,0x10,0x08,0x08,0x08,0x88,0xB0,0x40,0x00, 0x00,0x03,0x02,0x04,0x84,0x88,0x48,0x70,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x1E,0x12,0x21,0x21,0x20,0x40,0xC0,0x00, 0x00,0x02,0x0D,0x11,0x10,0x10,0x10,0x08,0x08,0x88, 0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00, 0x08,0x36,0xC2,0x02,0x02,0x02,0x02,0x02,0x03,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0B, 0x10,0x10,0x08,0x04,0x04,0x02,0x01,0x03,0x0C,0x30, 0xC0,0x40,0x78,0x07,0x00,0x00,0x01,0x01,0x02,0x04, 0x04,0x08,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00 }; static const unsigned char g1[] = { 40, 40 / 8, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30, 0xC8,0x08,0x04,0x08,0x30,0x40,0x80,0x80,0xC0,0x38, 0x06,0x02,0x02,0x1E,0xE0,0x00,0x00,0x80,0x80,0x40, 0x40,0x20,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x30,0x4C,0x84,0x84,0x04,0x08,0x08,0x08, 0x09,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x00,0x00, 0x20,0x58,0x44,0x43,0x40,0x80,0x80,0x80,0x80,0x00, 0x00,0xE0,0x20,0x10,0x10,0x10,0x09,0x0E,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,0x90,0x08,0x08,0x08,0x04,0x07,0x00, 0x00,0x01,0x01,0x01,0x01,0x02,0xC2,0x22,0x1A,0x04, 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x90, 0x10,0x10,0x10,0x20,0x21,0x21,0x32,0x0C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x04,0x02, 0x02,0x01,0x01,0x00,0x00,0x07,0x78,0x40,0x40,0x60, 0x1C,0x03,0x01,0x01,0x02,0x0C,0x10,0x20,0x10,0x13, 0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; static const unsigned char g2[] = { 40, 40 / 8, 0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFC,0x04,0x02,0x02,0x0C,0x30,0xC0, 0x80,0x80,0x60,0x18,0x06,0x02,0xC4,0x3C,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x03,0x04,0x19,0xA1,0x42,0x02, 0x04,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x02,0x04,0x04, 0x02,0x82,0x42,0x21,0x11,0x0A,0x04,0x00,0x00,0x00, 0x00,0x1C,0x14,0x22,0x22,0x22,0x41,0x41,0x80,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x01,0x82,0x82,0x44,0x44,0x44,0x28,0x38,0x00, 0x00,0x00,0x00,0x20,0x50,0x88,0x84,0x42,0x41,0x40, 0x20,0x20,0x40,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x20, 0x40,0x42,0x85,0x98,0x20,0xC0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x3C,0x23,0x40,0x60,0x18,0x06,0x01,0x01, 0x03,0x0C,0x30,0x40,0x40,0x20,0x3F,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 }; static const unsigned RXD = BIT2; static const unsigned SWITCH = BIT3; static const unsigned LCD_DC = BIT0; static const unsigned LCD_CE = BIT4; static const unsigned LCD_CLK = BIT5; static const unsigned LCD_BACKLIGHT = BIT6; static const unsigned LCD_DATA = BIT7; int main(void) { WDTCTL = WDTPW | WDTHOLD; P1REN = RXD | SWITCH; P1DIR = LCD_DC | LCD_CE | LCD_CLK | LCD_BACKLIGHT | LCD_DATA; P1OUT = LCD_CLK | LCD_DC | RXD | SWITCH | LCD_CE | LCD_BACKLIGHT; Nokia5110 lcd; lcd.reset(); lcd.init(); lcd.clear(); for(int x = -47; x < 14; ++x) { lcd.bitmap(ti, x, 0); __delay_cycles(20000); } lcd.printv(0, 0, "MSP430"); lcd.printv(70, 0, "Nokia"); lcd.printv(78, 2, "5110"); __delay_cycles(2000000); lcd.clear(); for(int x = 14; x < 84; ++x) { lcd.bitmap(ti, x, 0); __delay_cycles(20000); } lcd.home(); char c; for(c = 33; c <= 116; ++c) { lcd.print(c); } __delay_cycles(2000000); lcd.clear(); lcd.print(0, 5, "Template Class"); for(; { for(signed char x = -39; x < 84; ) { lcd.bitmap(g0, x++, 0); __delay_cycles(100000); lcd.bitmap(g1, x++, 0); __delay_cycles(100000); lcd.bitmap(g2, x++, 0); __delay_cycles(100000); } } return 0; }
  3. 1 point
    This is my attempt for a basic library to control an 16x2 or more LCD display using 6 PIN and controling the hd44780 in 4bit mode. Main .c: http://dl.dropbox.com/u/13477186/MSP430 ... _example.c Library .h: http://dl.dropbox.com/u/13477186/MSP430 ... _hd44780.h Library .c: http://dl.dropbox.com/u/13477186/MSP430 ... _hd44780.c Makefile : http://dl.dropbox.com/u/13477186/MSP430 ... 0/Makefile It working great for my needs so far. Work on my 4 line display too.. My next step will be to make this library support the use of an 595 for 3 pin operation. I would also like some way to allow multiple display... But it seem doing this will require using more memory, and I'm trying to stay away from that. I'll would love some constructive feedback... Thanks Moc UPDATE 22h34 4 feb 12: I've lowered the footprint from 800byte to 440 byte for the demo program using compiler optimization and code change.
  4. 1 point

    i2c Explorer

    NOTE: This was built using IAR, for an msp430 with the USI peripheral. It will need editing to work on USCI peripherals or if compiled in CCS or GCC. Updated 12/12/12: http://forum.43oh.com/topic/126-i2c-explorer/?p=25918 I like i2c, and have one main project I want to create based on turning a scrolling led display into a computer/net/micro controller accessible one (it has an i2c eeprom, and its original mc is still in use). Having gotten the launchpad, it was one step closer to completion. The next step was getting i2c protocol working and such. With the builtin USI of the launchpad, and Joby's SPI explorer (which uses NJ's uart to boot), I was able to make an i2c Explorer. It uses the UART code without modification (except that I am using IAR instead of mspgcc or CCS) and modified Joby's command processing, with the i2c USI built from scratch. There are a handful of commands. [- i2c START bx or 0bx- Transmit Binary number hx or 0x- Transmit Hex number x- Transmit Decimal number r read with Acknowledge (Ack) n read with No-Acknowledge (Nack) s Search for i2c Slaves ]- i2c STOP Nearly the same commands as the buspirate/busninja/spi-explorer. I broke out the nack read because it was easier, allows more control, and not all i2c slaves want/expect a nack on the last read. It is not completely refined. Still some stuff that needs to be removed/polished (Slave search should only output on responded addresses, instead of needing someone to search through all 255 address tests responses.) Bus speed is non-standard as far as I can see (USI Clock is SMCLK at 1mhz, divided at 128 as per TI's USI application note. 1mhz/128 = 7812hz = ~8khz???) This needs to be fixed, and a TI introduction to USI/USCI powerpoint shows that the bus can be driven at 500khz at 1mhz clock. Probably just needs the correct divider selection (Divide clock by 2 for 500k (400k i2c speed) or by 8 for 125k (100k i2c speed). This is beta/preliminary release. Only been tested with a PCF8574. Code clocks in at 1920 bytes, with no optimization (Standard IAR project with no defaults changed). UART at 9600 like normal, pin 1.7 is sda, pin 1.6 is scl (can't be changed due to USI so remove the p1.6 led jumper) and p1.0 is a status light. Will be testing with faster speed and more i2c devices soon. i2c.zip
  • Create New...