I'm trying to control this HC-SR4 Ultrasonic sensor by simply ON an LED when an object closer than 1m is detected. I'm using TIM2 for the trigger signal (Pin PB10), and TIM4 to receive Echo signal (Pin PB6). and the LED is connected to Pin PB7. when I load the code below, the LED simply turns ON, whether there's an object or not, it's just ON.
Any idea where did I go wrong?
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// switch from HSE to HSI clock 16MHz
void HSI_config(){
RCC->CR |= RCC_CR_HSION; // Turn On HSI oscillator
RCC->CFGR |= RCC_CFGR_SW; // Select HSI clock
RCC->CFGR |= RCC_CFGR_SWS_HSI;
RCC->CR |= RCC_CR_HSIRDY; // wait for HSI stabilize
}
// Configure GPIO Port B
void GPIO_config(){
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 << (2*6)); // Clear bit 12 & 13 Alternate function mode
GPIOB->MODER |= 0x02 << (2*6); // set as Alternate function mode
GPIOB->OSPEEDR &= ~(0x03<< (2*6)); // 40 MHz speed
GPIOB->OSPEEDR |= 0x03<< (2*6); // 40 MHz speed
GPIOB->PUPDR &= ~(1<<6); // NO PULL-UP PULL-DOWN
GPIOB->OTYPER &= ~(1<<6); // PUSH-PULL
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 TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_Enable(){
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->CCER |= TIM_CCER_CC1E; // ENABLE COUNTER CAPTURE
TIM4->DIER |= TIM_DIER_CC1IE; // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
NVIC_SetPriority(TIM4_IRQn, 1); // SET PRIORITY TO 1
NVIC_EnableIRQ(TIM4_IRQn); //ENABLE TIM4 INTERRUPT IN NVIC
}
// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_Enable(){
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
TIM2->PSC = 15; // 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 downcounting counter direction
TIM2->CR1 |= TIM_CR1_CEN; // Enable Counter
}
//Initialize the float variables.
volatile uint8_t timespan = 0; // Total pulse width
volatile uint8_t lastcounter = 0; // Timer counter value of the last event
volatile uint8_t newcounter = 0; // Timer counter value of the current event
volatile uint8_t overflow = 0; // Count the number of overflows
volatile uint8_t PulseEnd = 0; // Declare end of pulse
void Echo_TIM4_IRQHandler(){
if ((TIM4->SR & TIM_SR_UIF) != 0){ // Check the update even flag
overflow = overflow + 1; // 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
PulseEnd = 1;
}
}
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
// Capture error
while (1){};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int main(void){
float Distance = 0.0f; // actual distance in cm
int Pulsesent = 0;
HSI_config();
setSysTick();
GPIO_config();
TIM4_Enable();
Echo_TIM4_IRQHandler();
while(1){
if (Pulsesent == 0) {
(Pulsesent = 1);
TIM2_Enable();
}
if(Pulsesent && PulseEnd){
Pulsesent = 0;
if(overflow == 1){
timespan = 0;
}
else {
Distance = (timespan / 58) ;
}
Delay(1);
}
if (Distance <= 100){
GPIOB->BSRRL = (1<<7);
}
else {
GPIOB->BSRRL = (0<<7);
}
}
}
Regardless of the variable states, the register GPIOB->BSRRL will only reset the GPIOB bits that are '1's. GPIOB->BSRRL is the lower 16bits of a 32bit register. The upper 16 bits will set the GPIOB pins when bits that are '1'.
So to turn the LED off you will need something similar to GPIOB->BSRRH = (1<<7);. (this will upset Barny though, very specific, nothing portable, requires knowledge of the hardware connected to the chip..etc. ).