Ich versuche, diesen HC-SR4-Ultraschallsensor zu steuern, indem ich einfach eine LED einschalte, wenn ein Objekt näher als 100 cm erkannt wird. Ich verwende TIM2 für das Triggersignal (Pin PB10) und TIM4, um das Echosignal (Pin PB6) zu empfangen. und die LED ist mit Pin PB7 verbunden. Wenn ich den folgenden Code lade, schaltet sich die LED einfach ein, egal ob es ein Objekt gibt oder nicht, es ist nur EIN.
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
//Initialize the timers variables.
volatile int timespan = 0; // Total pulse width
volatile int lastcounter = 0; // Timer counter value of the last event
volatile int newcounter = 0; // Timer counter value of the current event
volatile int overflow = 0; // Count the number of overflows
void SetHSI(void);
void Delay(int);
void GPIO_config(void);
void TIM2_Trigger(void);
void TIM4_Init(void);
void TIM4_Echo_Read(void);
void LED (void);
int main(void){
SetHSI();
GPIO_config();
TIM2_Trigger();
TIM4_Init();
while(1){
TIM4_Echo_Read();
LED();
Delay(100);
}
}
void Delay(int x){
//input milliseconds, delay that number of milliseconds
int a,b;
for(a=0; a<x; a++){
for(b=0; b<1000; b++){
}
}
}
//set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)//
void SetHSI(void) {
// Turn on HSI (16MHz)
RCC->CR |= RCC_CR_HSION;
// Wait until HSI is ready
while( (RCC->CR & RCC_CR_HSIRDY) == 0);
// Select HSI as system clock
RCC->CFGR &= ~RCC_CFGR_SW_HSI;
RCC->CFGR |= RCC_CFGR_SW_HSI;
while( (RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI ); // Wait till HSI
}
// Configure GPIO Port B
void GPIO_config(void){
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; // Reset GPIOB clock
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST; // Clear Reset
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock
//PB6 Echo Pin
GPIOB->MODER &= ~(0x03 << 12); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= (0x02 << 12); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< 12); // 40 MHz speed
GPIOB->OSPEEDR |= (0x03<< 12); // 40 MHz speed
GPIOB->PUPDR &= ~(0X3<<12); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<6); // PUSH-PULL
GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6; // Clear pin 6 for alternate function
GPIOB->AFR[0] |= 0x2 << (4*6); // set PB pin 6 as AF2 (TIM4_CH1)
//PB10 Pluse Generating Pin
GPIOB->MODER &= ~(0x03 << (2*10)); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= 0x02 << (2*10); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< (2*10)); // 40 MHz speed
GPIOB->OSPEEDR |= 0x03<< (2*10); // 40 MHz speed
GPIOB->PUPDR &= ~(1<<10); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<10); // PUSH-PULL
GPIOB->AFR[1] |= 0x1 << (4*2); // set PB pin 10 as AF1 (TIM2_CH3)
//PB7 LED ON/OFF
GPIOB->MODER |= GPIO_MODER_MODER7_0; // General purpose output mode
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // Max High speed 50MHz
}
// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_Trigger(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
TIM2->PSC = 159; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM2->ARR = 0XFFFF; // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // 111: PWM mode 1
TIM2->CCMR2 |= TIM_CCMR2_OC3PE; // CH3 Output Preload Enable
TIM2->CR1 |= TIM_CR1_ARPE; // Auto-reload Prelaod Enable
TIM2->CCER |= TIM_CCER_CC3E; // Enable Output for CH3
TIM2->EGR |= TIM_EGR_UG; // Force Update
TIM2->SR &= ~TIM_SR_UIF; // Clear the Update Flag
TIM2->DIER |= TIM_DIER_UIE; // Enable Interrupt on Update
TIM2->CR1 &= ~TIM_CR1_DIR; // Set upcounting counter direction
TIM2->CCR3 &= ~(TIM_CCR3_CCR3); // Clear CCR3 (Channel 3)
TIM2->CCR3 |= 0x1; // Load the register
TIM2->CR1 |= TIM_CR1_CEN; // Enable the counter
}
// CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_Init(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // ENABLE TIM4 CLOCK
TIM4->PSC = 15; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM4->ARR = 0xFFFF; // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
TIM4->CCMR1 &= ~TIM_CCMR1_CC1S; // CLEAR CAPTURE/COMPARE REGISTER
TIM4->CCMR1 |= 0X1; // SELECT CH1 INPUTE CAPTURE
TIM4->CCMR1 &= ~TIM_CCMR1_IC1F; // DISABLE DIGITAL FILTERING
TIM4->CCER |= (1<<1 | 1<<3); // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC); // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
TIM4->DIER |= TIM_DIER_UIE; // UPDATE INTERRUPT ENABLE
TIM4->CCER |= TIM_CCER_CC1E; // ENABLE COUNTER CAPTURE
TIM4->DIER |= TIM_DIER_CC1IE; // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
TIM4->CR1 |= TIM_CR1_CEN; // Enable the counter
NVIC_SetPriority(TIM4_IRQn, 1); // SET PRIORITY TO 1
NVIC_EnableIRQ(TIM4_IRQn); //ENABLE TIM4 INTERRUPT IN NVIC
}
void TIM4_Echo_Read(void){
if ((TIM4->SR & TIM_SR_UIF) != 0){ // Check the update event flag
overflow++; // if UIF = 1, increment overflow counter
TIM4->SR &= ~TIM_SR_UIF; // clear UIF
}
if ((TIM4->SR & TIM_SR_CC1IF) != 0){ // Check capture event flag
newcounter = TIM4->CCR1; // read capture value, store as newcounter
timespan = (newcounter - lastcounter)+(65536 * overflow); // calculate the total pulse width
lastcounter = newcounter; // save the value of newcounter as lastcounter to be used for the next cycle
overflow = 0; // clear overflow counter
}
}
void LED (void){
int Distance; // actual distance in cm
Distance = (timespan / 58);
if (Distance <= 100){
GPIOB->BSRRL = (1<<7);
}
else {
GPIOB->BSRRH = (1<<7);
}
}
Hier sind die Ergebnisse, wenn ich den Debugger ausführe:
1/ Newcounter liest den CCR1-Wert. (z. B. 0X000000000001AD2E), timespan lädt den Wert der Gleichung und Distance lädt den Wert der Gleichung (timespan/58).
2/ Der Wert von Distance ist immer weit über 100, selbst wenn ein Objekt 50 cm entfernt ist. Generell spiegeln die Werte nicht den tatsächlichen Zustand wieder.
Ganz zu schweigen davon, dass die LED seltsamerweise die ganze Zeit eingeschaltet ist, obwohl die obigen Ergebnisse zu einer AUS-LED führen sollten.
Ich kann die mit dem Echo-Pin (PB6) verbundene LED blinken sehen, was meiner Meinung nach bedeutet, dass ein kontinuierliches Signal empfangen wird.
Gedanken?
PS Ich hätte float für Distance verwenden sollen, aber aufgrund eines Debugger-Problems habe ich es durch int ersetzt, bis ich die oben genannten Probleme gelöst habe.
Ich möchte den aktualisierten Code teilen, der tatsächlich funktioniert (keine Bibliothek erforderlich):
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
//Initialize the timers variables.
volatile int timespan = 0; // Total pulse width
volatile int lastcounter = 0; // Timer counter value of the last event
volatile int newcounter = 0; // Timer counter value of the current event
volatile int overflow = 0; // Count the number of overflows
void SysTick_Handler(void);
void SetHSI(void);
void LED_GPIO(void);
void TIM4_C1_Init(void);
void TIM2_C3_Init(void);
void TIM4_IRQHandler(void);
void LED (void);
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
while (1); // Capture error
}
}
volatile uint32_t msTicks=0; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int main(void){
SysTick_Handler();
setSysTick();
SetHSI();
LED_GPIO();
TIM2_C3_Init();
TIM4_C1_Init();
while(1){
LED();
Delay(100);
}
}
/*----------------------------------------------------------------------------
set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)
*----------------------------------------------------------------------------*/
void SetHSI(void) {
// Turn on HSI (16MHz)
RCC->CR |= RCC_CR_HSION;
// Wait until HSI is ready
while( (RCC->CR & RCC_CR_HSIRDY) == 0);
// Select HSI as system clock
RCC->CFGR &= ~RCC_CFGR_SW_HSI;
RCC->CFGR |= RCC_CFGR_SW_HSI;
while( (RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI ); // Wait till HSI
}
// Configure GPIO Port B
void LED_GPIO(void){
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock
//PB7 LED ON/OFF
GPIOB->MODER |= GPIO_MODER_MODER7_0; // General purpose output mode
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7; // Max High speed 50MHz
}
// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_C3_Init(void){
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock
//PB10 Pluse Generating Pin
GPIOB->MODER &= ~(0x03 << (2*10)); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= 0x02 << (2*10); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< (2*10)); // 40 MHz speed
GPIOB->OSPEEDR |= 0x03<< (2*10); // 40 MHz speed
GPIOB->PUPDR &= ~(1<<10); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<10); // PUSH-PULL
GPIOB->AFR[1] |= 0x1 << (4*2); // set PB pin 10 as AF1 (TIM2_CH3)
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
TIM2->PSC = 159; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM2->ARR = 0XFFFF; // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
TIM2->CR1 |= TIM_CR1_DIR; // Set downcounting counter direction
TIM2->CCMR2 &= ~(TIM_CCMR2_OC3M); // Clear OC3M (Channel 3)
TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
TIM2->CCMR2 |= TIM_CCMR2_OC3PE; // CH3 Output Preload Enable
TIM2->CR1 |= TIM_CR1_ARPE; // Auto-reload Prelaod Enable
TIM2->CCER |= TIM_CCER_CC3E; // Enable Output for CH3
TIM2->EGR |= TIM_EGR_UG; // Force Update
TIM2->SR &= ~TIM_SR_UIF; // Clear the Update Flag
TIM2->DIER |= TIM_DIER_UIE; // Enable Interrupt on Update
TIM2->CCR3 &= ~(TIM_CCR3_CCR3); // Clear CCR3 (Channel 3)
TIM2->CCR3 |= 0x1; // Load the register
TIM2->CR1 |= TIM_CR1_CEN; // Enable the counter
}
// CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_C1_Init(void){
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; // Enable GPIOB clock
GPIOB->MODER &= ~(0x03 << 12); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= (0x02 << 12); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< 12); // 40 MHz speed
GPIOB->OSPEEDR |= (0x03<< 12); // 40 MHz speed
GPIOB->PUPDR &= ~(0X3<<12); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<6); // PUSH-PULL
GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6; // Clear pin 6 for alternate function
GPIOB->AFR[0] |= 0x2 << (4*6); // set PB pin 6 as AF2 (TIM4_CH1)
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // ENABLE TIM4 CLOCK
TIM4->PSC = 15; // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
TIM4->CCMR1 &= ~TIM_CCMR1_CC1S; // CLEAR CAPTURE/COMPARE REGISTER
TIM4->CCMR1 |= 0X1; // SELECT CH1 INPUTE CAPTURE
TIM4->CCMR1 &= ~TIM_CCMR1_IC1F; // DISABLE DIGITAL FILTERING
TIM4->CCER |= (1<<1 | 1<<3); // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC); // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
TIM4->CCER |= TIM_CCER_CC1E; // ENABLE COUNTER CAPTURE
TIM4->DIER |= TIM_DIER_CC1IE; // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
TIM4->DIER |= TIM_DIER_CC1DE;
TIM4->DIER |= TIM_DIER_UIE; // UPDATE INTERRUPT ENABLE
TIM4->CR1 &= ~TIM_CR1_DIR; // Set downcounting counter direction
TIM4->CR1 |= TIM_CR1_CEN; // Enable the counter
NVIC_SetPriority(TIM4_IRQn, 1); // SET PRIORITY TO 1
NVIC_EnableIRQ(TIM4_IRQn); //ENABLE TIM4 INTERRUPT IN NVIC
}
void TIM4_IRQHandler(void){
if ((TIM4->SR & TIM_SR_UIF) != 0){ // Check the update event flag
overflow++; // if UIF = 1, increment overflow counter
TIM4->SR &= ~TIM_SR_UIF; // clear UIF
}
if ((TIM4->SR & TIM_SR_CC1IF) != 0){ // Check capture event flag
newcounter = TIM4->CCR1; // read capture value, store as newcounter
timespan = (newcounter - lastcounter)+(65536 * overflow); // calculate the total pulse width
lastcounter = newcounter; // save the value of newcounter as lastcounter to be used for the next cycle
overflow = 0; // clear overflow counter
}
}
void LED (void){
float Distance; // actual distance in cm
Distance = (timespan / 58.0);
if (Distance > 0.0 && Distance <= 100.0){
GPIOB->BSRRL = (1<<7);
}
else {
GPIOB->BSRRH = (1<<7);
}
}
NVIC_SetPriority(TIM4_IRQn, 1);
NVIC_EnableIRQ(TIM4_IRQn);
der Funktionsname übereinstimmte, es funktionierte. Der Grund, warum ich das geändert habe, float
ist int
, dass STM32L1 keine FPU hat. float
Ich habe jedoch versucht, es nach dem Schreiben anstelle von auszuführen int
, und es hat tatsächlich funktioniert, aber mit einer etwas langsamen Reaktion, und der Distance
Wert wurde beim Ausführen des Debuggers nicht so gut angezeigt. Daher int
stattdessen
verwendet
Lichtwerke
DiBosco
DiBosco
Lichtwerke
DiBosco
DiBosco
Lichtwerke
DiBosco
DiBosco
Lichtwerke
DiBosco
Lichtwerke
DiBosco
Lichtwerke
Chris Stratton
newcounter
in einem Register zu führen.DiBosco
Chris Stratton