快速 PWM 1kHz |使用 RC 接收器进行 6V DC 发动机控制 || ATtiny2313

问题描述 投票:0回答:1

这是我的程序,无法正常工作。

无论遥控器上的拉杆位置如何,MCU 都会向引脚 D PB2 4.7V 发送信号。其他引脚A PB3、B PB2、C PD5 为0V。发动机不运转。

数据表链接:https://ww1.microchip.com/downloads/en/DeviceDoc/doc8246.pdf

  • TCCR0A 表格 82 页
  • TCCR1A 表格 111 页

我应该如何设置寄存器以在引脚上生成 PWM 信号?

  • PB3 + PB2 发动机左转
  • PB4 + PC5 引擎右转
  • RC 接收器通过 PD2 引脚向 MCU 发送 PWM 信号。

我正在 Microchip Studio 中编写程序,以使用 RC 无线电接收器控制 DC 6V 发动机(graupner 400 max 4,0A)。

我正在使用 ATtiny2313A 和 F_CPU 16 MHz。

为了控制电机,我想生成频率为 1 kHz 的 PWM 信号。

非常感谢。

#define F_CPU 16000000L
#define MCU attiny2313
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#define A PB3
#define D PB2
#define B PB4
#define C PD5
volatile uint16_t R = 0;
volatile uint8_t R0 = 0;
volatile uint16_t R1 = 0;
void measurePWM() {
    TCNT1 = 0;
    while (!(PIND & (1 << PD2)));
    while (PIND & (1 << PD2));
    R = TCNT1;
}
int main(void) {
TCCR0A = (1 << COM0A1) | (1 << WGM02) | (1 << WGM01) | (1 << WGM00);
TCCR1A = (1 << COM1A1) | (1 << WGM12) | (1 << WGM10);
TCCR0B = (1 << COM0B1) | (1 << WGM02) | (1 << WGM01) | (1 << WGM00) | (1 << CS01);
TCCR1B = (1 << COM1B1) | (1 << WGM12) | (1 << WGM10);
    DDRB |= (1 << DDB2) | (1 << DDB3) | (1 << DDB4);
    DDRD |= (1 << DDD5);
    PORTB &= ~((1 << A) | (1 << D) | (1 << B));
    PORTD &= ~(1 << C);
    DDRD &= ~(1 << PD2);
    PORTD &= ~(1 << PD2);
    while (1) {
        measurePWM();
        R0 = (R - 958) * 255 / (1815 - 958);
        R1 = (R - 958) * 65534 / (1815 - 958);
        if (R >= 1500) {
            OCR0A = 0;
            OCR1A = 0;
            OCR0B = R0;
            OCR1B = R1;
        } else if (R <= 1300) {
            OCR0A = 0;
            OCR1A = 0;
            OCR0B = R0;
            OCR1B = R1;
        } else {
            OCR0A = 0;
            OCR0B = 0;
            OCR1A = 0;
            OCR1B = 0;
        }
        _delay_ms(100);
    }
    return 0;
}
avr attiny motordriver
1个回答
0
投票

如果你想产生一个PWM,你可以使用定时器来实现。检查Tiny2313A的数据表。第71页的框图显示,timer0中已经集成了波形生成模式。如果您想使用其他引脚,则需要使用定时器中断。

定时器支持两种 PWM 生成模式

  • FastPWM(第 77 页)
  • 相位校正 PWM(第 79 页)

使用集成 PWM 模式生成约 1kHz 波形的简单示例:

FastPWM 的 PWM 频率可通过 enter image description here 计算。对于您的系统时钟速度,我们使用 64 (N) 的预分频器获得约 976 Hz 的频率 f_PWM。

#define F_CPU 16000000UL

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

ISR(TIMER0_OVF)
{
  PORTB |= (1<<PB2);
}

ISR(TIMER0_OCR0A)
{
  PORTB &= ~(1<<PB2);
}

int main(void)
{
  // Timer initialisation:
  TCCR0A = (1<<WGM01) | (1<<WGM00);  // For FastPWM
  OCR0A = 127;                       // For 50% duty cycle
  TIMSK = (1<<TOIE0) | (1<<OCIE0A);  // Enable timer overflow and ocr register overflow interrupt

  TCCR0B = (1<<CS01) | (1<<CS00);    // For presacler 64

  // Port setup
  DDRB = (1<<PB2);

  // Enable interrupts globally
  sei();

  while(1)
  {
    // Do something that is not time critical...
  }
}

现在可以通过 OCR0A 寄存器控制占空比。

如果使用微控制器的 OC 引脚,则无需使用 ISR,因为定时器本身会设置 OC 引脚。您已经在示例中使用了它。

如果要测量外部pwm时钟周期,则需要使用外部中断来扩展程序。预定义引脚触发外部中断。通过引脚的状态和附加定时器,可以测量当前的占空比,例如:

#define F_CPU 16000000UL

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

volatile unsigned int count = 0;
volatile unsigned int duty_cycle = 0;

ISR(INT0_vect)
{
  if(ISR PIN is HIGH)
  {
    // Calculate duty cycle in %
    duty_cycle = count * 100 / temp;

    // Reset Timer
    TCNT0 = 0;
  }
  else
  {
    count = TCNT0
  }
}

int main(void)
{
  // Enable external interrupt:
  MCUCR = (1<<ISC00);  // Any logical change will call the interrupt
  GIMSK = (1<<INT0);   // Enable external interrupt 0

  // Timer initialisation:
  TCCR0B = (1<<CS01) | (1<<CS00);    // For presacler 64
  // The lower the prescaler gets the higher the precision of the measurement. It is necessary that the datatype becomes no overflow (unsigned int -> max. value 65535)

  sei();  // Enable interrupts globally

  while(1)
  {
    // Do something that is not time critical...
  }
}

也许这有帮助。目前我没有平台可以测试...

© www.soinside.com 2019 - 2024. All rights reserved.