Jump to content

timotet

Members
  • Content Count

    223
  • Joined

  • Last visited

  • Days Won

    1

Reputation Activity

  1. Like
    timotet reacted to brain in Stm32f0 discovery st-link error   
    No not that. But it's alright. See attchment for what I meant.
     
    Did you by any chance program GPIOs in your application program that are also SWD pins. If yes, change your GPIO to something else for now. To reprogram the board, hold it in reset and try to connect immediately after you release reset. This will hopefully allow gdb to connect even before the chip starts its application program.
     

  2. Like
    timotet got a reaction from fj604 in MSP430 USI i2c and Adafruit LCD backpack   
    Ive had this Adafruit Lcd backpack for a while and thought I would get it working with the launchpad.
    I'm using a sparkfun level converter, and I am powering the LCD via the TP1 port on the launchpad.
    For the i2c code I used fj604's from here: viewtopic.php?f=10&t=1037
    The code sends characters 2 different ways, one char at a time , and using oPossums tiny printf
    from here: viewtopic.php?f=10&t=1732
    Maybe someone can use this. The code is attached, its a CCSv5 project.
     
     
    here is my setup

     
    here is the backpack. (I added the led for debugging)

     
    small video(really impressive!)


    LCDi2cdemo.zip
  3. Like
    timotet reacted to oPossum in Time & Temperature on Nokia 7110   
    Sorry about the confusion over the license. Anything I post here is for others to learn from and use in any way they want. I don't really care much if I get credit for it. Any exceptions to this would be clearly noted. I have not put a copyright and GPLv3 notice in most of the code I have posted here because the presence of a copyright can give the impression that the code may not be copied and used by others. I certainly don't want to give that impression. Any code I have posted here without specific license is GPLv3 - Copyright 201x Kevin Timmerman
  4. Like
    timotet got a reaction from woodgrain in Tiny printf() - C version   
    So I tried just for fun to re-build the project from scratch.
     
    I started a new project in CCS.
    I copied the code from the beginning of this thread, and the serial.asm code from the post oPossum pointed out.
     
    3 separate files one project. Tried to compile no dice!
     
    compared the project with the one you posted that works great.
    The only difference I found was when I copied and pasted the .asm file from the the other post the file ends up indented
    to the right by 4 spaces in the editor window , and wont compile.
    I removed the 4 spaces from each line and it works great.
     
    Maybe this will help someone maybe not.
     
    thanks for the great code oPossum, and thanks for helping me get it going bluehash!
    This forum is awesome!!! :clap:
  5. Like
    timotet got a reaction from SugarAddict in $4.30 LCD Booster - Sold Out   
    Thanks SugarAddict!
    Got my lcds and they are killer! Also got the "smile it improves face time note"
     
    Oregon to Mass. and back
    Awesome!
     
    thanks again
  6. Like
    timotet reacted to V0JT4 in Universal Ripple Control Receiver   
    I'm using I2C in my project with USCI. Here is code for write and read with repeated start, 8 or 16 bit EEPROM data address is possible. It was inspired by Anderson's code. May be useful for someone else.
     
    i2c.h

    #ifndef I2C_H_ #define I2C_H_ typedef unsigned char u8; typedef signed char s8; typedef unsigned int u16; typedef signed int s16; typedef struct { u8 count; u8 state; u16 address; u8 *buffer; } i2c_data_t; #define size_tr(size, addr16) ((size-1)<<1)|(addr16 & 0x01) // number of bytes to transfer(1 to 128, 2+ for RX), device ID, buffer pointer, is 16bit addressing, memory address #define i2c_tx(size, id, buffer, addr16, address) i2c_trans(size_tr(size,addr16), id, buffer, address) #define i2c_rx(size, id, buffer, addr16, address) i2c_trans(size_tr(size,addr16), id|0x01, buffer, address) // number of bytes to transfer|16 bit addressing, device ID|dirrection, buffer pointer, memory address void i2c_trans(u8 size, u8 id, u8 buffer[], u16 address); void i2c_init(void); // setup u8 i2c_int(void); // data transfer interrupt u8 i2c_eint(void); // NACK interrupt #endif /*I2C_H_*/
     
    i2c.c

    #include "msp430g2553.h" #include "i2c.h" // i2c states #define WRITE 0x00 #define READ 0x01 #define ADDR16 0x02 #define ADDRTR 0x04 #define REPSTT 0x08 i2c_data_t i2c_data = {0, 0, 0, 0}; void i2c_init(void) { P1SEL |= BIT6 + BIT7; //Set I2C pins P1SEL2 |= BIT6 + BIT7; UCB0CTL1 |= UCSWRST; //Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; //Use SMCLK, keep SW reset UCB0BR0 = 12; //fSCL = SMCLK/12 = ~100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //Clear SW reset, resume operation IE2 |= UCB0TXIE | UCB0RXIE; //Enable TX, RX interrupt UCB0I2CIE = UCNACKIE; // NACK interrups } void i2c_trans(u8 size, u8 id, u8 *buffer, u16 address) { i2c_data.state = (id & READ) | ADDRTR; // byte counter if (size & 0x01) i2c_data.state |= ADDR16; i2c_data.count = (size >> 1) + 1; // byte counter i2c_data.address = address; // byte counter i2c_data.buffer = buffer; // byte counter UCB0I2CSA = id >> 1; // Slave Address 01101000 0x68 RTC //Slave Address 01010000 0x50 EEPROM UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts // Remain in LPM0 until all data is transferred } u8 i2c_int(void) { if (i2c_data.state == WRITE) { if (i2c_data.count > 0) { //Check TX byte counter UCB0TXBUF = *i2c_data.buffer++; // Load TX buffer i2c_data.count--; //Decrement TX byte counter } else if (i2c_data.count == 0) { //last byte transferred UCB0CTL1 |= UCTXSTP; //I2C stop condition while (UCB0CTL1 & UCTXSTP); //Ensure stop condition got sent IFG2 &= ~UCB0TXIFG; //Clear USCI_B0 TX int flag return 1; //Exit LPM0 } } else if (i2c_data.state == READ) { *i2c_data.buffer++ = UCB0RXBUF; i2c_data.count--; //Decrement RX byte counter if (i2c_data.count == 1) { //Check RX byte counter, 1 byte remaining UCB0CTL1 |= UCTXSTP; // I2C stop condition } if (i2c_data.count == 0) { //Check RX byte counter, last byte received while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent return 1; // Exit LPM0 } } else if (i2c_data.state & ADDR16) { // high byte address transmit UCB0TXBUF = _swap_bytes(i2c_data.address); i2c_data.state &= ~ADDR16; } else if (i2c_data.state & ADDRTR) { // low byte address transmit UCB0TXBUF = i2c_data.address; i2c_data.state &= ~ADDRTR; if (i2c_data.state) { // repeated Start for RX i2c_data.state |= REPSTT; } } else if (i2c_data.state & REPSTT) { // repeated start required i2c_data.state &= ~REPSTT; UCB0CTL1 &= ~UCTR; // I2C RX UCB0CTL1 |= UCTXSTT; // I2C repeated Start condition for RX IFG2 &= ~UCB0TXIFG; //Clear USCI_B0 TX int flag } return 0; } u8 i2c_eint(void) { if (UCB0STAT & UCNACKIFG) { // send STOP if slave sends NACK UCB0CTL1 |= UCTXSTP; UCB0STAT &= ~UCNACKIFG; return 1; } return 0; }
     
    example main.c

    #include "msp430g2553.h" #include "i2c.h" u8 txdata[] = {'H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D'}; u8 rxdata[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; void main(void) { WDTCTL = WDTPW + WDTHOLD; //Stop WDT BCSCTL1 = CALBC1_1MHZ; //Set DCO to 1MHz DCOCTL = CALDCO_1MHZ; // UART setup P1SEL = BIT1 + BIT2; //Set RXD and TXD P1SEL2 = BIT1 + BIT2; UCA0CTL1 |= UCSSEL_2 | UCSWRST; //Have USCI use SMCLK AKA 1MHz main CLK UCA0BR0 = 104; //Baud = 9600 UCA0BR1 = 0; UCA0MCTL = UCBRS_1; //Modulation UCA0CTL1 &= ~UCSWRST; //Start USCI i2c_init(); // init I2C __delay_cycles(20000); //Just a start up delay i2c_rx(11, 0xA0, rxdata, 0, 0); //i2c RX data u8 i = 0; while (i < 11) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = rxdata[i]; //UART TX data i++; } i2c_tx(11, 0xA0, txdata, 0, 0); //i2c TX 11 bytes("HELLO WORLD") __delay_cycles(20000); //Allow EEPROM to write data i2c_rx(11, 0xA0, rxdata, 0, 0); //i2c RX data i = 0; while (i < 11) { while (!(IFG2 & UCA0TXIFG)); UCA0TXBUF = rxdata[i]; //UART TX data i++; } __bis_SR_register(CPUOFF + GIE); //Wait for a reset } // I2C data transfer vector #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if (i2c_int()) __bic_SR_register_on_exit(CPUOFF); //Exit LPM0; } // I2C status vector #pragma vector = USCIAB0RX_VECTOR __interrupt void USCIAB0RX_ISR(void) { if (i2c_eint()) { while (!(IFG2 & UCA0TXIFG)); // send error via UART UCA0TXBUF = '#'; } }
  7. Like
    timotet reacted to V0JT4 in Universal Ripple Control Receiver   
    So far I have built two versions of simple message logger based on LaunchPad, first uses almost unmodified FMX-100 and the next one dropped top board and required some wire cutting on bottom board. I needed to use capacitor to smoothen the signal, 10uF with 2kOhm resistor to LED and opto coupler works just fine. So far I have around 100 hours recorded. Now it's time to concentrate on software part.
     
    Old receiver ZPA FMX-100:

    Inside:

    Message format, time is in secconds:

    Message recorded on scope:

    Logger V1:

    Logger V2:

    Receiver schema V0.8:

    Receiver board V0.8:

    Log sample, time is counted from system start just to get picture how often messages come:

    A1000B00000100P___0____________ +314:11 m:s A1000B01000000P_____1__________ +320:9 m:s A1001B10000000P___1____1_____1_ +324:12 m:s A1000B00110010P_______1_1___1__ +325:32 m:s A1000B00000100P_________0______ +326:52 m:s A0001B11000000P_______1_1___1__ +328:11 m:s A0010B10000000P______00________ +336:9 m:s A1010B11000100P00____00____0__0 +337:28 m:s A1000B00100000P____000_________ +338:47 m:s A1000B00001001P_0___010________ +340:8 m:s A1000B00010000P____0_______0__0 +341:27 m:s
  8. Like
    timotet got a reaction from tanh in Nokia 5110 display   
    I wrote some code for the nokia lcd using spi a couple of months ago and after seeing Robs post I thought I'd post mine as well.

    sorry about the video quality I lost my good camera in a drift boat accident






    here's the code:
      /* * 4/5/11 * talk to nokia 5011 LCD with spi */ #include #define PIN_SCLK BIT5 //display pin 7 / msp430 pin 7 //port p1.5 #define PIN_DNMOSI BIT6 //display pin 6 / msp430 pin 14 //port p1.6 these are used for USI SPI mode #define PIN_DC BIT4 //display pin 5 / msp430 pin 12 //port P2.4 #define PIN_RESET BIT3 //display pin 4 / msp430 pin 11 //port p2.3 #define PIN_SCE BIT1 //display pin 3 / msp430 pin 9 //port p2.1 #define PIN_VCC BIT0 //display pin 1 / msp430 pin 8 //port p2.0 #define LCD_X 84 //columns #define LCD_Y 48 //rows #define cmd 0 //for command data #define info 1 //for character data unsigned char * Flash_ptr = (unsigned char *) 0x1040; unsigned char * Flash_pOnes = (unsigned char *) 0x1042; unsigned char * Flash_pTens = (unsigned char *) 0x1044; unsigned char * Flash_pHunds = (unsigned char *) 0x1046; volatile char data = 0; //char for data to lcd volatile char pressCount = 0; //keep track of button presses volatile char number = 0; //char for data to lcd volatile char ones = 0; //used as placeholder for counting volatile char tens = 0; volatile char hunds = 0; const unsigned char table [][5] = { {0x00, 0x00, 0x00, 0x00, 0x00}// (space) ,{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, 0x55, 0x22, 0x50}// & ,{0x00, 0x05, 0x03, 0x00, 0x00}// ' ,{0x00, 0x1C, 0x22, 0x41, 0x00}// ( ,{0x00, 0x41, 0x22, 0x1C, 0x00}// ) ,{0x08, 0x2A, 0x1C, 0x2A, 0x08}// * ,{0x08, 0x08, 0x3E, 0x08, 0x08}// + ,{0x00, 0x50, 0x30, 0x00, 0x00}// , ,{0x08, 0x08, 0x08, 0x08, 0x08}// - ,{0x00, 0x60, 0x60, 0x00, 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, 0x45, 0x4B, 0x31}// 3 ,{0x18, 0x14, 0x12, 0x7F, 0x10}// 4 ,{0x27, 0x45, 0x45, 0x45, 0x39}// 5 ,{0x3C, 0x4A, 0x49, 0x49, 0x30}// 6 ,{0x01, 0x71, 0x09, 0x05, 0x03}// 7 ,{0x36, 0x49, 0x49, 0x49, 0x36}// 8 ,{0x06, 0x49, 0x49, 0x29, 0x1E}// 9 ,{0x00, 0x36, 0x36, 0x00, 0x00}// : ,{0x00, 0x56, 0x36, 0x00, 0x00}// ; ,{0x00, 0x08, 0x14, 0x22, 0x41}// < ,{0x14, 0x14, 0x14, 0x14, 0x14}// = ,{0x41, 0x22, 0x14, 0x08, 0x00}// > ,{0x02, 0x01, 0x51, 0x09, 0x06}// ? ,{0x32, 0x49, 0x79, 0x41, 0x3E}// @ ,{0x7E, 0x11, 0x11, 0x11, 0x7E}// A ,{0x7F, 0x49, 0x49, 0x49, 0x36}// B ,{0x3E, 0x41, 0x41, 0x41, 0x22}// C ,{0x7F, 0x41, 0x41, 0x22, 0x1C}// D ,{0x7F, 0x49, 0x49, 0x49, 0x41}// E ,{0x7F, 0x09, 0x09, 0x01, 0x01}// F ,{0x3E, 0x41, 0x41, 0x51, 0x32}// 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, 0x04, 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 ,{0x46, 0x49, 0x49, 0x49, 0x31}// S ,{0x01, 0x01, 0x7F, 0x01, 0x01}// T ,{0x3F, 0x40, 0x40, 0x40, 0x3F}// U ,{0x1F, 0x20, 0x40, 0x20, 0x1F}// V ,{0x7F, 0x20, 0x18, 0x20, 0x7F}// W ,{0x63, 0x14, 0x08, 0x14, 0x63}// X ,{0x03, 0x04, 0x78, 0x04, 0x03}// Y ,{0x61, 0x51, 0x49, 0x45, 0x43}// Z ,{0x00, 0x00, 0x7F, 0x41, 0x41}// [ ,{0x02, 0x04, 0x08, 0x10, 0x20}// "\" ,{0x41, 0x41, 0x7F, 0x00, 0x00}// ] ,{0x04, 0x02, 0x01, 0x02, 0x04}// ^ ,{0x40, 0x40, 0x40, 0x40, 0x40}// _ ,{0x00, 0x01, 0x02, 0x04, 0x00}// ` ,{0x20, 0x54, 0x54, 0x54, 0x78}// a ,{0x7F, 0x48, 0x44, 0x44, 0x38}// b ,{0x38, 0x44, 0x44, 0x44, 0x20}// c ,{0x38, 0x44, 0x44, 0x48, 0x7F}// d ,{0x38, 0x54, 0x54, 0x54, 0x18}// e ,{0x08, 0x7E, 0x09, 0x01, 0x02}// f ,{0x08, 0x14, 0x54, 0x54, 0x3C}// g ,{0x7F, 0x08, 0x04, 0x04, 0x78}// h ,{0x00, 0x44, 0x7D, 0x40, 0x00}// i ,{0x20, 0x40, 0x44, 0x3D, 0x00}// j ,{0x00, 0x7F, 0x10, 0x28, 0x44}// k ,{0x00, 0x41, 0x7F, 0x40, 0x00}// l ,{0x7C, 0x04, 0x18, 0x04, 0x78}// m ,{0x7C, 0x08, 0x04, 0x04, 0x78}// n ,{0x38, 0x44, 0x44, 0x44, 0x38}// o ,{0x7C, 0x14, 0x14, 0x14, 0x08}// p ,{0x08, 0x14, 0x14, 0x18, 0x7C}// q ,{0x7C, 0x08, 0x04, 0x04, 0x08}// r ,{0x48, 0x54, 0x54, 0x54, 0x20}// s ,{0x04, 0x3F, 0x44, 0x40, 0x20}// 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 ,{0x0C, 0x50, 0x50, 0x50, 0x3C}// y ,{0x44, 0x64, 0x54, 0x4C, 0x44}// z ,{0x00, 0x08, 0x36, 0x41, 0x00}// { ,{0x00, 0x00, 0x7F, 0x00, 0x00}// | ,{0x00, 0x41, 0x36, 0x08, 0x00}// } ,{0x08, 0x08, 0x2A, 0x1C, 0x08}// -> ,{0x08, 0x1C, 0x2A, 0x08, 0x08} // <- }; const unsigned char nice [] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x80, 0x00, 0x18, 0xE0, 0x80, 0x80, 0x80, 0x8E, 0x70, 0x00, 0x00, 0xE0, 0x1C, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x00, 0x00, 0x80, 0x40, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x12, 0x14, 0x08, 0x04, 0x02, 0x02, 0x41, 0x41, 0x81, 0x81, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x82, 0x82, 0x04, 0x0E, 0x11, 0x10, 0x60, 0x98, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x18, 0x60, 0x80, 0xFE, 0x02, 0x00, 0x00, 0x10, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x42, 0x82, 0x84, 0x05, 0x09, 0x08, 0x02, 0x02, 0x11, 0x91, 0x89, 0x49, 0x44, 0x84, 0x82, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x07, 0x04, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, 0x04, 0x07, 0x04, 0x00, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x10, 0x26, 0x22, 0x10, 0x19, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x19, 0x10, 0x22, 0x26, 0x10, 0x19, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0C, 0x30, 0x40, 0x40, 0x82, 0x06, 0x06, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x30, 0x0C, 0x02, 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, 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, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const unsigned char button [] = { 0x00, 0x00, 0x00, 0xC0, 0x30, 0x10, 0x08, 0x08, 0x10, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x48, 0x68, 0x64, 0x54, 0x54, 0x4C, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE0, 0x03, 0x02, 0x04, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x2C, 0x34, 0x54, 0x64, 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x3E, 0x20, 0x00, 0x1E, 0x25, 0x25, 0x25, 0x16, 0x00, 0x61, 0x47, 0x38, 0x07, 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, 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, 0x00, 0x00, 0x00, 0x08, 0xF8, 0x88, 0x88, 0x70, 0x00, 0x08, 0xF8, 0x10, 0x08, 0x18, 0x00, 0xF0, 0x28, 0x28, 0x28, 0xB0, 0x00, 0x90, 0x28, 0x28, 0x48, 0x98, 0x00, 0x90, 0x28, 0x28, 0x48, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x88, 0x08, 0xF0, 0x08, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x00, 0x08, 0xFF, 0x08, 0x88, 0x00, 0x00, 0x08, 0xFF, 0x08, 0x88, 0x00, 0x00, 0xF0, 0x08, 0x08, 0x08, 0xF0, 0x08, 0xF0, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x10, 0xF0, 0x00, 0x01, 0x00, 0x01, 0x80, 0x80, 0x80, 0x01, 0x01, 0x00, 0x81, 0x80, 0x00, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x01, 0x00, 0x80, 0x80, 0x80, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x28, 0x08, 0x07, 0x00, 0x00, 0x10, 0x1F, 0x10, 0x00, 0x00, 0x0F, 0x12, 0x12, 0x12, 0x0B, 0x00, 0x0D, 0x12, 0x12, 0x0F, 0x10, 0x00, 0x19, 0x12, 0x12, 0x14, 0x09, 0x00, 0x0F, 0x12, 0x12, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; ////////////////////////////function prototypes///////////////////////// void LcdWrite(char CMD,char data); void LcdInit(); void LcdClear(); void LcdString(char *characters); void LcdCharacter(const char character); void LcdNumber(); void gotoXY(char x, char y); void LcdBmp(const unsigned char my_array[]); void sendArray(const unsigned char digit[], char length); void delay(int ms); void loadFlash(); ////////////////////////////main/////////////////////////////////// void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // calibrate basic clock system control 1 to 1mhz DCOCTL = CALDCO_1MHZ; // calibrate DCO to 1mhz IE1 |= WDTIE; //enable watchdog timer interrupt P1SEL &= ~(BIT0 + BIT3); //enable port 1.0 and 1.3 P1IN &= ~BIT3; //input signal == low P1DIR |= BIT0; //set p1.0 red led to output P1DIR &= ~BIT3; // set p1.3 as an input P1OUT |= BIT0 + BIT3; // p1.0 high led is on //pullup for p1.3 P1REN |= BIT3; // Resistor Enable for p1.3 pull up P1IES |= BIT3; // Interrupt Edge Select - 0: trigger on rising edge, 1: trigger on falling edge P1IFG &= ~BIT3; //interrupt flag for p1.3 is off P1IE |= BIT3; // enable interrupt P2SEL &= ~(BIT1 + BIT4 + BIT3 + BIT0); //turns on port 2 P2DIR |= (BIT1 + BIT4 + BIT3 + BIT0); //set as outputs P2OUT &= ~(BIT4 + BIT3 + BIT1 + BIT0); //set pins low USICTL0 |= 0x6B; USICTL1 |= 0X91; //USICKCTL |= 0xE8; //divide by 128 USICKCTL |= 0xA8; // divide by 32 USICTL0 &= ~USISWRST; // Reset & release USI USICNT |= 8; // send 8 bits FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator //_bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt _BIS_SR(GIE); //enable interrupts LcdInit(); loadFlash(); //load counter values from before power down for(; { //infinite loop do{ LcdWrite(cmd , 0x0C); // LCD 0x0C for black on white //0x0d for inverse P1OUT |= BIT0; // turn on port 1.0 led gotoXY(0,0); LcdBmp(button); } while(0x08 & P1IN); } } //////////////////////ISR's////////////////////////////////// // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; // Clear pending flag P2OUT |= PIN_SCE; //SCE pin high } #pragma vector=PORT1_VECTOR __interrupt void PORT1_ISR(void) { P1IFG &= ~BIT3; // clear interrupt flag WDTCTL = WDT_MDLY_32; //watchdog delay for debounce 32milli seconds// interval timer mode pressCount++; //increment button presses P1OUT &= ~BIT0; //turn off led LcdClear(); LcdWrite(cmd , 0x0D); // LCD 0x0C for black on white //0x0d for inverse gotoXY(0,0); LcdBmp(nice); delay(1000); LcdClear(); gotoXY(0,0); LcdString("************"); gotoXY(10,1); LcdString("now was'nt"); gotoXY(25,3); LcdString("that"); gotoXY(12,5); LcdString("exciting"); delay(700); LcdClear(); gotoXY(20,0); LcdString("Number"); gotoXY(10,2); LcdString("of button"); gotoXY(0,4); //locate cursor LcdString("press's"); ones = pressCount; if(ones > 9){ //write # of press's to lcd tens++; ones = 0; pressCount = 0; if(tens > 9){ hunds++; tens = 0; ones = 0; pressCount = 0; if(hunds > 9){ pressCount = 0; hunds = 0; tens = 0; ones = 0; } } } number = ones; //write the ones column gotoXY(67,5); LcdNumber(); number = tens; gotoXY(61,5); LcdNumber(); number = hunds; gotoXY(55,5); LcdNumber(); delay(1000); LcdClear(); //gotoXY(0,0); //LcdBmp(finger); //delay(500); FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY; // Clear Lock bit *Flash_ptr = 0; // Dummy write to erase Flash segment // *Flash_pOnes = 0; // *Flash_pTens = 0; // *Flash_pHunds = 0; FCTL1 = FWKEY + WRT; // Set WRT bit for write operation *Flash_ptr = pressCount; // Write value to flash *Flash_pOnes = ones; *Flash_pTens = tens; *Flash_pHunds = hunds; FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCK; // Set LOCK bit } #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) //use watchdog for button debounce { IFG1 &= ~WDTIFG; // clear interrupt flag WDTCTL = WDTPW + WDTHOLD; // put WDT back in hold state // pressCount++; //increment button presses } //////////////////////////////functions////////////////////////// void gotoXY(char x, char y) { LcdWrite(cmd ,(0x40 | y & 0x07)); // Y row == 0100 0yyy LcdWrite(cmd ,(0x80 | x & 0x7F)); // X column == 1xxx xxxx } void LcdBmp(const unsigned char my_array[]) { unsigned short index = 0; for (index = 0; index < 504; index++) { LcdWrite(info,my_array[index]); } } void LcdCharacter(char character) { char index = 0; LcdWrite(info,0x00); for (index = 0; index < 5; index++) { LcdWrite(info,table[character - 0x20][index]); } LcdWrite(info,0x00); } void LcdString(char *characters) { while (*characters){ LcdCharacter(*characters++); } } void LcdNumber(){ switch(number){ case 0: sendArray(table[16],5); break; case 1: sendArray(table[17],5); break; case 2: sendArray(table[18],5); break; case 3: sendArray(table[19],5); break; case 4: sendArray(table[20],5); break; case 5: sendArray(table[21],5); break; case 6: sendArray(table[22],5); break; case 7: sendArray(table[23],5); break; case 8: sendArray(table[24],5); break; case 9: sendArray(table[25],5); break; default: pressCount = 0; //reset pressCount to 0 } } void LcdClear(void) { int i,j; LcdWrite(cmd, 0x80); LcdWrite(cmd, 0x40); for (i=0;i<6;i++) // number of rows for (j=0;j LcdWrite(info, 0x00); } void delay(int ms)// Delays by the specified Milliseconds { while (ms--){ __delay_cycles(1000); //set to 1000 for 1 Mhz } } void sendArray(const unsigned char digit[], char length) { char charIndex = 0; while(charIndex < length) { LcdWrite(info , digit[charIndex]); charIndex++; } } void LcdInit(void) { P2OUT |= PIN_VCC; //power to LCD P2OUT |= PIN_RESET; //set RESET high P2OUT &= ~PIN_RESET; //set RESET low delay(35); P2OUT |= PIN_RESET; //set RESET high P2OUT |= PIN_SCE; //SCE pin high LcdWrite(cmd , 0x21); // LCD Extended instruction set LcdWrite(cmd , 0xBF); // Set LCD Vop (Contrast). //0xE0 - BF may have to play with LcdWrite(cmd , 0x07); // Set Temp coefficent. //0x04 =t0 //0x05=t1 // 0x06=t2 // 0x07=t3 LcdWrite(cmd , 0x13); // LCD bias mode 1:100 0x10 //1:48 0x13 LcdWrite(cmd , 0x20); // LCD basic instruction set LcdWrite(cmd , 0x08); // lcd blank LcdWrite(cmd , 0x0C); // LCD 0x0C for black on white //0x0d for inverse } void LcdWrite(char CMD, char data) { if(CMD == cmd){ P2OUT &= ~PIN_DC; //set LCD to command mode } else{ P2OUT |= PIN_DC; //set lcd to data mode } P2OUT &= ~PIN_SCE; //SCE pin low USISRL |= data; // load shift register with data to send USICNT |= 8; // shift out 8 bits delay(1); } void loadFlash() { pressCount = *Flash_ptr; // load values from before power down if(*Flash_ptr == 0xFF){ pressCount = 0; } ones = *Flash_pOnes; if(*Flash_pOnes == 0xFF){ ones = 0; } tens = *Flash_pTens; if(*Flash_pTens == 0xFF){ tens = 0; } hunds = *Flash_pHunds; if(*Flash_pHunds == 0xFF){ hunds = 0; } } I found a couple of bitmap converters for displaying bitmaps on the lcds

    bitmap 2 LCD http://bitmap2lcd.com
    lcd assistant http://en.radzio.dxp.pl/bitmap_converter/

    The program stores the # of button press's in flash so when power is restored the count doesn't start over.
    Maybe this will help somebody. :thumbup:
    cheers
  9. Like
    timotet got a reaction from GeekDoc in MSP430 USI i2c and Adafruit LCD backpack   
    Ive had this Adafruit Lcd backpack for a while and thought I would get it working with the launchpad.
    I'm using a sparkfun level converter, and I am powering the LCD via the TP1 port on the launchpad.
    For the i2c code I used fj604's from here: viewtopic.php?f=10&t=1037
    The code sends characters 2 different ways, one char at a time , and using oPossums tiny printf
    from here: viewtopic.php?f=10&t=1732
    Maybe someone can use this. The code is attached, its a CCSv5 project.
     
     
    here is my setup

     
    here is the backpack. (I added the led for debugging)

     
    small video(really impressive!)


    LCDi2cdemo.zip
  10. Like
    timotet got a reaction from bluehash in MSP430 USI i2c and Adafruit LCD backpack   
    Ive had this Adafruit Lcd backpack for a while and thought I would get it working with the launchpad.
    I'm using a sparkfun level converter, and I am powering the LCD via the TP1 port on the launchpad.
    For the i2c code I used fj604's from here: viewtopic.php?f=10&t=1037
    The code sends characters 2 different ways, one char at a time , and using oPossums tiny printf
    from here: viewtopic.php?f=10&t=1732
    Maybe someone can use this. The code is attached, its a CCSv5 project.
     
     
    here is my setup

     
    here is the backpack. (I added the led for debugging)

     
    small video(really impressive!)


    LCDi2cdemo.zip
  11. Like
    timotet got a reaction from dacoffey in MSP430 USI i2c and Adafruit LCD backpack   
    Ive had this Adafruit Lcd backpack for a while and thought I would get it working with the launchpad.
    I'm using a sparkfun level converter, and I am powering the LCD via the TP1 port on the launchpad.
    For the i2c code I used fj604's from here: viewtopic.php?f=10&t=1037
    The code sends characters 2 different ways, one char at a time , and using oPossums tiny printf
    from here: viewtopic.php?f=10&t=1732
    Maybe someone can use this. The code is attached, its a CCSv5 project.
     
     
    here is my setup

     
    here is the backpack. (I added the led for debugging)

     
    small video(really impressive!)


    LCDi2cdemo.zip
  12. Like
    timotet reacted to oPossum in Time & Temperature on Nokia 7110   
    This uses code from Software RTC, Using the internal temperature sensor and Nokia 5110 template class. The code has been modified and refined a bit for this project.
     



     
    main.cpp

    #include #include #include #include #include "nokia7110tl.h" using namespace nokia7110; 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 }; /* P1.0 Reset P1.3 Temp Sensor (Not used) P2.0 Serial Data P2.1 Backlight P2.2 Chip Select P2.3 Data/Command P2.4 Serial Clock P2.5 Pushbutton */ // P1 static const unsigned LCD_RESET = BIT0; static const unsigned RXD = BIT2; static const unsigned SWITCH = BIT3; // P2 static const unsigned LCD_DATA = BIT0; static const unsigned LCD_BACKLIGHT = BIT1; static const unsigned LCD_CE = BIT2; static const unsigned LCD_DC = BIT3; static const unsigned LCD_CLK = BIT4; static const unsigned LCD_BTN = BIT5; Nokia7110 lcd; void show_time(const struct tm *t) // Show time on LCD { static const char *dow[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; int x, w; const char *s; div_t d; if(t->tm_hour < 10) { x = -2; lcd.fill(0, 0, 9, 2, 0); d.rem = t->tm_hour; } else { x = 3; lcd.fill(0, 0, 3, 2, 0); d = div(t->tm_hour, 10); lcd.pd12(d.quot, x, 0); } lcd.pd12(d.rem, x + 11, 0); lcd.pd12(11, x + 22, 0); d = div(t->tm_min, 10); lcd.pd12(d.quot, x + 27, 0); lcd.pd12(d.rem, x + 38, 0); lcd.pd12(11, x + 49, 0); d = div(t->tm_sec, 10); lcd.pd12(d.quot, x + 54, 0); lcd.pd12(d.rem, x + 65, 0); lcd.fill(x + 76, 0, 7 - x, 2, 0); if(t->tm_mon < 9) { x = -5; lcd.fill(0, 2, 6, 2, 0); d.rem = t->tm_mon + 1; } else { x = 0; d = div(t->tm_mon + 1, 10); lcd.pd12(d.quot, x, 2); } lcd.pd12(d.rem, x + 11, 2); lcd.pd12(13, x + 22, 2); d = div(t->tm_mday, 10); lcd.pd12(d.quot, x + 30, 2); lcd.pd12(d.rem, x + 41, 2); lcd.pd12(13, x + 52, 2); d = div(t->tm_year % 100, 10); lcd.pd12(d.quot, x + 60, 2); lcd.pd12(d.rem, x + 71, 2); if(x) lcd.fill(x + 82, 2, 1 - x, 2, 0); s = dow[t->tm_wday]; w = strlen(s) * 6; x = (83 - w) >> 1; lcd.fill(0, 4, x, 1, 0); lcd.print((unsigned char)x, (unsigned char)4, s); x += w; lcd.fill(x, 4, 83 - x, 1, 0); } // 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); lcd.pd12(d.rem, x -= 12, y); } while(d.quot); if(neg) lcd.pd12(14, x -= 12, y); while(x) lcd.pd12(10, x -= 12, y); } // Print integer from -999 to 9999 using 6 x 8 font void print_int(int i, unsigned x, const unsigned y) { if(i < -999 || i > 9999) return; const unsigned e = x; x += 24; const unsigned neg = i < 0; if(neg) i = -i; div_t d; d.quot = i; do { d = div(d.quot, 10); lcd.print(x -= 6, y, '0' + d.rem); } while(d.quot); if(neg) lcd.print(x -= 6, y, '-'); while(x > e) lcd.print(x -= 6, y, ' '); } void draw_bargraph(int f) { int x, y, bg; char c; unsigned char bgc[9] = { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0 }; char *bgl[8] = { "90", "80", "70", "60", "50", "40", "30", "20" }; x = 20; // bg = (f - (x - 5)) * 4 / 5; // for(y = 7; y >= 0; --y) { // lcd.pos(83, y); // if(bg < 0) { c = bgc[8]; } else if (bg > 7) { c = bgc[7]; } else { c = bgc[bg]; } lcd.write((unsigned char *)&c, 1, lcd_data); lcd.print(bgl[y], c); bg -= 8; } // } time_t tt; // Time in seconds since epoch unsigned adc; // ADC value #pragma vector = WDT_VECTOR // - Watchdog timer interrupt vector __interrupt void wdt_isr(void) // This interrupt will occur once per second { // ++tt; // Increment time_t __bic_SR_register_on_exit(LPM0_bits); // Wakeup main code } // // #pragma vector = ADC10_VECTOR // ADC conversion complete interrupt __interrupt void ADC10_ISR(void) // { // adc = ADC10MEM; // Read ADC __bic_SR_register_on_exit(LPM0_bits); // Wakeup main code } // int main(void) { int x, y; char c; struct tm ts; int dc, dk, df; // Temperature in degrees C, K, and F WDTCTL = WDTPW | WDTHOLD; P1REN = RXD | SWITCH; P1DIR = LCD_RESET; P1OUT = RXD | SWITCH | LCD_RESET; P2DIR = LCD_DC | LCD_CE | LCD_CLK | LCD_BACKLIGHT | LCD_DATA; P2REN = LCD_BTN; P2OUT = LCD_CLK | LCD_DC | LCD_CE | LCD_BACKLIGHT | LCD_BTN; ADC10CTL0 = 0; // Configure ADC ADC10CTL1 = INCH_10 | ADC10DIV_3; // ADC10CTL0 = SREF_1 | ADC10SHT_3 | REFON | ADC10ON | ADC10IE; ADC10CTL0 |= ADC10IE; // Enable ADC conversion complete interrupt // // 32 kHz xtal loading //BCSCTL3 = XCAP_1; // 6 pF (default) BCSCTL3 = XCAP_2; // 10 pF //BCSCTL3 = XCAP_3; // 12.5 pF // WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL; // Use WDT as interval timer IE1 |= WDTIE; // Enable WDT interrupt _EINT(); // Enable interrupts // // Set initial time - there is no UI for this ts.tm_hour = 13; // Hour ts.tm_min = 37; // Minute ts.tm_sec = 42; // Second ts.tm_mon = 3; // Month (0 based!) ts.tm_mday = 20; // Day of Month ts.tm_year = 2012 - 1900; // Year ts.tm_wday = 5; // Day of Week - Not used by mktime() ts.tm_yday = 0; // Not used by mktime() ts.tm_isdst = 0; // DST flag - Not used by rtc_tick() // tt = mktime(&ts); // Convert tm struct to time_t // lcd.reset(); lcd.init(); lcd.clear(); lcd.print(30, 6, "MSP430"); lcd.print(18, 7, "Nokia 7110"); for(x = -47; x < 24; ++x) { lcd.bitmap(ti, x, 0); __delay_cycles(20000); } __delay_cycles(2000000); for(; x < 96; ++x) { lcd.bitmap(ti, x, 0); __delay_cycles(20000); } lcd.clear(); lcd.print(9, 7, "Character Set"); x = y = 0; lcd.pos(x, y); for(c = 32; c < 128; ++c) { lcd.print(c); if(++x >= 16) x = 0, lcd.pos(x, ++y); } __delay_cycles(3000000); lcd.clear(); ts.tm_hour = ts.tm_min = ts.tm_sec = 88; ts.tm_mon = 87; ts.tm_mday = ts.tm_year = 88; ts.tm_wday = 5; show_time(&ts); lcd.pd12(15, 48, 5); lcd.pd12(17, 59, 5); lcd.print(24, 7, "\x7F""C"); lcd.print(66, 7, "\x7F""K"); print_int(8888, 5); print_int(8888, 0, 7); print_int(8888, 42, 7); for(x = 15; x < 96; ++x) draw_bargraph(x); __delay_cycles(3000000); lcd.clear(); // lcd.pd12(15, 48, 5); // Degrees lcd.pd12(17, 59, 5); // F lcd.print(24, 7, "\x7F""C"); // C lcd.print(66, 7, "\x7F""K"); // K // for(; { // for-ever show_time(localtime(&tt)); // Convert time_t to tm struct and show on LCD __bis_SR_register(LPM0_bits + GIE); // Sleep until WDT interrupt ADC10CTL0 |= (ENC | ADC10SC); // Begin ADC conversion __bis_SR_register(LPM0_bits + GIE); // Sleep until conversion complete // // Convert to temperature dc = ((27069L * adc) - 18169625L) >> 16; // Vref = 1.5V dk = ((27069L * adc) - 268467L) >> 16; // Vref = 1.5V df = ((48724L * adc) - 30634388L) >> 16; // Vref = 1.5V // // Display on LCD print_int(df, 5); // Degrees F print_int(dc, 0, 7); // Degrees C print_int(dk, 42, 7); // Degrees K draw_bargraph(df); // Deg F Bargraph } // return 0; }
     
    nokia7110tl.h - C++ template class for Nokia 7110 (SED1565)

    namespace nokia7110 { 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 volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> struct Nokia7110 { void write(const unsigned char *cmd, unsigned len, const lcd_cmd_type type = lcd_data); void reset(void); void init(void); void home(void); void pos(unsigned char x, unsigned char y); void clear(unsigned char x = 0); void fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z); 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(const char *s); inline void print(unsigned char x, unsigned char y, const char *s) { pos(x, y); print(s); }; void print(const char *s, unsigned char m); void printv(unsigned char x, unsigned char y, char *s); void pd12(unsigned n, unsigned x, unsigned y); }; template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::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 volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::reset(void) { if(&_RP == &PNONE) { // --- 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* _SP |= _CLK; } } // --- Reset pulse on CLK or DC as needed if(&_CP == &PNONE) { // No DC port, use CLK to reset _SP &= ~_CLK; __delay_cycles(_RD); _SP |= _CLK; } else { // Use DC to reset _CP &= ~_DC; __delay_cycles(_RD); _CP |= _DC; } } else { _RP &= ~_RST; if(&_EP != &PNONE) { if(&_SP == &_EP) { _SP |= (_CLK | _CE); } else { _SP |= _CLK; _EP |= _CE; } } else { _SP |= _CLK; } __delay_cycles(_RD); _RP |= _RST; } __delay_cycles(_RD); } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::init(void) { static const unsigned char init[] = { 0xA6, //Display: Normal 0xA3, //LCD Bias Settings: 1/7 0xA1, //ADC Selection: Reverse 0xC0, //Common Output: Normal Direction //0xC8, //Common Output: Upside Down 0x22, //Set the V5 output Voltage 0x81, //Set Electronic Volume Register 0x2E, //Power Controller Set // Booster circuit: ON // Voltage regulator circuit: ON // Voltage follower circuit: OFF 0x2F, //Power Controller Set // Voltage follower circuit: ON 0xE3, //Non-OPeration Command 0x40, //Set the start line 0xAF, //LCD On //0xA5, //Display All Points: ON 0xA4, //Display All Points: NORMAL }; write(init, sizeof(init), lcd_command); } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::home(void) { static const unsigned char home[] = { 0xB0, 0x11, 0x02 }; write(home, sizeof(home), lcd_command); } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pos(unsigned char x, unsigned char y) { unsigned char c[3]; x += 18; c[0] = 0xB0 | y; c[1] = 0x10 | (x >> 4); c[2] = x & 0x0F; write(c, sizeof(c), lcd_command); } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::clear(unsigned char x) { for(unsigned y = 0; y < 9; ++y) { pos(0, y); write(&x, 96, lcd_data_repeat); } } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z) { unsigned yy = y + h; unsigned char c[3]; x += 18; c[1] = 0x10 | (x >> 4); c[2] = (x & 0x0F); for(;y < yy; ++y) { c[0] = 0xB0 | y; write(c, sizeof(c), lcd_command); write(&z, w, lcd_data_repeat); } } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::bitmap(const unsigned char *bmp, signed char x, signed char y, unsigned char w, unsigned char h) { unsigned char c[3]; unsigned char ww; if(x < 0) { ww = w + x; bmp -= x; x = 0; } else if(x + w >= 96) { ww = (96 - x); } else { ww = w; } x += 18; c[0] = 0xB0 | y; c[1] = 0x10 | (x >> 4); c[2] = x & 0x0F; while(h--) { write(c, sizeof(c), lcd_command); write(bmp, ww); bmp += w; ++c[0]; } } 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 volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(char c) { write(&font[c - 32][0], 5); write(&font[0][0], 1); } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s) { while(*s) { write(&font[*s - 32][0], 5); write(&font[0][0], 1); ++s; } } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::print(const char *s, unsigned char m) { unsigned char c; while(*s) { c = font[*s - 32][0] ^ m; write(&c, 1); c = font[*s - 32][1] ^ m; write(&c, 1); c = font[*s - 32][2] ^ m; write(&c, 1); c = font[*s - 32][3] ^ m; write(&c, 1); c = font[*s - 32][4] ^ m; write(&c, 1); write(&m, 1); ++s; } } template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::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; } } 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 }; template volatile unsigned char &_EP, unsigned char _CE, volatile unsigned char &_RP, unsigned char _RST, unsigned _RD> void Nokia7110<_SP, _CLK, _DATA, _CP, _DC, _EP, _CE, _RP, _RST, _RD>::pd12(unsigned n, unsigned x, unsigned y) { pos(x, y); write(num11x16[n], 11, lcd_data); pos(x, ++y); write(num11x16[n] + 11, 11, lcd_data); } } // namespace
  13. Like
    timotet reacted to oPossum in USCI UART bit rate setting   
    The MSP430x2xx Family User's Guide has several forumulas and tables for UART bit rate calculation. Makes it look more complicated than it is. Here is simple code to setup the bit rate divisor and modulator (for oversampling mode).
     
    First you need to know the SMCLK frequency and the desired bit rate.

    const unsigned long smclk_freq = 16000000; // SMCLK frequency in hertz const unsigned long bps = 19200; // Async serial bit rate Then a 20 bit divisor value can be calculated.
    const unsigned long brd = (smclk_freq + (bps >> 1)) / bps; // Bit rate divisor Shift and mask to setup the registers.
    UCA0BR1 = (brd >> 12) & 0xFF; // High byte of whole divisor UCA0BR0 = (brd >> 4) & 0xFF; // Low byte of whole divisor UCA0MCTL = ((brd << 4) & 0xF0) | UCOS16; // Fractional divisor, oversampling mode That's it! 
    A function for UART setup at a specified bit rate...

    const unsigned long smclk_freq = 16000000; // SMCLK frequency in hertz void setup_UART(const unsigned long bps) // Async serial bit rate { const unsigned long brd = (smclk_freq + (bps >> 1)) / bps; // Bit rate divisor UCA0CTL1 = UCSWRST; // Hold USCI in reset to allow configuration UCA0CTL0 = 0; // No parity, LSB first, 8 bits, one stop bit, UART (async) UCA0BR1 = (brd >> 12) & 0xFF; // High byte of whole divisor UCA0BR0 = (brd >> 4) & 0xFF; // Low byte of whole divisor UCA0MCTL = ((brd << 4) & 0xF0) | UCOS16; // Fractional divisor, oversampling mode UCA0CTL1 = UCSSEL_2; // Use SMCLK for bit rate generator, release reset }
  14. Like
    timotet reacted to zeke in Anyone notice the 8-pin MSP430 yet?   
    Presenting the MSP430G2230.
     
    Only 8 pins!
  15. Like
    timotet reacted to oPossum in Software Real Time Clock (RTC) - two methods   
    The Launchpad comes with a 32.768 kHz crystal that can be used when timing more precise than the DCO is needed. The crystal frequency is useful for simple timing tasks, such as a RTC, because it is a power of 2. That allows a simple cascade of 15 flip-flops to create a 1 pulse per second time base. It is common for microcontroller timers to have prescalers, postscalers and/or preset divisors that are simply a tap on the flip-flip chain. The watchdog timer in the MSP430 is an example of a timer with power of 2 presets (64, 512, 8192, 32768). TimerA units have a prescaler with power of 2 presets (1, 2, 4, 8).
     
    The sample code in this post uses the watchdog timer to create an interrupt that occurs once per second. TimerA can also be used to do this. One of the advantages of using TimerA is the ability to change the preset +/- 1 every N cycles to allow for calibration and temperature compensation of the crystal. I chose to use the watchdog timer so that TimerA was free to be used for alarm tones or PWM backlight control.
     

     
    Using the C standard library time functions for a RTC
    The C standard library provides several functions for working with real time. The function prototypes are in time.h. The type time_t is typically an integer type that is in units of 1 second. It doesn't have to be that, but usually is. The epoch is usually January 1, 1970 for "unix time." Be aware that CCS uses an epoch of January 1, 1900 and time_t is unsigned rather than signed. I assume GCC uses the more common unix time epoch and time_t is signed.
     
    Since time_t is in units of 1 second, the ISR for timekeeping is trivial...

    #pragma vector = WDT_VECTOR // - Watchdog timer interrupt vector __interrupt void wdt_isr(void) // This interrupt will occur once per second { // ++tt; // Increment time_t } //
     
    To display the time it can be converted to a tm structure that has elements for hours, minutes, day, month, ect. There are two functions to do this: gmtime() and localtime(). gmtime() converts to UTC, and localtime converts to the time zone for the set locale. Both functions take a time_t and return a pointer to a static tm struct.
     
    To set the time the mktime() function will convert a tm struct to a time_t value. It will also determine day of week and day or year for you.
     
    Benefits
    Tivial ISR. Simple and efficient.
    Portable code - the C standard library time functions work on almost any device with a C compiler.
    Easy to calulate time deltas - use ordinary integer math on time_t values.
    Easy to compare times using <, >, ==, etc.
    Compact representation of time (32 bit time_t typically) is good for timestamps of data logs.
    Some file systems (not FAT unfortunately) use time_t as for timestamps.
     
    Concerns
    Converting from time_t to tm struct takes quite a few clock cycles, so not good for low power (battery powered) systems.
    Time functions take up quite a bit of flash - will not fit in G2211 for example.
     
    Software model of a hardware RTC
    Hardware real time clocks typically have counters for seconds, minutes, hours, ect. Each counter will reset at the appropriate
    limit - 60 seconds, 24 hours, ect. This approch can be use for a software RTC. The ISR has more code than the previous version...

    #pragma vector = WDT_VECTOR // - Watchdog timer interrupt vector __interrupt void wdt_isr(void) // This interrupt will occur once per second { // if(++t.tm_sec > 59) { // Increment seconds, check for overflow t.tm_sec = 0; // Reset seconds if(++t.tm_min > 59) { // Increment minutes, check for overflow t.tm_min = 0; // Reset minutes if(++t.tm_hour > 23) { // Increment hours, check for overflow t.tm_hour = 0; // Reset hours ++t.tm_yday; // Increment day of year if(++t.tm_wday > 6) // Increment day of week, check for overflow t.tm_wday = 0; // Reset day of week // Increment day of month, check for overflow if(++t.tm_mday > dim[t.tm_mon][is_leap_year(t.tm_year + 1900)]) { t.tm_mday = 1; // Reset day of month if(++t.tm_mon > 11) { // Increment month, check for overflow t.tm_mon = 0; // Reset month t.tm_yday = 0; // Reset day of year ++t.tm_year; // Increment year } // - year } // - month } // - day } // - hour } // - minute } //
     
    Most of the time the ISR will just increment the seconds member and return. The worst case is at the end of the year when the year is incremented and all other counters are reset to inital values.
     
    There is no need for any conversion for display of the time or setting the time. Be aware that day of week and day of year must be explicity set and can be out-of-sync if not properly set.
     
    Benefits
    No conversion function needed for display of time or setting of time.
    Small code size. Fits in G2211.
    High efficiency is good for battery powered applications.
    Use of tm struct provides some familiarity to those who have used the C standard library functions.
     
    Concerns
    No easy to way calulate time delta.
    No support for time zones / localization.
    Time comparison (for alarms) requires more MCU cycles because several structure members require comparason rather than just a long integer.
     


    This sample code can be configured to use either of the two methods descibed by (un)commenting the "#define USE_STDLIB_TIME" in main.c
     
    main.c

    #include #include #include #include "rtc.h" #include "lcd.h" //#define USE_STDLIB_TIME // Use functions in time.h void show_time(const struct tm *t) // Show time on LCD { static const char *dow[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; int x, w; const char *d; if(t->tm_hour < 10) { x = -1; lcd_fill(0, 1, 10, 2, 0); } else { x = 4; lcd_fill(0, 1, 4, 2, 0); lcd_pd12(t->tm_hour / 10, x, 1); } lcd_pd12(t->tm_hour % 10, x + 11, 1); lcd_pd12(11, x + 22, 1); lcd_pd12(t->tm_min / 10, x + 27, 1); lcd_pd12(t->tm_min % 10, x + 38, 1); lcd_pd12(11, x + 49, 1); lcd_pd12(t->tm_sec / 10, x + 54, 1); lcd_pd12(t->tm_sec % 10, x + 65, 1); lcd_fill(x + 76, 1, 8 - x, 2, 0); if(t->tm_mon < 9) { x = -4; lcd_fill(0, 3, 7, 2, 0); } else { x = 1; lcd_fill(0, 3, 1, 2, 0); lcd_pd12((t->tm_mon + 1) / 10, x, 3); } lcd_pd12((t->tm_mon + 1) % 10, x + 11, 3); lcd_pd12(13, x + 22, 3); lcd_pd12(t->tm_mday / 10, x + 30, 3); lcd_pd12(t->tm_mday % 10, x + 41, 3); lcd_pd12(13, x + 52, 3); lcd_pd12(t->tm_year %100 / 10, x + 60, 3); lcd_pd12(t->tm_year % 10, x + 71, 3); lcd_fill(x + 82, 3, 2 - x, 2, 0); d = dow[t->tm_wday]; w = strlen(d) * 6; x = (84 - w) >> 1; lcd_fill(0, 5, x, 1, 0); lcd_print(d, x, 5); x += w; lcd_fill(x, 5, 84 - x, 1, 0); } // struct tm ts; // Time structure time_t tt; // Time in seconds since epoch // // #pragma vector = WDT_VECTOR // - Watchdog timer interrupt vector __interrupt void wdt_isr(void) // This interrupt will occur once per second { // #ifdef USE_STDLIB_TIME // ++tt; // Increment time_t #else // rtc_tick(&ts); // Increment tm struct #endif // __bic_SR_register_on_exit(LPM0_bits); // Wakeup main code } // // void main(void) // { // WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset // lcd_init(); // Init LCD lcd_clear(0); // lcd_print("MSP430 RTC", 12, 0); // // // 32 kHz xtal loading //BCSCTL3 = XCAP_1; // 6 pF (default) BCSCTL3 = XCAP_2; // 10 pF //BCSCTL3 = XCAP_3; // 12.5 pF // WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL; // Use WDT as interval timer IE1 |= WDTIE; // Enable WDT interrupt _EINT(); // Enable interrupts // // Set initial time - there is no UI for this ts.tm_hour = 13; // Hour ts.tm_min = 37; // Minute ts.tm_sec = 42; // Second ts.tm_mon = 3; // Month (0 based!) ts.tm_mday = 20; // Day of Month ts.tm_year = 2012 - 1900; // Year ts.tm_wday = 5; // Day of Week - Not used by mktime() ts.tm_yday = 0; // Not used by mktime() ts.tm_isdst = 0; // DST flag - Not used by rtc_tick() // #ifdef USE_STDLIB_TIME // Convert tm struct to time_t tt = mktime(&ts); // #endif // // for(; { // for-ever #ifdef USE_STDLIB_TIME // show_time(localtime(&tt)); // Convert time_t to tm struct and show on LCD #else // show_time(&ts); // Show time on LCD #endif // __bis_SR_register(LPM0_bits + GIE); // Sleep until WDT interrupt } // } //
     
    rtc.h

    void rtc_tick(struct tm *t);
     
    rtc.c - Software model of hardware RTC

    #include static int is_leap_year(const int y) { if(y & 3) return 0; // Not divisible by 4 switch(y % 400) { // Divisible by 100, but not by 400 (1900, 2100, 2200, 2300, 2500, 2600) case 100: case 200: case 300: return 0; } return 1; // Divisible by 4 and !(100 and !400) } void rtc_tick(struct tm *t) { static const signed char dim[12][2] = { // Number of days in month for non-leap year and leap year 31, 31, // January 28, 29, // February 31, 31, // March 30, 30, // April 31, 31, // May 30, 30, // June 31, 31, // July 31, 31, // August 30, 30, // September 31, 31, // October 30, 30, // November 31, 31 // December }; // // if(++t->tm_sec > 59) { // Increment seconds, check for overflow t->tm_sec = 0; // Reset seconds if(++t->tm_min > 59) { // Increment minutes, check for overflow t->tm_min = 0; // Reset minutes if(++t->tm_hour > 23) { // Increment hours, check for overflow t->tm_hour = 0; // Reset hours ++t->tm_yday; // Increment day of year if(++t->tm_wday > 6) // Increment day of week, check for overflow t->tm_wday = 0; // Reset day of week // Increment day of month, check for overflow if(++t->tm_mday > dim[t->tm_mon][is_leap_year(t->tm_year + 1900)]) { t->tm_mday = 1; // Reset day of month if(++t->tm_mon > 11) { // Increment month, check for overflow t->tm_mon = 0; // Reset month t->tm_yday = 0; // Reset day of year ++t->tm_year; // Increment year } // - year } // - month } // - day } // - hour } // - minute } //
     
    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_fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z); void lcd_print(const char *s, unsigned x, unsigned y); void lcd_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 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); } void lcd_fill(unsigned x, unsigned y, unsigned w, unsigned h, unsigned char z) { unsigned yy = y + h; unsigned char c[2]; c[0] = 0x80 | x; for(;y < yy; ++y) { c[1] = 0x40 | y; lcd_send(c, sizeof(c), lcd_command); lcd_send(&z, w, lcd_data_repeat); } } 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(const 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 lcd_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); }
  16. Like
    timotet 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); }
  17. Like
    timotet reacted to chibiace in LP screw terminal power connector   
    I needed something to test my lm2576 3.3v switch mode power supply that i had built the other day, so i desoldered the male headers at the bottom of the launchpad and slotted in a cheap 2 way screw terminal.
     

     
    there is a tiny bit of over hang and only G G V are visible on the silkscreen but that is alright for me.
    im sure to use this for battery hookup in the future.
     
    if those 0.1" screw terminals weren't so damned expensive i would replace all of the other female headers with them. :twisted:
  18. Like
    timotet got a reaction from bluehash in Rigol DS1052E $315 shipped!   
    Ok I will fix when I get home! thanks
     
    this can be removed thanks
  19. Like
    timotet reacted to bluehash in Rigol DS1052E $315 shipped!   
    Click the upload attachment tab, below the submit button.
  20. Like
    timotet got a reaction from gatImmusepete in Rigol DS1052E $315 shipped!   
    So I got the Rigol. It is my first true DSO. Im really happy so far.
    I played with it a fair amount this weekend, and I went back and forth on weather to do "the hack".
    So this morning I said WTF! its only money and went for it.
    Here are the results.
     
    before notice model number

    after notice model number :clap:

    apparently you can now go down to a 2ns rise time

    not Rise(2) look at Time 2.000ns
     
    anyhow I'm not complaining this should be more than enough for me.
    if you want to do it check out http://www.eevblog.com/forum/blog-speci ... mmy-guide/
  21. Like
    timotet reacted to oPossum in Setting up the DCO properly   
    That is very similar to what I see with the Fraunchpad (MSP430FR5739). I can't get the scope to really sync well.
     
    The G series chips seem reasonably stable. This is a G2553 with these settings for DCO:
    DCOCTL 0x00
    BCSCTL1 0x87
    BCSCTL2 0x00
    BCSCTL3 0x05
     
    Looks like about +/- 3 ns jitter.
     


     
    With the modulator set to 7, there are clearly two different clock periods in use.
     


     
    16 MHz factory calibration.
     


  22. Like
    timotet reacted to cubeberg in Etch A Sketch   
    This is an LCD version of an Etch-A-Sketch. Made this for my daughter's 5th birthday.
     
    LCD is a 128*128 Powertip T6963c LCD
    5v for the LCD and LP is supplied by a 5v cell phone backup
    2x 100k linear pots used for control
    Negative contrast (-13v) is currently supplied by two 9v batteries - I'll be making one with a MC34063 later
    The shake detection was salvaged from a toy - no idea where to get them (I need to turn down the number of shakes needed)
    I used an old Floppy Drive cable to connect the LCD to an LP booster made on perfboard
     
    Many thanks to RobG for his assistance (see here for more information)
     


     
    Source is attached. This used every pin on the 2553, including XIN/XOUT. I have another of these for another project - I'll need to add an I/O expander to reduce the pin count.
     
    I'll post some pictures of the inside later
    EtchASketch_V2.zip
  23. Like
    timotet reacted to oPossum in 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; }
     


  24. Like
    timotet reacted to oPossum in 16 channel software PWM using a single timer   
    This is a method of generating multichannel PWM using a single timer.

    A linked list of events is used to allow a very efficient ISR and very low CPU usage.

    This is the linked list entry structure...
    typedef struct { // PWM ISR info struct unsigned time; // Time for on/off action to occur unsigned port_off; // Port pins to turn off unsigned port_on; // Port pins to turn on void *next; // Next entry in linked list } TPWM; // ...and the ISR...
    (written in C for clarity, using assembly would reduce the size and execution time by half)
    __interrupt void Timer0_A1 (void) { volatile unsigned x = TAIV; // Clear interrupt flag P1OUT &= ~pa->port_off; // Port pins off P2OUT &= ~pa->port_off >> 8; // P1OUT |= pa->port_on; // Port pins on P2OUT |= pa->port_on >> 8; // pa = pa->next; // Next entry in list TACCR1 = pa->time; // Update timer compare time } When an interrupt occurs, the ports are updated, the timer is updated, and the next linked list entry is made the active entry. An interrupt will only occur when port pin(s) have to be changed. Very simple and efficient.

    The tradeoff is a rather complex chunk of code to maintain the linked list. The code shown here uses a simple, but rather crude, method of reducing glitches that can occur when the linked list is manipulated. The code will wait for the current pulse to complete before removing the list entry for it. There are better ways to do this, but the code is much more complex due to the many corner cases that must be handled. There is no disruption in the PWM output when PWM values are changed. All PWM outputs are active as long as the timer and global interrupt are enabled.

    The PWM period is 2^16 / SMCLK and the resolution is 2^8 / SMCLK (8 bit resolution).
    So for a 16 MHz clock:
    period = 65,536 / 16,000,000 = 4.096 ms
    resolution = 256 / 16,000,000 = 16 us
    frequency = 16,000,000 / 65,536 = 244.24 Hz

    An interrupt will occur no more than 17 times the base frequency when all 16 channels are active and set to different non-zero/non-max values. So at 16 MHz there will be no more than 4151 interrupts per second. Assuming 100 cycles per interrupt (the C compiler should be able to do better than that) would be 415,100 cycles per second of 16,000,000 or 2.6% CPU usage (worst case).

    The resolution can be increased as long as there are not other interrupts that use too many cycles. Consider the worst case scenario of two back-to-back PWM interrupts with another interrupt in between. The maximum time allowed for other interrupts is the PWM resolution minus the PWM ISR time - it has to squeeze in between back-to-back PWM interrupts.

    Complete code with test case...
    #include "msp430g2553.h" #include "string.h" typedef struct { // PWM ISR info struct unsigned time; // Time for on/off action to occur unsigned port_off; // Port pins to turn off unsigned port_on; // Port pins to turn on void *next; // Next entry in linked list } TPWM; // TPWM pw[17], *pi; // Array and inactive list head volatile TPWM *pa; // Active list entry void pwm_set(const unsigned pin, const unsigned time) { const unsigned mask = 1 << pin; // const unsigned tm = time & 0xFF00; // Limit closeness of entries TPWM *b, *p, *n; // // // -- Try to find existing active entry for this pin for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) { if(p->port_off & mask) { // Found it if(p->time == tm) return; // - Time is the same, nothing to do, return... while(pa != p); // Wait for this entry to be active while(pa == p); // Wait for this entry to become inactive // Safe to remove now if(p->port_off == mask) { // - Entry is only used for this pin, remove it b->next = p->next; // Remove link p->next = pi; // Add to inactive list pi = p; // } else { // - Entry is used for multiple pins p->port_off &= ~mask; // Remove this pin from the entry } // break; // Found the pin, so stop searching } // } // // - Update first entry in list if(tm == 0) { // If time is 0, turn off and return pw[0].port_on &= ~mask; // pw[0].port_off |= mask; // return; // } else { // If time is non-zero, turn on pw[0].port_on |= mask; // pw[0].port_off &= ~mask; // if(time == 0xFFFF) return; // If max, no need to turn off, so return } // // // Find where the new turn off entry will go for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) if(p->time >= tm) break; // Stop when an entry of >= time is found // if(p->time == tm) { // If same time, use existing entry p->port_off |= mask; // Add this pin return; // All done... } // // n = pi; // Get an entry from the inactive list pi = n->next; // // n->port_off = mask; // Setup new entry n->port_on = 0; // n->time = tm; // // n->next = p; // Insert in to active list b->next = n; // } void pwm_detach(unsigned pin) { const unsigned mask = 1 << pin; TPWM *b, *p; // Try to find existing active entry for this pin for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) { if(p->port_off & mask) { // Found it if(p->port_off == mask) { // Entry is only used for this pin, remove it _DINT(); if(pa == p) pa = p->next; b->next = p->next; _EINT(); p->next = pi; pi = p; } else { p->port_off &= ~mask; // Remove this pin from the entry } break; } } pw[0].port_on &= ~mask; // Don't turn on or off pw[0].port_off &= ~mask; } void pwm_init(void) { unsigned n; memset(pw, 0, sizeof(pw)); // Clear entire array pa = &pw[0]; // Active list always begins with first array element pa->next = &pw[0]; // Begin with only 1 entry in list pi = &pw[1]; // First inactive entry is second array element for(n = 1; n < sizeof(pw)/sizeof(TPWM) - 1; ++n) // Link the inactive entries pw[n].next = &pw[n + 1]; // // TACTL = TASSEL_2 + MC_2 + ID_0; // Setup timer, continuous mode, SMCLK/1 TACCTL1 = CCIE; // Enable timer interrupt _EINT(); // Enable interrupts } #pragma vector = TIMER0_A1_VECTOR __interrupt void Timer0_A1 (void) { volatile unsigned x = TAIV; // Clear interrupt flag P1OUT &= ~pa->port_off; // Port pins off P2OUT &= ~pa->port_off >> 8; // P1OUT |= pa->port_on; // Port pins on P2OUT |= pa->port_on >> 8; // pa = pa->next; // Next entry in list TACCR1 = pa->time; // Update timer compare time } // Test case for 2 channels - Launchpad LEDs void main(void) { unsigned n, o; WDTCTL = WDTPW | WDTHOLD; // Disable watchdog DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // P1DIR = BIT0 | BIT6; // Enable outputs for LEDs on Launchpad pwm_init(); // Initialize software PWM for(;;-) { pwm_set(0, n); pwm_set(6, o); n += 100; o += 123; __delay_cycles(100000); } } // Test case for all 16 channels void main(void) { unsigned n; unsigned w[16]; unsigned r[16] = { 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145 }; WDTCTL = WDTPW | WDTHOLD; // Disable watchdog DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // P2SEL = 0; // Allow P2.6 and P2.7 to be used as GPIO P1DIR = P2DIR = 0xFF; // Enable all P1 and P2 pins as output pwm_init(); // Initialize software PWM for(;;-) { for(n = 0; n < 16; ++n) { pwm_set(n, w[n]); w[n] += r[n]; } __delay_cycles(100000); } } Two PWM outputs with the pulse with changing at different rates (lower trace is faster). The two outputs are the Launchpad LEDs.




    All 16 channels.

  25. Like
    timotet reacted to oPossum in DIY Mini Launchpad   
    Make use of the second MCU (and female headers) included with the Launchpad 50 mm x 50 mm board size - low cost from Seeed & iTead Mostly through hole - anyone can build this Populate with components as needed Mounting holes for secure attachment Power, P1.6 & P1.0 LEDs LED enable jumpers Reset & P1.3 switch Coaxial power jack and/or terminal block Optional Microchip MCP1700/1702 voltage regulator 6 pin power/program/debug/serial connector UART line swap jumper Prototype with Launchpad, build permanent project with this.
    lp_mini.brd
    lp_mini.sch

×
×
  • Create New...