定时器-超声波测距实验

传感器名称:HC-SR04(超声波测距传感器),可以测量当前位置和障碍物之间的距离

实验:

用手掌放在传感器前方模拟障碍物,传感器测量的就是当前位置和手掌之间的距离,测量得到距离之后使用单片机上的串口和USB转TTL模块把测量结果发送到电脑上

1.HCSR-04模块的使用方法

超声波测距传感器基本原理:

向Trig引脚输入一个不小于10μs脉冲信号,传感器开始工作,

通过左边T眼睛向外发送超声波(8个周期40kHz大约为0.2毫秒),发送完超声波后Echo引脚立即输出一个高电压,超声波在空气中传播遇到障碍物反射回来形成一个回声,右边眼睛R接收回声,当全部回声(8个周期)接收完后,Echo引脚向外输出一个低电压,所以距离=脉宽(时间)*340m/s÷2。

脉宽可以通过定时器的输入捕获功能获得

2.搭建电路

Trig引脚启动测量,通过引脚输入一个不小于10μs信号,脉冲不需要十分精确所以选用普通引脚PA0

Echo引脚用于返回测量结果,返回形式也是脉冲,需要测量脉冲的脉宽用到定时器的输入捕获功能,所以引脚接到定时器1(TIM1)的通道1(CH1)PA8引脚

USB转TTL模块:选择单片机的串口引脚PA9、PA10

2.1初始化串口:

a.初始化引脚

b.初始USART化模块本身

开启USART模块本身时钟、设置参数、闭合总开关

#include "stm32f10x.h"

void App_USARTl_Init (void);

int main(void)
{
	App_USARTl_Init ();
	
	while(1)
	{
	}
}

void App_USARTl_Init (void)
{
	//#1.初始化Io引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	// PA9 AF PP Tx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//PA10 IPU Rx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//#2.初始化UsART1
	//#2.1开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//#2.2初始化USART1的参数
	USART_InitTypeDef USART_InitStruct;
	
	USART_InitStruct.USART_BaudRate = 115200;
	USART_InitStruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_Init (USART1, &USART_InitStruct);
	
	//#2.3闭合总开关
	USART_Cmd(USART1,ENABLE);
}

测试代码:在串口调试助手打印字符串'Hello word ' (使用到Mylib库里面usart.h文件)

#include "stm32f10x.h"
#include "usart.h"

void App_USARTl_Init (void);

int main(void)
{
	App_USARTl_Init ();
	
	My_USART_SendString(USART1, "Hello world. \r\n");
	
	while(1)
	{
	}
}

void App_USARTl_Init (void)
{
	//#1.初始化Io引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	// PA9 AF PP Tx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//PA10 IPU Rx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//#2.初始化UsART1
	//#2.1开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//#2.2初始化USART1的参数
	USART_InitTypeDef USART_InitStruct;
	
	USART_InitStruct.USART_BaudRate = 115200;
	USART_InitStruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_Init (USART1, &USART_InitStruct);
	
	//#2.3闭合总开关
	USART_Cmd(USART1,ENABLE);
}

3.梳理思路

HC-SR04传感器是超声波测距传感器,超声波测距传感器返回测量结果的方式,根据Echo引脚返回一个脉冲信号,需要测量脉冲信号的脉宽,只有测量出模块才得出于障碍物的距离

测量脉宽需要用到定时器的输入捕获功能

用定时器其中一个通道去捕获输入信号的上升沿,用另外一个信号去捕获输入信号的下降沿,再用两个捕获的结果作差,作差结果就是脉宽。(CCR1-CCR2)*分辨率


4.初始化时基单元

定时器分别率:图中台阶宽度为分别率,台阶越小测量结果越精细,分辨率不可以无限小,HC-SR04精度最高为3mm,3mm转换为时间是8微秒(3/340m/s=8微秒左右),台阶宽度小于8微秒,

定时器周期:图中溢出一次的时间为周期,周期越长越好,但是时基单元内的寄存器都是16位寄存器,范围为000000000000到111111111111也就是0到65535,所以ARR取最大值,ARR=65535周期为最大值

分别率为1微秒

周期为65535

定时器为TIM1,TIM1挂在APB2上,PCLK2当前频率为72Hz,APB2的分频系数为1分屏,所以TIM1的倍屏系数为1倍屏,TIM1频率=PCLK2*1=72*1=72Hz

定时器的分辨率为1us,PSC=71Hz

ARR=65535

RCR=0

void App_HCSR04_Init (void);//初始化传感器函数

开启定时器时钟

配置时基单元参数

void App_HCSR04_Init (void)
{
	//#1.初始化时基单元
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 65535;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	
	TIM_TimeBaseInit (TIM1, &TIM_TimeBaseInitStruct);
	
}


5.初始化输入捕获

这里用到的是输入捕获功能,手册建议GPIO配置为浮空输入,Echo引脚空闲时两边都是低电压,最好GPIO配置为输入下拉,当设置为输入下拉时,当Echo引脚意外断开时输入下拉模式可以提供一个默认的低电压,低电压可以模拟脉冲信号空闲状态,所以最好设置为输入下拉模式

初始化输入捕获:

初始化IO引脚、初始化输入捕获本身(初始化通道)

	//#2.初始化输入捕获
	//#2.1.初始化Io引脚PA8 IPD
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
 
	//#2.2.初始化输入捕获的通道1
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICFilter = 0;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
	
	TIM_ICInit (TIM1, &TIM_ICInitStruct);
	
	//#2.3.初始化输入捕获的通道2
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICFilter = 0;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;
	
	TIM_ICInit (TIM1, &TIM_ICInitStruct);


6.编程

6.1、向CNT写0

6.2清除CC1和CC2标志位

	while(1)
	{
		//#1.向cNT写0
		TIM_SetCounter (TIM1,0);
		
		//#2.清除cc1和cc2标志位
		TIM_ClearFlag (TIM1, TIM_FLAG_CC1);
		TIM_ClearFlag (TIM1, TIM_FLAG_CC2);
	}

6.3开启定时器TIM_Cmd

		//3.开启定时器
		TIM_Cmd (TIM1, ENABLE)

6.4初始化Echo引脚

	//.初始化rig引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);

6.5发送脉冲

先向引脚写1变成高电压,中间延迟10微秒,再向引脚写0变成低电压

延迟函数:delay函数最短延迟时间为1毫秒,1毫秒=1000微秒,但是不太合适,

微秒级延迟函数void DelayUs (uint32_t us);// 微秒级延迟

		//#4.向RIG引脚发送10us的脉冲
		GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_SET);
		DelayUs (10);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_RESET);

6.6不断查询cc1和cc2标志位

		//#5.等待测量完成
		while (TIM_GetFlagStatus (TIM1, TIM_FLAG_CC1) ==RESET);
		while (TIM_GetFlagStatus (TIM1, TIM_FLAG_CC2)== RESET);

6.7关闭定时器

6.8计算测量结果

		uint16_t ccr1 = TIM_GetCapture1 (TIM1);
		uint16_t ccr2 = TIM_GetCapture2 (TIM1);
		
		float distance =(ccr2-ccr1) * 1.0e-6f * 340.0f / 2;
		
		My_USART_Printf(USART1, "distance = %.4f\r\n" ,distance);
		
		Delay (100);

总代码

#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"

void App_USARTl_Init (void);
void App_HCSR04_Init (void);

int main(void)
{
	App_USARTl_Init ();
	App_USARTl_Init ();
	
	My_USART_SendString(USART1, "Hello world. \r\n");
	
	while(1)
	{
		//#1.向cNT写0
		TIM_SetCounter (TIM1,0);
		
		//#2.清除cc1和cc2标志位
		TIM_ClearFlag (TIM1, TIM_FLAG_CC1);
		TIM_ClearFlag (TIM1, TIM_FLAG_CC2);
		
		//3.开启定时器
		TIM_Cmd (TIM1, ENABLE);
		
		//#4.向RIG引脚发送10us的脉冲
		GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_SET);
		DelayUs (10);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0,Bit_RESET);
		
		//#5.等待测量完成
		while (TIM_GetFlagStatus (TIM1, TIM_FLAG_CC1) ==RESET);
		while (TIM_GetFlagStatus (TIM1, TIM_FLAG_CC2)== RESET);
		
		//#6.关闭定时器
		TIM_Cmd(TIM1,DISABLE);
		
		uint16_t ccr1 = TIM_GetCapture1 (TIM1);
		uint16_t ccr2 = TIM_GetCapture2 (TIM1);
		
		float distance =(ccr2-ccr1) * 1.0e-6f * 340.0f / 2;
		
		My_USART_Printf(USART1, "distance = %.4f\r\n" ,distance);
		
		Delay (100);

	}
}

void App_USARTl_Init (void)
{
	//#1.初始化Io引脚
	GPIO_InitTypeDef GPIO_InitStruct;
	
	// PA9 AF PP Tx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//PA10 IPU Rx
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init (GPIOA, &GPIO_InitStruct);
	
	//#2.初始化UsART1
	//#2.1开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//#2.2初始化USART1的参数
	USART_InitTypeDef USART_InitStruct;
	
	USART_InitStruct.USART_BaudRate = 115200;
	USART_InitStruct.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_Init (USART1, &USART_InitStruct);
	
	//#2.3闭合总开关
	USART_Cmd(USART1,ENABLE);
}

void App_HCSR04_Init (void)
{
	//#1.初始化时基单元
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 65535;
	TIM_TimeBaseInitStruct.TIM_Prescaler = 71;
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
	
	TIM_TimeBaseInit (TIM1, &TIM_TimeBaseInitStruct);
	
	//#2.初始化输入捕获
	//#2.1.初始化Io引脚PA8 IPD
	RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA, &GPIO_InitStruct);
 
	//#2.2.初始化输入捕获的通道1
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
	TIM_ICInitStruct.TIM_ICFilter = 0;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
	
	TIM_ICInit (TIM1, &TIM_ICInitStruct);
	
	//#2.3.初始化输入捕获的通道2
	TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
	TIM_ICInitStruct.TIM_ICFilter = 0;
	TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Falling;
	TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_IndirectTI;
	
	TIM_ICInit (TIM1, &TIM_ICInitStruct);
	
	//.初始化rig引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
}

.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值