红外超声波测距

一、HC-SR04

1.1实物介绍

HC-SR04超声波测距模块提供2cm~400cm的测距功能,精度达3mm。

以下图片截取自深圳市捷深科技有限公司的《HC-SR04超声波测距模块说明书》
在这里插入图片描述

1.2电器参数和时序图

在这里插入图片描述
在这里插入图片描述
通过时序图我们可以知道,我们给HC-SR04发送长达10us的TTL脉冲,然后模块就会进行测距,测距的结果通过回响信号传达,回响的TTL电平信号时间即是超声波从HC-SR04模块发出,触碰到障碍物后返回到HC-SR04模块的时间总和。

TTL是逻辑电平标准,当电压达到2.4V5V之间,那么为逻辑1(高电平),电压在0V0.4V之间,那么为逻辑0(低电平)。所以我们可以直接通过GPIO口来输出以及输入时序所需的电平信号。

总所周知,声音的速度为340m/s,因此我们将回响电平的时间除340再除2之后得到的就是单位为米的测距结果。

二、RS232和RS485

2.1RS232介绍

(1)RS232是串口协议在电气层面的实现,RS-232标准接口定义了电压范围,规定逻辑“1”的电平为-5V~-15 V,逻辑“0”的电平为+5 V~+15V;
(2)Soc的串口引脚一般是3.3V或者5V的电压,所以Soc的串口引脚要使用RS232必须添加TTL电平转RS232电平的转换芯片;
(3)RS232的接口有多种(DB9接口、四线接口、三线接口),但是起主要作用的都是TX和RX引脚,可以简单理解成,RS232和UART的区别就是使用的电压范围不一样

2.2RS232的特点

(1)优点:RS232标准接口的传输距离更长,在15米左右;
(2)接口的信号电平值较高,易损坏接口电路的芯片,又因为与TTL电平不兼容故需使用电平转换芯片才能与Soc的串口引脚连接;

2.3RS485介绍

(1)RS485采用的是差分信号,用的双绞线,传输距离可达上千米;
(2)RS485常用的是两根线,因为采用的是差分信号,所以只能同时传输一组信号,是半双工的;(也有4根线的RS485,实现全双工)
(3)RS485总线可以挂接多个设备,最多不超过32个,采用主从模式;
(4)虽然485支持挂载多个设备,但是没有规定主从设备之间是如何通信的,需要编程人员考虑,可以参考I2C协议的主从实现;

三、Modbus协议

详情参考:https://blog.csdn.net/jf_52001760/article/details/130192127

四、实验

4.1接线方法

HC-SR04

GNDGND
VCC5V
TrigGPIOA_6
EchoDPIOA_7

OLED

GNDGND
VCC3V
SCKGPIOB8
SDACPIOB9

4.2代码部分

#include "stm32f10x.h"                  // Device header
#include "Delay.h"           //使用的是b站江科大的延时函数,可以自己用别的替代延时功能
#include "OLED.h"            //使用的是b站江科大的OLED驱动代码,用于展示测距结果,可以在相应的地方更换为串口通信展示到电脑的串口助手上

uint8_t flag=0;                //用于记录中断信号是上升沿还是下降沿
uint32_t number=0;            //记录定时器中断的次数
uint32_t times=0;            //记录回响信号的持续时间

int main(void){
    OLED_Init();
    OLED_ShowString(1,1,"Hello World!!!");

    //初始化GPIO口,Trig使用推挽输出,Echo使用浮空输入
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能GPIOA的外设时钟
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;                             //选择推挽输出模式
    itd.GPIO_Pin=GPIO_Pin_6;                                    //选择GPIO_Pin_6
    itd.GPIO_Speed=GPIO_Speed_50MHz;                            //默认选择50MHz
    GPIO_Init(GPIOA,&itd);

    itd.GPIO_Mode=GPIO_Mode_IN_FLOATING;                        //选择浮空输入模式
    itd.GPIO_Pin=GPIO_Pin_7;                                    //选择GPIO_Pin_7
    GPIO_Init(GPIOA,&itd);

    //AFIO映射中断引脚
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);         //使能AFIO的外设时针
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);  //选择外部中断源和中断通道

    //EXTI中断配置
    EXTI_InitTypeDef itd1;
    itd1.EXTI_Line=EXTI_Line7;                                  //echo使用的端口7,因此选择7号中断线
    itd1.EXTI_LineCmd=ENABLE;
    itd1.EXTI_Mode=EXTI_Mode_Interrupt;
    itd1.EXTI_Trigger=EXTI_Trigger_Rising_Falling;              //上升沿和下降沿都触发中断
    EXTI_Init(&itd1);

    //NVIC分配外部中断的中断优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);             //指定中断分组
    NVIC_InitTypeDef itd2;
    itd2.NVIC_IRQChannel=EXTI9_5_IRQn;                          //使用的端口7,因此选择这个参数
    itd2.NVIC_IRQChannelCmd=ENABLE;
    itd2.NVIC_IRQChannelPreemptionPriority=2;                   //抢占优先级
    itd2.NVIC_IRQChannelSubPriority=2;                          //响应优先级
    NVIC_Init(&itd2);

    //配置定时器
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    TIM_TimeBaseInitTypeDef itd3;
    itd3.TIM_ClockDivision=TIM_CKD_DIV1;                        //使用时钟分频1
    itd3.TIM_CounterMode=TIM_CounterMode_Up;                    //向上计数
    //72MHz/72/100=1000,每秒定时器计数1000个,因此每个计数为100us
    itd3.TIM_Period=72-1;                                       //预分频系数
    itd3.TIM_Prescaler=100-1;                                   //自动重装器
    itd3.TIM_RepetitionCounter=0;                               //该参数仅给高级定时器使用
    TIM_TimeBaseInit(TIM2,&itd3);
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                    //使能中断输出信号
    TIM_InternalClockConfig(TIM2);                              //选择内部时钟

    //NVIC分配定时器的中断优先级
    NVIC_InitTypeDef itd4;
    itd4.NVIC_IRQChannel=TIM2_IRQn;                             //指定Tim2的中断通道
    itd4.NVIC_IRQChannelCmd=ENABLE;
    itd4.NVIC_IRQChannelPreemptionPriority=1;                   //抢占优先级
    itd4.NVIC_IRQChannelSubPriority=1;                          //响应优先级
    NVIC_Init(&itd4);

    uint32_t distance;
    while(1){
        distance=0;
        for(int i=0;i<10;++i){              //每次取10次测距数据,取平均值减少误差
            GPIO_SetBits(GPIOA,GPIO_Pin_6);
            Delay_us(15);                   //根据说明书,需要提供至少10us的高电平
            GPIO_ResetBits(GPIOA,GPIO_Pin_6);
            Delay_ms(65);                   //根据说明书,每个周期至少需要等待60ms
            distance+=(times/5.8);          //根据说明书提供的公式,获取单位为mm的距离
        }
        distance/=10;
        OLED_ShowNum(2,1,distance,4);
    }
}

//定时器中断函数
void TIM2_IRQHandler(void){
    if(SET==TIM_GetITStatus(TIM2,TIM_FLAG_Update)){
        number++;                                   //每次中断将次数++
        TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
    }
}

//外部中断函数
void EXTI9_5_IRQHandler(void){
    if(SET==EXTI_GetITStatus(EXTI_Line7)){
        if(flag==0){
            //上升沿即回响电平开始,打开计数器
            number=0;flag=1;
            TIM_SetCounter(TIM2,0);
            TIM_Cmd(TIM2,ENABLE);

        }else{
            //下降沿即回响电平结束,统计高电平持续时长
            TIM_Cmd(TIM2,DISABLE);
            flag=0;
            times=number*100+TIM_GetCounter(TIM2);  //得到回响的高电平持续的us
        }
        EXTI_ClearITPendingBit(EXTI_Line7);
    }
}

4.3实现效果

在这里插入图片描述

4.4完整代码

完整的工程文件在这边:

链接:https://pan.baidu.com/s/1k4oXI_XNgQwquPyXXRIafQ
提取码:yvz6

参考

https://www.cnblogs.com/soliang/p/17870635.html
https://blog.csdn.net/weixin_42031299/article/details/128990256

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值