/* * Abstand Sensor * Das Ziel des Programms ist, den Abstand zwischen dem Modul und irgendeinem Objekt zu bestimmern. * Das Programm sollte wie folgt funktionieren: * Durch die Tatsache, dass die Pins 5V und GND des HC-SR04 Moduls mit den entsprechenden Pins des STM32F4 Boards verbunden sind, * ist das Modul mit Strom und Spannung versogt und funktionsbereit. * * Durch die Pin PC6 (TIMER 3 Channel 1) wird es ständig über den TRIGGER Pin des Moduls ein 10us Signal mit einem Intervall von 100ms geschickt, * damit ein Ping erstellt wird. * * Der ECHO Pin des Moduls ist mit dem Pin PB7 (TIMER 4) verbunden. * Von dem TIMER 4 benutzen wir zwei Channels (1 und 2). * * Der Channel 1 zäht die Zeit bis zu einem steigenden Flankt des ECHO Signals * und die Channel 2 zählt die Zeit bis zu einem falländen Flankt des ECHO Signals. * * Sobald eine fallände Flankt von der Channel 2 gezählt wird, wird einen ISR(Interrupt Service Routine) generiert. * In dem ISR wird es dann den entsprechenden Abstand des Objekts berechenen und letzendlich wird das Ergebnis auf der Konsole angezeigt. * Genutzte Pin Belegung: * ----------------------------------------------------------------------------------------- * Breadboard STM32F4 Discovery Board * HC-SR04 Pins * ----------------------------------------------------------------------------------------- * 5V 5V * TRIG PC6 * ECHO PB7 * GND GND */ /* Includes */ #include "stm32f4xx.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_tim.h" /************************************************************** Funktionen ****************************************************************************/ /* Funktion für die Initialisierung und Konfiguration des Triggerpins */ void Trigger_Init(void){ GPIO_InitTypeDef GPIO_TriggerStruct; /* Initialisierungsstruktur anlegen */ /* Takt für Allzweckeingabe/ -ausgabe C (GPIOC) einschalten */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); /* Pins festlegen */ GPIO_TriggerStruct.GPIO_Pin = GPIO_Pin_6; // PC6 ansprechen GPIO_TriggerStruct.GPIO_Mode = GPIO_Mode_AF; // Wechselfunktionsmodus festlegen GPIO_TriggerStruct.GPIO_OType = GPIO_OType_PP; // Totem-Pole-Ausgang (Push-Pull-Output) GPIO_TriggerStruct.GPIO_PuPd = GPIO_PuPd_UP; // PullUp Widerstand aktivieren GPIO_TriggerStruct.GPIO_Speed = GPIO_Speed_100MHz; // Die Zykluszeit, mit der die Register des Ports aktualisiert werden GPIO_Init(GPIOC, &GPIO_TriggerStruct); // Die Allzweckeingabe/ - ausgabe C (GPIOC) initialisieren /* Wechselfunktionkonfiguration für den Pin PC6 mit dem TIM3 */ GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3); } /* Funktion für die Initialisierung und Konfiguration des Echopins */ void Echo_Init(void){ GPIO_InitTypeDef GPIO_EchoStruct; /* Initialisierungsstruktur anlegen */ /* Takt für Allzweckeingabe/ -ausgabe B (GPIOB) einschalten */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* Pins festlegen */ GPIO_EchoStruct.GPIO_Pin = GPIO_Pin_7; // PB7 ansprechen GPIO_EchoStruct.GPIO_Mode = GPIO_Mode_AF; // Wechselfunktionsmodus festlegen GPIO_EchoStruct.GPIO_OType = GPIO_OType_PP; // Totem-Pole-Ausgang (Push-Pull-Output) GPIO_EchoStruct.GPIO_PuPd = GPIO_PuPd_UP; // PullUp Widerstand aktivieren GPIO_EchoStruct.GPIO_Speed = GPIO_Speed_100MHz; // Die Zykluszeit, mit der die Register des Ports aktualisiert werden GPIO_Init(GPIOB, &GPIO_EchoStruct); // Die Allzweckeingabe/ - ausgabe C (GPIOC) /* Wechselfunktionkonfiguration für den Pin PB7 mit dem TIM4 */ GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4); } /* Funktion für die Initialisierung und Konfiguration des TIMER3 für den Triggerpin */ void Timer3_TriggerInit(void){ uint16_t PrescalarValue3 = 0; // Variable, in der der Frequenzwert des TIMER3 gespeichert wird TIM_TimeBaseInitTypeDef TIM_TriggerStruct; /* Initialisierungsstruktur des TIMER3 für den Triggerpin des HC-SR04 Sensors */ /* Takt für den TIMER3 einschalten */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Berechnung, um den TIMER3 in 1000000 Hz laufen zu lassen */ PrescalarValue3 = (uint16_t)((SystemCoreClock / 2) / 100000) - 1; /* Konfiguration des TIMER3 für den Triggerpin */ TIM_TriggerStruct.TIM_Period = 0xFFFF; // entspricht dem maximalen Zykluswert 65535 TIM_TriggerStruct.TIM_Prescaler = PrescalarValue3; // Timervorteiler auf den PrescalarValue3 setzen TIM_TriggerStruct.TIM_ClockDivision = 0; TIM_TriggerStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TriggerStruct); // TIMER3 initialisieren } /* Initialisierung und Konfiguration des PWM(Pulse Wide Modulation) in dem Fall OC(Output Compare) Modus des TIMER3 Channel 1, um 10ms Pulse zu erstellen */ void Timer3_PWM_OCTriggerInit(void){ TIM_OCInitTypeDef TIM_OCTrigger; /* Initialisierungsstruktur anlegen*/ TIM_OCTrigger.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCTrigger.TIM_OutputState = TIM_OutputState_Enable; /* Wenn die Zählung 1 erreicht, fällt der TIMER3 Channel 1 auf Niederspannung und bleibt niedrig, bis die Zählung 65535 (Periodenwert) erreicht ist. Wenn wir wieder bei Null beginnen, haben wir wieder eine hohe Polarität.*/ TIM_OCTrigger.TIM_Pulse = 1; TIM_OCTrigger.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM3, &TIM_OCTrigger); /* Ausgabekanal 1 des TIMER4 initialisieren */ /* Zählen auf TIMER3 starten */ TIM_Cmd(TIM3, ENABLE); } /* Initialisierung und Konfiguration der NVIC(nested vector interrupt control auf Deutsch übersetzt verschachtelte Vektor-Interrupt-Steuerung) für den TIMER4 */ void NVIC_Timer4_Init(void){ /* Sobald der Timer4 Channel 2 eine fallende Flanke erkennt, generiert er die ISR(Interrupt-Service-Routine) */ NVIC_InitTypeDef NVIC_InitTimer4; /* Initialisierungsstruktur anlegen */ /* Takt für den TIMER4 einschalten */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); /* Konfiguration der NVIC des TIMER4 */ NVIC_InitTimer4.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitTimer4.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitTimer4.NVIC_IRQChannelSubPriority = 1; NVIC_InitTimer4.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitTimer4); } /* Funktion für die Initialisierung und Konfiguration des TIMER4 für den Echopin */ void Timer4_EchoInit(void){ TIM_TimeBaseInitTypeDef TIM_EchoStruct; /* Initialisierungsstruktur des TIMER4 für den Echopin des HC-SR04 Sensors */ /* Variable, in der der Frequenzwert des TIMER4 gespeichert wird */ uint16_t PrescalarValue4 = 0; /* Berechnung, um den TIMER4 in 2 MHz laufen zu lassen */ PrescalarValue4 = (uint16_t)((SystemCoreClock / 2) / 2000000) - 1; /* Konfiguration des TIMER4 für den Echopin */ TIM_EchoStruct.TIM_Period = 0xFFFF; TIM_EchoStruct.TIM_Prescaler = PrescalarValue4; TIM_EchoStruct.TIM_ClockDivision = 0; TIM_EchoStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_EchoStruct); } /* Initialisierung und Konfiguration des PWM(Pulse Wide Modulation) in dem Fall IC(Input Capture) Modus des TIMER4 Channel 1 und Channel 2 */ void Timer4_PWM_ICEchoInit(void){ TIM_ICInitTypeDef TIM_ICEcho; /* Initialisierungsstruktur anlegen */ /* Konfiguration Timer4 Channel 1, um die steigende Flanke am Echopin zu erfassen */ TIM_ICEcho.TIM_Channel = TIM_Channel_1; // Timer4 Channel 1 ansprechen TIM_ICEcho.TIM_ICPolarity = TIM_ICPolarity_Rising; // Steigende Flanke erfassen TIM_ICEcho.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICEcho.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICEcho.TIM_ICFilter = 0x0; TIM_PWMIConfig(TIM4, &TIM_ICEcho); /* Konfiguration Timer4 Channel 2, um die fallende Flanke am Echopin zu erfassen */ TIM_ICEcho.TIM_Channel = TIM_Channel_2; // Timer4 Channel 2 ansprechen TIM_ICEcho.TIM_ICPolarity = TIM_ICPolarity_Falling; // Fallende Flanke erfassen TIM_ICEcho.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICEcho.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICEcho.TIM_ICFilter = 0x0; TIM_PWMIConfig(TIM4, &TIM_ICEcho); /* Konfiguration des TIMER4 im Slave-Modus, damit der Zähler nach dem Erfassen der steigenden Flanke am Echopin zurückgesetzt wird. */ TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset); TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable); /* Zählen auf TIMER4 starten */ TIM_Cmd(TIM4, ENABLE); /* Timer4 Channel 2 Interrupt-Service-Routine aktivieren */ TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE); } /******************************************************************************************************************************************************/ int main(void) { /* System initialisieren */ SystemInit(); /* Initialisierung und Konfiguration des Triggerpins */ Trigger_Init(); /* Initialisierung und Konfiguration der TIMER3 für den Triggerpin */ Timer3_TriggerInit(); /* OC(Output Compare) Modus des TIMER3 Channel 1, um 10ms Pulse zu erstellen */ Timer3_PWM_OCTriggerInit(); /* Initialisierung und Konfiguration des Echopins */ Echo_Init(); /* NVIC(nested vector interrupt control auf Deutsch übersetzt verschachtelte Vektor-Interrupt-Steuerung) für den TIMER4 */ NVIC_Timer4_Init(); /* Initialisierung und Konfiguration der TIMER4 für den Echopin */ Timer4_EchoInit(); /* IC(Input Capture) Modus des TIMER4 Channel 1 und Channel 2 * Channel 1 erfasst die steigende Flanke am Echopin * Channel 2 erfasst die fallände Flanke am Echopin */ Timer4_PWM_ICEchoInit(); } /* Interrupt-Service-Routine des TIMER4 In dieser Funktion wird der nötige Code geschrieben, um den Abstand zu berechnen und auf dem Konsole zeigen zu lassen. */ __IO uint16_t IC2Value = 0; void TIM4_IRQHandler(void) { TIM_ClearITPendingBit(TIM4, TIM_IT_CC2); /* Löschung des alten Bits */ IC2Value = TIM_GetCapture2(TIM4); /* Zählerwert bei fallender Flanke des Echopulses */ printf("\nTIM_GetCapture2 : %d", IC2Value); printf(" Distance : %d cm", ((IC2Value / 116) - 6)); }