找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3384|回复: 0
打印 上一主题 下一主题
收起左侧

STM8L的TIM2捕获之超声波测距

[复制链接]
跳转到指定楼层
楼主
ID:140343 发表于 2016-10-10 00:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
应本订阅号一位读者要求,发布一个超声波的例程.本来打算用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得到的时间为高电平持续时间
   }
}

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表