这是我的程序,无法正常工作。
无论遥控器上的拉杆位置如何,MCU 都会向引脚 D PB2 4.7V 发送信号。其他引脚A PB3、B PB2、C PD5 为0V。发动机不运转。
数据表链接:https://ww1.microchip.com/downloads/en/DeviceDoc/doc8246.pdf
我应该如何设置寄存器以在引脚上生成 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;
}
如果你想产生一个PWM,你可以使用定时器来实现。检查Tiny2313A的数据表。第71页的框图显示,timer0中已经集成了波形生成模式。如果您想使用其他引脚,则需要使用定时器中断。
定时器支持两种 PWM 生成模式
使用集成 PWM 模式生成约 1kHz 波形的简单示例:
FastPWM 的 PWM 频率可通过 计算。对于您的系统时钟速度,我们使用 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...
}
}
也许这有帮助。目前我没有平台可以测试...