精华内容
下载资源
问答
  • 电子-超声波测距外部中断.zip,单片机/嵌入式STM32-F0/F1/F2
  • 电子-超声波测距外部中断需要进一步分析.zip,单片机/嵌入式STM32-F0/F1/F2
  • 基于stm32f103rct6的外部中断超声波测距,本测距方案稳定性高,不容易出现数据波动,测距范围在2-500cm左右,自带串口printf输出测试距离
  • 使用STM32的定时器与外部中断配合实现超声波模块的测距功能。 这里总体说一说此程序比较理想的执行情况: (1)超声波被调用初始化函数,定时器被设定为可中断,并且定时器开始计数; (2)计数到溢出,触发定时器...
  • 基于STM32的超声波测距(外部中断+定时器)

    千次阅读 多人点赞 2020-10-09 10:21:28
    基于STM32F103的超声波测距(定时器) 使用的硬件设备:stm32f103c8t6,0.96寸OLED,超声波模块HC-SR04 废话不多说,上程序就对了(亲测有效) 超声波模块ultrasound.h文件 #ifndef __ULTRASOUND_H #define __ULTRASOUND...

    基于STM32的超声波测距(外部中断+定时器)

    首先说明一下我使用的硬件:
    stm32f103c8t6最小系统、0.96寸OLED、超声波模块HC-SR04。

    再就是程序设计的一个思路:
    超声波模块的使用说明已经指出,给TRIG引脚一个不少于10微秒的高电平,模块自动发送8个40KHz的方波,接收到返回信号后引脚ECHO会输出高电平,其距离为ECHO引脚高电平时间*声速/2,每次测量间隔建议60ms以上。由此,我们可提取到需要使用到的三个芯片功能:1、定时器,2、外部中断,3、IO输出。

    下面是配置代码,进行一一介绍(不想看我哔哔的最下方有完整得超声波配置.c和.h +_+ ):
    1、外部中断和IO输出都是使用的GPIO所以使用一个配置函数
    1.1 GPIO宏定义参数:

    //超声波模块引脚配置
    #define ULTRASOUND_GPIO 						GPIOA
    #define ULTRASOUND_GPIO_CLK 				RCC_APB2Periph_GPIOA
    #define ULTRASOUND_TRIG 						GPIO_Pin_1
    #define ULTRASOUND_ECHO 						GPIO_Pin_0
    
    //超声波模块ECHO中断配置
    #define ULTRASOUND_GPIOSourceGPIO   GPIO_PortSourceGPIOA
    #define ULTRASOUND_PINSOURCE        GPIO_PinSource0
    #define ULTRASOUND_EXTI_LINE				EXTI_Line0
    #define ULTRASOUND_EXTI_IRQHandler  EXTI0_IRQHandler	//ECHO引脚中断服务函数
    

    1.2 GPIO端口配置函数Ultrasound_GPIO_Conf():
    这里要注意,中断的触发方式为上下边沿,用处在中断服务函数里面体现。

    static void Ultrasound_GPIO_Conf(void)//端口配置
    {
    	EXTI_InitTypeDef EXTI_InitStructure;
    	GPIO_InitTypeDef GPIO_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(ULTRASOUND_GPIO_CLK | RCC_APB2Periph_AFIO,ENABLE);//打开GPIOA和端口复用时钟
    	
    	GPIO_EXTILineConfig(ULTRASOUND_GPIOSourceGPIO,ULTRASOUND_PINSOURCE);//配置中断线A-0
    	
    	GPIO_InitStructure.GPIO_Pin = ULTRASOUND_ECHO;//ECHO端口配置
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//输入下拉
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(ULTRASOUND_GPIO,&GPIO_InitStructure);
    	GPIO_ResetBits(ULTRASOUND_GPIO, ULTRASOUND_ECHO);//拉低ECHO
    	
    	GPIO_InitStructure.GPIO_Pin = ULTRASOUND_TRIG; //TRIG端口配置
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//复用推挽输出
      GPIO_Init(ULTRASOUND_GPIO, &GPIO_InitStructure);//初始化GPIOA.9
    	
    	EXTI_InitStructure.EXTI_Line = ULTRASOUND_EXTI_LINE; //配置中断线A-0
    	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上下边沿触发
    	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    	EXTI_Init(&EXTI_InitStructure);
    
    	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //配置中断A-0
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);	
    }
    

    2、定时器配置(定时器在这里比较忙,它要进行返回信号高电平的计时,和测距间隔时间计时,所以要配置中断)
    2.1 定时器宏定义参数:

    //超声波模块定时器配置
    #define ULTRASOUND_TIM 							TIM2
    #define ULTRASOUND_TIM_CLK 					RCC_APB1Periph_TIM2
    #define ULTRASOUND_TIM_IRQ      		TIM2_IRQn
    #define ULTRASOUND_TIM_IRQHandler		TIM2_IRQHandler	//TIM2中断服务函数
    

    2.2 定时器配置函数Ultrasound_TIM_Conf():
    这里值得注意的是,在配置中断的时候必须要清除中断标志位,不然程序会死在NVIC_Init函数里面

    static void Ultrasound_TIM_Conf(void)//定时器配置
    {
    	uint16_t PrescalerValue;//分频系数
    	NVIC_InitTypeDef NVIC_InitStructure;
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    
    	RCC_APB1PeriphClockCmd(ULTRASOUND_TIM_CLK,ENABLE);//打开ULTRASOUND_TIM时钟
    	
    	PrescalerValue = (uint16_t)((SystemCoreClock / 2)  / 1000000) - 1;//计算分频系数(设定为:每秒计数100万次,每计一次为1us)
    	TIM_TimeBaseStruct.TIM_Period = 0xFDE8;//重载寄存器的值,定时周期
    	TIM_TimeBaseStruct.TIM_Prescaler = PrescalerValue;//预分频
    	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟切割
    	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
    	TIM_TimeBaseInit(ULTRASOUND_TIM,&TIM_TimeBaseStruct);//初始化ULTRASOUND_TIM
    	
    	TIM_ClearITPendingBit(ULTRASOUND_TIM,TIM_IT_Update);//清除中断标志位,配置时必须加上
    	TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, ENABLE);//事件更新中断配置
    	
    	NVIC_InitStructure.NVIC_IRQChannel = ULTRASOUND_TIM_IRQ; //配置ULTRASOUND_TIM中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);	
    
    	TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    }
    

    3、超声波模块初始化函数(将上面写的两个函数调用一下下就好了)

    void Ultrasound_Init(void)//超声波模块初始化
    {
    	Ultrasound_GPIO_Conf();//超声波控制端口配置
    	Ultrasound_TIM_Conf();//超声波控制计数器配置
    }
    

    4、超声波启动函数
    这里比较尴尬,使用定时器和中断的目的就是尽量没有延时,但这里出现了12us的延时(若小伙伴有好的方法,敬请出招)

    void Ultrasound_start(void)//超声波模块启动
    {
    	GPIO_SetBits(ULTRASOUND_GPIO, ULTRASOUND_TRIG);//拉高TRIG
    	
    	ULTRASOUND_TIM->CNT = 0x0000;	//清空计数器计数寄存器值
    	ULTRASOUND_TIM->ARR = 0xffff; //重载值重新设定
    	TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    	while(ULTRASOUND_TIM->CNT != 12);//大于10us,此处等待12us,
    	
    	GPIO_ResetBits(ULTRASOUND_GPIO, ULTRASOUND_TRIG);//拉低TRIG
    }
    

    5、距离获取函数
    这里比较花里胡哨,因为进行了一下数据筛选。ULTRASOUND_DIS_INDEX是一个宏定义,它是我设定的获取多少次数据,进行一次数据筛选。

    float Ultrasound_GetDistance(void)//获取距离数据
    {
    	uint8_t i,j;//循环变量
    	float distance_temp;//排序的临时变量
    	for(i = 0;i < ULTRASOUND_DIS_INDEX - 1;i ++ )//降序排列,找出最大值和最小值
    	{
    		for(j = 0;j < ULTRASOUND_DIS_INDEX - 1;j ++)
    		{
    			if(ultrasound_data[j] < ultrasound_data[j + 1])
    			{
    				distance_temp = ultrasound_data[j + 1];
    				ultrasound_data[j + 1] = ultrasound_data[j];
    				ultrasound_data[j] = distance_temp;
    			}
    		}	
    	}
    				
    	distance_temp = 0;//清零
    		
    	for(i = 2; i < ULTRASOUND_DIS_INDEX - 2;i ++)//去掉两个最大值和两个最小值
    	{
    		distance_temp += ultrasound_data[i];//获取的距离值累加
    	}
    	
    	distance_temp /= (ULTRASOUND_DIS_INDEX - 4);//求平均值
    	return distance_temp;
    }
    

    5、定时器中断服务函数
    比较简单,调用一下超声波启动函数就好。

    void ULTRASOUND_TIM_IRQHandler(void)//超声波所用TIM中断服务函数
    {
    	if(TIM_GetITStatus(ULTRASOUND_TIM,TIM_IT_Update) == SET)//判断是否有事件更新
    	{
    		Ultrasound_start();//启动超声波模块
    	}
    	TIM_ClearITPendingBit(ULTRASOUND_TIM,TIM_IT_Update);//清除中断标志位
    }
    

    5、外部中断服务函数(敲黑板,比较绕请细品)
    这里总体说一说此程序比较理想的执行情况:

    (1)超声波被调用初始化函数,定时器被设定为可中断,并且定时器开始计数;

    (2)计数到溢出,触发定时器中断,它会调用超声波启动函数Ultrasound_start();

    (3)超声波启动后,有回波信号,将触发外部中断(上边沿),进入外部中断直接关掉定时器中断和定时器,判断确实有回波信号,进入到(检测到返回信号)代码段,清空定时器的CNT寄存器,重设重载值ARR寄存器,开启定时器。此时,定时器进行ECHO引脚得高电平持续时间检测;

    (4)再一次中断来临(下降沿),还是直接关掉定时器中断触发和定时器,这次进入(返回信号结束)代码段,首先判断定时器是不是计数的高电平时间。若是,就判断我的获取次数是否已满,满了就置位flag, 没有满,就将定时器CNT寄存器里面的值提出来参与距离公式运算得到当前所测距离。执行到最后继续开启定时器中断和定时器,并重新设定重载值。此时定时器进行间隔时间计数。所以,定时器计数到溢出中断后,又会去调用一次超声波启动函数Ultrasound_start();

    (5)外部中断函数则在此等待下一次工作来临;

    void ULTRASOUND_EXTI_IRQHandler(void)	//超声波ECHO引脚所用中断服务函数
    {
    	if(EXTI_GetITStatus(EXTI_Line0)!=0)	//判断是否真是触发中断
    	{	
    		TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, DISABLE);//关闭计数器中断
    		TIM_Cmd(ULTRASOUND_TIM,DISABLE);	//关闭计数器
    		if(GPIO_ReadInputDataBit(ULTRASOUND_GPIO, ULTRASOUND_ECHO) == 1)	//检测到返回信号
    		{
    			ULTRASOUND_TIM->CNT = 0x0000;	//清空计数器计数寄存器值
    			ULTRASOUND_TIM->ARR = 0xffff;//重载值重设为计数最大值
    			TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    		}
    		
    		if(GPIO_ReadInputDataBit(ULTRASOUND_GPIO, ULTRASOUND_ECHO) == 0 )	//返回信号结束
    		{
    			if(ULTRASOUND_TIM->ARR == 0xffff) //需要确定计数器当前是不是在计数返回信号时间
    			{
    				if(d_count == ULTRASOUND_DIS_INDEX) //判断获取数据的次数
    				{
    					d_count = 0;	//清空次数计数值
    					ultrasound_flag = 1;	//置位超声波标志位
    				}
    				else
    				{
    					ultrasound_flag = 0;	//清空超声波标志位
    					ultrasound_data[d_count] = (float)(ULTRASOUND_TIM->CNT*34000)/1000000/2;	//计算距离,单位cm。并将数据存入待处理数据数组
    					d_count++;	//次数计数值自增
    				}
    			}
    			ULTRASOUND_TIM->ARR = 0xFDE8;//重载值为计数64ms
    			TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, ENABLE);//开启计数器中断
    			TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    		}
    		EXTI_ClearITPendingBit(EXTI_Line0);	//清除LINE上的中断标志位
    	}
    }
    

    6、主函数

    #include "common.h"
    
    char display_buff[100] = {0};
    int main()
    {
    	SysTickInit();//系统定时器设置
    	NVIC_PriorityGroupConfig(0);//中断分组
    	OLED_Init();//0.96寸OLED初始化
    	Ultrasound_Init();//超声波模块初始化
    	
    	while(1)	
    	{		
    		if(ultrasound_flag == 1)
    		{
    			sprintf(display_buff,"distance: %-5.2fcm    ",Ultrasound_GetDistance());//将数据打印到显示缓冲区
    			OLED_Print(0,8,(uint8_t*)display_buff,TYPE6X8,TYPE6X8);//显示数据
    		}
    	} 
    }
    
    

    7、下面是超声波配置完整的.c和.h
    == ultrasound.c ==

    #ifndef __ULTRASOUND_H
    #define __ULTRASOUND_H
    
    #include "common.h"
    
    //超声波模块引脚配置
    #define ULTRASOUND_GPIO 						GPIOA
    #define ULTRASOUND_GPIO_CLK 				RCC_APB2Periph_GPIOA
    #define ULTRASOUND_TRIG 						GPIO_Pin_1
    #define ULTRASOUND_ECHO 						GPIO_Pin_0
    
    //超声波模块ECHO中断配置
    #define ULTRASOUND_GPIOSourceGPIO   GPIO_PortSourceGPIOA
    #define ULTRASOUND_PINSOURCE        GPIO_PinSource0
    #define ULTRASOUND_EXTI_LINE				EXTI_Line0
    #define ULTRASOUND_EXTI_IRQHandler  EXTI0_IRQHandler	//ECHO引脚中断服务函数
    
    //超声波模块定时器配置
    #define ULTRASOUND_TIM 							TIM2
    #define ULTRASOUND_TIM_CLK 					RCC_APB1Periph_TIM2
    #define ULTRASOUND_TIM_IRQ      		TIM2_IRQn
    #define ULTRASOUND_TIM_IRQHandler		TIM2_IRQHandler	//TIM2中断服务函数
    
    #define ULTRASOUND_DIS_INDEX 				10
    
    extern uint8_t ultrasound_flag;//获取完成标志位变量
    extern float ultrasound_data[ULTRASOUND_DIS_INDEX];//距离数据存储数组
    
    void Ultrasound_Init(void);//模块使用初始
    void Ultrasound_start(void);//启动一次
    float Ultrasound_GetDistance(void);//获取距离数据
    
    #endif
    
    
    

    == ultrasound.c ==

    #include "ultrasound.h"
    
    float ultrasound_data[ULTRASOUND_DIS_INDEX] = {0};//数据存储
    uint16_t d_count = 0;//获取数据次数计数变量
    uint8_t ultrasound_flag = 0;//获取完成标志位变量
    
    static void Ultrasound_GPIO_Conf(void)//端口配置
    {
    	EXTI_InitTypeDef EXTI_InitStructure;
    	GPIO_InitTypeDef GPIO_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(ULTRASOUND_GPIO_CLK | RCC_APB2Periph_AFIO,ENABLE);//打开GPIOA和端口复用时钟
    	
    	GPIO_EXTILineConfig(ULTRASOUND_GPIOSourceGPIO,ULTRASOUND_PINSOURCE);//配置中断线A-0
    	
    	GPIO_InitStructure.GPIO_Pin = ULTRASOUND_ECHO;//ECHO端口配置
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//输入下拉
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(ULTRASOUND_GPIO,&GPIO_InitStructure);
    	GPIO_ResetBits(ULTRASOUND_GPIO, ULTRASOUND_ECHO);//拉低ECHO
    	
    	GPIO_InitStructure.GPIO_Pin = ULTRASOUND_TRIG; //TRIG端口配置
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//复用推挽输出
      GPIO_Init(ULTRASOUND_GPIO, &GPIO_InitStructure);//初始化GPIOA.9
    	
    	EXTI_InitStructure.EXTI_Line = ULTRASOUND_EXTI_LINE; //配置中断线A-0
    	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上下边沿触发
    	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    	EXTI_Init(&EXTI_InitStructure);
    
    	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //配置中断A-0
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);	
    }
    
    static void Ultrasound_TIM_Conf(void)//定时器配置
    {
    	uint16_t PrescalerValue;//分频系数
    	NVIC_InitTypeDef NVIC_InitStructure;
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
    
    	RCC_APB1PeriphClockCmd(ULTRASOUND_TIM_CLK,ENABLE);//打开ULTRASOUND_TIM时钟
    	
    	PrescalerValue = (uint16_t)((SystemCoreClock / 2)  / 1000000) - 1;//计算分频系数(设定为:每秒计数100万次,每计一次为1us)
    	TIM_TimeBaseStruct.TIM_Period = 0xFDE8;//重载寄存器的值,定时周期
    	TIM_TimeBaseStruct.TIM_Prescaler = PrescalerValue;//预分频
    	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟切割
    	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
    	TIM_TimeBaseInit(ULTRASOUND_TIM,&TIM_TimeBaseStruct);//初始化ULTRASOUND_TIM
    	
    	TIM_ClearITPendingBit(ULTRASOUND_TIM,TIM_IT_Update);//清除中断标志位,配置时必须加上
    	TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, ENABLE);//事件更新中断配置
    	
    	NVIC_InitStructure.NVIC_IRQChannel = ULTRASOUND_TIM_IRQ; //配置ULTRASOUND_TIM中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);	
    
    	TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    }
    
    void Ultrasound_Init(void)//超声波模块初始化
    {
    	Ultrasound_GPIO_Conf();//超声波控制端口配置
    	Ultrasound_TIM_Conf();//超声波控制计数器配置
    }
    
    void Ultrasound_start(void)//超声波模块启动
    {
    	GPIO_SetBits(ULTRASOUND_GPIO, ULTRASOUND_TRIG);//拉高TRIG
    	
    	ULTRASOUND_TIM->CNT = 0x0000;	//清空计数器计数寄存器值
    	ULTRASOUND_TIM->ARR = 0xffff; //重载值重新设定
    	TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    	while(ULTRASOUND_TIM->CNT != 12);//大于10us,此处等待12us,
    	
    	GPIO_ResetBits(ULTRASOUND_GPIO, ULTRASOUND_TRIG);//拉低TRIG
    }
    
    float Ultrasound_GetDistance(void)//获取距离数据
    {
    	uint8_t i,j;//循环变量
    	float distance_temp;//排序的临时变量
    	for(i = 0;i < ULTRASOUND_DIS_INDEX - 1;i ++ )//降序排列,找出最大值和最小值
    	{
    		for(j = 0;j < ULTRASOUND_DIS_INDEX - 1;j ++)
    		{
    			if(ultrasound_data[j] < ultrasound_data[j + 1])
    			{
    				distance_temp = ultrasound_data[j + 1];
    				ultrasound_data[j + 1] = ultrasound_data[j];
    				ultrasound_data[j] = distance_temp;
    			}
    		}	
    	}
    				
    	distance_temp = 0;//清零
    		
    	for(i = 2; i < ULTRASOUND_DIS_INDEX - 2;i ++)//去掉两个最大值和两个最小值
    	{
    		distance_temp += ultrasound_data[i];//获取的距离值累加
    	}
    	
    	distance_temp /= (ULTRASOUND_DIS_INDEX - 4);//求平均值
    	return distance_temp;
    }
    
    
    void ULTRASOUND_EXTI_IRQHandler(void)	//超声波ECHO引脚所用中断服务函数
    {
    	if(EXTI_GetITStatus(EXTI_Line0)!=0)	//判断是否真是触发中断
    	{
    		
    		TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, DISABLE);//关闭计数器中断
    		TIM_Cmd(ULTRASOUND_TIM,DISABLE);	//关闭计数器
    		if(GPIO_ReadInputDataBit(ULTRASOUND_GPIO, ULTRASOUND_ECHO) == 1)	//检测到返回信号
    		{
    			ULTRASOUND_TIM->CNT = 0x0000;	//清空计数器计数寄存器值
    			ULTRASOUND_TIM->ARR = 0xffff;//重载值重设为计数最大值
    			TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    		}
    		
    		if(GPIO_ReadInputDataBit(ULTRASOUND_GPIO, ULTRASOUND_ECHO) == 0 )	//返回信号结束
    		{
    			if(ULTRASOUND_TIM->ARR == 0xffff) //需要确定计数器当前是不是在计数返回信号时间
    			{
    				if(d_count == ULTRASOUND_DIS_INDEX) //判断获取数据的次数
    				{
    					d_count = 0;	//清空次数计数值
    					ultrasound_flag = 1;	//置位超声波标志位
    				}
    				else
    				{
    					ultrasound_flag = 0;	//清空超声波标志位
    					ultrasound_data[d_count] = (float)(ULTRASOUND_TIM->CNT*34000)/1000000/2;	//计算距离,单位cm。并将数据存入待处理数据数组
    					d_count++;	//次数计数值自增
    				}
    			}
    			ULTRASOUND_TIM->ARR = 0xFDE8;//重载值为计数64ms
    			TIM_ITConfig(ULTRASOUND_TIM, TIM_IT_Update, ENABLE);//开启计数器中断
    			TIM_Cmd(ULTRASOUND_TIM,ENABLE);	//开启计数器
    		}
    		EXTI_ClearITPendingBit(EXTI_Line0);	//清除LINE上的中断标志位
    	}
    }
    
    void ULTRASOUND_TIM_IRQHandler(void)//超声波所用TIM中断服务函数
    {
    	if(TIM_GetITStatus(ULTRASOUND_TIM,TIM_IT_Update) == SET)//判断是否有事件更新
    	{
    		Ultrasound_start();//启动超声波模块
    	}
    	TIM_ClearITPendingBit(ULTRASOUND_TIM,TIM_IT_Update);//清除中断标志位
    }
    
    

    8、实验结果
    在这里插入图片描述

    **若有不足之处还请各位指出。

    展开全文
  • stm32驱动HC-SR04超声波模块测距的中断例程,PA4->Trig,PA5->Echo 串口1打印测量距离。
  • 通过一个定时器 一个中断 理论上可接无限多个超声波 (需加门电路)
  • STM32CUBEMX EXTI外部中断

    2020-11-07 19:16:44
    STM32CUBEMX EXTI外部中断 STM32CUBEMX及Keil工程 提取码:v47e 使用stm32cubemx初始化 选择下中断模式 开启中断,在NVIC中选择中断优先级 LED引脚的配置(GPIO初始电平,模式,上下拉,速度) void HAL_GPIO_...

    STM32CUBEMX EXTI外部中断

    STM32CUBEMX及Keil工程
    提取码:v47e
    使用stm32cubemx初始化
    在这里插入图片描述
    选择下中断模式
    开启中断,选择中断优先级
    开启中断,在NVIC中选择中断优先级
    在这里插入图片描述
    LED引脚的配置(GPIO初始电平,模式,上下拉,速度)

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if(GPIO_Pin==GPIO_PIN_0)
    	{
    		HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);
    	}
    	if(GPIO_Pin==GPIO_PIN_13)
    	{
    		HAL_GPIO_TogglePin(LED_R_GPIO_Port,LED_R_Pin);
    	}
    }
    

    只需要重写回调函数即可,在回调函数中判断哪一个按键的中断,再实行相应的函数。

    中断回调函数

    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
    

    MY_QuinTA的笔记

    展开全文
  • 【五】零基础上手HAL库之—按键外部中断 5.1 前言 我们已经大致的了解了Cubemx软件中GPIO的基本操作了,接下来我们开始进入外部中断的操作,这是一个惊心动魄的时刻,为什么呢?在使用Hal库的同时你会感觉到其优势...

    【五】零基础上手HAL库之—按键外部中断

    按键开始

    5.1 前言

    我们已经大致的了解了Cubemx软件中GPIO的基本操作了,接下来我们开始进入外部中断的操作,这是一个惊心动魄的时刻,为什么呢?在使用Hal库的同时你会感觉到其优势性,开发效率大大提高带来的快感。

    前期准备

    • STM32各类型的板子(本人使用F103Rc和F407ZE)。
    • CubeMx软件,Keil_IDE。

    5.2 Key按键中断

    同样的我们先来看看按键模块的原理图部分:

    image-20210902231307814

    当按键没有按下时,按键部分相当于断路,PC13的电压相当于电容两端电压为3.3V。

    当按键按下时,按键部分相当于短路(即一根导线),PC13的电压和GND地相连为0V。

    所以按键从未按下到按下相当于是一个高电平到低电平的跳变,简称为下降沿。所以说我们在按键中断时选择的模式就是下降沿触发。

    幻灯片1

    1、新建工程

    image-20210831144827291

    搜索或者筛选芯片后,点击Start Project成功创建一个项目。

    幻灯片2

    2、时钟配置

    image-20210831145137213

    点击RCC进入时钟配置,配置高速时钟为外部晶振,软件自动配置了两个晶振的引脚如图PD0和PD1

    幻灯片3

    3、Debug配置为DAP

    image-20210901134555619

    幻灯片4

    4、GPIO配置为中断

    image-20210902223657851

    • ① GPIO模块配置模块
    • ② 各引脚配置: PC12/PC13(外部中断模式中断线12和13),共用一个中断向量。PC14/PC15输出模式为LED的两个引脚
    • ③ 引脚功能具体配置:
      • GPIO mode :上升沿/下降沿/上下降沿 中断和事件模式。
      • GPIO Pull-up/Pull-down:因为我的板子硬件上有上拉电阻即平常电平为高电平,所以配置为弱上拉形式。
      • User Lable:这里没有使用到用户标签为了方便在图中右半部分看到引脚所配置的功能。
    • ④ 输出模式配置:PC14/PC15配置为输出模式,控制LED灯亮灭。
    • ⑤ 外部中断线13:PC13为下降沿触发的外部中断模式,KEY1。
    • ⑥ 外部中断线12:PC12为下降沿触发的外部中断模式,KEY2。

    幻灯片5

    5、项目管理配置以及代码生成配置

    这里我们还是一样配置为最高的时钟频率72M,在对应的框中输入72,按下回车即可见到如下两图的变化。按下回车前如图:

    image-20210901135110375

    按下回车后如图:

    image-20210901135127689

    幻灯片6

    6、项目管理配置以及代码生成配置

    同样的我们填写好工程名KEY,选择好文件路径,以及所用的IDE以及版本号即可

    image-20210901135251221

    代码生成选择好这两个后点击右上角按钮,产生代码:

    image-20210901135319234

    幻灯片7

    7、业务逻辑代码

    7.1 API

    我们再来看看GPIO模块对应的API函数:

    /* 初始化和删除初始化函数,
    	HAL_GPIO_Init:cubemx生成代码后自动调用初始化函数
    	HAL_GPIO_DeInit:解除初始化,不想使用时可以主动使用*/
    void  HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);
    void  HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin);
    
    /* 操作GPIO的函数,包括读取,写入,翻转,加锁,中断服务函数以及回调函数
    	HAL_GPIO_ReadPin:读取引脚电平	返回值为(GPIO_PIN_RESET/GPIO_PIN_SET) 
    	HAL_GPIO_WritePin:写入引脚电平 
    	HAL_GPIO_TogglePin:翻转引脚电平
    	HAL_GPIO_LockPin:所以引脚当前电平,将无法改变
    	HAL_GPIO_EXTI_IRQHandler:引脚的中断服务函数
    	HAL_GPIO_EXTI_Callback:引脚的中断回调函数 */
    GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
    void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
    void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
    HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
    void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
    
    
    7.2 编写回调函数
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
    	if(GPIO_Pin == GPIO_PIN_12)
    	{
    		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_14);
    	}
    	
    	if(GPIO_Pin == GPIO_PIN_13)
    	{
    		HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
    	}
    }
    
    

    我们来看看回调函数是怎么工作的:

    ①:产生中断进入函数 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);

    ②:获取产生中断的引脚

    ③:清除对应引脚的标志位

    ④:进入回调函数对此行为进行处理,产生相应的动作

    ⑤:回到函数 void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);直至跳出函数。

    所以说回调函数相当于用户层的应用函数,也就是只需要在回调函数写入相应引脚产生中断而要做出的反应即可,不需要像标准库那样手动的清除标志位。

    所以16个外部中断只需要调用一个函数进行if判断即可,真正的模块化编程!!!!

    来看看外部中断还能做什么

    ​ 比如可以用来:超声波测距,编码器测速,按键中断等等,凡是要测上下降沿的应用均可使用。

    最后就是下载代码的兴奋时刻了:

    下载代码到板子中,我们按下不同的按键不同的LED对应的进行电平的翻转操作。

    好啦,外部中断就是这么简单就结束了,怎么样是不是感觉也很简单呀!

    展开全文
  • 电容输入 touchRead(pin) 及电容输入中断touchAttachInterrupt(pin, TSR , threshold) ESP32专门提供了电容触摸传感器的功能, 共有T0,T2~T9 共 9个touch传感器可用.分别对应引脚4、2、15、13、12、14、27、33、32. ...

    一. 电容输入 touchRead(pin) 及电容输入中断touchAttachInterrupt(pin, TSR , threshold)

    ESP32专门提供了电容触摸传感器的功能, 共有T0,T2~T9 共 9个touch传感器可用.分别对应引脚4、2、15、13、12、14、27、33、32. 无需设置PinMode

    touchRead(pin)

    返回值 0~255. 触摸强度
    注意: 摸得越瓷实,数值越小

    void setup()
    {
      Serial.begin(9600);
    }
    
    void loop()
    {
       Serial.printf("touch:%d\n",touchRead(4));
    }
    touchAttachInterrupt(pin, TSR , threshold)

    参数:

    • TSR :中断回调函数, 不能带参数, 不能有返回值。
    • threshold:阈值, 达到该阈值会触发此中断
    void TSR()
    {
      Serial.printf("我被按下了!\r\n");
      }
    
    void setup()
    {
      Serial.begin(9600);
      touchAttachInterrupt(4, TSR , 20);
    }
    
    void loop()
    {
      
    }

    二. 霍尔传感器

    ESP32自带霍尔传感器 , 当有磁场靠近时,会显示正负值

    hallRead()

    三. 外部中断

    1. 开启外部中断 attachInterrupt(pin,function,mode);

    参数:

    • pin: 外部中断引脚
    • function : 外部中断回调函数
    • mode : 5种外部中断模式, 见下表:
    中断触发模式说明
    RISING上升沿触发
    FALLING下降沿触发
    CHANGE电平变化触发
    ONLOW低电平触发
    ONHIGH高电平触发
    void func1()
    {
      Serial.printf("按键中断触发");
      }
    void setup()
    {
      Serial.begin(9600);
      attachInterrupt(0,func1,FALLING);
    }
    
    void loop()
    {
      
    }

    2. 关闭引脚中断 detchInterrupt(pin);

    无返回值

    四. 时间统计函数

    1. 开机至今的毫秒数 millis

    millis() 返回值是unsigned long 类型, 大约50天溢出一次

    2. 开机至今的微秒数 micros

    micros() 返回值是unsigned long 类型, 大约70分钟溢出一次

    五. 阻塞延时

    时间控制函数
        由于我们接下来的实验程序很多都用到延时函数,那么这里就介绍几个:

    delay() ----- 毫秒级延时
    delayMicroseconds() ----- 微秒级延时

    硬件定时器相关请见第六篇

    六. 引脚脉冲信号检测 pulseIn()

    pulseIn(pin,state)
    pulseIn(pin,state,timeout)

    参数:

    • pin : 引脚
    • state : 脉冲类型, 可选高或者低
    • timeout : 超时时间, 默认1秒钟. 单位为微秒, 无符号长整型.

    返回值: 脉冲宽度, 单位微秒, 数据类型为无符号长整型. 如果超时返回0

    例: 使用SR04超声波测距

    板上接线方式,VCC、trig(控制端)、 echo(接收端)、 out(空脚)、 GND

    #include <Arduino.h>
    int distance = 0;
    void setup()
    {
      Serial.begin(115200);
      pinMode(4, OUTPUT);
      digitalWrite(4, LOW);
    }
    
    void loop()
    {
      digitalWrite(4, HIGH);
      delayMicroseconds(20);
      digitalWrite(4, LOW);
      distance = pulseIn(18,HIGH)/58;
      Serial.printf("当前距离是:%d cm",distance);
      delay(1000);
    }
    展开全文
  • #include #include #define uint unsigned int #define uchar unsigned char sbit echo=P3^2; sbit trig=P2^3;...void into() interrupt 0 //外部中断 { } void timer() interrupt 1 //定时器0的中断 { }
  • 中断的概念及外部IO口输入中断INT0的测试 文章目录中断的概念及外部IO口输入中断INT0的测试1. 中断基础概念2. 中断的执行过程3. 中断作用及中断类型4. 中断嵌套5. 中断学习的材料6. 与STC15中断相关的概念中断结构图...
  • stm32 使用中断方式实现超声波测距

    千次阅读 2019-11-23 16:35:43
    超声波测距模块源代码 /************************************* ...外部中断 EXTI_Line6; 使用方法:总是调用 Hcsr04GetLength(); 每调用一次就会启动一次测距; 取三次的平均值保存到 全局变量 ultr...
  • #Arduino通过中断方式实现超声波测距 代码分享: #include <FlexiTimer2.h> int Ul_trigPin = 7, Ul_echoPin = 2; // 定义超声波的引脚 long Ul_duration; // 测到的距离 unsigned long Ul_starttime; ...
  • 一路超声波测距串口1,串口2和串口3输出距离 外部中断四路超声波测距
  • 原理: 1.给控制端Trig一个至少持续10us的高电平信号 2.模块内部自动发送8个40kHZ的...4.鉴于我已经在别的模块用过外部中断,所以使用定时器的输入捕获引脚,进行抓取,当识别到上升沿时定时器开始计时,识别到下降...
  • 解决CC2530在zstack中无法进入P0中断的问题 最近使用CC2530控制一个超声波模块,需要使用外部中断P0接收数据,定时器来计时。裸机程序没有问题,移植进入ZSTACK的时候无法进入中断P0。 但是可以使用P1的中断。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 659
精华内容 263
关键字:

超声波外部中断