一坨乱码 2024-02-02 16:11 采纳率: 50%
浏览 743

为什么stm32控制超声波模块,测出来的距离一直是0

用stm32f103c8t6控制HC-SR04模块来测距,用定时器输入捕获模式来测量。因为超声波模块返回的是一个信号,测量这个信号高电平的时间就可以测出来超声波距物体的距离,所以用定时器的输入捕获模式,其中我用的是定时器3的通道1和通道2,通道1是上升沿触发,通道2是下降沿触发。但是我最终的结果始终是0,我通过调试之后,发现好像接收到的信号没有高电平,所以导致返回的信息始终是0,下面是我写的代码,有没有人帮我看看是哪里的问题。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
void PWM_Init(void)
{
    //使用定时器3的通道1--PA6引脚
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    //设置PA6引脚--Echo
    //PA6引脚用来接收超声波发射回来的电平信号
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //设置PA5引脚--Trig
    //PA5引脚用来触发超声波,使其工作
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM3);        //选择TIM3为内部时钟
    
    //时基单元初始化
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;                //定义结构体变量
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
    TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;               //预分频器,即PSC的值
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
    
    //PWMI模式初始化
    TIM_ICInitTypeDef TIM_ICInitStructure;                            //定义结构体变量
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;                //选择配置定时器通道1
    TIM_ICInitStructure.TIM_ICFilter = 0xF;                            //输入滤波器参数
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;        //极性,选择为上升沿触发捕获
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;            //捕获预分频,选择不分频,每次信号都触发捕获
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;    //输入信号交叉,选择直通,不交叉
    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);                        //将结构体变量交给TIM_PWMIConfig,配置TIM3的输入捕获通道
    
    //选择触发源及从模式
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);                    //触发源选择TI1FP1
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);                    //从模式选择复位
                                                                    //即TI1产生上升沿时,会触发CNT归零
    
    //TIM使能
    TIM_Cmd(TIM3, ENABLE);            //使能TIM3,定时器开始运行
}

float Distance(void)
{
    //Trig引脚给一个触发信号,使超声波模块开始工作
    GPIO_SetBits(GPIOA, GPIO_Pin_5);
    Delay_us(40);
    GPIO_ResetBits(GPIOA, GPIO_Pin_5);
    
    //检测Echo高电平的时间
    float time = 0;

    //程序运行到这里说明检测到高电平
    time = TIM_GetCapture2(TIM3);
    
    //这里就返回一个高电平的时间
    return time;
}

主函数:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"

int main(void)
{
    OLED_Init();
    PWM_Init();
    
    while (1)
    {
        OLED_ShowNum(1, 1, Distance(), 5);
        Delay_ms(1000);
    }
}


  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-02-02 16:14
    关注

    引自免费微信小程序:皆我百晓生

    针对您提供的代码,STM32F103C8T6控制HC-SR04超声波模块测距的问题,主要存在以下几个疑点和可能的错误:

    1. 输入捕获通道设置不正确: 在您的PWM_Init函数中,您配置了TIM3的通道1(TIM_Channel_1)为上升沿触发捕获,但您应当配置通道2(TIM_Channel_2)用于捕获Echo信号的高电平时间。因为通常情况下,Trig引脚用作触发信号输出,Echo引脚接收回响信号。

      修改后的IC初始化部分应如下所示:

      TIM_ICInitTypeDef TIM_ICInitStructure;
      TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; // 更改为通道2
      ...
      TIM_PWMIConfig(TIM3, &TIM_ICInitStructure); 
      
    2. 未配置捕获中断及回调处理: 为了在Echo信号变为高电平时获取准确的时间,需要配置定时器输入捕获中断,并在中断服务程序里读取捕获值。您当前直接在Distance()函数里读取TIM_GetCapture2的值,这可能导致读取的时间不稳定或始终为0,因为没有通过中断来精确捕捉上升沿时刻。

    3. 主函数中缺少中断使能及清除操作: 在完成输入捕获中断配置后,应在主函数或其他适当位置开启中断,并确保每次测量前清除上一次的捕获值。

    下面是一个修正后的示例代码框架,包含了上述修改以及必要的中断处理部分:

    #include "stm32f10x.h"
    #include "Delay.h"
    
    #define TRIG_PIN GPIO_Pin_5
    #define ECHO_PIN GPIO_Pin_6
    
    void PWM_Init(void) {
        ...
        // Echo 输入捕获初始化
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
        ...
        TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
        
        // 开启TIM3通道2捕获中断
        NVIC_EnableIRQ(TIM3_IRQn);
        TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
    
        // 清除所有捕获寄存器
        TIM_ClearFlag(TIM3, TIM_FLAG_CC2);
    }
    
    // TIM3中断服务程序
    void TIM3_IRQHandler(void) {
        if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) {
            TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
            // 在这里记录Echo的高电平时间
            echo_capture_time = TIM_GetCapture2(TIM3);
        }
    }
    
    float Distance(void) {
        // 发送Trig脉冲
        ...
        
        // 等待并返回上一次测量得到的Echo高电平时间
        return echo_capture_time;
    }
    
    int main(void) {
        ...
        PWM_Init();
    
        while (1) {
            // 进行一次新的距离测量
            trigger_distance_measurement();
    
            // 在此延时期间,等待中断处理完成Echo高电平时间的捕获
            Delay_ms(100);
    
            OLED_ShowNum(1, 1, Distance(), 5);
            Delay_ms(1000);
        }
    }
    

    注意:trigger_distance_measurement()是假设的一个函数,用来触发发送Trig脉冲的操作,您可以将其整合到Distance()函数内或者作为单独的函数实现。同时,请根据实际硬件连接和系统需求调整延时时间。此外,还需要确保GPIO和NVIC中断配置正确无误。

    评论

报告相同问题?

问题事件

  • 创建了问题 2月2日