在AtMega32U4中生成PWM脉冲的代码

时间:2018-12-20 00:15:00

标签: c

所以这是我的实际问题,我需要使用ATMEGA32U4的PWM引脚控制FET的电压。有两个信号。一个信号打开和​​关闭LED,打开1ms(1MHz),然后关闭0.1ms。第二个信号是一个PWM,我希望它是50kHZ的频率,在1ms导通时间内在那个50kHz的时间段内具有30个这些脉冲的分辨率。希望有道理。 AtMega以16MHz时钟运行。

所以我正在使用两个定时器,一个定时器使用中断来控制LED,另一个定时器控制发送到FET的PWM信号。

我非常感谢您的帮助。

到目前为止,我已经提出了这个建议。请引导我。

#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include <avr/interrupt.h>


uint8_t tot_overflow;

void timer1_init()
{

TCCR1A |= (1 << CS01);      // set up timer with prescaler = 8
TCNT1 = 0;
TIMSK1 |= (1 << TOIE1);
sei();
tot_overflow = 0;
}

ISR(TIMER1_OVF_vect)
{
tot_overflow++;
}

int main(void)
{
DDRD |= (1 << 0);       //set Port D

timer1_init();

while(1)
{
    if (tot_overflow >= 250)  
    {
            PORTD ^= (1 << 0);    // toggles the led
            TCNT1 = 0;            // reset the counter
            tot_overflow = 0;     // reset the overflow counter

    }
}
}

void pwm_init()
{
DDRB = 1<<6;        // Generate 30kHz PWM signal on PB6

TC4H = (319) >> 8;  // Set TOP, write upper bits first.
OCR4B = (319) & 0xFF;

TCCR4A = (1<<COM4A1) | (1<<PWM4A);

TCCR4B = (1<<CS40);     // Start timer


TC4H = (320) >> 8;      // Set 100% duty cycle
OCR4A = (320) & 0xFF;

while(1)
{
}
}

2 个答案:

答案 0 :(得分:1)

以下是根据您的要求使用计时器的示例。它基本上使用两个定时器,这两个定时器都连接到输出引脚以产生PWM。其中一个额外触发中断以打开和关闭另一个计时器。

根据您提供的代码,您无法在1ms内完全打开LED。您将其连接到8位定时器,并且没有时钟分频器和比较值的组合(精确地为1ms)。您应该将LED连接到16位Timer / Counter1。

注意:我手头没有32u4,因此无法在真实的硬件上进行测试。考虑该代码“正在进行中”和越野车。

#define F_CPU 16000000UL

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

void timer1_init()
{
    OCR0A = 69;    // Set TOP (maximum value that counter counts to)
    OCR0B = 63;    // Set duty cycle to ~10/11

    // Trigger interrupts when comparison is reached and at top
    TIMSK0 = (1 << OCIE0B) | ( 1 << TOIE0);
    // Set fast PWM on OC0B, turn pin low when counter reaches OCR0B
    TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
    // Set fast PWM on OC0B, start timer with prescaler of 256
    TCCR0B = (1 << WGM02) | (1 << CS01);
}

void pwm_init()
{
    TC4H = (320) >> 8;  // Set TOP (maximum value that counter counts to)
    OCR4C = (320) & 0xFF;

    TC4H = (160) >> 8;  // Set 50% duty cycle
    OCR4B = (160) & 0xFF;

    TCCR4A = (1<<COM4B1) | (1<<PWM4B);  // Set fast PWM on OC4B
}

// This ISR is called when the timer reaches the top value
ISR(TIMER0_OVF_vect)
{
    // Turn on PWM
    TCCR4B = (1 << CS40);
}

// This ISR is called when the timer reaches the compare value
ISR(TIMER0_COMPB_vect)
{
    // Turn off PWM
    TCCR4B = 0;
}

int main(void)
{
    DDRD = (1 << 0);   // Set pin PD0 as output (LED)
    DDRB = (1 << 6);   // Set pin PB6 as output (FET)

    pwm_init();
    timer1_init();

    sei();
}

答案 1 :(得分:0)

#define F_CPU 16000000UL

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

void timer1_init()
{
OCR1A = 319;    // Set TOP (maximum value that counter counts to) 
OCR1B = 290;    // Set duty cycle to ~10/11

// Trigger interrupts when comparison is reached and at top
TIMSK1 = (1 << OCIE1B) | ( 1 << TOIE1);
// Set fast PWM on OC0B, turn pin low when counter reaches OCR0B
TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
// Set fast PWM on OC0B, start timer with prescaler of 8
TCCR1B = (1 << WGM12) | (1 << CS11);
}

// This ISR is called when the timer reaches the top value
ISR(TIMER1_OVF_vect)
{
// Turn on PWM
TCCR1B = (1 << CS10);
}

// This ISR is called when the timer reaches the compare value
ISR(TIMER1_COMPB_vect)
{
// Turn off PWM
TCCR1B = 0;
}

void pwm_init()
{
//define PC6 as output
DDRC |= (1 << 6);

//drive pins low
PORTC = 0x00;

//max counter value (50kHz)
ICR3 = 0x14;

//set duty to half
OCR3A = 0x0A;

//compare output mode:
TCCR3A = (1 << COM3A0) | (0 << COM3A0) | (0 << WGM31) | (0 << WGM30);

//prescaler/start timer:
TCCR3A = (1 << WGM33) | (0 << WGM12) | (0 << CS32) | (0 << CS31) | (1 << CS30);

}

int main(void)
{
timer1_init();
pwm_init();

while(1)
{
}
}