Hello !
I've been trying to win with my HC-SR04 ultrasonic ranging module and make it work but after many approaches I couldn't do it. I am using Arduino UNO but I don't want to use their libraries and Arudino IDE. Of course I tried their way - by doing while loops in pulseIn function but this doesn't seem as a good solution for me. So here is my idea:
Here is my code.
#define F_CPU 16000000UL #include#include #include #include #define MYDDR DDRB #define MYPORT PORTB #define MYPIN PINB #define TRIG 4 // PB4 // digital12 #define ECHO 5 // PCINT5 - PB5 // digital13 #define LED 0 // PB0 // digital8 #define BAUDRATE 9600 #define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1) #define MAX_RESP_TIME_MS 38 #define INSTR_PER_MS 16000 #define MAX_TICKS MAX_RESP_TIME_MS*INSTR_PER_MS volatile int przepelnienia=0; volatile int result=0; volatile bool running=false; char dist_char[6]; #pragma region USART void usartInit(void) { UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8); UBRR0L = (uint8_t)(BAUD_PRESCALLER); UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01)); } void usartSend( unsigned char data) { while(!(UCSR0A & (1<<UDRE0))); UDR0 = data; } void usartPutstring(char* StringPtr) { while(*StringPtr != 0x00){ usartSend(*StringPtr); StringPtr++;} } #pragma endregion USART void initHC() { MYDDR |= (1 << TRIG); // trigger output MYDDR &= ~(1 << ECHO); // echo input } void initTimer1() { // normal mode TCCR1A &= ~((1 << WGM10) | (1 << WGM11)); TCCR1B &= ~((1 << WGM12) | (1 << WGM13)); // no prescaling TCCR1B |= (1 << CS10); // enable overflow interrupt TIMSK1 |= (1 << TOIE1); } void initLED() { MYDDR |= (1 << LED); // led output } void initInterrupts() { PCICR |= (1 << PCIE0); // interrupts can be triggered on pins PCINT[7:0] PCMSK0 |= (1 << PCINT5); // PCINT5 will trigger an interrupt sei(); // set interrupts } void trigger() { MYPORT &= ~(1 << TRIG); // na wszelki wypadek _delay_us(2); MYPORT |= (1 << TRIG); // 10 mikrosekund sygnału _delay_us(10); MYPORT &= ~(1 << TRIG); } ISR(PCINT0_vect) { if((PINB & (1 << ECHO))) // if echo==1 { running=true; TCNT1=0; przepelnienia=0; } else // if echo==0 { running=false; uint32_t ticks=przepelnienia*65536+TCNT1; result=(ticks/2)/29.1; sprintf(dist_char, "% d", result); usartPutstring("Odleglosc: "); usartPutstring(dist_char); usartPutstring("mm\n\r"); } } ISR(TIMER1_OVF_vect) { if(running) przepelnienia++; } int main() { initHC(); initInterrupts(); usartInit(); initLED(); initTimer1(); _delay_ms(3000); while(1) { if(!running) { _delay_ms(100); trigger(); } } return 0; }
In ISR(PCINT0_vect) you can see that if there is any change on ECHO pin, I check whether it is from 0 to 1 or from 1 to 0. In the first situation I say the time counting has started (running=true), I initialize counter register with 0 and I initialize overflow counter variable (przepelnienia) with 0. If the change on ECHO pin is from 1 to 0, the counting is finished and I save the results and count the duration.
I think it should work fine but I am surely wrong because it gives me close but not exact distances. And the difference between the real and the measured distance is not always the same, it grows as the real distance grows.
Please, help me...
Greetings,
Daniel