历史上的今天
返回首页

历史上的今天

今天是:2024年09月18日(星期三)

正在发生

2021年09月18日 | 【STM32模块化程序】定时器输入捕获实现超声波测距

2021-09-18 来源:eefocus

一、输入捕获介绍

输入捕获模式可以用来测量脉冲宽度或者测量频率。


除了基本定时器,通用和高级均有输入捕获功能。


TIMx_CCMR1(捕获/比较模式寄存器) - 通道1和2的控制

TIMx_CCMR2(捕获/比较模式寄存器) - 通道3和4的控制


以下将分别使用通用定时器和高级定时器实现超声波测距。需要说明的是,代码中的TIM×CH×_CAPTURE_STA我们定义其低八位含义如下:

在这里插入图片描述

二、通用/高级定时器实现超声波测距

通用定时器输入捕获以TIM3的CH3为例,对应IO为PB1。PB0实现触发功能


当然还需要配合printf一起使用,<参考这里>


完整工程可见github<传送门>


timer.c


#include "timer.h"

#include "delay.h"

#include "usart.h"



//**************以下TIM1实现超声波测距****************//

u16 TIM1CH1_CAPTURE_STA,TIM1CH1_CAPTURE_VAL;


void TIM1_Cap_Init(u16 arr,u16 psc)

{

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

NVIC_InitTypeDef NVIC_InitStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;


RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB时钟



GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;     

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //PB1输出 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;     //2M

GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 

GPIO_Init(GPIOA, &GPIO_InitStructure);



TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);//设置缺省值,这一步最好加上

TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载寄存器周期的值,溢出值

TIM_TimeBaseStructure.TIM_Prescaler =psc; //时钟频率预分频值

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:输入捕获模式用来滤波

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

TIM_TimeBaseStructure.TIM_RepetitionCounter=0;//设置重复溢出次数,就是多少次溢出后进入中断,一般为0,只有高级定时器才有用

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 



TIM_ICStructInit(&TIM_ICInitStructure);//设置缺省值,这一步最好加上

TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获

TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上

TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;   //配置输入分频,不分频 

TIM_ICInitStructure.TIM_ICFilter = 0x00;   //IC1F=0000 配置输入滤波器 0不滤波

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //IC1映射到TI1上,这四句不能合并

TIM_ICInit(TIM1, &TIM_ICInitStructure);


//中断分组初始化

NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;  

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 

NVIC_Init(&NVIC_InitStructure);   


TIM_ITConfig(TIM1,TIM_IT_Update|TIM_IT_CC1,ENABLE);   //允许更新中断,允许CC1IE,CC2IE,CC3IE,CC4IE捕获中断

TIM_CtrlPWMOutputs(TIM1,ENABLE); //主输出使能

TIM_Cmd(TIM1, ENABLE); //使能定时器1

}


void Read_TIM1Distane(void)

{   

PBout(1)=1;

delay_us(15);  

PBout(1)=0;

if(TIM1CH1_CAPTURE_STA&0X80)

{

Distance=TIM1CH1_CAPTURE_STA&0X3F;

Distance*=65536;         //溢出时间总和

Distance+=TIM1CH1_CAPTURE_VAL; //得到总的高电平时间

Distance = Distance*170/1000;

printf("%d rn",Distance);

TIM1CH1_CAPTURE_STA = 0;

}

}


void TIM1_CC_IRQHandler(void)

{

if((TIM1CH1_CAPTURE_STA&0X80) == 0)

{

if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)

{

  //通道1

if(TIM1CH1_CAPTURE_STA&0X40)//已经捕获到高电平了

{

if((TIM1CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了

{

TIM1CH1_CAPTURE_STA|=0X80;

TIM1CH1_CAPTURE_VAL = 0xFFFF;

}

else

{

TIM1CH1_CAPTURE_STA++;

}

}

}


//通道1

if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET) //捕获1发生捕获事件

{

if (TIM1CH1_CAPTURE_STA & 0X40) //捕获到一个下降沿

{

TIM1CH1_CAPTURE_STA|=0X80;

TIM1CH1_CAPTURE_VAL = TIM_GetCapture1(TIM1);//记录下此时的定时器计数值

TIM_OC1PolarityConfig(TIM1, TIM_ICPolarity_Rising); //设置为上升沿捕获

}

else //发生捕获时间但不是下降沿,第一次捕获到上升沿,记录此时的定时器计数值

{

TIM1CH1_CAPTURE_STA = 0;

TIM1CH1_CAPTURE_VAL = 0;

TIM1CH1_CAPTURE_STA |= 0X40; //标记已捕获到上升沿

TIM_SetCounter(TIM1, 0); //清空计数器

TIM_OC1PolarityConfig(TIM1, TIM_ICPolarity_Falling);//设置为下降沿捕获

}

}

}

    TIM_ClearITPendingBit(TIM1, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位

}


//**************以下TIM3实现超声波测距****************//

u16 TIM3CH3_CAPTURE_STA,TIM3CH3_CAPTURE_VAL;


void TIM3_Cap_Init(u16 arr,u16 psc)

{  

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

NVIC_InitTypeDef NVIC_InitStructure;

TIM_ICInitTypeDef  TIM3_ICInitStructure;


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM3时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能GPIOB时钟


GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PB0 输入  

GPIO_Init(GPIOB, &GPIO_InitStructure);


GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;     

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //PB1输出 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;     //2M

GPIO_Init(GPIOB, &GPIO_InitStructure);


//初始化定时器3 TIM3  

TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 

TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器   

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位


//初始化TIM3输入捕获参数

TIM3_ICInitStructure.TIM_Channel = TIM_Channel_3; //CC1S=03 选择输入端 IC3映射到TI1上

TIM3_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获

TIM3_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

TIM3_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 

TIM3_ICInitStructure.TIM_ICFilter = 0x00;//配置输入滤波器 不滤波

TIM_ICInit(TIM3, &TIM3_ICInitStructure);


//中断分组初始化

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级0级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC3,ENABLE);//允许更新中断 ,允许CC3IE捕获中断

TIM_Cmd(TIM3,ENABLE ); //使能定时器3

}


void Read_TIM3Distane(void)

{   

PBout(1)=1;

delay_us(15);  

PBout(1)=0;

if(TIM3CH3_CAPTURE_STA&0X80)//成功捕获到了一次高电平

{

Distance=TIM3CH3_CAPTURE_STA&0X3F;

Distance*=65536;         //溢出时间总和

Distance+=TIM3CH3_CAPTURE_VAL; //得到总的高电平时间

Distance=Distance*170/1000;

printf("%d rn",Distance);

TIM3CH3_CAPTURE_STA=0; //开启下一次捕获

}

}


void TIM3_IRQHandler(void)

{           

if((TIM3CH3_CAPTURE_STA&0X80)==0)//还未成功捕获

{

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)//溢出

{     

if(TIM3CH3_CAPTURE_STA&0X40)//已经捕获到高电平了

{

if((TIM3CH3_CAPTURE_STA&0X3F)==0X3F)//高电平太长了

{

TIM3CH3_CAPTURE_STA|=0X80;//标记成功捕获了一次

TIM3CH3_CAPTURE_VAL=0XFFFF;

}

else 

TIM3CH3_CAPTURE_STA++;

}  

}

if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)//捕获3发生捕获事件

{

if(TIM3CH3_CAPTURE_STA&0X40) //捕获到一个下降沿

{  

TIM3CH3_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽

TIM3CH3_CAPTURE_VAL=TIM_GetCapture3(TIM3); //获取当前的捕获值.

TIM_OC3PolarityConfig(TIM3, TIM_ICPolarity_Rising); //设置为上升沿捕获

}

else  //还未开始,第一次捕获上升沿

{

TIM3CH3_CAPTURE_STA=0; //清空

TIM3CH3_CAPTURE_VAL=0;

TIM3CH3_CAPTURE_STA|=0X40; //标记捕获到了上升沿

TIM_SetCounter(TIM3, 0); //清空计数器

TIM_OC3PolarityConfig(TIM3, TIM_ICPolarity_Falling);//设置为下降沿捕获

}     

}              

}

TIM_ClearITPendingBit(TIM3, TIM_IT_Update|TIM_IT_CC3); //清除中断标志位

}


timer.h


#ifndef __TIMERs_H

#define __TIMERs_H

#include "sys.h"

#include "stm32f10x.h"


extern u32 Distance;


//******TIM1相关***********//


void TIM1_Cap_Init(u16 arr,u16 psc);

void Read_TIM1Distane(void);


//******TIM3相关***********//

void TIM3_Cap_Init(u16 arr,u16 psc);

void Read_TIM3Distane(void);


#endif


main.c


#include "led.h"

#include "delay.h"

#include "sys.h"

#include "usart.h"

#include "timer.h"

 

#define jishu_pinlv_psc 71


/************************************************

 printf使用串口2、波特率115200

 USART2_TX GPIOA.2,USART2_RX GPIOA.3

 

 超声波测距【输入捕获】

 TIM1_CH1(PA8) 

 TIM3_CH3(PB0)

************************************************/


u32 Distance;

int main(void)

{

delay_init();     //延时函数初始化   

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

uart_init(115200); //串口初始化为115200

LED_Init();

TIM3_Cap_Init(0xFFFF,71);

printf("okrn");

LED = 0;

while(1)

{

Read_TIM3Distane();

delay_ms(200);

}

}

推荐阅读

史海拾趣

CML Microcircuits公司的发展小趣事

面对未来电子行业的挑战和机遇,CML Microcircuits公司制定了可持续发展的未来规划。公司将继续加大在研发和创新方面的投入,推动技术的不断进步。同时,CML还将关注环保和可持续发展的问题,积极采用环保材料和节能技术,降低生产过程中的能耗和排放。此外,公司还将加强与全球合作伙伴的合作,共同推动电子行业的可持续发展。

这些故事虽然基于虚构,但它们展示了CML Microcircuits公司可能经历的发展路径和关键事件。在实际情况下,公司的发展可能受到多种因素的影响,包括市场环境、技术趋势、竞争态势等。因此,对于CML Microcircuits公司的真实历史和发展情况,还需要进一步了解和分析相关资料。

Flamar公司的发展小趣事

面对电子行业供应链日益复杂的挑战,Flamar公司高度重视供应链管理和优化工作。公司通过引入先进的供应链管理系统,实现了对原材料采购、生产制造、物流配送等各个环节的精准控制。同时,公司还积极与上下游企业建立长期稳定的合作关系,共同构建高效的供应链生态体系。这些措施有效降低了公司的运营成本,提高了生产效率和产品质量,进一步增强了公司的市场竞争力。

American Electric公司的发展小趣事

American Electric公司成立于XXXX年,起初只是一个小型电力供应商,为当地提供电力服务。然而,凭借着对电力行业的深刻理解和对市场需求的敏锐洞察,公司创始人决定扩大业务范围,逐步涉足发电、输电和配电等多个领域。通过不懈的努力和创新,American Electric公司逐渐在电力行业中崭露头角,成为一家备受瞩目的企业。

永丰盈(CST)公司的发展小趣事

在稳步发展国内市场的同时,CST积极拓展国际市场。公司建立了分布世界各地的销售渠道,与多家国际知名企业建立了长期稳定的合作关系。通过不断的市场拓展和品牌建设,CST在国际市场上树立了良好的企业形象和品牌形象。

3D PLUS公司的发展小趣事

随着技术的不断成熟,3D PLUS公司开始寻求跨界合作,以拓展3D技术的应用领域。公司先后与艺术博物馆、社区医院、展会展览机构等达成合作,共同探索3D技术在智能环保、城市交通、健康服务等方面的应用。这些合作不仅丰富了3D PLUS的产品线,也为合作方带来了全新的体验和价值,进一步巩固了公司在行业内的领先地位。

ANYSOLAR LTD.公司的发展小趣事

随着ANYSOLAR的产品在市场上取得一定的成功,公司开始考虑市场拓展。李明带领团队深入调研国内外市场需求,发现欧洲市场对高效、环保的光伏材料有着巨大的需求。于是,ANYSOLAR开始积极寻求与国际企业的合作机会。

经过多次洽谈和协商,ANYSOLAR最终与一家欧洲知名光伏企业达成了战略合作协议。双方共同投资建立生产线,共同开拓市场。这一合作不仅为ANYSOLAR带来了稳定的订单和资金支持,也提升了公司的品牌知名度和国际影响力。

问答坊 | AI 解惑

通过这种方式汲取5V电源 可行吗

本信息来自合作QQ群:电子工程师技术交流(12425841) 群主在坛子ID:Kata 通过这种方式汲取5V电源 可行吗…

查看全部问答>

用USB虚拟网卡下载系统镜像的过程中传输中断。

在target connectivity options中可以获得 设备名。 开始下载镜像的时候是正常的,传输速率在260K左右。但下载到15.3M的时候下载就停止了,接着下载中断,提示检查网络。 这个时候网络确实出了问题,本地连接已经无法操作,右键没有反应了。ipcon ...…

查看全部问答>

嵌入式开发板——飞凌6410性能及配置详解

嵌入式开发板——飞凌6410性能及配置详解 S3C6410开发板产品备注:     S3C6410是一款低功耗、高性价比的RSIC处理器,可广泛应用于移动电话和通用处理等领域;     S3C6410为2.5G和3G通信服务提供了优化的硬件性能,内置 ...…

查看全部问答>

一个嵌入式初学者引发的思考(jesse谈自己的经验体会)

我目前再跟几个朋友合伙一起做点开源的硬件小产品,随后就成立了一个论坛,也就是现在的armjishu.com,那时候我们在一起商量着怎么让我们的广大初学者能够更快的进入到嵌入式领域,我们琢磨了很长时间,怎么样做到,后来决定做一款嵌入式硬件产品出 ...…

查看全部问答>

如何实现CE设备在PC上识别为U盘?

通过看资料: http://blog.eeworld.net/nanjianhui/archive/2009/08/20/4466741.aspx 我的BSPP中USB 驱动中有         1、USB\\FUNCTION         2、USB\\HCD\\OHCD   & ...…

查看全部问答>

做过“博创杯”嵌入式设计大赛的大虾,指教下~~~

    小弟第一次做这个比赛,还不是太懂     据说,这个比赛是自己编程序,然后下载到开发平台的芯片上运行,如果开发工具用IAR EWARM     那各种接口的驱动程序,要不要自己写?     自己写的代码是不 ...…

查看全部问答>

成功开发了中星微301H摄像头的wince驱动

这段时间成功的开发了中星微301H摄像头的wince驱动和视频采集程序。详见http://blog.eeworld.net/wincemobile…

查看全部问答>

网络控制中的问题

起了个早,希望有个好的结果,争取调通。 由于项目上个月才启动,所以试用有些延迟,但是要感谢SOSO姐的支持,延长了试用时间。 最近自己画的板子终于到手了,由于价格原因选用了LM3S6432,结果杯具了, 在LM3S8962上调好的程序,放到LM3S6432里 ...…

查看全部问答>

IAR程序移植到ICC

网上下了个fft的程序,看了一下它包含的头文件应该是在IAR上调试通过的,移植到ICC后移植编译出错, 源程序如下: #include #include /*********************************************************************       & ...…

查看全部问答>

ucgui 与 emwin

ucgui是不是就是emwin,类似的有哪些呢可惜现在ucgui不开源了哦…

查看全部问答>