|
應(yīng)本訂閱號(hào)一位讀者要求,發(fā)布一個(gè)超聲波的例程.本來(lái)打算用STM8L-DISCOVERY板子上的LCD液晶屏顯示測(cè)量到的距離的.昨天寫(xiě)程序時(shí)發(fā)現(xiàn),LCD顯示的一個(gè)IO口和檢測(cè)超聲波回波的捕獲IO都是PB0,而且TIM2的這捕獲IO還不能復(fù)用到其他引腳,只有PB0這一個(gè)IO.所以不能使用LCD顯示了.今天我發(fā)現(xiàn),IAR功能還是很強(qiáng)大的,VIEW菜單下有一個(gè)LIVE WATCH功能,故名思議,就是一個(gè)實(shí)時(shí)顯示變量數(shù)據(jù)的功能,用起來(lái)太爽了,比用屏幕顯示還給力.第一次發(fā)現(xiàn)IAR的這個(gè)功能^_^

本例程,主要是通過(guò)TIM2的捕獲功能,測(cè)量超聲波發(fā)出后,出現(xiàn)的一個(gè)高電平時(shí)間,根據(jù)高電平的時(shí)間和聲速340m/s來(lái)計(jì)算距離.
這里要說(shuō)的是,第一次發(fā)現(xiàn)這個(gè)吃灰好久的超聲波模塊,竟然還有這么一個(gè)奇怪,我以前沒(méi)發(fā)現(xiàn),很方便的功能.就是超聲波模塊收到回波后,ECHO引腳會(huì)產(chǎn)生一個(gè)高電平,這個(gè)高電平的時(shí)間,就是超聲波從發(fā)射到返回的時(shí)間,只要測(cè)量這個(gè)高電平的時(shí)間,然后除2,就可以得到超聲波從發(fā)射處到目標(biāo)處的時(shí)間了.
如下圖,要想讓發(fā)射一次超聲波,只需給TRIG引腳一個(gè)大于10us的高電平,由于這個(gè)模塊是自帶了4M的晶振,所以可以自動(dòng)發(fā)送8個(gè)40KHz的脈沖(這個(gè)模塊的自動(dòng)化程度很高啊!),模塊接收到超聲波回波后,會(huì)在ECHO引腳輸出一個(gè)高電平,這個(gè)高電平的時(shí)間,就是超聲波從發(fā)射到接收的時(shí)間,用起來(lái)很方便.以前學(xué)習(xí)51時(shí),用過(guò)一個(gè)把超聲波做在板子上的開(kāi)發(fā)板,不是外接的模塊,還要自己寫(xiě)程序發(fā)送8個(gè)40KHz的脈沖,還要自己判斷開(kāi)始計(jì)時(shí)時(shí)間……用起來(lái)很麻煩.這個(gè)超聲波模塊的信號(hào)是HC-SR04.

下圖是本例程的實(shí)測(cè)波形,首先讓PC7產(chǎn)生一個(gè)45us的高電平,讓超聲波模塊發(fā)射超聲波,然后會(huì)在PB0引腳產(chǎn)生一個(gè)高電平,如下圖是實(shí)測(cè)的一個(gè)超聲波發(fā)射和接收波形,此時(shí)高電平的時(shí)間是9.6ms,所以超聲波從超聲波模塊到目標(biāo)位置的時(shí)間為9.6ms/2=4.8ms.有了時(shí)間,還有速度340m/s,根據(jù)公式,就可以求出距離34000/1000(cm/ms)*4.8ms=163cm.

看下圖,右側(cè)部分的tmp值就是計(jì)算后的距離,這個(gè)值此刻顯示的為162cm.通過(guò)IAR的這個(gè)Live Watch功能,可以很方便的查看此時(shí)的距離,我用手中的平板,在模塊上方移動(dòng),能夠看到距離數(shù)據(jù)會(huì)隨之改變.

TIM2的捕獲功能配置,和下圖是一樣的,IC1即捕獲通道1配置為在脈沖的上升沿發(fā)生發(fā)生捕獲,將TIM2的計(jì)數(shù)值復(fù)制到TIM2_CCR1寄存器中,同時(shí)計(jì)數(shù)器的值復(fù)位,從0重新開(kāi)始計(jì)數(shù),在脈沖的下降沿捕獲通道2發(fā)生捕獲,將此時(shí)計(jì)數(shù)器的值復(fù)制到TIM2_CCR2寄存器,此值為高電平脈沖時(shí)間.


/*硬件連接*/
//PC7 ---->TRIG
// PB0<----ECHO
/****************************************************************************************
*開(kāi)發(fā)環(huán)境:IAR for stm8 v6.5.3
*硬件平臺(tái):STM8L-DISCOVERY
*功能說(shuō)明:本例程,
*作 者:茗風(fēng)
****************************************************************************************/
#include"iostm8l152c6.h"
#include"stdint.h"
#include"stdbool.h"
uint16_t tim2_ccr1=0,tim2_ccr2=0;
bool bFinish_Flag=false;
#define a 0x01
#define b 0x02
#define c 0x04
#define d 0x08
#define e 0x10
#define f 0x20
#define g 0x40
#define m 0x80
/******************************************************************************************************
* 名 稱(chēng):void GPIO_Init(void)
* 功 能:初始化PC7為高速推挽輸出
* 入口參數(shù):無(wú)
* 出口參數(shù):無(wú)
* 說(shuō) 明:
* 范 例:無(wú)
******************************************************************************************************/
void GPIO_Config(void)
{
PC_CR1_C17 =1;//推挽輸出
PC_CR2_C27 =1;//高速輸出
PC_DDR_DDR7 =1;//PC7輸出
PC_ODR_ODR7 =0;//輸出低電平
}
/******************************************************************************************************
* 名 稱(chēng):void delay(void)
* 功 能:延時(shí)
* 入口參數(shù):無(wú)
* 出口參數(shù):無(wú)
* 說(shuō) 明:系統(tǒng)頻率為3M時(shí),理論計(jì)算延時(shí)時(shí)間為78ms
* 范 例:無(wú)
******************************************************************************************************/
void delay(void)
{
uint8_t i=255,j;
while(i--)//255*1.2+255*1.2*255
{
for(j=0;j<255;j++);
}
}
/******************************************************************************************************
* 名 稱(chēng):void CLOCK_Init(void)
* 功 能:系統(tǒng)時(shí)鐘切換為HSE,12M/4=3M
* 入口參數(shù):無(wú)
* 出口參數(shù):無(wú)
* 說(shuō) 明:
* 范 例:無(wú)
******************************************************************************************************/
void CLOCK_Config(void)
{
CLK_CKDIVR =0x2;//分頻值為4
/*000: System clock source/1
001: System clock source /2
010: System clock source /4
011: System clock source /8
100: System clock source /16
101: System clock source /32
110: System clock source /64
111: System clock source /128*/
//自動(dòng)切換
CLK_SWCR_SWEN =1;//允許切換時(shí)鐘
CLK_SWR =0x04;//寫(xiě)入一個(gè)八位的值,用于選擇目標(biāo)時(shí)鐘源
while(CLK_SWCR_SWBSY);//等待時(shí)鐘切換完成
//手動(dòng)切換
// CLK_SWR =0x08;//寫(xiě)入一個(gè)八位的值,用于選擇目標(biāo)時(shí)鐘源
// while(!CLK_ECKR_LSERDY);//等待目標(biāo)時(shí)鐘源穩(wěn)定
// CLK_SWCR_SWEN =1;//允許切換時(shí)鐘
/*
*0x01:HSI selected as system clock source
*0x02:LSI selected as system clock source
*0x04:HSE selected as system clock source
*0x08:LSE selected as system clock source
*/
}
/******************************************************************************************************
* 名 稱(chēng):void TIM2_Config(void)
* 功 能:STM8定時(shí)器2捕獲功能初始化
* 入口參數(shù):無(wú)
* 出口參數(shù):無(wú)
* 說(shuō) 明:PB0為捕獲輸入引腳,使用通道0
* 范 例:無(wú)
******************************************************************************************************/
void TIM2_Config(void)
{
PB_DDR_DDR0 =0;//輸入
PB_CR1_C10 =0;//浮空輸入
// PB_CR1_C10 =1;//上拉輸入
PB_CR2_C20 =0;//禁止外部中斷功能
CLK_PCKENR1_PCKEN10=1;//打開(kāi)定時(shí)器2時(shí)鐘
//------設(shè)置TIM2時(shí)鐘分頻值------
//我的電路板上,HSE接的是12M,四分頻后為3M
//正常情況應(yīng)該接16M,這樣分頻后不會(huì)出現(xiàn)3M這樣不利于計(jì)算時(shí)間的頻率
TIM2_PSCR_PSC=0;//分頻值 3M/2^0=3M/1=3000000Hz
//-重裝值,TIM2從0計(jì)數(shù)到此值,發(fā)生溢出-
// TIM2_ARRH=0;
// TIM2_ARRL=100;
//----AUTO_RELOAD 預(yù)裝載使能----
TIM2_CR1_ARPE =0;//不通過(guò)預(yù)裝載寄存器
TIM2_CR1_URS=1;//僅當(dāng)計(jì)數(shù)器溢出時(shí)才發(fā)生中斷請(qǐng)求
TIM2_CR1_UDIS=1;//禁止更新事件//計(jì)數(shù)器溢出屬于更新事件
TIM2_CR1_DIR=0;//向上計(jì)數(shù)
// TIM2_CCER1_CC1E=0;//清零使能位,為了配置寄存器
// TIM2_CCER1_CC2E=0;//清零使能位,為了配置寄存器
TIM2_CCMR1=0;
// TIM2_CCMR1=0x00; //IC1F=0000 輸入信號(hào)不分頻
TIM2_CCMR1 |=0x01;//CC1S=01 IC1 is mapped on TI1FP1
/*00: CC1 channel is configured as output
01: CC1 channel is configured as input, IC1 is mapped on TI1FP1
10: CC1 channel is configured as input, IC1 is mapped on TI2FP1
11: Reserved */
TIM2_CCMR2=0;
// TIM2_CCMR2=0x00;//IC1PSC=0 輸入信號(hào)不分頻
TIM2_CCMR2 |=0x02;// TIM2_CCMR2_CC2S=0x2
/* 00: CC2 channel is configured as output
01: CC2 channel is configured as input, IC2 is mapped on TI2FP2
10: CC2 channel is configured as input, IC2 is mapped on TI1FP2
11:CC2 channel is configured as input, IC2 is mapped on TRC */
TIM2_CCER1_CC1P=0;//上升沿時(shí)發(fā)生捕獲
TIM2_CCER1_CC2P=1;//下降沿時(shí)發(fā)生捕獲
TIM2_SMCR=0x54;//
// TIM2_SMCR_TS=0x05;//101 iput 1(TI1FP1) 頭文件有錯(cuò)誤
// TIM2_SMCR_SMS=0x04;//復(fù)位觸發(fā)模式
TIM2_CCER1_CC1E=1;//使能捕獲功能
TIM2_CCER1_CC2E=1;//使能捕獲功能
TIM2_IER_CC1IE=1;//開(kāi)啟捕獲中斷
TIM2_IER_CC2IE=1;//開(kāi)啟捕獲中斷
TIM2_CR1_CEN=1;//開(kāi)啟計(jì)數(shù)
}
void main(void)
{
static uint16_t tmp=0;
uint8_t cnts=0;
CLOCK_Config();//系統(tǒng)時(shí)鐘切換為HSE(12MHz/4=3MHz)
GPIO_Config();//超生波觸發(fā)引腳
// LCD_Config();
TIM2_Config();
asm("rim"); //enable interrupts
while(1)
{
PC_ODR_ODR7 =1;//保證最短10us的低電平
for(cnts=15;cnts>0;cnts--);
PC_ODR_ODR7 =0;
for(cnts=2;cnts>0;cnts--)
{
delay();
}
if(bFinish_Flag==true)
{
//1000000us/3000000=0.33us
//340(m/s)=34/1000(cm/us)=0.034cm/us
tmp=(float)tim2_ccr2*0.3333*0.017;
bFinish_Flag=false;
}
// asm("wfi");
}
}
#pragma vector=TIM2_CAPCOM_CC1IF_vector
__interrupt void TIM2_CAPCOM_CC1IF_ISR(void)
{
if(TIM2_SR1_CC1IF==1)
{
TIM2_SR1_CC1IF=0;//清除中斷標(biāo)志位
// tim2_ccr1=TIM2_CCR1H;
// tim2_ccr1<<=8;
// tim2_ccr1+=TIM2_CCR1L;
}
if(TIM2_SR1_CC2IF==1)
{
TIM2_SR1_CC2IF=0;//清除中斷標(biāo)志位
tim2_ccr2=TIM2_CCR2H;
tim2_ccr2<<=8;
tim2_ccr2+=TIM2_CCR2L;
bFinish_Flag=true;
//tim2_ccr2得到的時(shí)間為高電平持續(xù)時(shí)間
}
}
|
|