发新帖本帖赏金 15.00元(功能说明)我要提问
返回列表
打印
[单片机芯片]

基于CH32V103实现HC-SR04 超声波测距模块轮询读取距离数据

[复制链接]
5487|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 lilijin1995 于 2023-3-17 23:13 编辑

一般的我自己学习单片机,为了更加了解硬件,我都会画了一块CH32V103最小系统板,然后外接其他功能模块实现一些应用,现在秀一秀自己画的板子,虽然设计得不怎样,哈哈哈!!!


最近翻箱底有一款超声波测距,HC-SR04,


那么现在就开始实现HC-SR04 超声波测距模块轮询读取距离数据

硬件接口:根据规格书可以看到接口定义如下图:

我们定义PA0映射TRIG,PA1-TIM2CH2映射ECHO,供电为5V。

软件说明:
超声波时序图如下:

以上时序图表明你只需要提供一个 10uS 以上脉冲触发信号,该模块内部将
发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号 。
回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号
时间间隔可以计算得到距离。公式:uS/58=厘米或者 uS/148=英寸;或是:距离=
高电平时间*声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对
回响信号的影响。
这里主要是ECHO配置TIMCH2输入捕获配置,如下代码:
/*********************************************************************
* @fn      TIM2_ICapture_Init
*
* [url=home.php?mod=space&uid=247401]@brief[/url]   Initializes TIM1 input capture.
*
* @param   arr - the period value.
*          psc - the prescaler value.
*          ccp - the pulse value.
*
* [url=home.php?mod=space&uid=266161]@return[/url]  none
*/
void TIM2_ICapture_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef        GPIO_InitStructure = {0};

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
    NVIC_InitTypeDef        NVIC_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOA, GPIO_Pin_1);

    TIM_TimeBaseInitStructure.TIM_Period = arr;
    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x00;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInit(TIM2,&TIM_ICInitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_ITConfig(TIM2, TIM_IT_Update | TIM_IT_CC2, ENABLE);

    TIM_Cmd(TIM2, ENABLE);
}
我们直接在中断里面计算高电平时间,这里面参考了正点原子的输入捕获实验
//TIM2CH2_CAPTURE_STA
//bit7:捕获完成标志
//bit6:捕获到高电平标志
//bit5~0:捕获到高电平后定时器溢出的次数
u8  TIM2CH2_CAPTURE_STA=0;  //输入捕获状态
u16 TIM2CH2_CAPTURE_VAL;    //输入捕获值,用来记录捕获到下降沿的时候,TIM2_CNT的值

//定时器2中断服务程序
void TIM2_IRQHandler(void)
{

    if((TIM2CH2_CAPTURE_STA&0X80)==0)//还未成功捕获
    {
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)

        {

            if(TIM2CH2_CAPTURE_STA&0X40)//已经捕获到高电平了
            {
                if((TIM2CH2_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
                {
                    TIM2CH2_CAPTURE_STA|=0X80;//标记成功捕获了一次
                    TIM2CH2_CAPTURE_VAL=0XFFFF;
                }else TIM2CH2_CAPTURE_STA++;
            }
        }
    if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获2发生捕获事件
        {
            if(TIM2CH2_CAPTURE_STA&0X40)        //捕获到一个下降沿
            {
                TIM2CH2_CAPTURE_STA|=0X80;      //标记成功捕获到一次高电平脉宽
                TIM2CH2_CAPTURE_VAL=TIM_GetCapture2(TIM2);
                TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC2P=0 设置为上升沿捕获
            }else                               //还未开始,第一次捕获上升沿
            {
                TIM2CH2_CAPTURE_STA=0;          //清空
                TIM2CH2_CAPTURE_VAL=0;
                TIM_SetCounter(TIM2,0);
                TIM2CH2_CAPTURE_STA|=0X40;      //标记捕获到了上升沿
                TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Falling);     //CC1P=1 设置为下降沿捕获
            }
        }
    }

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位

}

捕获了高电平时间,直接除以58就是距离值:我们直接看我们的SR04驱动:
void SR04_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能PB,PE端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;               //LED0-->PB.5 端口配置
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //IO口速度为50MHz
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  //根据设定参数初始化GPIOB.5
    GPIO_SetBits(GPIOA,GPIO_Pin_0);                         //PB.5 输出高
    TIM2_ICapture_Init(0xFFFF,71);
    TRIG(0);
}



u32 SR04_Handler(void)
{
    u32 temp=0,Distance=0;

    //TRig
    Delay_Ms(1);
    TRIG(1);
    Delay_Ms(15);
    TRIG(0);

    //计算距离
if(TIM2CH2_CAPTURE_STA&0X80)        //成功捕获到了一次高电平
    {
        temp=TIM2CH2_CAPTURE_STA&0X3F;
        temp*=65536;                    //溢出时间总和
        temp+=TIM2CH2_CAPTURE_VAL;      //得到总的高电平时间
        Distance=(temp/58);
        printf("Distance:%d cm\r\n",Distance);  //打印总的高点平时间
        TIM2CH2_CAPTURE_STA=0;          //开启下一次捕获

        return Distance;
    }
     return 0;
}

下载验证:



使用特权

评论回复

打赏榜单

21ic小管家 打赏了 15.00 元 2023-04-14

沙发
tpgf| | 2023-4-10 16:55 | 只看该作者
超声波测距是不是对周围环境的要求特别高啊

使用特权

评论回复
板凳
qcliu| | 2023-4-10 17:08 | 只看该作者
超声波测距的距离限制一般是多少啊

使用特权

评论回复
地板
chenjun89| | 2023-4-10 20:03 | 只看该作者
这个超声波模块在我大学时代就有了,没想到现在还在卖。

使用特权

评论回复
5
drer| | 2023-4-11 10:23 | 只看该作者
其原理是根据发射和接收的时间差计算出发射点到障碍物的实际距离

使用特权

评论回复
6
coshi| | 2023-4-11 10:59 | 只看该作者
超声波测距原理与雷达原理是一样的

使用特权

评论回复
7
kxsi| | 2023-4-11 11:27 | 只看该作者
qcliu 发表于 2023-4-10 17:08
超声波测距的距离限制一般是多少啊

超声波测距一般的模块都是在3-4米左右

使用特权

评论回复
8
wiba| | 2023-4-11 12:01 | 只看该作者
手册上面最大是4m,但是在实际测量中达不到4m

使用特权

评论回复
发新帖 本帖赏金 15.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

162

帖子

7

粉丝