經過反覆的研究和調試,終於搞好了,所以說,只要靜下心,肯於研究,問題就會顯得沒那麼複雜。
博文寫之前,先要分析一下硬件的基本構造和樣式以及它的工作原理:
樣式如圖:
工作原理(很重要):
說明一下工作過程:
單片機型號:STM32F103VET
1.提供一個10us以上的脈衝
2.模塊會自動發出8個40KHz週期電平,並檢測回波
3.等待輸出迴響信號,
要注意這個電平是自動產生的,測試距離遠,這個脈寬就寬,與檢測距離成正比。
實現步驟:
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