STM32—TIMx实现编码器四倍频

本文介绍如何使用STM32的TIM2和TIM4定时器以编码器模式进行四倍频测速,详细讲解了配置过程,包括计数边沿设置、极性选择、使能和计数方向等,以及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.储备知识

通过STM32的定时器编码器接口模式对编码器进行四倍频,并使用M法测速得到小车电机的速度信息。
编码器的相关知识之前介绍过:编码器s
M法测速:读取每10ms的脉冲数,以脉冲数的多少代表速度的快慢。

二.TIMx的编码器模式介绍

TIMx的编码器模式,每个定时器只能测量一组AB相的值(编码器的AB相),分别使用CH1和CH2接AB相,通过判断CH1和CH2的输入信号,来实现编码器的测速。需要配置TI1和TI2的极性、计数边沿、自动装载值等信息来驱动编码器模式。在实现编码器后,电机的转速会以计数器的值来表示,然后在另一个TIMx的10ms中断程序中读取编码器计数器的值(读取完要置零)。
下面大概总结一下配置编码器模式的信息:

1.计数边沿设置

我是使用编码器四倍频技术测速,所以要对AB相的上下沿都要计数,也就是说TI1和TI2的上下沿都要触发计数器计时。
关于编码器计数模式,通过配置TIMx_SMCR寄存器中的SMS[2:0]位可以设置,参考手册中的原图如下:
在这里插入图片描述
在这里插入图片描述
所以,要配置编码器模式3才可以对TI1和TI2的上下沿都计数,即SMS=011。

2.选择极性和使能

设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性,如图:
在这里插入图片描述
在这里插入图片描述

3.使能

TIMx_CR1寄存器中的CEN=’1’用来使能计数器:
在这里插入图片描述
在这里插入图片描述

4.计数方向

在工作时,计数器只在0到TIMx_ARR寄存器的自动重装值之间进行连续计数,所以计数开始前要配置TIMx_ARR。
通过对AB相的输入捕获,可以得到电机的转动方向和转速,是通过计数器的计数方向和计数值来表示的,计数方向和编码器信号的对应关系如图:
在这里插入图片描述
四倍频配置如下:
在这里插入图片描述
得到的计数器计数过程就如图:
在这里插入图片描述

三.代码部分

在STM32中,可以用TIM2、TIM4的CH1、CH2来连接俩个电机的AB相,进行编码器测速,然后在TIM3进行10ms的中断读取计数器的值,这样就实现了编码器的四倍频测速,代码如下:

TIM2、TIM4初始化代码

/* 测量编码器输出的TIM初始化,TIMx编码器模式 
TIM2、TIM4编码器模式测速
A电机:PA0、PA1(TIM2的CH1、CH2)
B电机:PB6、PB7(TIM2的CH1、CH2)
*/
void Encoder_TIM2_TIM4_Init( void )
{
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_ICInitTypeDef TIM_ICInitStruct;
	
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE );
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM4, ENABLE );
	
	/* GPIO初始化 */
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
	GPIO_Init( GPIOA, &GPIO_InitStruct );
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_Init( GPIOB, &GPIO_InitStruct );
	
	/* 配置时基结构体 */
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = 65535;//定时器自动重装值
	TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
	TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStruct );
	TIM_TimeBaseInit( TIM4, &TIM_TimeBaseInitStruct );
	
	/* 编码器模式3,极性上升沿 */
	TIM_EncoderInterfaceConfig( TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );
	TIM_EncoderInterfaceConfig( TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising );

	/* 配置输入捕获结构体 */
	TIM_ICStructInit( &TIM_ICInitStruct );
	/*CCMR1寄存器位7:4是IC1F[3:0]:这几位定义了TI1输入的采样频率及数字滤波器长度。数字滤波器由一个事件计数器组成,它记
录到N个事件后会产生一个输出的跳变:*/
	TIM_ICInitStruct.TIM_ICFilter = 10;//1010:采样频率fSAMPLING=fDTS/16, N=5
	TIM_ICInit( TIM2, &TIM_ICInitStruct );
	TIM_ICInit( TIM4, &TIM_ICInitStruct );
	
	/* 中断配置 */
	TIM_ClearFlag( TIM2, TIM_IT_Update );
	TIM_ITConfig( TIM2, TIM_IT_Update, ENABLE );
	TIM_ClearFlag( TIM4, TIM_IT_Update );
	TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );
	
	/* 配置计数器的值 */
	TIM_SetCounter( TIM2, 0 );
	TIM_SetCounter( TIM2, 0 );
	
	/* 使能TIM */
	TIM_Cmd( TIM2, ENABLE );
	TIM_Cmd( TIM4, ENABLE );
	
}

读取编码器计数值

/* 读取编码器计数 */
int Read_Encoder( uint8_t TIMx )
{
	int Encoder;
	/* 读取相应TIM的计数器值CNT,然后清零 */
	switch(TIMx)
	{
		case 2:Encoder = (short)TIM2->CNT;TIM2->CNT=0;break;
		case 4:Encoder = (short)TIM4->CNT;TIM4->CNT=0;break;
		default:Encoder = 0;break;
	}
	
	return Encoder;
}

TIM2、TIM4中断程序

void TIM2_IRQHandler(void)
{
	/* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
0:无输入捕获产生;
1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
	if( TIM2->SR&0x0001 )
		;
	/* 清除中断标志位 */
	TIM2->SR&=~(1<<0);
}



void TIM4_IRQHandler(void)
{
	/* SR位:当捕获事件发生时该位由硬件置’1’,它由软件清’0’或通过读TIMx_CCR1清’0’。
0:无输入捕获产生;
1:计数器值已被捕获(拷贝)至TIMx_CCR1(在IC1上检测到与所选极性相同的边沿)。 */
	if( TIM4->SR&0x0001 )
		;
	/* 清除中断标志位 */
	TIM4->SR&=~(1<<0);
}

TIM3配置、中断读取计数器值

void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

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

	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(  //使能或者失能指定的TIM中断
		TIM3, //TIM2
		TIM_IT_Update ,
		ENABLE  //使能
		);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
							 
}
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
		Encoder_Left=(short)TIM2->CNT;
		TIM2->CNT=0;	
		}
}
### Docker 连接 VSCode 出现卡顿的原因分析 当使用 Docker 和 Visual Studio Code 结合进行远程开发时,可能会遇到性能不佳的情况。这通常是由于以下几个原因造成的: - **网络带宽不足**:如果主机与容器之间的通信依赖于低效的网络环境,则可能导致数据传输缓慢。 - **资源分配不合理**:Docker 容器内部未合理设置 CPU 或内存限额,造成争抢系统资源的现象。 - **文件同步机制效率低下**:某些情况下,默认采用的双向文件同步策略会增加不必要的负载。 ### 解决方案建议 为了改善这种状况,可以从多个角度入手优化配置: #### 调整 Docker Compose 文件参数 通过修改 `docker-compose.yml` 来指定更合适的硬件资源配置给目标服务实例[^2]: ```yaml version: '3' services: app: image: your_image_name deploy: resources: limits: cpus: "0.5" memory: 512M ``` #### 使用单向文件同步模式 对于不需要实时更新源码到宿主机的应用程序来说,可以关闭自动上传功能,仅保留下载方向的操作,从而减轻同步压力[^4]: ```json { "files.watcherExclude": { "**/.git/**": true, "**/*.log": true }, "remote.SSH.remotePlatform": "linux", "syncMode": "downloadOnly" // 设置为只读取不写入的方式 } ``` #### 增强本地缓存能力 利用 `.devcontainer` 目录下的 JSON 文件来定义额外的工作区选项,比如启用更大的磁盘空间配额或是开启特定工具链的支持[^5]: ```json { "name": "Your Project Name", "image": "your_docker_image", "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind", "settings": { "terminal.integrated.shell.linux": "/bin/bash" } } ``` 另外,在日常操作中也应注意保持良好的编码习惯,尽量减少大容量文件夹或项目的繁切换率;定期清理不再使用的镜像和卷宗以释放存储空间;以及确保所用版本均为官方最新稳定版等措施均有助于提升整体流畅度。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值