96线光电编码器测速电机用stm32c8t6控制得到电机实时转速,不使用HAL库函数的实现代码
时间: 2023-06-12 15:02:37 浏览: 140
以下是使用STM32C8T6控制96线光电编码器测速电机并得到电机实时转速的示例代码,不使用HAL库函数:
```c
#include "stm32c8t6.h"
#define PULSE_PER_REV 96 // 每转脉冲数
#define TIMER_FREQ 72000000 // 定时器时钟频率
#define PRESCALER 0 // 定时器预分频器值
#define ARR_VAL 0xFFFF // 定时器自动重载值
volatile uint32_t g_pulse_cnt = 0; // 脉冲计数器
volatile uint32_t g_last_pulse_cnt = 0; // 上一次的脉冲计数器值
volatile uint32_t g_cur_time = 0; // 当前时间
volatile uint32_t g_last_time = 0; // 上一次的时间
volatile uint32_t g_cur_speed = 0; // 当前速度
void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF) // 检查中断源是否为定时器更新中断
{
g_cur_time = TIM2->CNT; // 获取当前时间
g_cur_speed = (g_pulse_cnt - g_last_pulse_cnt) * TIMER_FREQ / (g_cur_time - g_last_time) / PULSE_PER_REV; // 计算当前速度
g_last_pulse_cnt = g_pulse_cnt; // 更新上一次的脉冲计数器值
g_last_time = g_cur_time; // 更新上一次的时间
TIM2->SR &= ~TIM_SR_UIF; // 清除中断标志位
}
}
void EXTI0_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR0) // 检查中断源是否为外部中断线0
{
g_pulse_cnt++; // 脉冲计数器加1
EXTI->PR |= EXTI_PR_PR0; // 清除中断标志位
}
}
void init_gpio(void)
{
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // 打开GPIOA时钟
GPIOA->MODER &= ~GPIO_MODER_MODER0; // 将PA0设置为输入模式
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR0; // 不使用上下拉电阻
}
void init_timer(void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // 打开TIM2时钟
TIM2->PSC = PRESCALER; // 设置预分频器
TIM2->ARR = ARR_VAL; // 设置自动重载值
TIM2->CNT = 0; // 将计数器清零
TIM2->DIER |= TIM_DIER_UIE; // 允许更新中断
TIM2->CR1 |= TIM_CR1_CEN; // 启动定时器
NVIC_EnableIRQ(TIM2_IRQn); // 使能TIM2中断
}
void init_exti(void)
{
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // 打开SYSCFG时钟
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA; // 将PA0映射到外部中断线0
EXTI->IMR |= EXTI_IMR_IM0; // 使能外部中断线0
EXTI->RTSR |= EXTI_RTSR_TR0; // 选择上升沿触发
NVIC_EnableIRQ(EXTI0_IRQn); // 使能EXTI0中断
}
int main(void)
{
init_gpio();
init_timer();
init_exti();
while(1)
{
}
}
```
在这个示例代码中,我们使用了TIM2定时器和PA0引脚作为外部中断线0来测量电机的速度。当PA0引脚接收到一个上升沿信号时,就会触发外部中断线0并执行`EXTI0_IRQHandler`函数,其中脉冲计数器`g_pulse_cnt`就会加1。定时器中断会在一定时间间隔内触发,执行`TIM2_IRQHandler`函数,我们就可以通过脉冲计数器的值来计算电机的实时转速了。注意,在这个示例代码中,我们没有使用HAL库函数,而是直接操作寄存器来控制STM32C8T6。
阅读全文