当前位置:   article > 正文

AVR单片机驱动两相四线步进电机_avr单片机控制电机转动

avr单片机控制电机转动

功能:由软件设定旋转角度实现正反转,根据旋转角度输出对应的脉冲个数。

我是根据正点原子步进电机定位实验写的。

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define PRESCALER 8 // 预分频系数
#define PWM_FREQUENCY 1500 // PWM频率(Hz)
#define TOP_VALUE ((F_CPU / PRESCALER / PWM_FREQUENCY) - 1) // 计算TOP值,注意数据类型

//串口初始化
#define MOTO_ENABLE PORTB &= ~(1 << PB4)
#define MOTO_DISABLE PORTB |= (1 << PB4)

#define MOTO_RIGHT PORTB |= (1 << PB6)
#define MOTO_LEFT PORTB &= ~(1 << PB6)

#define MAX_STEP_ANGLE  0.1125               /* 步距角 */
uint8_t g_run_flag;

typedef struct
{
    int angle ;                             /* 存取角度值 */
    uint8_t dir;                            /* 方向 */
    uint8_t en;                             /* 使能 */
    volatile uint32_t pulse_count;          /* 角度转脉冲的脉冲数 */
    volatile int add_pulse_count;           /* ???????????? */
} STEPPER_MOTOR;

extern  STEPPER_MOTOR g_stepper;
STEPPER_MOTOR g_stepper = {0};

void Io_Init(void)
{
    DDRB |= (1 <<PB4) | (1 << PB6);   //PB5设置为输出
    PORTB &= ~(1 << PB4);
}

//定时器停止函数
void Pwm_Oc1a_Stop(void)
{
    TCCR1A = 0;
    MOTO_DISABLE;
}

//定时器1快速PWM
void timer1_pwm_init(void) {
    DDRB |= (1 << PB5);
    PORTB  &= ~(1 << PB5);//输出低电平
    TCNT1 = 0;
    TCCR1B |=(1<<WGM13)|(1<<WGM12);//快速PWM,模式14   手册Page 122页 -> Table 61
    TCCR1A |=(1<<WGM11)|(0<<WGM10);
    TCCR1A |=(1<<COM1A1)|(0<<COM1A0);//OC1A输出模式,比较匹配时清零OC1A,在TOP时置位OC1A,手册Page 121页 -> Table 59
    TCCR1B |= (0<<CS12)|(0<<CS11)|(1<<CS10);//Page124页,Table 62,8分频:8MHz/8=1MHz(1us),即定时器每一步1us
    ICR1 = TOP_VALUE;//计数最大TOP值等于ICR1,PWM周期T=(ICR1+1)*1us,频率范围:15Hz(ICR1=0XFFFF) ~ 500KHz(ICR1=1,OCR1A=0) Page 113页-114页
    OCR1A = ICR1 / 2;
    TIMSK1 |= (1 << OCIE1A);
    sei();
}

//角度转脉冲实现
void step_angle2pulse(int angle)
{
    if (angle >= 0)        //根据角度正负值判断正传还是反转
    {
        MOTO_RIGHT;
    }else 
    {
        angle = -angle;        //取绝对值
        MOTO_LEFT;
    }
    
    g_stepper.pulse_count = angle / MAX_STEP_ANGLE;        //角度/步距角得出步数,一个步距角对应一个脉冲
    if (g_stepper.pulse_count == 0)
    {
        Pwm_Oc1a_Stop();
    }else 
    timer1_pwm_init();
    
}

uint8_t i = 0;
//中断服务函数

SIGNAL(TIMER1_COMPA_vect){
g_run_flag = 1;
g_stepper.pulse_count--;
if (PINB & (1 << PB6) )    //判断pb6电平状态,如果为高电平
{
    g_stepper.add_pulse_count++;    //脉冲个数累计
}else
{
    g_stepper.add_pulse_count--;    
}
if (g_stepper.pulse_count <= 0)
{
    Pwm_Oc1a_Stop();
    g_run_flag = 0;
}
    DDRG |= (1 << PG5);
    PORTG &= ~(1 << PG5);
}

void main(void){
    int angle = 0;
    Io_Init();
    step_angle2pulse(-360);
    
while(1){
 
}
}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/917802
推荐阅读
相关标签
  

闽ICP备14008679号