Jump to content
43oh

RobG

Members
  • Content Count

    3,117
  • Joined

  • Last visited

  • Days Won

    249

Reputation Activity

  1. Like
    RobG got a reaction from GeekDoc in Electricity monitor - need some help   
    @GeekDoc
    It does work on my board, I am using CCS. Must be debugger.
  2. Like
    RobG got a reaction from Kent in LaunchPad IR Receiver   
    Since I did the IR transmitter, I figured I need a receiver, so here's my first iteration.
    For this project, I am using Vishay's TSOP38238, which takes care of detecting, amplifying, filtering, and demodulating IR signal.
    Output from IR module is connected directly to port P1.1, which is configured as capture input.
    Timer's capture/compare capability is used to process the signal.
    P1.3-P1.5 are connected to LEDs to show the result (LEDs are toggled so sometimes they stay on, it's not a bug.)
    The only problem with this design is that some remotes could have shorter off period, which would screw up the logic (at least that's what I've read somewhere, but then again, you cannot always believe what you read on the net.)




    #include "msp430g2231.h" #define T05 300 #define T65 T05*13 #define T2 T05*4 #define T3 T05*6 unsigned int rxData = 0; // received data: A4-A0 and C6-C0 0000 AAAA ACCC CCCC unsigned int bitCounter = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT BCSCTL1 = CALBC1_1MHZ; // load calibrated data DCOCTL = CALDCO_1MHZ; P1DIR &= ~BIT1; // P1.1 input P1SEL = BIT1; // P1.1 Timer_A CCI0A P1OUT &= ~(BIT3 + BIT4 + BIT5); // P1.3-1.5 out P1DIR |= (BIT3 + BIT4 + BIT5); TACTL = TASSEL_2 | MC_2; // SMCLK, continuous mode CCTL0 = CM_2 | CCIS_0 | CAP | CCIE; // falling edge capture mode, CCI0A, enable IE __bis_SR_register(LPM0_bits + GIE); // switch to LPM0 with interrupts } #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { if(CCTL0 & CAP) { // start bit bitCounter++; // start counting bits CCR0 += T65; // add 6.5 bits to counter CCTL0 &= ~ CAP; // compare mode } else { switch (bitCounter) { case 0x1000: // received all bits bitCounter = 0; // reset counter // process received data, for example toggle LEDs switch (rxData & 0x001F) { // mask device number case 19: // Volume - 0010011 = 19 P1OUT ^= BIT3; break; case 18: // Volume + 0010010 = 18 P1OUT ^= BIT4; break; case 21: // Power 0010101 = 21 P1OUT ^= BIT5; break; } rxData = 0; // end process received data CCTL0 |= CAP; // capture mode break; default: // data bit if (CCTL0 & SCCI) { // bit = 1 CCR0 += T2; // add 2 bits to counter } else { // bit = 0 rxData |= bitCounter; // set proper bit of rxData CCR0 += T3; // add 3 bits to counter } bitCounter <<= 1; // increase (shift) bit counter break; } } }
    The first diagram shows how the current code works, the second one shows how it should work to be more reliable (new code to follow.)
  3. Like
    RobG got a reaction from NatureTM in Code Template   
    Here's a little code template I have created.
    Not sure what I am going to use it for, but someone might find it helpful.
    Handling of the interrupts is done in main rather than in interrupt routine itself.
     

    #include "msp430g2231.h" #define EV_TIMER BIT0 #define EV_PORT1 BIT1 #define EV_WDT BIT2 #define EV_USI BIT3 unsigned char events = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT // configure all here __bis_SR_register(LPM0_bits + GIE); // switch to LPM0 with interrupts while(1) { while(events) { if(events & EV_TIMER) { events &= EV_TIMER; // do your thing //clear TAIFG, etc. //enable interrupts, main, CCR0, CCR1, etc. } else if(events & EV_PORT1) { events &= ~EV_PORT1; // do your thing //P1IFG &= ~BITn; // clear IFG //P1IE |= BITn; // enable interrupt } else if(events & EV_WDT) { events &= ~EV_WDT; // do your thing IFG1 &= ~WDTIFG; //IE1 |= WDTIE; // enable WDT interrupt } else if(events & EV_USI) { events &= ~EV_USI; // do your thing USICTL1 &= ~USIIFG; //USICTL1 |= USIIE; // enable interrupts } } __bis_SR_register(LPM0_bits); // switch to LPM0 } } // WDT interrupt service routine #pragma vector=WDT_VECTOR __interrupt void Watchdog_Timer (void) { //IE1 &= ~WDTIE; // disable WDT interrupt events |= EV_WDT; __bic_SR_register_on_exit(LPM0_bits); // exit LPM0 } // Timer A interrupt service routine #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { //disable interrupts, main, CCR0, CCR1, etc. events |= EV_TIMER; __bic_SR_register_on_exit(LPM0_bits); // exit LPM0 } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { //P1IE &= ~BITn; // disable interrupt events |= EV_PORT1; __bic_SR_register_on_exit(LPM0_bits); // exit LPM0 } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { //USICTL1 &= ~USIIE; // disable interrupts events |= EV_USI; __bic_SR_register_on_exit(LPM0_bits); // exit LPM0 } // TODO Add ADC routine
  4. Like
    RobG got a reaction from NJC in Wrong calibrated DCO or wrong code?   
  5. Like
    RobG got a reaction from ScoMac in LaunchPad as Sony IR Remote   
    Sure, in this case we can do common collector.
     

  6. Like
    RobG reacted to OCY in LaunchPad as Sony IR Remote   
    Very good work.
     
    I have some small suggestions.
     
    You do not need to use P1.0 to modulate the 38 kHz sub-carrier with hardware (D2, D3, and R1). You could clear BIT4 of P1OUT and set/clear BIT4 of P1SEL to turn on/off the sub-carrier at P1.4. Connect P1.4 directly to the base of the transistor T1 and move R2 and D1 from the collector side to the emitter side of T1.
     
    Also, you do not need R3, R4, and R5. You could set BIT1, BIT2, and BIT3 of P1REN instead.
     
    With these small changes in firmware and some re-wiring , you freed one port pin and saved four resistors and two diodes.
  7. Like
    RobG got a reaction from GeekDoc in IR remote control help   
    Here's working example using the code above, TV Volume Down command is sent over and over:


  8. Like
    RobG got a reaction from bluehash in IR remote control help   
    Here's working example using the code above, TV Volume Down command is sent over and over:


  9. Like
    RobG got a reaction from bluehash in IR remote control help   
    I am working on optimizing that code so multiple commands can be used.
    When it comes to range and transistor, you can do something like this:
  10. Like
    RobG got a reaction from simpleavr in IR remote control help   
    I am working on optimizing that code so multiple commands can be used.
    When it comes to range and transistor, you can do something like this:
  11. Like
    RobG got a reaction from godisdie in LaunchPad controlling up to 8 RC Servos   
    Here's my take on controlling RC servos with LaunchPad.
    Again, I am using my favorite shift register, 74HC595 (later I will be adding another example which will use 74HC164.)
    Since the voltage may be different in your application and the default DCO is used, you will have to work out the timing.
     
    If you need only 4ch, look at this post.
    Here is another 4ch example with ADC
    The simplest single channel ADC -> Servo example is here
    And finally, 2ch version is here
     


     
    Besides LP you will need 74HC595 and 8 10k pull down resistors.

     

    #include unsigned int counter = 5; // Servo counter, start with 5 (see below in timer interrupt section.) unsigned int servoPosition[8] = {180, 180, 180, 180, 180, 180, 180, 180}; // Default servo position // DEMO counter unsigned int demoCounter = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT &= ~BIT0; // Port P1.0 will be used as serial out to set first bit P1DIR |= BIT0 + BIT2; // Port P1.0 & P1.2 out P1SEL &= ~BIT2; // An ugly way to clear register volatile int c; // This could be done by some sort of POR for( c = 0; c < 8; c++ ) { P1OUT |= BIT2; P1OUT &= ~BIT2; } P1SEL |= BIT2; // P1.2 TA1 option select CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 325; // ~2.5ms CCTL1 = OUTMOD_3; // CCR1 set/reset CCR1 = 180; // CCR1 duty cycle ~1.5ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { counter++; // Increase counter if(counter == 0x08) counter = 0; // Counter range 0 to 7 if(counter == 6) { // Set serial in to 1, then reset P1OUT |= BIT0; // Both clocks of 595 are connected together, serial in must be set earlier } else if(counter == 7) { P1OUT &= ~BIT0; } // DEMO demoCounter++; if(demoCounter == 800) servoPosition[0] = 80; if(demoCounter == 1600) servoPosition[0] = 280; if(demoCounter == 2000) servoPosition[7] = 280; if(demoCounter == 2400) servoPosition[7] = 180; if(demoCounter == 2800) servoPosition[7] = 280; if(demoCounter == 3200) servoPosition[0] = 130; if(demoCounter == 3600) servoPosition[0] = 230; if(demoCounter == 4000) { servoPosition[0] = 180; servoPosition[7] = 180; demoCounter = 0; } // END DEMO CCR1 = servoPosition[counter]; }
  12. Like
    RobG got a reaction from GeekDoc in LaunchPad, 74HC165, Switches   
    *******************
    Also checkout this post
    *******************
     
    In this example, I am demonstrating how to connect switches using parallel-serial shift register 74HC165.
    You can daisy chain as many 165s as you want.
    In my example I have 2 of them, which allowes me to connect up to 16 switches.
    In the video, I am using small 6 position DIP switch and all unused inputs are grounded and do not have pull-up resistors.
    Also, the state of switches is displayed on a 7 segment display (see my other post for how to connect 7 segment display.)
    De-bouncing is accomplished by comparing previous state with current (switchReady.)
     


     

    #include unsigned int data = 0; // data to be displayed unsigned int digitCounter = 0; // Digit counter unsigned char digit = 0; // Single digit to be displayed unsigned char hex7digit[16] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x58,0x5E,0x79,0x71}; // Hex to 7 digit map unsigned char digitSelector[4] = {0x01, 0x02, 0x04, 0x08}; // Digit selector map unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H unsigned int switchStatus = 0x0; // Pressed or released void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to latch both, 74HC165 and 74HC595 P1DIR |= 0x01; USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE; // In, out & clk enable, SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt, flag remains set USICKCTL = USIDIV_4 + USISSEL_2; // /16 SMCLK USICTL0 &= ~USISWRST; // USI released for operation USICNT = USI16B; // Enable 16 bit CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 625; // Approx. 5ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt WDTCTL = WDTPW + WDTHOLD; // Stop WDT } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { //P1OUT &= ~0x01; // You could latch input right now //P1OUT |= 0x01; if(digitCounter == 0) { // Update switch status every 20 ms switchReady = ~(USISR ^ switchStatus); // Copy USI's register to switchReady and switchStatus switchStatus = USISR; if((switchReady & 0x3F) == 0x3F) { // When all 6 switches are ready... data = switchStatus; // move input to data } } digitCounter++; // Increase digit counter digitCounter &= 0x03; // Mask, counter range is 0-3 digit = data>>(4 * digitCounter); // Shift digits right digit &= 0x0F; // Mask, we need first digit only USISRL = hex7digit[digit]; // Get segments from the map USISRH = digitSelector[digitCounter]; // USICNT |= 16; // Start USI } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; // Clear pending flag P1OUT &= ~0x01; // Latch data display (& input for next timer interrupt) P1OUT |= 0x01; }
     
    Schematic:

  13. Like
    RobG got a reaction from bluehash in LaunchPad, 74HC165, Switches   
    *******************
    Also checkout this post
    *******************
     
    In this example, I am demonstrating how to connect switches using parallel-serial shift register 74HC165.
    You can daisy chain as many 165s as you want.
    In my example I have 2 of them, which allowes me to connect up to 16 switches.
    In the video, I am using small 6 position DIP switch and all unused inputs are grounded and do not have pull-up resistors.
    Also, the state of switches is displayed on a 7 segment display (see my other post for how to connect 7 segment display.)
    De-bouncing is accomplished by comparing previous state with current (switchReady.)
     


     

    #include unsigned int data = 0; // data to be displayed unsigned int digitCounter = 0; // Digit counter unsigned char digit = 0; // Single digit to be displayed unsigned char hex7digit[16] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x58,0x5E,0x79,0x71}; // Hex to 7 digit map unsigned char digitSelector[4] = {0x01, 0x02, 0x04, 0x08}; // Digit selector map unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H unsigned int switchStatus = 0x0; // Pressed or released void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to latch both, 74HC165 and 74HC595 P1DIR |= 0x01; USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE; // In, out & clk enable, SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt, flag remains set USICKCTL = USIDIV_4 + USISSEL_2; // /16 SMCLK USICTL0 &= ~USISWRST; // USI released for operation USICNT = USI16B; // Enable 16 bit CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 625; // Approx. 5ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt WDTCTL = WDTPW + WDTHOLD; // Stop WDT } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { //P1OUT &= ~0x01; // You could latch input right now //P1OUT |= 0x01; if(digitCounter == 0) { // Update switch status every 20 ms switchReady = ~(USISR ^ switchStatus); // Copy USI's register to switchReady and switchStatus switchStatus = USISR; if((switchReady & 0x3F) == 0x3F) { // When all 6 switches are ready... data = switchStatus; // move input to data } } digitCounter++; // Increase digit counter digitCounter &= 0x03; // Mask, counter range is 0-3 digit = data>>(4 * digitCounter); // Shift digits right digit &= 0x0F; // Mask, we need first digit only USISRL = hex7digit[digit]; // Get segments from the map USISRH = digitSelector[digitCounter]; // USICNT |= 16; // Start USI } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; // Clear pending flag P1OUT &= ~0x01; // Latch data display (& input for next timer interrupt) P1OUT |= 0x01; }
     
    Schematic:

  14. Like
    RobG got a reaction from jsolarski in LaunchPad, 74HC165, Switches   
    *******************
    Also checkout this post
    *******************
     
    In this example, I am demonstrating how to connect switches using parallel-serial shift register 74HC165.
    You can daisy chain as many 165s as you want.
    In my example I have 2 of them, which allowes me to connect up to 16 switches.
    In the video, I am using small 6 position DIP switch and all unused inputs are grounded and do not have pull-up resistors.
    Also, the state of switches is displayed on a 7 segment display (see my other post for how to connect 7 segment display.)
    De-bouncing is accomplished by comparing previous state with current (switchReady.)
     


     

    #include unsigned int data = 0; // data to be displayed unsigned int digitCounter = 0; // Digit counter unsigned char digit = 0; // Single digit to be displayed unsigned char hex7digit[16] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x58,0x5E,0x79,0x71}; // Hex to 7 digit map unsigned char digitSelector[4] = {0x01, 0x02, 0x04, 0x08}; // Digit selector map unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H unsigned int switchStatus = 0x0; // Pressed or released void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to latch both, 74HC165 and 74HC595 P1DIR |= 0x01; USICTL0 |= USIPE7 + USIPE6 + USIPE5 + USIMST + USIOE; // In, out & clk enable, SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt, flag remains set USICKCTL = USIDIV_4 + USISSEL_2; // /16 SMCLK USICTL0 &= ~USISWRST; // USI released for operation USICNT = USI16B; // Enable 16 bit CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 625; // Approx. 5ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt WDTCTL = WDTPW + WDTHOLD; // Stop WDT } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { //P1OUT &= ~0x01; // You could latch input right now //P1OUT |= 0x01; if(digitCounter == 0) { // Update switch status every 20 ms switchReady = ~(USISR ^ switchStatus); // Copy USI's register to switchReady and switchStatus switchStatus = USISR; if((switchReady & 0x3F) == 0x3F) { // When all 6 switches are ready... data = switchStatus; // move input to data } } digitCounter++; // Increase digit counter digitCounter &= 0x03; // Mask, counter range is 0-3 digit = data>>(4 * digitCounter); // Shift digits right digit &= 0x0F; // Mask, we need first digit only USISRL = hex7digit[digit]; // Get segments from the map USISRH = digitSelector[digitCounter]; // USICNT |= 16; // Start USI } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; // Clear pending flag P1OUT &= ~0x01; // Latch data display (& input for next timer interrupt) P1OUT |= 0x01; }
     
    Schematic:

  15. Like
    RobG got a reaction from jsolarski in LaunchPad and fun with the flash (strobe & slave trigger)   
    Last weekend I was doing a little photo shoot and I was in need of extra flash source. I have an old Nikon SB-28 laying around so I figured I could use it if I had a slave trigger. Sure I can buy one from Amazon for <$10 (dumb one) or build one using 555 (which would ignore TTL pre-flash,) but why not go one step further and use LaunchPad.
     
    Step 1, build strobe light.
    This is pretty simple, just add opto-isolator and write short program.
    FL1 connects to the center pin of the hot shoe, FL2 to the side.
    If you need a hot shoe, you can get one cheap from BHPhotoVideo.com, just search for AS-E900 (or SK-E900, you'll get nice bracket as a bonus!)




    #include unsigned int sw = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to trigger flash P1DIR |= 0x01; CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 20000; // TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { if(sw = ~sw) { // Flash every other interrupt P1OUT |= 0x01; } else { P1OUT &= ~0x01; } }
     
    Step 2, add S2 to control speed.
     

    #include unsigned int counter = 0; unsigned int resetCounterAt = 100; unsigned int pressedS2 = 0; // BITn of switchReady and switchStatus corresponds to Port P1.n unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H unsigned int switchStatus = 0x0; // Pressed or released void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= BIT0; // Port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT3; // Port P1.3 as input P1OUT |= BIT3; // Pull up resistor P1REN |= BIT3; // Enable pull up resistor CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 1250; // Approx. 10ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode // we will use USI as a delay USICTL0 |= USIMST; // SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt USICKCTL = USIDIV_4 + USISSEL_2; // SMCLK/16 USICTL0 &= ~USISWRST; // USI released for operation _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { switchReady = ~(P1IN ^ switchStatus); switchStatus = P1IN; if(switchReady & BIT3 && !(switchStatus & BIT3)) { if(!pressedS2) { // Update only once resetCounterAt -= 20; if(resetCounterAt < 20) { resetCounterAt = 100; } pressedS2 = 1; // Set pressedS2 flag } } if(switchReady & BIT3 && switchStatus & BIT3) pressedS2 = 0; // S2 released, clear pressedS2 flag counter++; if( counter > resetCounterAt ) { counter = 0; P1OUT |= BIT0; // Flash on interrupt USICNT |= 8; // Start delay } } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; P1OUT &= ~BIT0; // Clear P1.0 }
     
     
    Step 3, add phototransistor to make it work as a slave trigger
    Since 70's are long gone, I don't think I will have any use for the strobe, so we will add phototransistor to make it work as a dumb slave trigger


    #include void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT P1OUT &= ~BIT0; // port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT7; // port P1.7 input P1IE |= BIT7; // P1.7 interrupt enabled P1IES &= ~BIT7; // P1.7 lo/high edge P1IFG &= ~BIT7; // P1.7 IFG cleared _bis_SR_register(LPM0_bits + GIE); // LPM0 with interrupts } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~BIT7; // disable P1.7 interrupt P1IFG &= ~BIT7; // P1.7 IFG cleared P1OUT |= BIT0; // flash on interrupt _no_operation(); // 1 cycle delay, just in case //__delay_cycles(50); // if there are problems wih trigger, longer delay may be needed P1OUT &= ~BIT0; // clear P1.0 P1IE |= BIT7; // enable P1.7 interrupt }
     
     
    Step 4, add delay to make it work with TTL pre-flash
    Since in TTL mode main flash is not the first one, we have to add delay to ignore pre-flash(s)
     
    As it turns out, this is not an easy task. Pre-flashes are far more complicated than I thought and simple delay may not work.
    So this is my first stab at it. I am simply ignoring first flash and triggering the slave on second one. If there's no second flash within 200ms, counter is reset. This setup works with my D80 and SB-28 in TTL mode except when flashing too close to detector.
     
    When I find some extra time, I will improve this thing or hopefully someone else will contribute.
     

    #include unsigned char mainFlash = 0; // 0 indicates pre-flash, 1 main flash void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT P1OUT &= ~BIT0; // port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT7; // port P1.7 input P1IE |= BIT7; // P1.7 interrupt enabled P1IES &= ~BIT7; // P1.7 lo/high edge P1IFG &= ~BIT7; // P1.7 IFG cleared CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 0; // timer idle TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, up mode _bis_SR_register(LPM0_bits + GIE); // LPM0 with interrupts } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~BIT7; // disable P1.7 interrupt P1IFG &= ~BIT7; // P1.7 IFG cleared if(mainFlash) { // this is a main flash, trigger slave P1OUT |= BIT0; // trigger slave _no_operation(); // 1 cycle delay, just in case P1OUT &= ~BIT0; // clear P1.0 mainFlash = 0; // clear flag CCR0 = 0; // no need for timer } else { // pre-flash CCR0 = 25000; // start timer, approx. 200ms mainFlash = 1; // set flag } P1IFG &= ~BIT7; // P1.7 IFG cleared P1IE |= BIT7; // enable P1.7 interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { if(mainFlash) { // for some reason, there was no main flash mainFlash = 0; // reset flag CCR0 = 0; // no need for timer } }
  16. Like
    RobG got a reaction from bluehash in LaunchPad and fun with the flash (strobe & slave trigger)   
    Last weekend I was doing a little photo shoot and I was in need of extra flash source. I have an old Nikon SB-28 laying around so I figured I could use it if I had a slave trigger. Sure I can buy one from Amazon for <$10 (dumb one) or build one using 555 (which would ignore TTL pre-flash,) but why not go one step further and use LaunchPad.
     
    Step 1, build strobe light.
    This is pretty simple, just add opto-isolator and write short program.
    FL1 connects to the center pin of the hot shoe, FL2 to the side.
    If you need a hot shoe, you can get one cheap from BHPhotoVideo.com, just search for AS-E900 (or SK-E900, you'll get nice bracket as a bonus!)




    #include unsigned int sw = 0; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to trigger flash P1DIR |= 0x01; CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 20000; // TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { if(sw = ~sw) { // Flash every other interrupt P1OUT |= 0x01; } else { P1OUT &= ~0x01; } }
     
    Step 2, add S2 to control speed.
     

    #include unsigned int counter = 0; unsigned int resetCounterAt = 100; unsigned int pressedS2 = 0; // BITn of switchReady and switchStatus corresponds to Port P1.n unsigned int switchReady = 0x0; // When BITn is 0, means switch is unstable H->L or L->H unsigned int switchStatus = 0x0; // Pressed or released void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= BIT0; // Port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT3; // Port P1.3 as input P1OUT |= BIT3; // Pull up resistor P1REN |= BIT3; // Enable pull up resistor CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 1250; // Approx. 10ms TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, upmode // we will use USI as a delay USICTL0 |= USIMST; // SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt USICKCTL = USIDIV_4 + USISSEL_2; // SMCLK/16 USICTL0 &= ~USISWRST; // USI released for operation _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { switchReady = ~(P1IN ^ switchStatus); switchStatus = P1IN; if(switchReady & BIT3 && !(switchStatus & BIT3)) { if(!pressedS2) { // Update only once resetCounterAt -= 20; if(resetCounterAt < 20) { resetCounterAt = 100; } pressedS2 = 1; // Set pressedS2 flag } } if(switchReady & BIT3 && switchStatus & BIT3) pressedS2 = 0; // S2 released, clear pressedS2 flag counter++; if( counter > resetCounterAt ) { counter = 0; P1OUT |= BIT0; // Flash on interrupt USICNT |= 8; // Start delay } } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; P1OUT &= ~BIT0; // Clear P1.0 }
     
     
    Step 3, add phototransistor to make it work as a slave trigger
    Since 70's are long gone, I don't think I will have any use for the strobe, so we will add phototransistor to make it work as a dumb slave trigger


    #include void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT P1OUT &= ~BIT0; // port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT7; // port P1.7 input P1IE |= BIT7; // P1.7 interrupt enabled P1IES &= ~BIT7; // P1.7 lo/high edge P1IFG &= ~BIT7; // P1.7 IFG cleared _bis_SR_register(LPM0_bits + GIE); // LPM0 with interrupts } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~BIT7; // disable P1.7 interrupt P1IFG &= ~BIT7; // P1.7 IFG cleared P1OUT |= BIT0; // flash on interrupt _no_operation(); // 1 cycle delay, just in case //__delay_cycles(50); // if there are problems wih trigger, longer delay may be needed P1OUT &= ~BIT0; // clear P1.0 P1IE |= BIT7; // enable P1.7 interrupt }
     
     
    Step 4, add delay to make it work with TTL pre-flash
    Since in TTL mode main flash is not the first one, we have to add delay to ignore pre-flash(s)
     
    As it turns out, this is not an easy task. Pre-flashes are far more complicated than I thought and simple delay may not work.
    So this is my first stab at it. I am simply ignoring first flash and triggering the slave on second one. If there's no second flash within 200ms, counter is reset. This setup works with my D80 and SB-28 in TTL mode except when flashing too close to detector.
     
    When I find some extra time, I will improve this thing or hopefully someone else will contribute.
     

    #include unsigned char mainFlash = 0; // 0 indicates pre-flash, 1 main flash void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT P1OUT &= ~BIT0; // port P1.0 will be used to trigger flash P1DIR |= BIT0; P1DIR &= ~BIT7; // port P1.7 input P1IE |= BIT7; // P1.7 interrupt enabled P1IES &= ~BIT7; // P1.7 lo/high edge P1IFG &= ~BIT7; // P1.7 IFG cleared CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 0; // timer idle TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK/8, up mode _bis_SR_register(LPM0_bits + GIE); // LPM0 with interrupts } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~BIT7; // disable P1.7 interrupt P1IFG &= ~BIT7; // P1.7 IFG cleared if(mainFlash) { // this is a main flash, trigger slave P1OUT |= BIT0; // trigger slave _no_operation(); // 1 cycle delay, just in case P1OUT &= ~BIT0; // clear P1.0 mainFlash = 0; // clear flag CCR0 = 0; // no need for timer } else { // pre-flash CCR0 = 25000; // start timer, approx. 200ms mainFlash = 1; // set flag } P1IFG &= ~BIT7; // P1.7 IFG cleared P1IE |= BIT7; // enable P1.7 interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { if(mainFlash) { // for some reason, there was no main flash mainFlash = 0; // reset flag CCR0 = 0; // no need for timer } }
  17. Like
    RobG got a reaction from NatureTM in MSP430 LaunchPad, 74HC595, 16 LEDs   
    EAGLE for Mac
  18. Like
    RobG got a reaction from NatureTM in MSP430 LaunchPad, 74HC595, 16 LEDs   
    This is schematic for Part 2:
     
    Moved to another post
  19. Like
    RobG got a reaction from SugarAddict in MSP430 LaunchPad, 74HC595, 16 LEDs   
    What is it?
    4 digit BCD counter using LaunchPad and two 74HC595 shift registers.
     
    Note: One important thing that I forgot to add is that since I am powering this from LP, I am using here 74HC595 and not HCT.
    LP provides 3.6V, HCT needs 5V.
     
    See it in action:


     

    #include unsigned int counter = 0; // Counter variable void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1OUT |= 0x01; // Port P1.0 will be used to latch P1DIR |= 0x01; USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE; // Out & clk enable, SPI Master USICTL1 |= USICKPH + USIIE; // Counter interrupt USICKCTL = USIDIV_7 + USISSEL_2; // /2 SMCLK USICTL0 &= ~USISWRST; // Enable USI USICNT = USI16B; // Enable 16 bit CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 10000; // Duration TACTL = TASSEL_2 + MC_1 + ID_3; // SMCLK, upmode _bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt } // Timer A0 interrupt service routine #pragma vector = TIMERA0_VECTOR __interrupt void Timer_A (void) { counter = _bcd_add_short(counter, 0x01); // Decimally increase counter's value USISR = counter; USICNT |= 16; // Start USI } // USI interrupt service routine #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { USICTL1 &= ~USIIFG; // Clear pending flag P1OUT &= ~0x01; // Latch data P1OUT |= 0x01; }
     
    In the coming parts, I will be increasing the number of digits to 8 and changing LEDs to 7-segment displays, maybe throw in a keyboard.

×
×
  • Create New...