-
Content Count
11 -
Joined
-
Last visited
Reputation Activity
-
Kent reacted to username in HC - SR04 Ultrasound Module Driver Code
Hey Kent,
Here is what I did with the trig pin and the echo pin. The Vin pin was set to 5V on the module.
-
Kent reacted to username in HC - SR04 Ultrasound Module Driver Code
Hey all,
Heres some code I wrote for an upcoming project which uses an ultrasound range detector. It uses a GPIO falling edge interrupt to determine time of echo pulse and uses a capture/compare pin w/ timer 1A for a ~100us pin trigger. The module is 5V so I power that off a test point on the launchpad and I use a open drain configuration bjt to get my 5V GPIO output for the trigger pin, then I use a resistor divider for the echo input.
Acouple drawbacks of using these modules:
-Distance measurement is relative to the module you buy
-Max sampling speed is relative to the module you buy
Code drawback:
-Apparently the MPS430G2553 GPIO falling edge interrupts can't detect short pulses so this doesn't work for super close proximity to the sensor.
/* * Author: Nathan Zimmerman * Date: 6/22/13 * * Description: A simple program to turn on a LED with the HC-SR04 * module if the module detects a object closer than 100 centimeters * * */ #include "msp430g2553.h" #include "stdint.h" //GPIO Pins #define trigger_pin BIT1 #define echo_input_pin BIT3 #define led BIT0 //Ultrasound parameters #define timer_period 62500 // 4 * 62500 = 250ms #define trigger_pulse (timer_period - 10) #define us_per_cm 14.5 // Depends on module #define time_to_trigger_us 450 #define distance_check 100 //centimeters //Statics static uint16_t echo_pulse_counts = 0; //Functions void clk_setup_1mhz(); void setup_trigger_pulse(); void setup_gpio_echo_interrupt(); uint16_t get_distance_cm(); //Main void main(void) { clk_setup_1mhz(); setup_trigger_pulse(); setup_gpio_echo_interrupt(); P1DIR |= led; P1OUT &= ~led; while(1) { if (get_distance_cm() < distance_check) { P1OUT |= led; } else { P1OUT &= ~led; } } } // End of main void clk_setup_1mhz() { BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; WDTCTL = WDTPW + WDTHOLD; } void setup_trigger_pulse() { P2DIR |= trigger_pin; P2OUT &= ~trigger_pin; P2SEL |= trigger_pin; TA1CCR0 = timer_period; TA1CCTL1 = OUTMOD_7; TA1CCR1 = trigger_pulse; TA1CTL = TASSEL_2 + MC_1+ ID_2; __enable_interrupt(); } void setup_gpio_echo_interrupt() { P1DIR &= ~echo_input_pin; P1OUT &= ~echo_input_pin; P1IE |= echo_input_pin; P1IES |= echo_input_pin; P1IFG &= ~echo_input_pin; } uint16_t get_distance_cm() { return (echo_pulse_counts - time_to_trigger_us)/ us_per_cm; } #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { echo_pulse_counts = TA1R; P1IFG &= ~echo_input_pin; } -
Kent reacted to RobG in LaunchPad IR Receiver
To make it toggle once, you will need another timer.
Once some command is detected, you start the timer. Then if the same command is detected before the time is up, you ignore it and restart the timer.
-
Kent reacted to RobG in LaunchPad IR Receiver
Here's the alternate code. It uses method from post #3 and port interrupt instead of timer's capture/compare feature.
Timer is used to measure pulse's width and for timeout when signal is lost half way through.
Enjoy.
#include "msp430g2553.h" #define T05 300 #define T25 T05*5 #define T35 T05*7 #define T50 T05*10 #define TMAX 65000 #define IR_DETECTOR_PIN BIT1 void reset(); 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; P1OUT &= ~(BIT0 + BIT6); // P1.0 & P1.6 out (LP LEDs) P1DIR |= (BIT0 + BIT6); P1REN |= IR_DETECTOR_PIN; // P1.1 pull-up P1OUT |= IR_DETECTOR_PIN; // P1.1 pull-up P1IE |= IR_DETECTOR_PIN; // P1.1 interrupt enabled P1IES |= IR_DETECTOR_PIN; // P1.1 high/low edge P1IFG &= ~IR_DETECTOR_PIN; // P1.1 IFG cleared CCR0 = TMAX; // interrupt if no edge for T32 TACTL = TASSEL_2 + MC_1; // SMCLK, up mode __bis_SR_register(LPM0_bits + GIE); // switch to LPM0 with interrupts } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { if (P1IFG & IR_DETECTOR_PIN) { P1IE &= ~IR_DETECTOR_PIN; if (bitCounter == 0) { P1IES &= ~IR_DETECTOR_PIN; // P1.1 low/high edge bitCounter++; TACTL |= TACLR; TACTL |= MC_1; CCTL0 = CCIE; } else { switch (bitCounter) { case 14: // received all bits // process received data, for example toggle LEDs switch (rxData & 0x001F) { // mask device number case 19: // Volume - 0010011 = 19 P1OUT ^= BIT0; break; case 18: // Volume + 0010010 = 18 P1OUT ^= BIT6; break; case 21: // Power 0010101 = 21 P1OUT |= BIT6; P1OUT |= BIT0; break; case 20: // Mute 0010100 = 20 P1OUT &= ~BIT6; P1OUT &= ~BIT0; break; } reset(); break; case 1: // start bit? if (TA0R < T35) { // could also add || TA0R > T50 reset(); } else { TACTL |= TACLR; TACTL |= MC_1; bitCounter++; } break; default: // data bit rxData >>= 1; if (TA0R > T25) { rxData |= 0x0800; // set bit 12 of rxData } TACTL |= TACLR; TACTL |= MC_1; bitCounter++; // increase bit counter break; } } P1IFG &= ~IR_DETECTOR_PIN; P1IE |= IR_DETECTOR_PIN; } } void reset() { CCTL0 &= ~CCIE; P1IES |= IR_DETECTOR_PIN; // P1.1 high/low edge rxData = 0; bitCounter = 0; } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A(void) { // reset P1IE &= ~IR_DETECTOR_PIN; reset(); P1IFG &= ~IR_DETECTOR_PIN; P1IE |= IR_DETECTOR_PIN; } -
Kent reacted to Mac in LaunchPad IR Receiver
Hi Rob,
I wonder if your SIRC remotes generate multiple output command packets per key press, and if so, how you might have worked around it? It seems even the quickest button press on my Sony remote generates three (3) output packets at around 45-msec intervals. I ended up using a repeat timer to filter out the extra commands, which also allows single or repeat operation. I'd love to hear how you did it.
If you or other members are interested, I use a slightly different method for decoding SIRC commands on my PIC projects. I simply count the number of 100-usec intervals the SIRC decoder IC output is low (24, 12, or 6). It's probably not the most robust or noise immune method but it works extremely well in my environment whether I'm using it in a an isochronous loop in main or in an ISR (interrupt service routine). I can hardly wait to try it on the MSP430 but with mid-terms next week I've had very little time to study the MSP430 Family Reference Manual.
Cheerful regards, Mike
/* * Mike McLaren's PIC SIRC decoder (100-usec intervals) */ if(reptmr) // if repeat timer running { reptmr--; // decrement it } if(irpin == 0) // if IR pin lo { count++; // inc 100-usec counter } else // if IR pin hi { if(count) // if new bit received { if(bitctr) // if rx-in-progress { sirc >>= 1; // make room for new bit sirc.12 = 0; // set new bit to '0' if(count > 900/100) // if a '1' bit (>900-us) sirc.12 = 1; // set new bit to '1' if(--bitctr == 0) // if last bit { if(reptmr == 0) // if repeat timer timed out { sonycmd = sirc; // pass new command to main reptmr = 2500; // reset 250-ms repeat timer } // } // } // else // not rx-in-progress so { if(count > 2000/100) // if new 'start' bit (>2000-us) bitctr = 12; // set rx-in-progress flag } count = 0; // clear 100-usec counter } }
-
Kent reacted to RobG 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.)