赞
踩
目录
在使用esp-idf v5.0.1框架开发28BYJ-48步进电机驱动时,发现使用延时产生脉冲驱动uln2003,其最快延时到10ms,再小一点都无法驱动步进电机,gpio口也没有输出,相比之下51单片机使用延时可以正常的工作,esp32驱动的步进电机太慢了。其具体原因尚不明白,后来采用定时器产生脉冲,最终得以解决。以下内容则包含硬件通用定时器的简单驱动程序。(注:使用的v5.0.1版本,低版本可能无法使用)
使用组件库:
#include "driver/gptimer.h"
可参考IDF中的gptimr的例程
五线四相步进电机需使用4个gpio口,选用如下,可自定义
- #define MOTOR_PIN_A 14
- #define MOTOR_PIN_B 27
- #define MOTOR_PIN_C 26
- #define MOTOR_PIN_D 25
接下来配置初始化gpio,及全局变量:
- // 目标步数(剩余步数)
- static uint32_t target_step = 0;
- // 电机方向
- static int8_t direction = -1;
-
-
- // 定义步进电机的时序(一二相励磁方式)
- static const uint8_t step_sequence[] = {
- (1<<0)|(0<<1)|(0<<2)|(0<<3), // Step 1
- (1<<0)|(1<<1)|(0<<2)|(0<<3), // Step 2
- (0<<0)|(1<<1)|(0<<2)|(0<<3), // Step 3
- (0<<0)|(1<<1)|(1<<2)|(0<<3), // Step 4
- (0<<0)|(0<<1)|(1<<2)|(0<<3),
- (0<<0)|(0<<1)|(1<<2)|(1<<3),
- (0<<0)|(0<<1)|(0<<2)|(1<<3),
- (1<<0)|(0<<1)|(0<<2)|(1<<3)
- };
-
-
- /**
- * @brief 步进电机初始化函数,初始化GPIO口
- *
- */
- void motor_gpio_init()
- {
- ESP_LOGI(TAG,"configured motor GPIO !\n");
-
- gpio_config_t io_conf;
-
- // 禁用中断
- io_conf.intr_type = GPIO_INTR_DISABLE;
- // 设置为输出模式
- io_conf.mode = GPIO_MODE_OUTPUT;
- // 设置输出电平为低电平
- io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
- // 设置输出电平为高电平
- io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
- // 配置GPIO
- io_conf.pin_bit_mask = (1ULL << MOTOR_PIN_A) | (1ULL << MOTOR_PIN_B) |
- (1ULL << MOTOR_PIN_C) | (1ULL << MOTOR_PIN_D);
- gpio_config(&io_conf);
-
- }
定时器初始化:
- //定时器操作句柄
- gptimer_handle_t gptimer = NULL;
-
- void step_timer_init()
- {
- ESP_LOGI(TAG, "Create timer handle");
-
- gptimer_config_t timer_config = {
- .clk_src = GPTIMER_CLK_SRC_DEFAULT,
- .direction = GPTIMER_COUNT_UP,
- .resolution_hz = 1000000, // 1MHz, 1 tick=1us
- };
- ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
-
- gptimer_event_callbacks_t cbs = {
- .on_alarm = step_timer_inr,
- };
- ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
-
- ESP_ERROR_CHECK(gptimer_enable(gptimer));
-
- ESP_LOGI(TAG, "Start timer, stop it at alarm event");
- gptimer_alarm_config_t alarm_config1 = {
- .reload_count = 0,
- .alarm_count = 10000, // period = 10ms
- .flags.auto_reload_on_alarm = true,
- };
- ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config1));
- ESP_ERROR_CHECK(gptimer_start(gptimer));
-
- }
定时器中断回调:
- static bool IRAM_ATTR step_timer_inr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *args)
- {
- BaseType_t high_task_awoken = pdFALSE;
-
- // 相序下标
- static int8_t phase_index = 0;
- switch(direction) {
- case 1: { // 顺时针旋转
- phase_index--;
- if(phase_index < 0) {
- phase_index = 7;
- }
- gpio_set_level(MOTOR_PIN_A, (step_sequence[phase_index] >> 0) & 0x1);
- gpio_set_level(MOTOR_PIN_B, (step_sequence[phase_index] >> 1) & 0x1);
- gpio_set_level(MOTOR_PIN_C, (step_sequence[phase_index] >> 2) & 0x1);
- gpio_set_level(MOTOR_PIN_D, (step_sequence[phase_index] >> 3) & 0x1);
-
- target_step--;
- if(target_step <= 0) {
- direction = -1;
- }
- break;
- }
- case 0: { //逆时针旋转
- phase_index++;
- if(phase_index >= 8) {
- phase_index = 0;
- }
- gpio_set_level(MOTOR_PIN_A, (step_sequence[phase_index] >> 0) & 0x1);
- gpio_set_level(MOTOR_PIN_B, (step_sequence[phase_index] >> 1) & 0x1);
- gpio_set_level(MOTOR_PIN_C, (step_sequence[phase_index] >> 2) & 0x1);
- gpio_set_level(MOTOR_PIN_D, (step_sequence[phase_index] >> 3) & 0x1);
-
- target_step--;
- if(target_step <= 0) {
- direction = -1;
- }
- break;
- }
- default : break;
- }
-
- // return whether we need to yield at the end of ISR
- return (high_task_awoken == pdTRUE);
- }
写了两个步进电机控制函数:
- // 设置步进电机步数及方向
- void step_set_steps(uint32_t step, int8_t dire)
- {
- // 步数乘以相序节拍
- target_step = step * 8;
- direction = dire;
- }
-
- // 设置步进电机转速 (freq ms)
- void step_update_freq(uint16_t freq)
- {
- ESP_LOGI(TAG, "Stop timer");
- ESP_ERROR_CHECK(gptimer_stop(gptimer));
-
- ESP_LOGI(TAG, "Start timer, update alarm value ");
- gptimer_alarm_config_t alarm_config = {
- .reload_count = 0,
- .alarm_count = freq * 1000, // period = freq ms
- .flags.auto_reload_on_alarm = true,
- };
- ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
- ESP_ERROR_CHECK(gptimer_start(gptimer));
- }
使用以上程序只能简单驱动电机旋转,实际应用还得根据需求作出调整和优化,现只是简单记录学习成果。
江畔何人初见月?江月何年初照人?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。