收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

STM32f4日记5之AB相编码器测速实验(TIM定时器的编码器模式使用)
板子:stm32f407zgt6正点原子迷你版
电机参数:减速比 1:90
线数:1170(13乘以90)

作者:shawn
2021.1.28
22:46
All rights reserved

//
鉴于目前网上的教学形态各异,很多带有迷惑、误导性质,所以写这篇文章交流自己的看法,也权当纪录自己的学习经历。
//
如果你觉得对你有帮助,请点赞同,这对我很重要,谢谢。
//
一、器材介绍
准备1.L298N,
2.带AB相编码器的电机,
3.给L298N供电的电源(建议保持电压为12V,博主以前用的供电5.6V左右,pwm波输出很离谱的频率100hz电机转的超快)(可以网购12v的电源适配器,大概4~5元左右,把头子切掉,扒开黑胶套,里面白线负极,红线正极,插市电就可以用,但请注意用电安全
4.杜邦线连接(L298N的介绍可以参考我的STM32日记3之diy小车实验(小车实验一:驱动小车转圈,直走,倒走))
明确:一般L298N输入10khzPWM波,电机功率达到最大
主要器材介绍:
1、电机
最简单判断电机好坏的判断方式就是拿6V左右的电池组加在它两边,看会不会转。(电压太大会烧掉)
在这里插入图片描述

2、AB相编码器
网上介绍如下:
编码器分为光电和霍尔编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器,我们可以通过编码器测量到位移或者速度信息。
编码器从输出数据类型上分,可以分为增量式编码器和绝对式编码器。
从编码器检测原理上来分,还可以分为光学式、磁式、感应式、电容式。常见的是光电编码器(光学式)和霍尔编码器(磁式)。两种(以下介绍为复制内容):
光电编码器是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。
光电编码器是由光码盘和光电检测装置组成。光码盘是在一 定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,检测装置检测输出若干脉冲信号,为判断转向,一般输出两组存在一 定相位差的方波信号。
霍尔编码器是一种通过磁电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。
霍尔编码器是由霍尔码盘和霍尔元件组成。霍尔码盘是在一 定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。
在这里插入图片描述
二、硬件连接
我在做这个实验的时候只使用的L298N的右边一端的out口
1.将L298N的OUT口分别接到电机编码器的M+,M-
2.L298N的ENB接pwm的输出口PF8
3.L298N的两个IN3,IN4接PF2跟PF6
4.单片机跟L298N共地
5.编码器跟单片机共地
6.编码器5V接单片机5V
7.编码器A,B相接单片机的TIM4的CH1跟CH2就是PD12,PD13
三、核心模块TIM定时器编码器模式讲解
参考STM32f4中文参考手册
编码器模式的好处:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
编码器模式是TIM自带的对编码处理的一种特殊的输入捕获模式
好处很直接:
在这里插入图片描述
1.当编码器出现抖动,它能够防止抖动,不影响计数,并且它可以采用四倍频的方法,使得误差减小4倍。
2.能通过检测TIMx_CR1的第四位DIR来判断电机的转动方向:正转还是反转,这功能很强
在这里插入图片描述
3.重要备注:当定时器检测到一个正向脉冲计数值**+1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!**这很重要划重点
所以我们并不能知道检测一个脉冲用了多少时间,所以还要再开一个定时器。
网上搜到的配置STM32F1编码器模式的方法不适用于F4
四、代码编写
思路:TIM13用来提供10khzPWM波跟占空比
TIM4配置编码器模式来实现对AB相编码器的处理
鉴于所以我们并不能知道检测一个脉冲用了多少时间,所以还要再开一个定时器TIM5
配置TIM4代码如下

void Encoder\_Init\_TIM4(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef  NVIC_InitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_ICInitTypeDef TIM_ICInitStructure;    

  RCC\_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);    
  RCC\_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);  
		
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13;          
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                    
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;              
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                  
  GPIO\_Init(GPIOD, &GPIO_InitStructure);                          

  GPIO\_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);           
	GPIO\_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);           
	
  TIM_TimeBaseStructure.TIM_Period = arr; 	                      
	TIM_TimeBaseStructure.TIM_Prescaler=psc;                        
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;       
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;           
	TIM\_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);                  
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;                  
  TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;	      
  TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;   
  TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;	            
  TIM_ICInitStructure.TIM_ICFilter =0;                            
  TIM\_ICInit(TIM4,&TIM_ICInitStructure);
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;                  
  TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;	      
  TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;   
  TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;	            
  TIM_ICInitStructure.TIM_ICFilter=0;                             
  TIM\_ICInit(TIM4,&TIM_ICInitStructure);
	
	TIM\_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising );
		
  NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;                   
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;                   
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;      
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x02;            
	NVIC\_Init(&NVIC_InitStructure);                                 
		
	TIM\_ITConfig(TIM4,TIM_IT_Update,ENABLE);                        
	TIM\_Cmd(TIM4,ENABLE);   
}




最难配置的已经告诉大家了
最重要的是这个函数TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising );
配置的编码器模式,具体模式为TIM_EncoderMode_TI12
其它timer.h里代码如下

void TIM5\_Int\_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC\_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);            	
	
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  										TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 	
	TIM_TimeBaseInitStructure.TIM_Period=arr;   										
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	
	TIM\_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
	
	TIM\_ITConfig(TIM5,TIM_IT_Update,ENABLE); 										     
	TIM\_Cmd(TIM5,ENABLE); 																           
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn; 									 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; 			 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02; 						 
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC\_Init(&NVIC_InitStructure);
	
}




void TIM4\_IRQHandler(void)
{
		if(TIM\_GetITStatus(TIM4,TIM_IT_Update)==SET)                    
	{   
		Encoder_Timer_Overflow++;     		
	}
	TIM\_ClearITPendingBit(TIM4,TIM_IT_Update);  

}

u32 Read\_Encoder(void)
{
  u32 Count;                                                      
  u16 Current_Count;                                              
	u16 Enc_Timer_Overflow_one;	                                   

  Enc_Timer_Overflow_one=Encoder_Timer_Overflow;                  
  Current_Count = TIM\_GetCounter(TIM4);                           
  Encoder_Timer_Overflow=0;                                       
	if((TIM4->CR1&0x0010) == 0x0010)                                
    Count = (u32)((-1\*Enc_Timer_Overflow_one)\*(4\*ENCODER_PPR-4) + (Current_Count - Previous_Count));  
	else                                                            


![img](https://img-blog.csdnimg.cn/img_convert/71e5cb09048eb5e2ccc40eaf59b7a22e.png)
![img](https://img-blog.csdnimg.cn/img_convert/4ea793dbb70bd3c6d06f7f1f06d31d4b.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐