cs
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "buzzer.h"
#include "key.h"
#include "Relay.h"
#include "Shake.h"
#include "Exti.h"
#include "usart.h"
#include "stdio.h"
#include "Time.h"
void delay(uint16_t time)
{
uint16_t i = 0;
while(time --)
{
i = 12000;
while(i --);
}
}
int main()
{
led_init();
Base_Time_Init();
while(1)
{
}
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
delay(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
3.控制超声波测距步骤
- 初始化超声波引脚和定时器时钟
- 初始化引脚模式和定时器中断
- 编写定时器中断函数测距
获取距离:
- Trig引脚输出高电平10us
- 定时器计算Trig引脚的高电平时间 高电平时间=中断次数+不足一次中断的次数
- 时间换算成距离
- 串口打印距离
time.h
cs
#ifndef _TIME_H
#define _TIME_H
void Base_Time_Init(void);
void HC_SR04_Init(void);
void Open_Tim(void);
void Close_Tim(void);
int Get_Echo_Tim(void);
float Get_Length(void);
#endif
time.c
cs
#include "Time.h"
#include "stm32f10x.h"
void delay_us(uint32_t us)
{
us *= 8;
while(us--);
}
void delay_ms(uint32_t ms)
{
while(ms--)
{
delay_us(1000);
}
}
int tim_count;
void Base_Time_Init(void)
{
TIM_TimeBaseInitTypeDef Time_Initstructure;
NVIC_InitTypeDef NVIC_Initstructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
Time_Initstructure.TIM_ClockDivision = TIM_CKD_DIV1;
Time_Initstructure.TIM_CounterMode = TIM_CounterMode_Up;
Time_Initstructure.TIM_Period = 1000-1;
Time_Initstructure.TIM_Prescaler = 72-1;
Time_Initstructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&Time_Initstructure);
TIM_Cmd(TIM2,DISABLE);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_Initstructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initstructure.NVIC_IRQChannelSubPriority =0;
NVIC_Init(&NVIC_Initstructure);
}
void HC_SR04_Init(void)
{
GPIO_InitTypeDef GPIO_Initstructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//Trig B11
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB,&GPIO_Initstructure);
//Echo B10
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOB,&GPIO_Initstructure);
}
void Open_Tim()
{
TIM_SetCounter(TIM2, 0);
tim_count = 0;
TIM_Cmd(TIM2,ENABLE);
}
void Close_Tim()
{
TIM_Cmd(TIM2,DISABLE);
}
//获取定时器中断次数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
tim_count++;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
//获取总的高电平时间
int Get_Echo_Tim()
{
uint16_t sum_tim;
sum_tim = tim_count * 1000 ;
sum_tim += TIM_GetCounter(TIM2);
TIM_SetCounter(TIM2, 0);
delay_ms(50);
return sum_tim;
}
float Get_Length(void)
{
uint16_t time = 0;
float length;
int i = 0;
float sum = 0;
while(i != 5)
{
//hc_sr04 work
GPIO_SetBits(GPIOB,GPIO_Pin_11);
delay_us(20);
GPIO_ResetBits(GPIOB,GPIO_Pin_11);
//定时器计算高电平时间
while( GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_10) == 0); //等待echo引脚低电平到高电平的跳变
Open_Tim();
while( GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_10) == 1);
Close_Tim();
//时间换算距离
time = Get_Echo_Tim();
length = ((float)time/58.0) ;
sum += length;
i++;
}
length = sum/5.0;
return length;
}
注:
1.1ms = 1000us = 1000 000ns
2.高电平时间=中断次数+不足一次中断的次数
- 中断次数用定时器中断函数来计算
- 不足一次中断的次数,用CNT计数器中记得次数
所以这里,设置预分频系数为72hz,自动重装载寄存器设为1000,此时定时器每1ms触发一事件,即计数器每计1000个数为1ms,每记一个数为1us
3.获取总的定时器时间完之后,要把CNT计数器清0
而且要延时等待50ms,寄存器写入是需要时间的,在连续测量之间添加间隔
这样既能保证模块正常工作,又能提高代码效率和可读性
4.打开定时器的时候,最好把CNT计数器和全局变量都清0
5.length = ((float)time/58.0) ;
6.最后取五次的平均值
mian
cs
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "buzzer.h"
#include "key.h"
#include "Relay.h"
#include "Shake.h"
#include "Exti.h"
#include "usart.h"
#include "stdio.h"
#include "Time.h"
void delay(uint16_t time)
{
uint16_t i = 0;
while(time --)
{
i = 12000;
while(i --);
}
}
int main()
{
float length;
led_init();
my_usart_init();
Base_Time_Init();
HC_SR04_Init();
while(1)
{
length = Get_Length();
printf("%lf\r\n",length);
}
}