一:超聲波模塊
1:工作原理
采用IO觸發測距,給至少10us的高電平信號。
模塊自動發送8個40KHz的方波,自動檢測是否有信號返回。
·有信號返回,通過IO輸出一高電平,高電平持續時間就是超聲波從發射到返回的時間聲波從發射到返回的時間
· HC-SRO4超聲波測距模塊提供2cm-400cm的測距功能,精度達3mm。
2.硬件接線
四根杜邦線,VCC連接單片機3.3-5V (推薦5V供電),GND接到板子的GND, Trig 為外部觸發信號輸入,輸入一個10us的高電平即可觸發模塊測距,Echo即為 回響信號輸出,測距結束時此管引腳輸出一個低電平,電平寬度反映超聲主返時間之和。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3.控制超聲波測距步驟
初始化超聲波引腳和定時器時鐘·? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 初始化引腳模式和定時器中斷
Tim.c
#include "stm32f10x.h"
#include "Tim.h"uint16_t mountus;void delay_us(uint32_t us)
{us *=8;while(us--);}void delay_ms(uint32_t ms)
{while(ms--){delay_us(1000);}}void Base_Tim_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;NVIC_InitTypeDef NVIC_Initstruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);TIM_TimeBaseInitstruct.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInitstruct.TIM_CounterMode=TIM_CounterMode_Up ;TIM_TimeBaseInitstruct.TIM_Period=1000-1;TIM_TimeBaseInitstruct.TIM_Prescaler=72-1;TIM_TimeBaseInitstruct.TIM_RepetitionCounter=0;TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitstruct);TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE);TIM_Cmd(TIM2, DISABLE);NVIC_Initstruct.NVIC_IRQChannel=TIM2_IRQn ;NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority=0;NVIC_Initstruct.NVIC_IRQChannelSubPriority=0;NVIC_Initstruct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_Initstruct);}void HC04_Init()
{GPIO_InitTypeDef GPIO_Initstruct;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,ENABLE);GPIO_Initstruct.GPIO_Pin= GPIO_Pin_11;GPIO_Initstruct.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Initstruct.GPIO_Speed=GPIO_Speed_10MHz;GPIO_Init( GPIOB, &GPIO_Initstruct);GPIO_Initstruct.GPIO_Pin=GPIO_Pin_10;GPIO_Initstruct.GPIO_Mode= GPIO_Mode_IPD;GPIO_Init( GPIOB, &GPIO_Initstruct);}void open_Tim()
{mountus=0;TIM_SetCounter( TIM2,0);TIM_Cmd(TIM2, ENABLE);}void close_Tim()
{TIM_Cmd(TIM2, DISABLE);}void TIM2_IRQHandler ()
{if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){mountus++;TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}}int Get_Echo_Time()
{uint16_t t=0;t=mountus*1000;t=t+TIM_GetCounter(TIM2);TIM_SetCounter( TIM2,0);delay_ms(50);return t;}float Get_Length()
{int i=0;float sum=0;uint16_t t=0;float length=0;while(i<5){ GPIO_SetBits(GPIOB,GPIO_Pin_11);delay_us(20);GPIO_ResetBits(GPIOB,GPIO_Pin_11);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == RESET );open_Tim();i++;while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == SET );close_Tim();t=Get_Echo_Time();length=((float)t/58.0);sum=sum+length;}length=sum/5.0;return length;}
Tim.h
#ifndef _TIM_H_
#define _TIM_H_void Base_Tim_Init(void);
void HC04_Init(void);
float Get_Length(void);#endif
main.c
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "Bear.h"
#include "key.h"
#include "relay.h"
#include "shake.h"
#include "wireless.h"
#include "exti_key.h"
#include "usart.h"
#include "stdio.h"
#include "Tim.h"void delay(uint16_t time)//延時1ms 軟件延時粗延時
{uint16_t i=0;while(time --){i=12000;while(i --);}}int main()
{float length=0;LED_Init();Base_Tim_Init();HC04_Init();my_usart_Init();while(1){length = Get_Length();printf("%lf\r\n",length );}}
代碼心得
1:
定時器中斷工作機制
定時器配置:
在您的代碼中,TIM2配置為1MHz計數頻率(72MHz主頻/72分頻)
自動重裝載值1000 → 每1ms(1000μs)產生一次更新中斷
每1ms觸發一次中斷,與高電平持續時間無關
中斷頻率由定時器配置決定,不是由外部信號決定
2
為什么需要延遲?
1:
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));/* Set the Counter Register value */TIMx->CNT = Counter;
}
實際上這個函數是對一個寄存器進行了賦值,所以我們需要一定的時間去讓寄存器賦值,這個就是他的作用,我們這里用了50ms,就是充分讓 寄存器賦值 這個步驟可以完成!
在原始代碼中:
c
int Get_Echo_Time() {t = mountus*1000 + TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);delay_ms(50); // 關鍵延遲return t; }
這個延遲解決了兩個問題:
傳感器恢復時間:
HC-SR04需要50-60ms的恢復周期
連續測量會導致傳感器無法響應
中斷沖突預防:
重置定時器(
TIM_SetCounter(0)
)和mountus=0
操作需要時間無延遲時,下次測量可能打斷重置過程
3總結代碼
定時器中斷由定時器硬件觸發,與Echo引腳狀態無關
mountus
記錄的是時間流逝(每1ms增加),不是信號事件高電平期間定時器持續運行,通過:
中斷次數(
mountus
) → 完整毫秒數當前計數值 → 亞毫秒時間
延遲50ms解決了傳感器恢復和操作原子性問題
最佳實踐:用中斷保護替代延遲,并在主循環中管理傳感器時序
1. 基本概念對比
數據類型 | 符號 | 位寬 | 范圍 | 頭文件 |
---|---|---|---|---|
int | 有符號 | 32位 | -2,147,483,648 到 2,147,483,647 | 內置 |
uint16_t | 無符號 | 16位 | 0 到 65,535 | #include <stdint.h> |
uint32_t | 無符號 | 32位 | 0 到 4,294,967,295 | #include <stdint.h> |