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

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

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

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

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


/*硬件連接*/
//PC7 ---->TRIG
// PB0<----ECHO
/****************************************************************************************
*開發環境:IAR for stm8 v6.5.3
*硬件平臺:STM8L-DISCOVERY
*功能說明:本例程,
*作 者:茗風
****************************************************************************************/
#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
/******************************************************************************************************
* 名 稱:void GPIO_Init(void)
* 功 能:初始化PC7為高速推挽輸出
* 入口參數:無
* 出口參數:無
* 說 明:
* 范 例:無
******************************************************************************************************/
void GPIO_Config(void)
{
PC_CR1_C17 =1;//推挽輸出
PC_CR2_C27 =1;//高速輸出
PC_DDR_DDR7 =1;//PC7輸出
PC_ODR_ODR7 =0;//輸出低電平
}
/******************************************************************************************************
* 名 稱:void delay(void)
* 功 能:延時
* 入口參數:無
* 出口參數:無
* 說 明:系統頻率為3M時,理論計算延時時間為78ms
* 范 例:無
******************************************************************************************************/
void delay(void)
{
uint8_t i=255,j;
while(i--)//255*1.2+255*1.2*255
{
for(j=0;j<255;j++);
}
}
/******************************************************************************************************
* 名 稱:void CLOCK_Init(void)
* 功 能:系統時鐘切換為HSE,12M/4=3M
* 入口參數:無
* 出口參數:無
* 說 明:
* 范 例:無
******************************************************************************************************/
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*/
//自動切換
CLK_SWCR_SWEN =1;//允許切換時鐘
CLK_SWR =0x04;//寫入一個八位的值,用于選擇目標時鐘源
while(CLK_SWCR_SWBSY);//等待時鐘切換完成
//手動切換
// CLK_SWR =0x08;//寫入一個八位的值,用于選擇目標時鐘源
// while(!CLK_ECKR_LSERDY);//等待目標時鐘源穩定
// CLK_SWCR_SWEN =1;//允許切換時鐘
/*
*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
*/
}
/******************************************************************************************************
* 名 稱:void TIM2_Config(void)
* 功 能:STM8定時器2捕獲功能初始化
* 入口參數:無
* 出口參數:無
* 說 明:PB0為捕獲輸入引腳,使用通道0
* 范 例:無
******************************************************************************************************/
void TIM2_Config(void)
{
PB_DDR_DDR0 =0;//輸入
PB_CR1_C10 =0;//浮空輸入
// PB_CR1_C10 =1;//上拉輸入
PB_CR2_C20 =0;//禁止外部中斷功能
CLK_PCKENR1_PCKEN10=1;//打開定時器2時鐘
//------設置TIM2時鐘分頻值------
//我的電路板上,HSE接的是12M,四分頻后為3M
//正常情況應該接16M,這樣分頻后不會出現3M這樣不利于計算時間的頻率
TIM2_PSCR_PSC=0;//分頻值 3M/2^0=3M/1=3000000Hz
//-重裝值,TIM2從0計數到此值,發生溢出-
// TIM2_ARRH=0;
// TIM2_ARRL=100;
//----AUTO_RELOAD 預裝載使能----
TIM2_CR1_ARPE =0;//不通過預裝載寄存器
TIM2_CR1_URS=1;//僅當計數器溢出時才發生中斷請求
TIM2_CR1_UDIS=1;//禁止更新事件//計數器溢出屬于更新事件
TIM2_CR1_DIR=0;//向上計數
// TIM2_CCER1_CC1E=0;//清零使能位,為了配置寄存器
// TIM2_CCER1_CC2E=0;//清零使能位,為了配置寄存器
TIM2_CCMR1=0;
// TIM2_CCMR1=0x00; //IC1F=0000 輸入信號不分頻
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 輸入信號不分頻
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;//上升沿時發生捕獲
TIM2_CCER1_CC2P=1;//下降沿時發生捕獲
TIM2_SMCR=0x54;//
// TIM2_SMCR_TS=0x05;//101 iput 1(TI1FP1) 頭文件有錯誤
// TIM2_SMCR_SMS=0x04;//復位觸發模式
TIM2_CCER1_CC1E=1;//使能捕獲功能
TIM2_CCER1_CC2E=1;//使能捕獲功能
TIM2_IER_CC1IE=1;//開啟捕獲中斷
TIM2_IER_CC2IE=1;//開啟捕獲中斷
TIM2_CR1_CEN=1;//開啟計數
}
void main(void)
{
static uint16_t tmp=0;
uint8_t cnts=0;
CLOCK_Config();//系統時鐘切換為HSE(12MHz/4=3MHz)
GPIO_Config();//超生波觸發引腳
// 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;//清除中斷標志位
// tim2_ccr1=TIM2_CCR1H;
// tim2_ccr1<<=8;
// tim2_ccr1+=TIM2_CCR1L;
}
if(TIM2_SR1_CC2IF==1)
{
TIM2_SR1_CC2IF=0;//清除中斷標志位
tim2_ccr2=TIM2_CCR2H;
tim2_ccr2<<=8;
tim2_ccr2+=TIM2_CCR2L;
bFinish_Flag=true;
//tim2_ccr2得到的時間為高電平持續時間
}
}
|