Based on stm32 input capture dual-channel mode ultrasonic ranging HC-SR04

Tip: After the article is written, the table of contents can be automatically generated. How to generate it can refer to the help document on the right

Article Directory


Some time ago, I ran into a lot of problems in a project about ultrasonic distance measurement through input capture mode. After I solved it, I had a lot of ideas and recorded some in the article.

1. Introduction to HC-SR04

There are usually two ultrasonic components on the ultrasonic sensor module, one for transmitting and one for receiving.

There are four pins on the board: VCC, GND, Trig (trigger), Echo (response).

Working voltage and current: 5V, 15mA. Special attention must be paid to the 5V power supply here. After the STlink is connected to 32, it cannot provide 5V voltage. The power supply must be connected to the STlink.

Sensing distance: 2~400cm

Sensing angle: not less than 15 degrees

The area of ​​the object to be measured should not be less than 50 square centimeters and should be as flat as possible

Two, the code part

Principle introduction

Use TI1 as the input capture channel, and map the captured level to the two internal channels

Channel 1 is set as a rising edge trigger, and the value of CNT will be recorded into CCR1 at the moment of triggering. At the same time, set channel 1 trigger with slave mode, and set the slave mode to zero CNT

Channel 2 is set as a falling edge trigger, and the CNT will be recorded into CCR2 at the moment of triggering. Since the CNT has been set to zero when the rising edge is triggered, the value of CNT at this time is the duration of the high level.

sample code


#include "stm32f10x.h"                  // Device header

void IC_Init(void)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//turn on the clock
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//drop down input mode
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    TIM_InternalClockConfig(TIM3);//Use internal clock source to power Timer 3
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//Capture input without division
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//count up mode
    TIM_TimeBaseInitStructure.TIM_Period = 65536-1;  //arr
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;   //PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    //open channel 1
    TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //Enable capture channel 1
    TIM_ICInitStructure.TIM_ICFilter = 0xF;//Filter out high frequency fluctuations
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//rising trigger capture
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//no frequency division
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//Direct channel input
    TIM_ICInit(TIM3,&TIM_ICInitStructure);//Initialize input capture as rising edge capture
    //open channel 2
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //Enable capture channel 2
    TIM_ICInitStructure.TIM_ICFilter = 0xF;//Filter out high frequency fluctuations
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//Falling edge trigger capture
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//no frequency division
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;//Cross channel input
    TIM_ICInit(TIM3,&TIM_ICInitStructure);//Initialize input capture as falling edge capture
    //Select trigger slave mode
    TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//trigger slave mode
    TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//Set to zeroing mode for CNT

uint32_t IC_GetHigttime(void)
    return TIM_GetCapture2(TIM3);


#include "stm32f10x.h"                 
#include "ic.h"
#include "delay.h"

#define Trig_High GPIO_SetBits(GPIOB,GPIO_Pin_7)
#define Trig_Low  GPIO_ResetBits(GPIOB,GPIO_Pin_7)

u32 high_time;
float istance;

void HC_Sr04Init(void)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);    //Enable peripheral clock for GPIOB
    GPIO_InitTypeDef GPIO_InitStructure;                                    //Define the structure
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //Set GPIO port as push-pull output
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;                        //Set GPIO port 5
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //Set the GPIO port speed to 50Mhz
    GPIO_ResetBits(GPIOB,GPIO_Pin_7);                        //output low level
    Delay_us(15);                                            //Delay 15 microseconds

void HC_SR04GetDistance(void)
    Trig_High;                    //output high level
    Trig_Low;                    //output low level
  high_time = IC_GetHigttime();
  istance = high_time*0.17;


It needs to be reminded that after the timer is initialized, the introduction of the input channel must be initialized to the multiplexing push-pull mode if you want to output the load level


Tags: Embedded system stm32 Single-Chip Microcomputer

Posted by rhyspaterson on Thu, 23 Mar 2023 08:41:07 +1030