经过反复的研究和调试,终于搞好了,所以说,只要静下心,肯于研究,问题就会显得没那么复杂。
博文写之前,先要分析一下硬件的基本构造和样式以及它的工作原理:
样式如图:
说明一下工作过程:
单片机型号:STM32F103VET
1.提供一个10us以上的脉冲
2.模块会自动发出8个40KHz周期电平,并检测回波
要注意这个电平是自动产生的,测试距离远,这个脉宽就宽,与检测距离成正比。
实现步骤:
1.用按键来调用测距功能,后期可以修改成自动循环测距,但循环测距的周期要在60ms以上,不然会有干扰
按键接在PC0口
2.打开串口1(USART1),为了在电脑上用串口调试助手看测试的距离值。
3.打开定时器TIM3,这里设置了5us中断一次,读者也可以用其它定时器完成
4.开外部中断1,映射到PA1口外部中断
这样就差不多了
接线:
按键接在PC0
超声波测距模块,trig接在PA0
超声波测距模块,Echo接在PA1
超声波测距模块,VCC接在5V上
下面看代码,因为代码分的文件比较多。只贴出核心代码:
核心代码如下:
main.c
#include"stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include "key.h"
#include "time.h"
#include "exti.h"
#include "Ultrasonic.h"
int main(void)
{
unsigned int rang = 0;
/*初始化串口*/
delay_init();
key_init_wt();
//TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms
Ultrasonic_config();
EXTI_config();
TIM3_Int_Init(4,71); // 5us
USART1_Config();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
USART1_printf(USART1,"\r\nHello World\r\n");
while(1)
{
if(0 == KEY1)
{
delay_ms(10);
if(0 == KEY1)
{
while(0 == KEY1);
USART1_printf(USART1,"\r\n\r\n");
Ultrasonic_Ranging();
USART1_printf(USART1,"\r\ntime_count=%d\n",time_count);
rang = (unsigned int)(((time_count*0.000005*340)/2)*1000);
USART1_printf(USART1,"\r\nDistance=%d\n",rang);
}
while(0 == KEY1);
}
}
}
time.c
#include "sys.h"
#include "key.h"
unsigned int cnt=0;
//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE ); //失能指定的TIM3中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 8; //从优先级8级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
cnt++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIM3更新中断标志
}
}
exti.c
#include "stm32f10x.h" // Device header
#include "stm32f10x_gpio.h"
#include "Ultrasonic.h"
#include "time.h"
#include "delay.h"
int EXTI_flag=0;
void EXTI_config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // 开启功能复原IO时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_IN_FLOATING; // 浮空输入
GPIO_Init(GPIOA,&GPIO_InitStruct); // 根据GPIO_InitStruct中指定的参数初始化外设GPIOA寄存器
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); // 选择GPIOA管脚的1管脚用作外部中断线
EXTI_InitStruct.EXTI_Line = EXTI_Line1; // 选中外部中断线0
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 设置EXTI线路为中断请求
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 上升沿,下降沿都触发
EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 使能
EXTI_Init(&EXTI_InitStruct); // 根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//选择中断向量 下面很重要
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//响应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
//使能中断向量
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//初始化中断向量配置
NVIC_Init(&NVIC_InitStructure);
}
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)) // 检查指定的EXTI线路触发请求发生与否
{
if(1 == Echo)
{
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //
//USART1_printf(USART1,"\r\nwan\r\n");
//delay_ms(10000);
//EXTI_flag = 1;
}
else
{
TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE);
//USART1_printf(USART1,"\r\ntin\r\n");
//EXTI_flag = 0;
}
EXTI_ClearITPendingBit(EXTI_Line1); // 清除EXTI线路挂起位
}
}
Ultrasonic.c
#include "stm32f10x_gpio.h"
#include "Ultrasonic.h"
#include "delay.h"
#include "time.h"
#include "usart.h"
unsigned int time_count = 0;
void Ultrasonic_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 使能或者失能APB2外设时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
//GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Ultrasonic_Ranging(void)
{
Trig = 0;
delay_us(10); // 10us
Trig = 1;
delay_us(20); // 10us以上的脉冲
Trig = 0;
delay_ms(1000);
USART1_printf(USART1,"cnt = %d\n",cnt);
time_count = cnt;
cnt = 0;
}
精度还是可以的
Demo源码可下载:https://download.csdn.net/download/XiaoCaiDaYong/12039906