STM32单片机+4个HC-SR04超声波测距传感器+OLED屏幕+源代码(定时器中断、高级定时器TIM1、普通定时器TIM2、TIM3、TIM4)

目录

1.硬件设备

2.软件代码说明

3.源代码


1.硬件设备

1.STM32F103C8T6开发板

2.4个超声波测距传感器(我这里目前就只有一个超声波传感器,其他3个只要接上线就可以用)

3.OLED屏幕

4.ST-link烧录器

5.杜邦线若干

2.软件代码说明

第一步:开启外设时钟,APB1为TIM2和TIM3、TIM4的总线,APB2为GPIO口的总线(不知道外设在哪条总线上可查询32手册AHB/APB桥(APB)小节)。直接调用标准库函数RCC_APB1PeriphClockCmd()和RCC_APB2PeriphClockCmd()选择对应外设设置成ENABLE,GPIO口选择GPIOA,这样对应的外设时钟就开启了。

第二步:GPIO口初始化配置,调用GPIO_Init()结构体函数进行配置,查手册可知GPIO口模式为普通推挽输出模式,GPIOA口选择Pin_0口,引脚传输频率通常选择50MHz。

第四步:定时器中断配置,调用TIM_ITConfig()开启定时器中断源。调用NVIC_PriorityGroupConfig()选择中断源分组,这里选择2分组即:两个抢占优先级和两个响应优先级,如果对中断优先级没有太大要求,通常选择2分组,抢占和响应各两个。调用NVIC_Init()结构体进行中断初始化,TIM2抢占给2,响应给1,TIM3抢占给2,响应给1;STM32的中断优先级处理首先看抢占优先级,只有当两个中断的抢占优先级不同时,抢占优先级高的中断才会打断抢占优先级低的中断。在这里,TIM3的抢占优先级为1,而TIM2的抢占优先级为2。因此,TIM3的抢占优先级高于TIM2。当两个中断同时请求服务时,TIM3的中断会先被响应,因为它具有更高的抢占优先级。响应优先级在这种情况下不起作用,因为它们的抢占优先级已经不同,响应优先级只在多个中断具有相同抢占优先级时才有意义(值越小级别越高)。

第五步:开启定时器使能,调用TIM_Cmd()开启

注意:当配置多个定时器初始化时,只需重新配置结构体成员即可。

在HCSR04.C文件分别定义了4组

HCSR04_Init1(),HCSR04_Start1(),HCSR04_GetValue1()

HCSR04_Init2(),HCSR04_Start2(),HCSR04_GetValue2()

HCSR04_Init3(),HCSR04_Start3(),HCSR04_GetValue3()

HCSR04_Init4(),HCSR04_Start4(),HCSR04_GetValue4()

超声波驱动函数,求超声波测的距离值。

#include "stm32f10x.h"                  // Device header
#include "HCSR04.h"
#include "Delay.h"
#include "Timer.h"
uint16_t Time1,Time2,Time3,Time4;//高电平时间

void HCSR04_Init1()
{
	RCC_APB2PeriphClockCmd(Trig_RCC1, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStruct.GPIO_Pin = Trig_Pin1;          //PA0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//io口速度50MHZ
	GPIO_Init(Trig_Port1, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;		//上拉输入
	GPIO_InitStruct.GPIO_Pin = Echo_Pin1;					//PA1
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Echo_Port1, &GPIO_InitStruct);
	
	GPIO_ResetBits(Trig_Port1, Trig_Pin1);
}

void HCSR04_Start1()
{
	GPIO_SetBits(Trig_Port1, Trig_Pin1);
	Delay_us(45);
	GPIO_ResetBits(Trig_Port1, Trig_Pin1);
	Timer_Init1();
}

uint16_t HCSR04_GetValue1()
{
	HCSR04_Start1();
	Delay_ms(100);
	return ((Time1 * 0.0001) * 34000) / 2;  // cm/s  [(0.00001s*340m/s)/2] * 100
//	return Time;
}

//------------------------------------------------------------------------------

void HCSR04_Init2()
{
	RCC_APB2PeriphClockCmd(Trig_RCC2, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStruct.GPIO_Pin = Trig_Pin2;          //PA0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//io口速度50MHZ
	GPIO_Init(Trig_Port2, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;		//上拉输入
	GPIO_InitStruct.GPIO_Pin = Echo_Pin2;					//PA1
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Echo_Port2, &GPIO_InitStruct);
	
	GPIO_ResetBits(Trig_Port2, Trig_Pin2);
}

void HCSR04_Start2()
{
	GPIO_SetBits(Trig_Port2, Trig_Pin2);
	Delay_us(45);
	GPIO_ResetBits(Trig_Port2, Trig_Pin2);
	Timer_Init2();
}

uint16_t HCSR04_GetValue2()
{
	HCSR04_Start2();
	Delay_ms(100);
	return ((Time2 * 0.0001) * 34000) / 2;  // cm/s  [(0.00001s*340m/s)/2] * 100
//	return Time;
}


//------------------------------------------------------------------------------
void HCSR04_Init3()
{
	RCC_APB2PeriphClockCmd(Trig_RCC3, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStruct.GPIO_Pin = Trig_Pin3;          //PA0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//io口速度50MHZ
	GPIO_Init(Trig_Port3, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;		//上拉输入
	GPIO_InitStruct.GPIO_Pin = Echo_Pin3;					//PA1
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Echo_Port3, &GPIO_InitStruct);
	
	GPIO_ResetBits(Trig_Port3, Trig_Pin3);
}

void HCSR04_Start3()
{
	GPIO_SetBits(Trig_Port3, Trig_Pin3);
	Delay_us(45);
	GPIO_ResetBits(Trig_Port3, Trig_Pin3);
	Timer_Init3();
}

uint16_t HCSR04_GetValue3()
{
	HCSR04_Start3();
	Delay_ms(100);
	return ((Time3 * 0.0001) * 34000) / 2;  // cm/s  [(0.00001s*340m/s)/2] * 100
//	return Time;
}

//------------------------------------------------------------------------------
void HCSR04_Init4()
{
	RCC_APB2PeriphClockCmd(Trig_RCC4, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStruct.GPIO_Pin = Trig_Pin4;          //PA0
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//io口速度50MHZ
	GPIO_Init(Trig_Port4, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;		//上拉输入
	GPIO_InitStruct.GPIO_Pin = Echo_Pin4;					//PA1
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Echo_Port4, &GPIO_InitStruct);
	
	GPIO_ResetBits(Trig_Port4, Trig_Pin4);
}

void HCSR04_Start4()
{
	GPIO_SetBits(Trig_Port4, Trig_Pin4);
	Delay_us(45);
	GPIO_ResetBits(Trig_Port4, Trig_Pin4);
	Timer_Init4();
}

uint16_t HCSR04_GetValue4()
{
	HCSR04_Start4();
	Delay_ms(100);
	return ((Time4 * 0.0001) * 34000) / 2;  // cm/s  [(0.00001s*340m/s)/2] * 100
//	return Time;
}

TIM2、TIM3、TIM4中断函数:两个定时器中断函数有自己专门的函数名字,可以在标准库文件Start中md.s中找到(如下图),在中断中调用TIM_GetITStatus()用if判断是否为对应定时器中断,如果是TIM_GetITStatus()==SET(即等于1)则进入中断执行程序,最后需要清理中断调用TIM_ClearITPendingBit()为下一次中断做准备;

在HCSR04.H文件分别声明了4组超声波驱动函数,以及下面4组GPIO口的重命名:

Trig_Port1,Trig_Pin1,Trig_RCC1,Echo_Port1,Echo_Pin1, Echo_RCC1

Trig_Port2,Trig_Pin2,Trig_RCC2,Echo_Port2,Echo_Pin2, Echo_RCC2

Trig_Port3,Trig_Pin3,Trig_RCC3,Echo_Port3,Echo_Pin3, Echo_RCC3

Trig_Port4,Trig_Pin4,Trig_RCC4,Echo_Port4,Echo_Pin4, Echo_RCC4

在Timer.C文件分别定义了4组

定时器初始化Timer_Init(),定时器中断函数TIMX_IRQHandler()

注意Timer_Init()2是高级定时器TIM1,其他三个都是普通定时器

在Timer.H文件分别声明了4组Timer_Init1(),Timer_Init2(),Timer_Init3(),Timer_Init4()定时器初始化函数

3.源代码

《STM32单片机+4个HC-SR04超声波测距传感器+OLED屏幕》源代码资源-CSDN文库

4.超声波模块资料

超声波传感器原理图、模块资料资源-CSDN文库

  • 20
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
以下是使用STM32F407和HC-SR04超声波测距模块的示例代码: ```c #include "stm32f4xx.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_tim.h" #include "misc.h" #define TRIG_PIN GPIO_Pin_0 #define ECHO_PIN GPIO_Pin_1 #define GPIO_PORT GPIOA uint32_t distance = 0; void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = TRIG_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ECHO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIO_PORT, &GPIO_InitStructure); } void TIM_Configuration(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ICInitTypeDef TIM_ICInitStructure; TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter = 0x0; TIM_ICInit(TIM2, &TIM_ICInitStructure); TIM_Cmd(TIM2, ENABLE); } uint32_t GetDistance(void) { GPIO_SetBits(GPIO_PORT, TRIG_PIN); Delay_us(10); GPIO_ResetBits(GPIO_PORT, TRIG_PIN); uint32_t start_time = 0; uint32_t end_time = 0; uint32_t timeout = 0; while (GPIO_ReadInputDataBit(GPIO_PORT, ECHO_PIN) == RESET) { if (++timeout > 1000000) { return 0xFFFFFFFF; } } start_time = TIM_GetCounter(TIM2); timeout = 0; while (GPIO_ReadInputDataBit(GPIO_PORT, ECHO_PIN) == SET) { if (++timeout > 1000000) { return 0xFFFFFFFF; } } end_time = TIM_GetCounter(TIM2); if (end_time > start_time) { distance = (end_time - start_time) * 10 / 58; } else { distance = (start_time - end_time) * 10 / 58; } return distance; } int main(void) { GPIO_Configuration(); TIM_Configuration(); while (1) { GetDistance(); } return 0; } ``` 此代码初始化GPIO和定时器,然后在主循环中调用`GetDistance()`函数来获取测量到的距离。该函数使用超声波模块发送一个10微秒的脉冲,然后等待接收到回波。通过测量回波的时间来计算距离,并返回结果。在本例中,距离以毫米为单位表示。如果无法检测到回波或测量超时,则返回0xFFFFFFFF。 需要注意的是,在本例中,我们使用了定时器的输入捕获模式来测量回波的时间。我们使用TIM2的通道2来读取ECHO引脚的状态,并在上升沿触发捕获。此代码假设您已正确配置STM32F407的时钟源。如果您遇到问题,请参阅STM32F407参考手册。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式Dora

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值