Jump to content

RobG

Members
  • Content Count

    3,117
  • Joined

  • Last visited

  • Days Won

    248

Everything posted by RobG

  1. Sure, we need 595 to shift just one 1, so before first shift, we have to set input to 1, after that it's all zeros. Every clock, we move that 1 to the next out. Output is active when clock is 0. When clock is 1, output is disabled (Hi-Z.) We have to set 1 on the input one clock earlier, because shift registers are one ahead of the latches when both clocks are connected together.
  2. RobG

    PWM codes and TimerA

    Why don't you just toggle it in the interrupt? This part should be executed only once, put it in the main TBCCR0 = 512 - 1; // PWM Period TBCCTL2 = OUTMOD_7; // TBCCR2 reset/set TBCTL = TBSSEL_2 + MC_1; // SMCLK, up mode Get rid of for, then in the interrupt routine, use if statement to toggle duty cycle if(toggle ^= 1) { TBCCR2 = DUTY_1; } else { TBCCR2 = DUTY_2; } One more question, why are you using two timers? You have interrupt for timer A, but changing CCR on timer B.
  3. 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]; }
  4. Yes I am Next week I will do another one, controlling up to 8 servos using 74HC164
  5. The way I am doing it for multiple switches is by using shift register to read the position and the timer to control frequency at which they are read. Also, I have two variables, one to store position information and one to store information about position changes. After getting information from the register, I am XORing it with the positions from previous read and storing it in change variable. Then I am updating position variable. If the bit in the change variable is set, it means switch is not stable and should not be used at this time. When the bit is clear, it means switch did not change it's position since the last time we read it and could be considered stable. One thing about this solution is that you need a wake up switch if you want to preserve power. Example, let's say we have one 165 with 8 switches, first var is change var, second is position, switches are off. 00000000 00000000 Now we flip one switch 00000001 00000001 00000001 Then on the next interrupt 00000000 00000001 Now we switch it off 00000000 00000001 00000000 And next interrupt 00000000 00000000 Just my $0.02
  6. The only problem is that 164 doesn't have output latch which means your data will be shifting each time you send it to 164 and your output will be unreliable. This might be fine if you are using it for display purposes and you are shifting fast enough, but if you are planning to control relays for example, 164 is a bad choice.
  7. ******************* 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:
  8. Posted the video. BTW, my schematic shows 4 single digit displays, but on my video, I am using one 4 digit display from Futurlec. I chose that one because it requires less connections. Also, I am using 74HC595 instead of 74HCT595 which is listed on the diagram. Resistors are 220 ohms.
  9. 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 } }
  10. Hi, I am powering it directly from LaunchPad, so it's about 3.6V. I am using 330ohm resistors to limit the current to about 5mA. 74HCT595 can source/sink up to 35mA. One more thing, I am using HC series, not HCT, sorry for the confusion. Rob.
  11. **************** For the latest, see this post **************** In this example, I have replaced LEDs with four 7 segment displays. Note: I am using HC series, not HCT. LaunchPad provides 3.6V, HCT needs 5V. #include unsigned int counter = 0; // Counter variable unsigned int digitCounter = 0; // Digit counter unsigned char digit = 0; // Single digit to be displayed unsigned char bcd7digit[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; // BCD to 7 digit map unsigned char digitSelector[4] = {0x01, 0x02, 0x04, 0x08}; // Digit selector map 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, flag remains set USICKCTL = USIDIV_7 + USISSEL_2; // /128 SMCLK USICTL0 &= ~USISWRST; // USI released for operation USICNT = USI16B; // Enable 16 bit CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 500; // 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) { digitCounter++; // Increase digit counter digitCounter &= 0x03; // Mask, counter range is 0-3 digit = counter>>(4 * digitCounter); // Shift digits right digit &= 0x0F; // Mask, we need first digit only USISRL = bcd7digit[digit]; // Get segments from the map USISRH = digitSelector[digitCounter]; // if(digitCounter == 0) { counter = _bcd_add_short(counter, 0x01);// Decimally increase counter's when on first digit } 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; }
  12. This is schematic for Part 2: Moved to another post
  13. 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...