草庐IT

STM32编码器模式(带方向/正交编码)

君墨蘭 2023-12-01 原文

STM32编码器模式

  • 看前说明:这里重点介绍的时STM32的定时器编码器模式,是根据STMF10x参考手册,如果有使用过编码器或编码器不一样的可以直接跳过前面的编码器介绍,直接看理论分析与程序部分。

1、编码器介绍

  • 这里需要注意的参数
  1. 输出脉冲线数:1024线:编码器每旋转一周输出的脉冲的个数,这个数据就是你在编写的定时器的重装载值
  • 两种编码器的区别
    • 从图中看就会来的更加直接:
      1. 带方向的编码器只有一路的脉冲输出,另外一路就是编码器的正反转的信号,零位信号就是编码器的机械零位。
  1. 正交编码器两路的脉冲输出,在判断电机的正反转时,是更加A、B两相的波形来的,其实就是看哪路波形超前,这里用32的定时器编码器功能就只需要去查计数器的方向位来判断电机的正反转。
  2. 引脚说明

2、脉冲计数对应电机速度的数据两种处理方式

(1) 定时器中断法,计算电机的圈数(过程小题大做,不推荐

  • 前面提到了编码器的线数为1024线(编码器每转一周就会输出1024个脉冲),那么你的重装载值为(1024-1),当计数值达到1024就会发生溢出中断,也就是说识别到了脉冲数为1024个(编码器转了一圈)。每发生一次中断,就说明电机转了一圈

(1)脉冲计数法,直接根据单位时间内所采集到的脉冲数作为电机的转速(更加精准,推荐

  • 编码器在实际的测数使用时确实是根据,电机转一圈:编码器转多少圈的方式来实际测量电机的转速的,但是在其本质就还是编码器的输出的脉冲数,所以直接计算编码器的单位时间的脉冲数推算电机的速度是一样的,数据来的更加直接、精准。

3、STM32定时器编码器模式理论分析

(1)定时器编码器模式选择

  • 首先是定时器编码器模式的选择,其实就是选择在那一个通道计数,还是两个通道都要计数也就是这三种模式。
    • 对于带方向的就只有一路脉冲,所以选择其中一路通道就ok了。
    • 对于正交编码器而言有两路脉冲,所以就选择第三中方式,两路通道都计数。

(2)定时器编码器输入极性的选择

  • 看懂这张图才是,确定输入极性的关键所在:所谓极性就是选择在输入脉冲信号的上升沿计数还是下降沿计数。

(3)定时器编码器输入极性的寄存器配置


CC1S=01(TIMx_CCMR1寄存器,IC1FP1映射到TI1) 
CC2S=01(TIMx_CCMR1寄存器,IC2FP2映射到TI2) 
CC1P=0(TIMx_CCER寄存器,IC1FP1不反相,IC1FP1=TI1) 
CC2P=0(TIMx_CCER寄存器,IC2FP2不反相,IC2FP2=TI2) 
SMS=011(TIMx_SMCR寄存器,所有的输入均在上升沿和下降沿有效). 
CEN=1(TIMx_CR1寄存器,计数器使能)
  • 这里解释一下
    • TIx 就相当于输入信号的 TIM4->CH1 TIM4->CH2;
    • TIxF 滤波后信号;
    • TIxFPx经过带极性选择的边缘检测器过后的产生的信号;

4、结合手册函数刨析库函数

(1)STM32定时器编码器模式的库函数配置代码

/*TIM2初始化为编码器接口*/
void Encoder_Init_TIM2(void)
{
	//结构体变量的创建
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
	TIM_ICInitTypeDef TIM_ICInitStructure;  
	GPIO_InitTypeDef GPIO_InitStructure;
	//RCC时钟使能
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器4的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
	
 	//编码器引脚的配置,对于定时器的通道管脚在用户手册上的==8.3.7定时器复用功能重映射==
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	//端口选择
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);				//根据设定参数初始化GPIOA
	
	//定时器的基本配置,这里主要介绍定时器的编码器模式,不做过多解释
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
	TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 
	TIM_TimeBaseStructure.TIM_Period = 0xffff; //设定计数器自动重装值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	//编码器模式选择与配置
	//参数一TIMx:定时器的选择
	//参数二TIM_EncoderMode:编码器模式的选择
	//参数三TIM_IC1Polarity:通道一的极性选择
	//参数四TIM_IC2Polarity:通道二的极性选择
//具体配置->正交编码器:配置如下
	TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
//带方向的编码器配置如下->区别只在于带方向的编码器只有一个脉冲输入,而正交编码器有两个脉冲输入
	TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_ICFilter = 10;
	TIM_ICInit(TIM2, &TIM_ICInitStructure);
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	//Reset counter
	TIM_SetCounter(TIM2,0);
	TIM_Cmd(TIM2, ENABLE); 
} 

(2)刨析

  1. 转到void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode, uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity)函数下可以看到如下代码:
/* Get the TIMx SMCR register value */
  tmpsmcr = TIMx->SMCR;
  
  /* Get the TIMx CCMR1 register value */
  tmpccmr1 = TIMx->CCMR1;
  
  /* Get the TIMx CCER register value */
  tmpccer = TIMx->CCER;
  • 再看下面来自用户手册中的截图,就不用我再继续挖下去了

5、编码器速度的读取

  • 前面已经说过了编码器的脉冲计数对应电机速度的数据处理方法,这里就继续说明了。
  • 速度是单位时间为前提的,我这里采用的是直接计算单位时间对应的脉冲数来推算电机的速度的。这里的单位时间也就是采样率的意思,就是我们间隔多少时间去采集然后清零脉冲计数值一次。这里的采样率不能太高,也不能太低。对电机的控制,一般采样率=5毫秒越小就越接近瞬时速度,为什么不能过小想必不用说大家也知道。所以这里就需要一个定时器来计算采样周期
//配置定时器1每5毫秒中断一次,在中断函数中读取编码器数值
void Time1_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStrure;
	NVIC_InitTypeDef NVIC_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
	//定时器的基本配置
	TIM_TimeBaseStrure.TIM_Period = 1000-1;//计数的次数
	TIM_TimeBaseStrure.TIM_Prescaler = 7200-1;//控制频率72000000/7200=10000;频率=10000HZ
	TIM_TimeBaseStrure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStrure.TIM_ClockDivision = 0;
	TIM_TimeBaseStrure.TIM_RepetitionCounter = 0;//重复计数次数
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStrure);
	
	TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断标志位
	TIM_ITConfig(TIM1,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//开启中断更新和触发中断源
	
	NVIC_InitStruct.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	TIM_Cmd(TIM1,ENABLE);
}
int Read_Encoder(void)
{
	int value_1;
	value_1=(int)TIM_GetCounter(TIM2);
	TIM_SetCounter(TIM2,0);
	return value_1;
}
void TIM1_UP_IRQHandler()
{
	int circle_count ;
	if(TIM_GetITStatus(TIM1,TIM_IT_Update) != RESET)
	{
		circle_count = Read_Encoder();
		TIM_ClearITPendingBit(TIM1,TIM_IT_Update);//清空中断标志位
	}
}

有关STM32编码器模式(带方向/正交编码)的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  5. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  8. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  9. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

  10. ruby-on-rails - 有没有一种工具可以在编码时自动保存对文件的增量更改? - 2

    我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功

随机推荐