大数跨境
0
0

STM32F407基础教程11——定时器应用之超声波传感器

STM32F407基础教程11——定时器应用之超声波传感器 Easy单片机
2025-06-20
1
导读:超声波传感器的使用

前言

在前面的教程中已经讲过GPIO口配置、中断控制系统NVIC配置、外部中断EXTI和定时器配置等内容。本文将通过一个简单的超声波传感器将之前所讲的内容都应用起来。

一、超声波传感器简介

1.超声波传感器特点

HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm超声波测距模块有4个引脚:

  • VCC:电源,连接单片机的5V

  • GND电源负,连接单片机的地(GND

  • TRIG:触发控制信号输入引脚给此引脚一个至少10us的高电平脉冲启动一次测距。

  • ECHO:回响信号输出引脚模块测距完成后,此引脚会输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间。

2.超声波传感器测距原理

当给TRIG引脚一个至少10us的高电平脉冲时,模块自动发送840khz的方波,自动检测是否有信号返回;检测到信号返回,ECHO引脚输出高电平,高电平持续的时间就是超声波从发射到返回的时间。
探测距离=高电平时间*声速/2;

1建议测量周期60ms以上,以防止发射信号对测量信号的影响。

【注2】声速取340m/s34000cm/s

二、超声波程序设计思路

STM32F407开发板的PA2引脚连接TRIG引脚,PA2引脚输出一个10us以上的高电平脉冲来触发测距。PA1引脚连接ECHO引脚,并设置为外部中断,同时检测上升沿和下降沿。当ECHO上升沿时,表示接收到返回信号,此时启动定时器开始计时;当ECHO下降沿时,表示信号结束,此时停止定时器计数,并计算距离。

1.程序设计步骤

(1)初始化TRIG引脚(PA2)为推挽输出,初始状态为低电平。

(2)初始化ECHO引脚(PA1)为浮空输入,并配置为外部中断,同时设置上升沿和下降沿触发。

(3)配置NVIC,设置通断分组、中断通断、抢占和响应优先级等

(4)配置定时器TIM3,使其1us计数一次。

(5)编写外部中断函数,判断是上升沿还是下降沿。上升沿时,启动定时器;下降沿时,停止定时器,读取计数器的值,并计算距离。

(6)编写延时函数、获取距离、发送触发信号等函数

2.程序如下(以下函数都定义在main.c中)

/*1-TRIG引脚配置-推挽输出*/void TRIG_Config(){/*1-定义结构体*/GPIO_InitTypeDef GPIO_InitStruct;  //定义结构体/*2-开启GPIOF时钟*/RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); /*3-初始化相关参数*/GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2; //选择A2引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; //输出速度GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;   //推挽输出GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 上拉/*4-完成初始化*/GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_ResetBits(GPIOA, GPIO_Pin_2); // 初始化为低电平}
/*2-ECHO引脚配置-配置PA1为EXTI中断输入脚*/void ECHO_Config(){/*1-定义相关结构体*/NVIC_InitTypeDef NVIC_InitStructure;//NVIC结构体GPIO_InitTypeDef GPIO_InitStruct;//GPIO结构体EXTI_InitTypeDef  EXTI_InitStructure;//EXTI结构体/*2-开相应时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//开时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); /*3-PA1配置为输入引脚*/GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;  //A1引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //输入模式GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //浮空模式GPIO_Init(GPIOA, &GPIO_InitStruct);/*4-设置中断线与IO引脚的映射关系*/SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1);/*5-EXTI配置*/EXTI_InitStructure.EXTI_Line = EXTI_Line1;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升沿下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能EXTI中断EXTI_Init(&EXTI_InitStructure);/*6-NVCI配置*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//设置中断分组NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断NVIC_Init(&NVIC_InitStructure);
/*3-TIM3配置*/void TIM3_Init(){/*1-定义TIM3结构体*/TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;/*2-开启TIM3时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM2时钟/*3-时基配置*/TIM_TimeBaseStructure.TIM_Period = 0xffff;//自动重装载ARR值TIM_TimeBaseStructure.TIM_Prescaler = 84-1;//预分频PSC值,1MHzTIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//1分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//完成初始化/*4-使能定时器*///TIM_Cmd(TIM3,ENABLE);}
/*4-延时函数*///延时函数:微秒级别void delay_us(uint32_t nus){uint32_t tmp;while(nus--){SysTick->LOAD = 168000000/8/1000000;	//计数初值,延时1usSysTick->VAL = 0;//清空当前值SysTick->CTRL |= 0x1;	//开始计数do{tmp = SysTick->CTRL;//获取CTRL状态}while((tmp&0x1) && !(0x1<<16));SysTick->VAL = 0;//清空当前值SysTick->CTRL &= 0;//关闭计数}//毫秒级别 void delay_ms(uint32_t nms){uint32_t tmp;while(nms--){SysTick->LOAD = 168000000/8/1000;SysTick->VAL = 0;SysTick->CTRL |= 0x1;			do{tmp = SysTick->CTRL;			}while((tmp&0x1) && !(0x1<<16));SysTick->VAL = 0;SysTick->CTRL &= 0;}}
/*5-发送触发信号和测距函数*/// 发送10us触发脉冲void Ultrasonic_Trigger(void) {GPIO_SetBits(GPIOA, GPIO_Pin_2);   // 高电平delay_us(15);                      // 保持15usGPIO_ResetBits(GPIOA, GPIO_Pin_2); // 拉低}//计算距离 float Get_Distance(void) {// 距离 = (时间 * 声速) / 2 // 声速340m/s = 34000cm/s = 0.034cm/usreturn (TIM3_Capture * 0.034) / 2.0;}
/*6-main.c*/#include "stm32f4xx.h"#include "LED.h"// 全局变量uint32_t TIM3_Capture = 0;uint8_t  Echo_State = 0// 0:空闲 1:已捕获上升沿float distance = 0;//上述函数都定义在main函数之前 int main(){   LED_Init();TIM3_Init();TRIG_Config();ECHO_Config();while(1){Ultrasonic_Trigger();      // 发送触发信号delay_ms(100);             // 每100ms测量一次     distance = Get_Distance();if(distance < 10LED0_ON();//简单用LED灯测试 ,可用OLED或串口显示数据 else LED0_OFF();	 }}/*中断服务函数*/void EXTI1_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line1) != RESET) {if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)) { // 上升沿TIM3->CNT = 0;            // 计数器清零TIM_Cmd(TIM3, ENABLE);    // 启动定时器Echo_State = 1;           // 标记已捕获上升沿else {                  // 下降沿if (Echo_State) {TIM_Cmd(TIM3, DISABLE); // 停止定时器TIM3_Capture = TIM3->CNT; // 获取计数值Echo_State = 0;          // 重置状态}}EXTI_ClearITPendingBit(EXTI_Line1);}}
总结:虽然超声波传感器比较简单,但应用起来还是涉及到比较多的知识点,比如引脚的配置、中断、定时器等。这也算是对前面讲述的内容做个总结吧。后续会继续介绍定时器的输入捕获、比较输出等功能。

【声明】内容源于网络
0
0
Easy单片机
本公众号专注于单片机技术开发领域。用于记录和分享单片机开发相关技术知识,学习笔记,设计示例和基础教程。包括C/C++、51单片机、STM32单片机、PCB设计等。
内容 62
粉丝 0
Easy单片机 本公众号专注于单片机技术开发领域。用于记录和分享单片机开发相关技术知识,学习笔记,设计示例和基础教程。包括C/C++、51单片机、STM32单片机、PCB设计等。
总阅读3
粉丝0
内容62