sobota, 2 stycznia 2016

[5] STM32F4 - Discovery - HC-SR04, wyświetlacz HD44780

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();
 }
}