这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【let'sdo|2026年第2期】简易超声波测距仪实践-超声距离测量实现

共2条 1/1 1 跳转至

【let'sdo|2026年第2期】简易超声波测距仪实践-超声距离测量实现

菜鸟
2026-07-31 18:01:32     打赏

一. 前言

本文继续来实现超声波传感器距离采集。

传感器见3942 Adafruit Industries LLC | 超声波接收器、发射器 - DigiKey

5V供电,驱动Trig给 10uS以上高电平, echo检测高电平时间,即超声波来回时间,一半时间对应的即距离。这里如果是3.3V系统则需要对echo进行分压(附送了2个10K电阻)。

二. GPIO驱动

驱动trig发送高脉冲。这里使用引脚P3.12

 

Gpio.c

#include "fsl_common.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "pin_mux.h"

#define BOARD_TRIG_GPIO GPIO3                /*!<@brief GPIO peripheral base pointer */
#define BOARD_TRIG_GPIO_PIN 12U              /*!<@brief GPIO pin number */
#define BOARD_TRIG_GPIO_PIN_MASK (1U << 12U) /*!<@brief GPIO pin mask */

/* Symbols to be used with PORT driver */
#define BOARD_TRIG_PORT PORT3                /*!<@brief PORT peripheral base pointer */
#define BOARD_TRIG_PIN 12U                   /*!<@brief PORT pin number */
#define BOARD_TRIG_PIN_MASK (1U << 12U)      /*!<@brief PORT pin mask */

		const gpio_pin_config_t trig_pin_config = {
        .pinDirection = kGPIO_DigitalOutput,
        .outputLogic = 0U
    };
		
		const port_pin_config_t trig_port_pin = {/* Internal pull-up/down resistor is disabled */
                                       kPORT_PullDisable,
                                       /* Low internal pull resistor value is selected. */
                                       kPORT_LowPullResistor,
                                       /* Fast slew rate is configured */
                                       kPORT_FastSlewRate,
                                       /* Passive input filter is disabled */
                                       kPORT_PassiveFilterDisable,
                                       /* Open drain output is disabled */
                                       kPORT_OpenDrainDisable,
                                       /* Low drive strength is configured */
                                       kPORT_LowDriveStrength,
                                       /* Normal drive strength is configured */
                                       kPORT_NormalDriveStrength,
                                       /* Pin is configured as P3_12 */
                                       kPORT_MuxAlt0,
                                       /* Digital input enabled */
                                       kPORT_InputBufferEnable,
                                       /* Digital input is not inverted */
                                       kPORT_InputNormal,
                                       /* Pin Control Register fields [15:0] are not locked */
                                       kPORT_UnlockRegister};
		
void gpio_init(void) 
{
    CLOCK_EnableClock(kCLOCK_GateGPIO3);
	  CLOCK_EnableClock(kCLOCK_GatePORT3);
	  RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);
	  RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);


    /* Initialize GPIO functionality on pin PIO3_12 (pin 38)  */
    GPIO_PinInit(BOARD_TRIG_GPIO, BOARD_TRIG_PIN, &trig_pin_config);


    /* PORT3_12 (pin 38) is configured as P3_12 */
    PORT_SetPinConfig(BOARD_TRIG_PORT, BOARD_TRIG_PIN, &trig_port_pin);
}

void gpio_trig_set(uint8_t level) 
{
	if (level) {
		GPIO_PortSet(BOARD_TRIG_GPIO, 1u << BOARD_TRIG_GPIO_PIN);
	} else {
		GPIO_PortClear(BOARD_TRIG_GPIO, 1u << BOARD_TRIG_GPIO_PIN);
	}
}

gpio.h

#ifndef GPIO_H
#define GPIO_H

void gpio_init(void);
void gpio_trig_set(uint8_t level);

#endif

注意:

GPIOPORT都要使能时钟释放复位,否则会进入hardfault

    CLOCK_EnableClock(kCLOCK_GateGPIO3);

  CLOCK_EnableClock(kCLOCK_GatePORT3);

  RESET_ReleasePeripheralReset(kGPIO3_RST_SHIFT_RSTn);

  RESET_ReleasePeripheralReset(kPORT3_RST_SHIFT_RSTn);

三. Timer驱动

为了定时发送trig,使用一个定时器。

Timer.c

#include "fsl_ctimer.h"
#include "fsl_debug_console.h"

#define FREE_CTIMER     CTIMER1         /* Timer 1 for free run*/

void timer_freetimer_init(void)
{
    /* CTimer functional clock needs to be greater than or equal to SYSTEM_CLK */
    CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, 16); /* Max div 16 96/16=6M */
    CLOCK_AttachClk(kFRO_HF_to_CTIMER1);
	  //frohf = CLOCK_GetCTimerClkFreq(kCLOCK_FroHf);
	  //uint32_t systemclk = CLOCK_GetCTimerClkFreq(kCLOCK_SYSTEM_CLK);
	  //CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, frohf/systemclk); 
	  uint32_t ctimerclk = CLOCK_GetCTimerClkFreq(1);
		PRINTF("ctimer1clk=%d\r\n",ctimerclk);
	
    ctimer_config_t config;
    CTIMER_GetDefaultConfig(&config);
    CTIMER_Init(FREE_CTIMER, &config);
    CTIMER_StartTimer(FREE_CTIMER);
}

uint32_t timer_freetimer_get(void) 
{
	return CTIMER_GetTimerCountValue(FREE_CTIMER);
}

void timer_freetimer_delayus(uint32_t us)
{
	uint32_t t0 = timer_freetimer_get();
	uint32_t t1;
	while(1){
		t1 = timer_freetimer_get();
		if(t1 - t0 >= us*6) {
			break;
		}
	}
}

timer.h

#ifndef TIMER_H
#define TIMER_H

void timer_freetimer_init(void);
uint32_t timer_freetimer_get(void);
void timer_freetimer_delayus(uint32_t us);

#endif


注意:

CTimer的时钟频源必须要大于等于SYSTEM_CLK

否则仿真运行到CTIMER_Init时仿真挂掉

分频最大16分频。



四. 脉宽捕获

使用ctimer得捕获功能,要捕获高脉宽,所以使用两个引脚,P1.8P1.9

一个捕获上升沿,一个捕获下降沿,两者之差几位高脉宽。

Capture.c

#include "fsl_common.h"
#include "fsl_port.h"
#include "fsl_gpio.h"
#include "fsl_inputmux.h"
#include "pin_mux.h"
#include "fsl_debug_console.h"
#include "fsl_ctimer.h"

#define CAPTURE_CTIMER     CTIMER0         /* Timer 0 for capture */

static volatile uint32_t s_cap_value = 0;
static volatile int s_done_flag = 1;  /* -1 timeout 1 done 0 not done*/

static volatile uint32_t s_cap0_value[2];
static volatile uint32_t s_cap0_tog = 0;
static volatile uint32_t s_cap1_value[2];
static volatile uint32_t s_cap1_tog = 0;

void ctimer_capture0_callback(uint32_t flags)
{
  //CTIMER_ClearStatusFlags(CAPTURE_CTIMER, kCTIMER_Capture0Flag);
	//s_cap0 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_0);
}

void ctimer_capture1_callback(uint32_t flags)
{
	uint32_t cap0;
	uint32_t cap1;
  //CTIMER_ClearStatusFlags(CAPTURE_CTIMER, kCTIMER_Capture1Flag);
	//s_cap1 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_1);
	CTIMER_StopTimer(CAPTURE_CTIMER);
	cap0 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_0);
	cap1 = CTIMER_GetCaptureValue(CAPTURE_CTIMER, kCTIMER_Capture_1);
	s_cap_value = cap1 - cap0;
	s_cap1_value[s_cap1_tog] = cap1;
	s_cap0_value[s_cap0_tog] = cap0;
	s_cap0_tog ^= 0x01;
	s_cap1_tog ^= 0x01;
	s_done_flag = 1;
}

void ctimer_match0_callback(uint32_t flags)
{
	s_done_flag = -1;
}


ctimer_callback_t ctimer_callback_table[] = {
	ctimer_match0_callback, NULL, NULL, NULL, NULL, ctimer_capture1_callback, NULL, NULL
};
 
void capture_init(void)
{
    /* CTimer functional clock needs to be greater than or equal to SYSTEM_CLK */
    CLOCK_SetClockDiv(kCLOCK_DivCTIMER0, 16); /* Max div 16 96/16=6M */
    CLOCK_AttachClk(kFRO_HF_to_CTIMER0);
	  uint32_t ctimerclk = CLOCK_GetCTimerClkFreq(0);
		PRINTF("ctimer0clk=%d\r\n",ctimerclk);
	
    /* Write to GPIO1: Peripheral clock is enabled */
    CLOCK_EnableClock(kCLOCK_GateGPIO1);
    /* write to INPUTMUX0: Peripheral clock is enabled */
    CLOCK_EnableClock(kCLOCK_GateINPUTMUX0);
    /* Write to PORT1: Peripheral clock is enabled */
    CLOCK_EnableClock(kCLOCK_GatePORT1);
    /* GPIO1 peripheral is released from reset */
    RESET_ReleasePeripheralReset(kGPIO1_RST_SHIFT_RSTn);
    /* INPUTMUX0 peripheral is released from reset */
    RESET_ReleasePeripheralReset(kINPUTMUX0_RST_SHIFT_RSTn);
    /* CTIMER0 peripheral is released from reset */
    RESET_ReleasePeripheralReset(kCTIMER0_RST_SHIFT_RSTn);
    /* PORT1 peripheral is released from reset */
    RESET_ReleasePeripheralReset(kPORT1_RST_SHIFT_RSTn);
	
    /* INPUTMUX0: Peripheral clock is enabled */
    RESET_PeripheralReset(kINPUTMUX0_RST_SHIFT_RSTn);
    /*  CtimerInp8/9 connect to Timer0Captsel 0/1 */
    INPUTMUX_Init(INPUTMUX0);
    INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_CtimerInp8ToTimer0Captsel);
    INPUTMUX_AttachSignal(INPUTMUX0, 1U, kINPUTMUX_CtimerInp9ToTimer0Captsel);
		
    const port_pin_config_t port1_8_pin2_config = {/* Internal pull-up/down resistor is disabled */
                                                   .pullSelect = kPORT_PullDisable,
                                                   /* Low internal pull resistor value is selected. */
                                                   .pullValueSelect = kPORT_LowPullResistor,
                                                   /* Fast slew rate is configured */
                                                   .slewRate = kPORT_FastSlewRate,
                                                   /* Passive input filter is disabled */
                                                   .passiveFilterEnable = kPORT_PassiveFilterDisable,
                                                   /* Open drain output is disabled */
                                                   .openDrainEnable = kPORT_OpenDrainDisable,
                                                   /* Low drive strength is configured */
                                                   .driveStrength = kPORT_LowDriveStrength,
                                                   /* Normal drive strength is configured */
                                                   .driveStrength1 = kPORT_NormalDriveStrength,
                                                   /* Pin is configured as CT_INP8 */
                                                   .mux = kPORT_MuxAlt4,
                                                   /* Digital input enabled */
                                                   .inputBuffer = kPORT_InputBufferEnable,
                                                   /* Digital input is not inverted */
                                                   .invertInput = kPORT_InputNormal,
                                                   /* Pin Control Register fields [15:0] are not locked */
                                                   .lockRegister = kPORT_UnlockRegister};
    /* PORT1_8 (pin 2) is configured as CT_INP8 */
    PORT_SetPinConfig(PORT1, 8U, &port1_8_pin2_config);			
																									
    const port_pin_config_t port1_9_pin3_config = {/* Internal pull-up/down resistor is disabled */
                                                   .pullSelect = kPORT_PullDisable,
                                                   /* Low internal pull resistor value is selected. */
                                                   .pullValueSelect = kPORT_LowPullResistor,
                                                   /* Fast slew rate is configured */
                                                   .slewRate = kPORT_FastSlewRate,
                                                   /* Passive input filter is disabled */
                                                   .passiveFilterEnable = kPORT_PassiveFilterDisable,
                                                   /* Open drain output is disabled */
                                                   .openDrainEnable = kPORT_OpenDrainDisable,
                                                   /* Low drive strength is configured */
                                                   .driveStrength = kPORT_LowDriveStrength,
                                                   /* Normal drive strength is configured */
                                                   .driveStrength1 = kPORT_NormalDriveStrength,
                                                   /* Pin is configured as CT_INP9 */
                                                   .mux = kPORT_MuxAlt4,
                                                   /* Digital input enabled */
                                                   .inputBuffer = kPORT_InputBufferEnable,
                                                   /* Digital input is not inverted */
                                                   .invertInput = kPORT_InputNormal,
                                                   /* Pin Control Register fields [15:0] are not locked */
                                                   .lockRegister = kPORT_UnlockRegister};
    /* PORT1_9 (pin 3) is configured as CT_INP9 */
    PORT_SetPinConfig(PORT1, 9U, &port1_9_pin3_config);	
																									 
		ctimer_config_t ctimerConfig;
    /*
     * ctimerConfig.mode = kCTIMER_TimerMode;
     * ctimerConfig.input = kCTIMER_Capture_0;
     * ctimerConfig.prescale = 0;
     */
    CTIMER_GetDefaultConfig(&ctimerConfig);

    CTIMER_Init(CAPTURE_CTIMER, &ctimerConfig);

    /*
     * Setup the capture, but don't enable the interrupt. And enable the interrupt
     * later using CTIMER_EnableInterrupts. Because if enable interrupt usig
     * CTIMER_SetupCapture, the CTIMER interrupt is also enabled in NVIC, then default
     * driver IRQ handler is called, and callback is involed. To show the capture
     * function easily, the default ISR and callback is not used.
     */
    CTIMER_SetupCapture(CAPTURE_CTIMER, kCTIMER_Capture_0, kCTIMER_Capture_RiseEdge, false);
    CTIMER_SetupCapture(CAPTURE_CTIMER, kCTIMER_Capture_1, kCTIMER_Capture_FallEdge, true);
		
		CTIMER_RegisterCallBack(CAPTURE_CTIMER, &ctimer_callback_table[0], kCTIMER_MultipleCallback);
		
    /*
     * Enable the interrupt, so that the kCTIMER_Capture0Flag can be set when
     * edge captured.
     */
    //CTIMER_EnableInterrupts(CAPTURE_CTIMER, kCTIMER_Capture0InterruptEnable);
    //CTIMER_EnableInterrupts(CAPTURE_CTIMER, kCTIMER_Capture1InterruptEnable);
		
		/* match for timeout */
		const ctimer_match_config_t match_config = {
		.enableCounterReset = true,
		.enableCounterStop = true,
		.matchValue = 100*6*1000UL,
		.outControl = kCTIMER_Output_NoAction,
		.enableInterrupt = true,
		.outPinInitState = false,
		};
		CTIMER_SetupMatch(CAPTURE_CTIMER, kCTIMER_Match_0, &match_config);																							 
}

void capture_start(void)
{
	s_done_flag = 0;
	CTIMER_Reset(CAPTURE_CTIMER);
	CTIMER_StartTimer(CAPTURE_CTIMER);		
	
}

/*  -1 timeout 
 *  1   done
 *  0  not done
 */ 
int capture_isdone(void)
{
	return s_done_flag;
}

uint32_t capture_get_value(void)
{
	return s_cap_value;
}

Capture.h

#ifndef CAPTURE_H
#define CAPTURE_H

void capture_init(void);
void capture_start(void);
int capture_isdone(void);
uint32_t capture_get_value(void);

#endif

五. 测试

先获取来回时间,单位us

int get_distance(void)
{
capture_start();
 
gpio_trig_set(1);
timer_freetimer_delayus(10);
gpio_trig_set(0);
while(1){
int done = capture_isdone();
if(done == -1) {
return -1;
} else if(done == 1) {
return capture_get_value()/6; /* uS */
}
}
}

1S采集一次并打印

int main(void)
{
 

    char ch;
 
    /* Init board hardware. */
    BOARD_InitHardware();
 
    PRINTF("MCUX SDK version: %s\r\n", MCUXSDK_VERSION_FULL_STR);
 
    PRINTF("hello world.\r\n");
 
gpio_init();
  timer_freetimer_init();
capture_init();
gpio_trig_set(0);

    while (1)
    {    int distance = get_distance();
  if(distance < 0) {
PRINTF("get distance err\r\n");
} else {
PRINTF("distance:%dmm\r\n", distance*340/(2*1000));
}
  timer_freetimer_delayus(1000000);    }
}

打印如下

image.pngimage.png

这里实测手里的手机高度,

官方数据是163mS,实测162mm左右,所以看到准确度还可以。

image.png

六.总结

以上实现了超声距离采集,后续就可以驱动屏幕进行显示。

仿真器连不上,尝试暗按ISP按键,再重新上电再连接。





关键词: FRDM-MCXA153     超声波     测距仪    

院士
2026-08-02 11:33:12     打赏
2楼

谢谢分享。


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]