STM32F1与STM32CubeIDE快速入门-定时器编码(Encoder)模式 定时器编码(Encoder)模式 1、定时器编码器模式 在编码器接口模式下,定时器模块作为具有两个输入的数字计数器运行。计数器由两个输入引脚上的每个有效转换计时。评估两个输入的转换序列并生成计数脉冲以及方向信号。根据顺序,计数器向上或向下计数。所以你不必单独检测这些脉冲,看看哪个先检测旋转方向和这种工作。现在,由于编码器模式硬件支持,所有这些都由硬件完成。
在编码器接口模式下配置的定时器提供有关传感器当前位置的信息。用户可以通过使用在捕获模式下配置的第二个定时器测量两个编码器事件之间的周期来获取动态信息(速度、加速度、减速度)。指示机械零位的编码器输出可用于此目的。根据两个事件之间的时间,也可以定期读取计数器。
在文中,我们将讨论 STM32 定时器编码器模式。 我们还将在编码器模式下使用定时器模块进行 STM32 旋转编码器接口。 我们将使用它来控制另一个实验室中 LED 的亮度。
编码器是广泛用于众多应用中的电子设备。 编码器可用作电机速度和位置传感应用、距离和长度测量等的传感器。 与电位计不同,编码器也可以用作输入设备,用户可以不受限制地转动。
编码器有不同类型,例如绝对类型和增量类型。 当编码器断电时,绝对编码器会保持位置信息。 编码器的位置在通电后立即可用。 编码器值与受控机械的物理位置之间的关系在装配时设置。 系统无需返回校准点即可保持位置精度。
增量编码器将立即报告位置变化,这是某些应用程序中必不可少的功能。 但是,它不会报告或跟踪绝对位置。 因此,由增量编码器监控的机械系统可能必须移动到固定参考点以初始化绝对位置测量。
我们将在本文中使用的旋转编码器是增量编码器,也称为正交编码器。 基本上,它是一个具有 2 个异相输出通道的增量编码器,用于许多需要检测运动方向的自动化应用中。 每个通道提供特定数量的每转等距脉冲 (PPR),并且运动方向通过一个通道领先或落后于另一个通道的相位关系来检测。
当需要更高的分辨率时,计数器可以从一个通道对正交编码器的脉冲串的前沿和后沿进行计数,这使每转的脉冲数增加一倍 (x2)。 对正交编码器的两个通道(A 和 B 通道)的前沿和后沿进行计数将使每转的脉冲数增加四倍 (x4)。
正如我们在之前的文章中所讨论的,定时器模块可以运行多种模式,其中一种模式是编码器模式。 定时器从外部通道的引脚获取时钟,可以选择计数边沿极性、预分频器值和输入滤波器周期。 编码器模式下STM32定时器的硬件提供了一个完整的硬件解决方案,用于检测信号和决定向上或向下计数的方向,这大大简化了连接此类传感器的固件开发过程。
1)编码器模式下的 STM32 定时器
两个输入 TI1 和 TI2 用于连接到增量编码器。 计数器由 TI1FP1 或 TI2FP2(输入滤波器和极性选择后的 TI1 和 TI2)上的每个有效转换计时。 评估两个输入的转换序列并生成计数脉冲以及方向信号。
根据计数器向上或向下计数的顺序,硬件会相应地修改 TIMx_CR1 寄存器中的 DIR 位。 DIR 位在任何输入(TI1 或 TI2)的每次转换时计算,无论计数器仅对 TI1、仅 TI2 或 TI1 和 TI2 计数。
编码器接口模式仅用作具有方向选择的外部时钟。 这意味着计数器只是在 0 和 TIMx_ARR 寄存器中的自动重载值之间连续计数。
在此模式下,计数器会根据增量编码器的速度和方向自动修改,因此其内容始终代表编码器的位置。 计数方向对应于所连接传感器的旋转方向。 外部增量编码器可以直接连接到 MCU,无需外部接口逻辑。
2、定时器配置
第二步、选择芯片 :
第三步、配置系统时钟
第四步、设置系统调试
第五步、配置定时器
第六步、配置串口通信
第七步、配置GPIO
保存工程配置,并生成代码。
3、代码生成与功能实现 STM32Cube IDE生成的主要代码如下:
1)定时器初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 /\*\* \* @brief TIM2 Initialization Function \* @param None \* @retval None \*/ static void MX\_TIM2\_Init(void) { /\* USER CODE BEGIN TIM2\_Init 0 \*/ /\* USER CODE END TIM2\_Init 0 \*/ TIM_Encoder_InitTypeDef sConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; /\* USER CODE BEGIN TIM2\_Init 1 \*/ /\* USER CODE END TIM2\_Init 1 \*/ htim2.Instance = TIM2; htim2.Init.Prescaler = 0; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 65535; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; sConfig.EncoderMode = TIM_ENCODERMODE_TI1; sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC1Prescaler = TIM_ICPSC_DIV1; sConfig.IC1Filter = 10; sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; sConfig.IC2Prescaler = TIM_ICPSC_DIV1; sConfig.IC2Filter = 0; if (HAL\_TIM\_Encoder\_Init(&htim2, &sConfig) != HAL_OK) { Error\_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL\_TIMEx\_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error\_Handler(); } /\* USER CODE BEGIN TIM2\_Init 2 \*/ /\* USER CODE END TIM2\_Init 2 \*/ }
2)串口初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /\*\* \* @brief USART1 Initialization Function \* @param None \* @retval None \*/ static void MX\_USART1\_UART\_Init(void) { /\* USER CODE BEGIN USART1\_Init 0 \*/ /\* USER CODE END USART1\_Init 0 \*/ /\* USER CODE BEGIN USART1\_Init 1 \*/ /\* USER CODE END USART1\_Init 1 \*/ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL\_UART\_Init(&huart1) != HAL_OK) { Error\_Handler(); } /\* USER CODE BEGIN USART1\_Init 2 \*/ /\* USER CODE END USART1\_Init 2 \*/ }
3)GPIO初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /\*\* \* @brief GPIO Initialization Function \* @param None \* @retval None \*/ static void MX\_GPIO\_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /\* GPIO Ports Clock Enable \*/ \_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE(); /\*Configure GPIO pin : PA2 \*/ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL\_GPIO\_Init(GPIOA, &GPIO_InitStruct); }
4)主程序入口及功能实现
在main.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 /\* USER CODE BEGIN PV \*/ uint8_t MSG[50] = {'\0'}; /\* USER CODE END PV \*/ /\*\* \* @brief The application entry point. \* @retval int \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_TIM2\_Init(); MX\_USART1\_UART\_Init(); /\* USER CODE BEGIN 2 \*/ HAL\_TIM\_Encoder\_Start(&htim2, TIM_CHANNEL_ALL); /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ while (1) { /\* USER CODE END WHILE \*/ /\* USER CODE BEGIN 3 \*/ if (HAL\_GPIO\_ReadPin(GPIOA, GPIO_PIN_2)) { sprintf(MSG, "Encoder Switch Released, Encoder Ticks = %d\n\r", ((TIM2->CNT) >> 2)); HAL\_UART\_Transmit(&huart1, MSG, sizeof(MSG), 100); } else { sprintf(MSG, "Encoder Switch Pressed, Encoder Ticks = %d\n\r", ((TIM2->CNT) >> 2)); HAL\_UART\_Transmit(&huart1, MSG, sizeof(MSG), 100); } HAL\_Delay(100); } /\* USER CODE END 3 \*/ }
4、程序运行结果
文章来源: https://iotsmart.blog.csdn.net/article/details/123362391
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!