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

共1条 1/1 1 跳转至

【let'sdo|2026年第2期】简易超声波测距仪实践-成果贴

专家
2026-08-22 17:26:32     打赏

一、任务简介

本次活动是使用FRDM-MCXA153开发板驱动超声波传感器测距,用LCD1601显示屏显示测距结果。

二、方案介绍

1、显示部分

图片1.png

由于LCD1601使用的是并口,并且是工作于5V电源的,而FRDM-MCXA153开发板的GPIO、外设默认是3.3V的逻辑电平,因此并口模式下要考虑并口的接口的电平匹配问题。所以这里选择PCF8574T模块,将并口通讯转为I2C通讯,减少了接口引脚,测试上也更方便。

2、传感器部分

图片2.png

本次活动使用的是HC-SR04,工作电源同样是5V。这种传感器的特点是,提供触发信号后,等待返回信号的电平变化,根据脉冲的高电平的持续时间计算距离。而在这个信号是微秒级的,因此使用FRDM-MCXA153驱动时,考虑使用CTimer外设捕捉回波信号的电平变化。

三、方案设计

1、电路组成框图

 

图片3.png

2、程序流程

1)主程序

 

图片4.png

2)CTimer中断处理

 

图片5.png

四、方案实现

1、主程序

程序以frdmmcxa153_lpi2c_polling_b2b_master例程为主,参考frdmmcxa153_ctimer_capture例程,加入CTimer的处理部分。主程序部分代码如下:

// 初始化CTimer0
void InitCTimerCapture(void) {
    ctimer_config_t ctimerConfig;
    CTIMER_GetDefaultConfig(&ctimerConfig);
    // 可选:设置预分频器以调整计数时钟,这里使用默认的96MHz
    CTIMER_Init(DEMO_CTIMER, &ctimerConfig);

    // 配置通道0捕获上升沿、下降沿,并使能中断
    CTIMER_SetupCapture(DEMO_CTIMER, kCTIMER_Capture_0, kCTIMER_Capture_BothEdge, true);

    // 使能CTIMER中断
    CTIMER_EnableInterrupts(DEMO_CTIMER, kCTIMER_Capture0InterruptEnable);

    // 开放CTIMER0中断
    EnableIRQ(CTIMER0_IRQn);

    // 启动CTIMER0
    CTIMER_StartTimer(DEMO_CTIMER);
}
// CTIMER0 中断处理函数
void CTIMER0_IRQHandler(void) {
    uint32_t status = CTIMER_GetStatusFlags(DEMO_CTIMER);

    if (status & kCTIMER_Capture0Flag) {
        // 1. 立即清除标志位,防止重复进入
        CTIMER_ClearStatusFlags(DEMO_CTIMER, kCTIMER_Capture0Flag);

        // 2. 读取捕获值(此时硬件已锁存)
        uint32_t captureValue = CTIMER_GetCaptureValue(DEMO_CTIMER, kCTIMER_Capture_0);

        // 3. 根据当前状态处理
        if (edgeState == WAITING_RISING) {
            riseValue = captureValue;              // 保存上升沿时刻
            edgeState = WAITING_FALLING;           // 切换状态
            // 配置为下降沿捕获,为下一个边沿做准备
            //CTIMER_SetupCapture(DEMO_CTIMER, CAPTURE_FALL_CH, kCTIMER_Capture_FallEdge, true);
            captureDone = 2;
        }
        else if (edgeState == WAITING_FALLING) {
            fallValue = captureValue;              // 保存下降沿时刻
            edgeState = WAITING_RISING;            // 恢复状态,准备下一次测量
            // 配置为上升沿捕获
            //CTIMER_SetupCapture(DEMO_CTIMER, CAPTURE_FALL_CH, kCTIMER_Capture_RiseEdge, true);
            captureDone = 4;                       // 标记一次完整测量完成
        }
    }
}


// 触发一次测距,并等待结果
void TriggerAndGetDistance(void) {
	uint8_t str[17]={0};
	//PRINTF("CaptureDone = %d \r\n", captureDone);
    if (captureDone == 0) {
        // 1. 触发 Trig:至少10us高电平(占用绿色LED - P3.13所在引脚)
        GPIO_PinWrite(TRIG_PIN_GPIO, TRIG_PIN, 1U);
        SDK_DelayAtLeastUs(10, CLOCK_GetFreq(kCLOCK_CoreSysClk));
        GPIO_PinWrite(TRIG_PIN_GPIO, TRIG_PIN, 0U);

        captureDone = 1;

        // 测试用代码,产生ECHO上升沿信号,模拟输出ECHO信号(占用蓝色LED - P3.0所在引脚)
        // 需要短接 P3.0 -> P1.8
        ECHO_1();


    } else if (captureDone == 2) {
    	// 捕捉到上升沿了
    	//PRINTF("TriggerAndGetDistance captureDone = 2 \r\n");
    	captureDone = 3;
    	// 等待 captureDone 变成4

    } else if (captureDone == 3) {
    	// 测试用代码,产生下降沿信号
    	ECHO_0();


    }
    if (captureDone == 4) {
		// 计算时间差和距离
		uint32_t pulseWidth = fallValue - riseValue;
		// 假设CTimer时钟为96MHz,每个计数周期约为10.4ns (1/96MHz)
		// 距离 (cm) = 时间 (us) * 声速 (cm/us) / 2
		//float distance = (float)pulseWidth * 0.0000000104f * 34600.0f / 2.0f;
		float distance = (float)pulseWidth * 0.0001802;
		//PRINTF("Dist = %.2fcm \r\n", distance);
		PRINTF("Dist = %d.%02dcm \r\n", (int)distance, (int)((distance - (int)distance) * 100));
		snprintf(str, sizeof(str), "Dist:%6d.%02dcm", (int)distance, (int)((distance - (int)distance) * 100));

		// 禁止所有可屏蔽中断 (防止干扰I2C通讯)
		__disable_irq();

		LCD_SetCursor(0, 0);
		LCD_Print(str);
		LCD_SetCursor(0, 1);
		LCD_Print(&str[8]);

		// 允许所有可屏蔽中断
		__enable_irq();

		// 延迟200mS,准备执行下一次(SDK_DelayAtLeastUs:微秒级阻塞延时函数)
		SDK_DelayAtLeastUs(200000, CLOCK_GetFreq(kCLOCK_CoreSysClk));

    	captureDone = 0;
    }

}



/*!
 * @brief Main function
 */
int main(void) {
	uint32_t currentCounter = 0U;
	uint8_t str[16]={0};

	BOARD_InitHardware();

	// 初始化CTimer
	DEMO_InitCtimerInput();

	// 初始化LED
	LED_INIT();

	// 输出假的echo信号(蓝色LED所在P3.0,要短路到P1.8上模拟上,模拟超声波传感器的echo信号)
	GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, LOGIC_LED_ON);
	GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_GREEN_GPIO_PIN, LOGIC_LED_ON);
	GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_BLUE_GPIO_PIN, LOGIC_LED_ON);

	// 初始化I2C
	InitI2C();

	// 初始化LPTMR
	InitLptmr();

    // 初始化CTIMER
	InitCTimerCapture();

	// 初始化LCD
	LCD_Init();

	LCD_SetCursor(0, 0);
	LCD_Print(" EEPW & ");
	LCD_SetCursor(0, 1);
	LCD_Print("DigiKey ");

	// 启动LPTMR
	LPTMR_StartTimer(DEMO_LPTMR_BASE);

	delay_ms(5000);
	LCD_Clear();

	while (1) {
		// 开始测距
		TriggerAndGetDistance();
	}
}

五、实测效果

 <iframe src="//player.bilibili.com/player.html?isOutside=true&aid=117036382429042&bvid=BV1jouc6xEXi&cid=40587300587&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>



共1条 1/1 1 跳转至

回复

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