STM32f407系列之超声波模块

目录

1、模块说明

2、时序图

3、注意事项

4、完整代码


1、模块说明

VCC引脚:5V电源

TRIG引脚:触发信号引脚,单片机给超声波模块一个信号,超声波模块就会工作。

ECHO引脚:回响信号引脚,当超声波模块已经测量距离成功后,通过该引脚告诉单片机当前超声波传输的时间。

GND:信号地。

2、时序图

看时序图的技巧,从上到下,从左到右,因为一般的时序图是隐含了时间轴。如何区分t1、t2、t3、t4,就是要找出它们的变化点。

 

 

 

超声波模块实物硬件连接如下:

  • 参考角度1

  • 参考角度2

3、注意事项

1)不同的温度,声音的传播速度是不一样的

2)超声波的测量误差为3mm,可根据3mm的测距求出测量时间,求算如下:

 3)可编写简单代码如下

int32_t sr04_get_distance(void)
{
    uint32_t t=0;
    uint32_t d=0;
    
    //1.PB6引脚输出至少10us以上的高电平
    PBout(6)=1;
    
    delay_us(20);
    
    PBout(6)=0;    

    //2.等待超声波模块测距完毕,标志性的动作就是回响信号引脚从输出低电平变为输出高电平
    //在等待过程当中,最好添加超时处理
    
    t=0;
    while(PEin(6)==0)
    {
    
        delay_us(1);
        
        t++;
        
        //超时处理
        if(t >= 1000000)
            return -1;
    }
    
    
    //3.测量PE6引脚的高电平时间,该高电平的持续时间就是超声波模块的传输时间
    
    t=0;
    while(PEin(6))
    {
        
        delay_us(9); //9us == 3mm
        t++;
        
        //超时处理
        if(t >= 1000000)
            return -2;    
    }

    //4.将时间转换为距离
    d =  t*3/2;
    
    return  d;
}

加超时处理(属于容错处理中的一部分)有以下原因:

1)硬件问题:引脚连接有问题、超声波模块的损坏

2)软件问题:延时不准确

4、完整代码

沿用串口的代码模板:

#include "stm32f4xx.h"
#include <stdio.h>
static GPIO_InitTypeDef GPIO_InitStruct;//不加*
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;

#define PEout(x) *(volatile uint32_t *)(0x42000000+(GPIOE_BASE+0x14-0x40000000)*32+(x)*4)
#define PFout(x) *(volatile uint32_t *)(0x42000000+(GPIOF_BASE+0x14-0x40000000)*32+(x)*4)
#define PAin(x) *(volatile uint32_t *)(0x42000000+(GPIOA_BASE+0x10-0x40000000)*32+(x)*4)
#define PEin(x) *(volatile uint32_t *)(0x42000000+(GPIOE_BASE+0x10-0x40000000)*32+(x)*4)
#define PBout(x) *(volatile uint32_t *)(0x42000000+(GPIOB_BASE+0x14-0x40000000)*32+(x)*4)
#define PBin(x) *(volatile uint32_t *)(0x42000000+(GPIOB_BASE+0x10-0x40000000)*32+(x)*4)


struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;

int fputc(int ch, FILE *f) {
    USART_SendData(USART1,ch);
    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    return ch;
}

void delay_us(uint32_t n)
{
    //使用系统始终的8分频作为系统定时器的时钟源
    SysTick->CTRL = 0; // Disable SysTick
    SysTick->LOAD = n*21-1; // Count from 255 to 0 (256 cycles)
    SysTick->VAL = 0; // Clear current value as well as count flag
    SysTick->CTRL = 1; // Enable SysTick timer with processor clock
    while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    SysTick->CTRL = 0; // Disable SysTick
}


void delay_ms(uint32_t n)
{

    while(n--)
    {
        SysTick->CTRL = 0; // Disable SysTick,关闭系统定时器后才能取配置
        SysTick->LOAD = 21000-1;     // 填写计数值,就是我们的延时时间
        SysTick->VAL = 0;             // 清空标志位
        SysTick->CTRL = 1;             // 选中21MHz的时钟源,并开始让系统定时器工作
        while ((SysTick->CTRL & 0x10000)==0);//等待计数完毕
        
    }
    SysTick->CTRL = 0; // 不再使用就关闭系统定时器
}

void usart1_init(uint32_t baud)
{
    //打开PA硬件时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    //打开串口1硬件时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    //PA9,PA10配置为复用功能模式
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    //将PA9和PA10引脚连接到串口1
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

    //配置串口1相关参数:波特率、无校验位、8位数据位、1个停止位
    USART_InitStructure.USART_BaudRate = baud;            //波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
    /* When using Parity the word length must be configured to 9 bits */
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//允许收发数据
    USART_Init(USART1, &USART_InitStructure);

    //配置串口1的中断触发方法:接收一个字节触发中断 
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    //配置串口1的中断优先级
    
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    //使能串口1工作
    USART_Cmd(USART1, ENABLE);
}

void sr04_init(void)
{
    //端口B硬件时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    
    //端口E硬件时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);

    
    //配置PB6为输出模式
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB,&GPIO_InitStruct);
    
    //配置PE6为输入模式
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOE,&GPIO_InitStruct);
    
    //PB6初始状态为低电平
    PBout(6)=0;
}

int32_t sr04_get_distance(void)
{
    uint32_t t=0;
    int32_t d=0;
    //PB6高电平
    PBout(6)=1;
    //持续10us以上
    delay_us(20);
    //PB6低电平
    PBout(6)=0;
    //等待回响信号(等待PE6出现高电平)
    while(PEin(6)==0)
    {
        t++;
        delay_us(1);
        if(t>=1000000)
            return -1;
    }
        
    //测量高电平的时间
    t=0;
    while(PEin(6))
    {
        t++;
        delay_us(9);  //9us=3mm
        if(t>=1000000)
            return -2;
    }
    //得到距离
    t=t/2;   //时间是超声波从发射到返回的时间
    d=3*t;
    return d;
}

int main()
{
    int32_t d=0;
    //打开端口F的硬件时钟,就是为端口F供电
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
    
    //配置引脚
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOF,&GPIO_InitStruct);//为何传地址
    usart1_init(115200);//串口1波特率115200bps
    PFout(9)=1;
    sr04_init();
    
    while(1)
    {
        d=sr04_get_distance();
        if(d>0)
        {
            if(d>=20 && d<=4000)
            {
                printf("distance=%dmm\r\n",d);
            }
        }
        delay_ms(1000);
    }
    //为何用此循环
}

void USART1_IRQHandler(void)
{
    uint32_t d;
    //检测标志位
    if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
    {
        //接收数据
        d=USART_ReceiveData(USART1);
        //将接收到的数据返发给PC
        USART_SendData(USART1,d);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
        if(d=='1') PFout(9)=1;
        if(d=='0') PFout(9)=0;
        //清空标志位
        USART_ClearITPendingBit(USART1,USART_FLAG_RXNE);
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在STM32F407上使用HCSR04超声波传感器进行测距,需要进行以下步骤: 1. 连接HCSR04超声波传感器到STM32F407开发板上。将VCC引脚连接到3.3V电源,GND引脚连接到GND,Trig引脚连接到STM32F407的GPIOx(x为对应的GPIO口)的输出引脚,Echo引脚连接到STM32F407的GPIOx(x为对应的GPIO口)的输入引脚。 2. 在STM32CubeMX中配置GPIO口,将Trig引脚配置为输出模式,将Echo引脚配置为输入模式。 3. 在代码中初始化GPIO口,配置Trig引脚为推挽输出模式,配置Echo引脚为上拉输入模式。 4. 在代码中编写测距函数,包括向Trig引脚输出一个至少10us的高电平,然后等待Echo引脚变高,再计算Echo引脚高电平持续的时间,最后根据公式计算出距离。 以下是一个简单的示例代码: ``` #include "stm32f4xx_hal.h" #define TRIG_PIN GPIO_PIN_0 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_1 #define ECHO_PORT GPIOA void delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim6, 0); while (__HAL_TIM_GET_COUNTER(&htim6) < us); } float get_distance() { uint32_t duration; float distance; HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); delay_us(2); HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); delay_us(10); HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); while (!HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN)); uint32_t start = HAL_GetTick(); while (HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN)); duration = HAL_GetTick() - start; distance = duration * 0.034 / 2; // 距离公式 return distance; } int main(void) { HAL_Init(); SystemClock_Config(); // 配置系统时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIO时钟 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = TRIG_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = ECHO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct); while (1) { float distance = get_distance(); printf("Distance: %.2fcm\r\n", distance); HAL_Delay(1000); } } ``` 注意:这只是一个简单的示例代码,具体实现方式可能因开发板和库的不同而有所不同,需要自行进行适配。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值