W tym poście chciałbym przedstawić program obsługujący czujnik HC-SR04 oraz wyświetlacz HD44780. Ten drugi już opisywałem w jednym z poprzednich postów. Natomiast działanie HC-SR04 zaprezentowałem w dziale dotyczącym Arduino. Wobec tego przypomnę tylko najważniejsze elementy działania tego czujnika.
Czujnik
W tym temacie zastosowałem czujnik ultradźwiękowy pozwalający na pomiar odległości w zakresie od 2 cm do 200 cm. Kąt pracy wynosi 15-30 stopni.
Rys. 1. Czujnik HC-SR04 - wygląd zewnętrzny
Aby rozpocząć wykonywanie pomiarów należy podać stan wysoki na pin Trigger o czasie trwania 10us. Po inicjalizacji następuje wysłanie 8 krótkich impulsów o częstotliwości 40kHz. Odbiornik po wysłaniu sygnału pomiarowego oczekuje na sygnał powracający od przeszkody tzw. Echo. Po odebraniu danych na pin Echo podawany jest stan wysoki, którego długość jest proporcjonalna do zmierzonej odległości. Czas trwania impulsu wynosi od 150us do 25ms. Maksymalny czas oczekiwania na odbiór wiadomości wynosi 38ms.
Przeliczanie odległości następuje na podstawie wzoru zawartego w dokumentacji czujnika:
Gdzie: O - odległość, t - czas trwania impulsu;
Podstawowa część wzoru została wyprowadzona na podstawie prędkości rozchodzenia się dźwięku w powietrzu. Dźwięk przebywa odległość do i od czujnika. Jego prędkość w powietrzu wynosi 340m/s.
Poprawka do wzoru głównego została oszacowana na podstawie rozdzielczości czujnika i noty katalogowej podobnego czujnika US-015, ponieważ są one tego samego typu i działają na takiej samej zasadzie. W nocie czujnika HC-SR04 są umieszczone dane tylko dotyczące jego rozdzielczości (czyli 0,3cm), są to za małe dane aby poprawnie ocenić jego dokładność.
Rys. 2. Schemat blokowy działania czujnika HC-SR04
Podłączenie
Wyświetlacz należy podłączyć do następujących wyprowadzeń:
- VSS - GND
- VDD - 5V
- V0 - potencjometr
- RS - PB2
- RW - GND
- E - PB7
- D0-D3 - NC
- D4 - PC12
- D5 - PC13
- D6 - PC14
- D7 - PC15
- A - 3V
- K - GND
Natomiast czujnik HC-SR04:
- VCC - 5V
- GND - GND
- Echo - PD6
- Trig - PD4
Programowanie
W pierwszej kolejności gdy już wyświetlacz jest oprogramowany należy zająć się testowanym czujnikiem. Dla przypomnienia wyświetlacz został opisany w poprzednim poście, wobec tego nie będę go tutaj opisywał.
Na samym początku należy zdeklarować potrzebne piny i rozpocząć inicjalizację czujnika:
uint8_t HCSR04_Init(void) { GPIO_InitTypeDef GPIOInit; //Inicjalizacja funkcji opózniajacej DELAY_Init(); //Inicjalizacja pinów //Wlaczenie zegara RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //Trigger PD4, jako wyjscie GPIOInit.GPIO_Mode = GPIO_Mode_OUT; GPIOInit.GPIO_Pin = GPIO_Pin_4; GPIOInit.GPIO_OType = GPIO_OType_PP; GPIOInit.GPIO_PuPd = GPIO_PuPd_DOWN; GPIOInit.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOD, &GPIOInit); //Echo PD6, Jako wejscie GPIOInit.GPIO_Mode = GPIO_Mode_IN; GPIOInit.GPIO_Pin = GPIO_Pin_6; GPIOInit.GPIO_OType = GPIO_OType_PP; GPIOInit.GPIO_PuPd = GPIO_PuPd_DOWN; GPIOInit.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOD, &GPIOInit); //Podanie sygnalu niskiego na pin Trigger GPIOD->BSRRH = GPIO_Pin_4; //Rozpoczyna pomiary, sprawdza czy czujnik jest gotowy i pracuje if (HCSR04READ()) { return 1; } //Zwraca 0 jesli cos jest nie tak return 0; }
W kolejnym kroku należy odtworzyć wartość jaka została obliczona przez czujnik. Wykorzystuje się do tego licznik Systick, który generuje przerwania co 1us w czasie występowania stanu wysokiego na pinie Echo. Liczba przerwań zostaje zsumowana po czym obliczona zostaje odległość w cm. Na samym końcu obliczona wartość zostaje przez funckję zwrócona i przekazana do pętli głównej programu.
float HCSR04READ(void) { uint32_t time; uint32_t timeout; float dystans = 0; //Sygnal niski na trigger GPIOD->BSRRH = GPIO_Pin_4; //Opóznienie 2us Delay(2); //Sygnal wysoki na trigger GPIOD->BSRRL = GPIO_Pin_4; //Opóznienie 10 us Delay(10); //Sygnal niski na trigger GPIOD->BSRRH = GPIO_Pin_4; //Po takiej inicjalizacji nastepuje dokonanie pomiarow //Troche czasu na odpowiedz timeout = 1000000; while (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == Bit_RESET) { if (timeout-- == 0x00) { return -1; } } //Rozpoczecie pomiaru czasu impulsu time = DELAY_Time(); //Wpisanie tekstu //Petla while czeka do momentu kiedy sygnal bedzie 0 while (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == Bit_SET); //Pobranie czasu trwania stanu wysokiego time = DELAY_Time() - time; //Obliczenie odleglosci dystans = (float)time / 58.0; //Zwrócenie odleglosci return dystans; }
Główna pętla programu wygląda następująco:
int main(void) { //Zdefiniowanie zmiennych char res[20]; uint32_t Czas; float Odleglosc; //Inicjalizacja wyswietlacza HD44780_Init(16, 2); //Inicjalizacja czujnika HCSR04_Init(); while (1) { //Pomiar odleglosci Czas = HCSR04READ(); //Wyswietlenie zmierzonego czasu sprintf(res, "Czas:%d", (int)Czas); HD44780_Puts(0, 0, res); //Przetworzenie wyniku w cm Odleglosc = (float)Czas/58.0; sprintf(res, "O:%.3f", Odleglosc); HD44780_Puts(0, 1, res); //Wynik w calach Odleglosc = (float)Czas/148.0; sprintf(res, "%.3f", Odleglosc); HD44780_Puts(10, 1, res); Delayms(1000); HD44780_Clear(); } }