STM32外部中断读取编码器计数值

STM32外部中断读取编码器计数值:


stm32的定时器是可以直接读取编码器的正交信号的,这也说明定时器的强大之处,但是呢,stm32的定时器个数是有限的,当用一个定时器来读取编码器的,那这个定时器就不能再干其他任何事情了,驱动四个电机只需要一个定时器,但是读取编码器也直接用掉了一个定时器,这是对硬件资源极大的浪费


定时器在一个项目中往往还有比读取编码器更重要的作用,因此,读取编码器这种简单的活就不要再让定时器做了,太浪费硬件资源了,所以,本文提供外部中断的方法来读取编码器的正交信号,毕竟stm32的每一个引脚都可以配置外部中断的。利用提供的三个函数
GuiStar_Encoder_Init,
GuiStar_Encoder_Read_Current_Value,
GuiStar_Encoder_GetSpeed。

代码中用到了IO.h和IO_Init,它们是初始化IO口为浮空输入模式的封装,源码如下:

提示:下面的两个文件的作用是stm32位带操作和stm32引脚初始化函数的封装,如果要深究位带操作,建议看野火哥的视频,本次的编码器读取只用到了IO_Init这个函数,没有涉及位带操作

其实位带操作也仅仅是原理很难理解而已,但是用起来是真的香啊,它把stm32单片机玩儿出了51单片机的感觉。哈哈


IO.h

#ifndef __IO_H
#define __IO_H


#include "stm32f10x.h"

#define SYSTEM_SUPPORT_OS
																	    
	 

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12)    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12)    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) 
 

#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  


void IO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin_x, GPIOMode_TypeDef GPIO_Mode);

#endif

IO.c:

#include "stm32f10x.h"

/**
  * @brief  完成指定IO口的时钟开启,模式选择
  * @param  GPIOx        			可选GPIOA,GPIOB,GPIOC,GPIOD
  * @param  GPIO_Pin_x   			选择Pin
  * @param  GPIO_Mode   			选择GPIO模式,有以下八种模式可供选择:
			  GPIO_Mode_AIN 		模拟输入
			  GPIO_Mode_IN_FLOATING 浮空输入
			  GPIO_Mode_IPD 		下拉输入
			  GPIO_Mode_IPU 		上拉输入
			  GPIO_Mode_Out_OD 		开漏输出(带上拉或者下拉)
			  GPIO_Mode_Out_PP 		推挽输出(带上拉或者下拉
			  GPIO_Mode_AF_OD 		复用开漏输出(带上拉或者下拉)
			  GPIO_Mode_AF_PP 		复用推挽输出(带上拉或者下拉)
  * @param 
  * @retval 无
  */
void IO_Init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin_x, GPIOMode_TypeDef GPIO_Mode)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	if(GPIOx==GPIOA)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
		GPIO_Init(GPIOA, &GPIO_InitStructure);
	}
	
	if(GPIOx==GPIOB)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
		GPIO_Init(GPIOB, &GPIO_InitStructure);
	}
	
	if(GPIOx==GPIOC)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
		GPIO_Init(GPIOC, &GPIO_InitStructure);
	}

	if(GPIOx==GPIOD)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
		GPIO_Init(GPIOD, &GPIO_InitStructure);
	}
}


接下来的两个文件中涉及外部中断的配置,我之前封装过相关函数了,请看这里外部中断函数封装

GuiStar_Encoder.h:

#ifndef __GUISTAR_ENCODER_H__
#define __GUISTAR_ENCODER_H__

#include "stm32f10x.h"                  // Device header
#include "IO.h"
#include "GuiStar_EXTI.h"

void GuiStar_Encoder_Init(GPIO_TypeDef* INT1_Port, uint16_t INT1_Pin,GPIO_TypeDef* INT2_Port, uint16_t INT2_Pin, uint8_t Reversal);
int GuiStar_Encoder_Read_Current_Value(void);
int GuiStar_Encoder_GetSpeed(void);

#endif

GuiStar_Encoder.c:

#include "GuiStar_Encoder.h"
GPIO_TypeDef* 			INT2_port;
uint16_t 				INT2_pin;
uint8_t 				reversal;
int GuiStar_Encoder_Current_Value=0;

void Encoder_IQHeader(void)
{
	if(GPIO_ReadInputDataBit(INT2_port,INT2_pin)==SET)
	{
		if(reversal==0)
			GuiStar_Encoder_Current_Value++;
		else GuiStar_Encoder_Current_Value--;
	}
	else if(GPIO_ReadInputDataBit(INT2_port,INT2_pin)==RESET)
	{
		if(reversal==0)
			GuiStar_Encoder_Current_Value--;
		else GuiStar_Encoder_Current_Value++;
	}
}

/**	
  * @brief  	外部中断读取正交编码器初始化函数
  * @param  	INT1_Port 选择接口一的端口(GPIOA,GPIOB,GPIOC,GPIOD)
  * @param  	INT1_Pin  选择接口一的引脚 GPIO_Pin_x(x从0到15)
  * @param  	INT2_Port 选择接口二的端口(GPIOA,GPIOB,GPIOC,GPIOD)
  * @param  	INT2_Pin  选择接口二的引脚 GPIO_Pin_x(x从0到15)
  * @param  	Reversal  是否反向(给0正向,给1反向,正向与反向是相对的)
  * @attention  两个接口不能同时选择9到10引脚,也不能同时选择10到15引脚!!!
  * @retval 
  */
void GuiStar_Encoder_Init(GPIO_TypeDef* INT1_Port, uint16_t INT1_Pin,GPIO_TypeDef* INT2_Port, uint16_t INT2_Pin, uint8_t Reversal)
{
	u8 INT1_Num=0;
	u8 INT2_Num=0;
	INT2_port=INT2_Port;
	INT2_pin=INT2_Pin;
	reversal=Reversal;
	for(;((1<<INT1_Num) & (INT1_Pin))==0;)
	{
		INT1_Num++;
	};
	for(;((1<<INT2_Num) & (INT2_Pin))==0;)
	{
		INT2_Num++;
	};
	
	IO_Init(INT1_Port,INT1_Pin,GPIO_Mode_IN_FLOATING);//初始化接口1引脚为浮空输入
	IO_Init(INT2_Port,INT2_Pin,GPIO_Mode_IN_FLOATING);//初始化接口2引脚为浮空输入
	GuiStar_EXTI_Init(INT1_Port,INT1_Pin,EXTI_Trigger_Rising);//配置接口1外部中断
	
	if(INT1_Num==0)
	{
		GuiStar_EXTI_SetEXTI0_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num==1)
	{
		GuiStar_EXTI_SetEXTI1_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num==2)
	{
		GuiStar_EXTI_SetEXTI2_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num==3)
	{
		GuiStar_EXTI_SetEXTI3_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num==4)
	{
		GuiStar_EXTI_SetEXTI4_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num>=5&&INT1_Num<=9)
	{
		GuiStar_EXTI_SetEXTI9_5_IRQHandler(Encoder_IQHeader);
	}
	else if(INT1_Num>=10&&INT1_Num<=15)
	{
		GuiStar_EXTI_SetEXTI15_10_IRQHandler(Encoder_IQHeader);
	}
}

/**
  * @brief  返回正交编码器当前值
  * @param  无
  * @retval 正交编码器当前值
  */
int GuiStar_Encoder_Read_Current_Value(void)
{
	return GuiStar_Encoder_Current_Value;
}

/**
  * @brief  函数内部先将编码器当前计数值锁存,再清零计数变量(GuiStar_Encoder_Current_Value),最后返回锁存值
  * @param  无
  * @retval 无
  */
int GuiStar_Encoder_GetSpeed(void)
{
	int temp;
	temp=GuiStar_Encoder_Current_Value;//先将编码器当前计数值锁存
	GuiStar_Encoder_Current_Value=0;//再清零计数变量(GuiStar_Encoder_Current_Value)
	return temp;//返回锁存值
}


本文结束,感谢观看!

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuiStar_李什么恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值