72-HC_SR04-Library (STM32F4)

Mit dieser Library kann der Ultraschall-Abstands-Sensor vom Typ (HC-SR04) an die STM32F4-CPU angeschlossen werden.

Wieder ein DANKE an “Joerg” für den Sensor

Das Modul wird an 5V angeschlossen und mit einem 10 us langen Hi-Impuls über den Pin “Trigger” zu einer Abstandsmessung veranlasst.

Die Länge vom Hi-Pegel am “Echo-Pin” die das Modul daraufhin zurückliefert ist ein Maß für den ermittelten Abstand.

Der Sensor soll laut Datenblatt Abstände von 2 cm bis 400 cm mit einer Auflösung von 3 mm Messen können. Ich habe hier etwa 5 cm bis 130 cm messen können, das hängt wohl sehr viel von der Umgebung ab.

Ein Hinweis zur Benutzung der Library : Der gemessene Abstandswert wird als “float” in “cm” zurückgeliefert und bei einem Timeout (z.B. wenn kein Sensor angeschlossen ist oder wenn der Abstand > 5m) , wird eine -1 als Fehlererkennung zurückgeliefert)

Nach der Messung macht die Funktion ein Delay von 60ms (der Wert steht im H-File) weil laut Datenblatt der Sensor nicht schneller abgefragt werden soll.
(falls ihr in eurem Programm sicherstellt das eh nicht schneller gepollt wird, könnt ihr das löschen)

Hinweis zur Pinbelegung : Der Trigger-Pin kann im H-File beliebig gewählt werden, aber der Echo-Pin muss zum benutzten Timer passen (weil der im Input-Capture-Mode betrieben wird)

Bilder :

hcsr04

Pinbelegung :

1
2
PA0 = Echo-Pin
PD3 = Trigger-Pin

Voraussetzungen :

1
2
Benutzte Module der CooCox-IDE : GPIO, TIM, MISC
Benutzte Librarys : keine

Funktionen :

1
2
void UB_HCSR04_Init(void);          // init vom Sensor
float UB_HCSR04_Distance_cm(void);  // Abstandsmessung (in cm)

Beispiel :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//--------------------------------------------------------------
// File     : main.c
// Datum    : 22.12.2013
// Version  : 1.0
// Autor    : UB
// EMail    : mc-4u(@)t-online.de
// Web      : www.mikrocontroller-4u.de
// CPU      : STM32F4
// IDE      : CooCox CoIDE 1.7.4
// GCC      : 4.7 2012q4
// Module   : CMSIS_BOOT, M4_CMSIS_CORE
// Funktion : Demo der HC-SR04-Library
// Hinweis  : Diese zwei Files muessen auf 8MHz stehen
//              "cmsis_boot/stm32f4xx.h"
//              "cmsis_boot/system_stm32f4xx.c"
//--------------------------------------------------------------
 
#include "main.h"
#include "stm32_ub_led.h"
#include "stm32_ub_hcsr04.h"
 
int main(void)
{
  float abstand;
 
  SystemInit(); // Quarz Einstellungen aktivieren
 
  // init der LEDs
  UB_Led_Init();
 
  // init vom HC-SR04
  UB_HCSR04_Init();
 
  while(1)
  {
    // Messung vom Abstand
    abstand=UB_HCSR04_Distance_cm();
    if(abstand>0) {
      // LEDs je nach Entfernung schalten
      UB_Led_Off(LED_RED);
      UB_Led_On(LED_ORANGE);
      if(abstand<10.0) UB_Led_On(LED_GREEN); else UB_Led_Off(LED_GREEN);
      if(abstand<15.0) UB_Led_On(LED_BLUE); else UB_Led_Off(LED_BLUE);
    }
    else {
      // außerhalb vom Messbereich
      UB_Led_On(LED_RED);
      UB_Led_Off(LED_GREEN);
      UB_Led_Off(LED_BLUE );
      UB_Led_Off(LED_ORANGE);
    }
  }
}

Hier die Library zum Download :

ub_stm32f4_hcsr04_v100

Hier der komplette CooCox-Projektordner zum Download :

Demo_72_HCSR04


12 Antworten auf 72-HC_SR04-Library (STM32F4)

  1. Joerg sagt:

    ich hat die Dinger schon ein paar Jahre liegen, vielleicht durch Alterung die nur noch geringe Reichweite. Am Atmega damals war größerer Abstand möglich soweit ich mich erinnere.

  2. Christoph sagt:

    hi!

    zunächst mal Glückwunsch und Dank für deine Arbeit. Da hast du schon eine Menge auf die Beine gestellt.

    Ich habe aber auch eine Frage bzw. ein Problem mit dem Code. Eigentlich ist es vielleicht eher ein Verständnisproblem bei der Timer Initialisierung:
    Du bildest du Differenz von 2 Capture Zeiten.
    start=TIM_GetCapture1(TIM2);
    stop=TIM_GetCapture2(TIM2);
    HCSR04.delay_us=start-stop;
    Aber woher kommen denn 2 Zeiten der Trigger ist doch nur der Receive Pin, also Input 1. Verstehe nicht wie das gedacht ist und funktioniert.

    Kurzes Feedback mit Erklärung wäre genial!

  3. Christoph sagt:

    Schande über mich – kurz nach Hilferuf erkenne ich, dass der periph. driver offenbar eine spezielle Funktion TIM_PWMIConfig() hat. Der wird dann wohl die beiden channels scharf schalten.
    Sorry, habe ich fast 4 Stunden nicht geblickt. Man sieht aber auch den Nachteil eines Treiberpaketes gegenüber einzelnem Bitsetzen ist. Man muss die Funktionen kennen da hilft das Datenblatt nicht ;-)

  4. Maurice sagt:

    All I can say is thank you so much for posting this! It has helped me a lot!!!

  5. Niels sagt:

    Hi,

    This code works realy well. I’m trying to get more ultrasones to work, one after the other. I can’t get it to work. Can you give me some tips for it?

    Tanks.

    • admin_ub sagt:

      easy…change the function “P_HCSR04_Trigger”
      so you can set multiple trigger outputs
      and connect all echo pins with a wired or (some bat46 diodes and a single pull up resistor)

  6. alex sagt:

    hello,

    code ist echt hilfreich und verständlich.
    ich wollte die abstandsmessung periodisch mit einem zusätzlichen timer5 anstoßen.

    leider bleibt der code hängen.
    habe nur die Timer init in die main eingebaut und die timer5 isr

    TIM_TimeBaseInitTypeDef TIM_TimeBase_InitStructure2;
    NVIC_InitTypeDef NVIC_InitStructure2;

    NVIC_InitStructure2.NVIC_IRQChannel = TIM5_IRQn;
    NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0x0A;
    NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0x0A;
    NVIC_Init(&NVIC_InitStructure2);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

    TIM_TimeBase_InitStructure2.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBase_InitStructure2.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBase_InitStructure2.TIM_Period = 1999;
    TIM_TimeBase_InitStructure2.TIM_Prescaler = 17999;
    TIM_TimeBaseInit(TIM5, &TIM_TimeBase_InitStructure2);

    TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM5, ENABLE);

    ————————————————–

    void TIM5_IRQHandler(void) {

    float abstand = 0;
    char text[10];

    TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
    GPIOG->ODR ^= GPIO_Pin_13; // PG13 toggeln

    itoa(zahl, text, 10);

    abstand = UB_HCSR04_Distance_cm();
    itoa(abstand, text, 10);

    if (abstand > 0) {
    // LEDs je nach Entfernung schalten
    UB_Font_DrawString(10, 160, text, &Arial_14x22, RGB_COL_BLACK,
    RGB_COL_WHITE);

    } else {
    // außerhalb vom Messbereich
    itoa(zahl, text, 10);
    UB_Font_DrawString(10, 130, text, &Arial_14x22, RGB_COL_BLACK,
    RGB_COL_WHITE);
    }
    zahl++;
    }
    ————————-
    wenn ich “abstand = UB_HCSR04_Distance_cm();” auskommentiere dann funktioniert die ISR und die zahl wird auf dem Display hochgezählt. ganz strange.
    wenn ich “abstand = UB_HCSR04_Distance_cm();” wieder einkommentiere dann höre ich den US-Sensor direkt summen. aber das programm hängt.
    lese ich “abstand = UB_HCSR04_Distance_cm();” in der main while aus dann funktioniert alles.

    hat wer eine idee woran es liegen kann?

  7. Lucas sagt:

    mach mal statt:
    NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0x0A;
    NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0x0A;

    das hier:
    NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 0×01;
    NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 0×00;

    die 0x0A gehen nicht bei beiden Prioritys (sieh dir dazu mal die datei “misc.c” aus der StdPeriphLib an) Es gibt spezielle einstellungen da gehts bis 0x0E aber nicht bei beiden gleichzeitig (siehe Funktion in misc.c: void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup))! Wahrscheinlich wird dein Priority (0x0A) durch 0×00 ersetzt und blockiert damit die TIM_IRQ, in der die Messung stattfindet!

    Lg Lue

    • alex sagt:

      danke für die antwort.
      habe die prioritäten geändert aber es hat sich nix geändert.
      das programm bleibt einfach hängen – nichtmal die isr werden angesprungen.
      wenn ich den abstand in der main while permanent abfrage dann funktioniert auch die timer5_isr ohne probleme.

      • Lucas sagt:

        MÖGLICHKEIT 1:
        Dann versuch mal in der main-Schleife direkt nach “SystemInit();” das hier einzufügen:

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);

        damit kannst du
        0-7 für Preemption Priority und
        0-1 für Subpriorit
        auswählen. (Falls du aus bestimmten gründen mehr Subprioritys brauchst siehe “misc.c” dafür gibts dann ander NVIC_PriorityGroup_X konfigurationen.)

        Du benötigst auf jeden Fall ein höhere PreemptionPriority als TIM2&7 von der Distanzmessung also mindestens 0×01!

        MÖGLICHKEIT 2:
        Mach mal die Initialisierung von deinem TIMER5 bevor du die NVIC_Init von TIM5_IRQ machst!

        MÖGLICHKEIT 3:
        Noch ein Tipp, sicherheitshalber so –>

        void TIM5_IRQHandler(void)
        {
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
        //
        //Dein Code
        }
        }

        Sonst hab ich momentan auch keinen Plan!

        • Lucas sagt:

          PS: Mit “höhere PreemptionPriority als TIM2&7″ meinte ich natürlich, dass die Zahl höher sein muss, das bedeutet natürlich dann eine niedrigere Priorität.

      • admin_ub sagt:

        bei deinem eigentlichen Fehler kann ich dir auch nicht weiterhelfen…aber eines als Hinweis :
        eine ISR hält man so kurz wie möglich
        und Code um den Bildschirm zu beschreiben
        gehört da nicht rein…das führt zu BUGs wenn außerhalb
        der ISR zur gleichen Zeit aufs Display geschrieben wird

        warum setzt du nicht einfach ein Flag in der ISR
        (das ist eine Zeile Code)
        und fragst dieses in der Main-Loop ab
        (oder wo auch immer du die Messwerte anzeigen willst)


Wie hat Dir dieser Artikel gefallen?

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (Noch keine Bewertungen)
Loading...

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.