CODE
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/iom16.h>
#define F_CPU 8000000UL
#define TIME 100
#define max_pwm 800 //(опредеяет период шим)
#define limit_pwm 800 //максимальное значение выдаваемое с помощью шим
#define PWM_DDR DDRB
#define PWM_PORT PORTB
#define PWM_PIN PB3
unsigned int t16=0;
unsigned char status_pwm=0;
unsigned int k=0;
void pause(unsigned long int t)
{
unsigned long int i;
for (i=0;i<=(t-1);i++);
};
void pwm_gen(unsigned int cmp16) //программная генерация ШИМ
{
unsigned long int cnt;
for (cnt=0;cnt<=max_pwm;cnt++)
{
if (cnt==0)
PWM_PORT |= (1<<PWM_PIN);
if (cnt>=cmp16)
PWM_PORT &= (0<<PWM_PIN);
};
};
ISR(INT0_vect) //прерывание по нажатию кнопки
{
pause(200*TIME);
pause(200*TIME);
pause(200*TIME);
pause(200*TIME);
if (status_pwm==0)
{
for (k=0;k<=limit_pwm;k++)
{ pwm_gen(k);};
PWM_PORT |= (1<<PWM_PIN);
status_pwm=1;
}
else
{
PWM_PORT &= (0<<PWM_PIN);
status_pwm=0;
};
};
int main(void)
{
DDRD = 0x00;
PORTD |= (1<<PD2); //источник тока для прерывания от кнопки.
PWM_DDR = 0xFF;
PWM_PORT = 0x00;
GICR |= (1 << INT0); //разрешаем прерывание инт 0 и по фронту на пине
MCUCR |= (1 << ISC01) | (0 << ISC00);
sei();
while(1)
{
asm volatile ("nop\n\t":

;
}
return 0;
}
Забавная идея постоянно вися в ISR после возникновения прерывания генерировать шимированный сигнал.
Во-первых зачем использовать long int там где обычного int вполне достаточно.
Во-вторых при входе в обработчик прерываний ставить кучу задержек - плохая идея.
В-третьих конструкция PWM_PORT &= (0<<PWM_PIN); не имеет смысла если хотите сбросить пин управления светодиодом.
Поставте чтоли PWM_PORT &= ~(1<<PWM_PIN);
По-поводу программы.
У вас сложно реализовано зажигание светодиода, пауза, гашение в void pwm_gen(unsigned int cmp16);
Упростите до:
Код
void pwm_gen(unsigned int cmp16) //программная генерация ШИМ
{
PWM_PORT |= (1<<PWM_PIN); //зажгли
while(cmp16--); //подождали
PWM_PORT &= ~(1<<PWM_PIN); //погасили
};
MCUCR |= (1 << ISC01) | (0 << ISC00); - лень искать в документации по какому фронту тут устанавливается генерирование прерываний.
Если по обоим то возможно выключается по второму фронту.
Действительно ли вызов функций pause обеспечивает 80 мС? Проверте - может быть антидребезг не работает.
Как вариант попробуйте очищать флаг внешнего прерывания при выходе из обработчика ISR.
Ну и может стоит в целом пересмотреть концепцию построения программы?
Использовать таймер-счётчик в режиме ШИМ, ввести опрос кнопки с програмным антидребезгом, вместо висения в ISR использовать установку флага что было прерывание и обрабатывать его в основном цикле программы.
Сообщение отредактировал rezident - May 17 2010, 20:04
Причина редактирования: Оформление цитаты исходника.