Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: помогите с программкой
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
essev
Всем привет.

Устройство на АВР Мега16 реализует следующую логику:

Нажимаем кнопку и плавно зажигается светодиод - далее он горит на максимум.
Если еще раз нажать кнопку, то светодиод тухнет.

Написал программку, проверил все в протеусе (версия 7.6)...работает нормально. Но в железе тупит нереально.
Светодиод плавно загорается и после этого тухнет, хотя кнопку не нажимал...

Антидребезг сделал простой задержкой на 80 мс. Но проблема не исчезла.
Кварц - внутренняя RC-цепочка 8 Мгц

Помогите, пожалуйста. Все файлы прилагаются
mempfis_
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":smile.gif;
}


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 использовать установку флага что было прерывание и обрабатывать его в основном цикле программы.
skilful
Цитата(mempfis_ @ May 16 2010, 22:23) *
Забавная идея постоянно вися в ISR после возникновения прерывания генерировать шимированный сигнал.


ну задача получилась такая, что ШИМ генерится однократно и плавно зажигается диод только после нажатия кнопки.

Цитата(mempfis_ @ May 16 2010, 22:23) *
Во-первых зачем использовать long int там где обычного int вполне достаточно.


с этим полностью согласен

Цитата(mempfis_ @ May 16 2010, 22:23) *
Во-вторых при входе в обработчик прерываний ставить кучу задержек - плохая идея.


а как победить дребезг. Существует вроде несколько программных способов, но почему задержки плохо?

Цитата(mempfis_ @ May 16 2010, 22:23) *
В-третьих конструкция PWM_PORT &= (0<<PWM_PIN); не имеет смысла если хотите сбросить пин управления светодиодом.
Поставте чтоли PWM_PORT &= ~(1<<PWM_PIN);

что в протеусе, что в авр студии сбрасывается хорошо smile.gif


Цитата(mempfis_ @ May 16 2010, 22:23) *
По-поводу программы.
У вас сложно реализовано зажигание светодиода, пауза, гашение в void pwm_gen(unsigned int cmp16);
Упростите до:
void pwm_gen(unsigned int cmp16) //программная генерация ШИМ
{
PWM_PORT |= (1<<PWM_PIN); //зажгли

while(cmp16--); //подождали

PWM_PORT &= ~(1<<PWM_PIN); //погасили
};


спасибо - упрощу smile.gif


Цитата(mempfis_ @ May 16 2010, 22:23) *
MCUCR |= (1 << ISC01) | (0 << ISC00); - лень искать в документации по какому фронту тут устанавливается генерирование прерываний.
Если по обоим то возможно выключается по второму фронту.
Действительно ли вызов функций pause обеспечивает 80 мС? Проверте - может быть антидребезг не работает.


авр студио дает 20 мс на ф-ю pause

Цитата(mempfis_ @ May 16 2010, 22:23) *
Как вариант попробуйте очищать флаг внешнего прерывания при выходе из обработчика ISR.

ок

Цитата(mempfis_ @ May 16 2010, 22:23) *
Ну и может стоит в целом пересмотреть концепцию построения программы?
Использовать таймер-счётчик в режиме ШИМ, ввести опрос кнопки с програмным антидребезгом, вместо висения в ISR использовать установку флага что было прерывание и обрабатывать его в основном цикле программы.


спасибо за должную критику smile.gif я проги не часто пишу - вот поэтому столько кривостей.
но пока не понятно почему обработчик прерывания в реальной железке с ума сходит...
mempfis_
Цитата
ну задача получилась такая, что ШИМ генерится однократно и плавно зажигается диод только после нажатия кнопки

Забавно то что в программе ето делается вися в обработчике прерывания....

Цитата
а как победить дребезг. почему задержки плохо?

Элементарно - раз в 10-30 мС снимаете состояние пина и сохраняете в массив из 3-5 значений. Если у кнопки активный 0 то делаете над всем массивом OR (если 1 то AND) и если в результате получаете активное состояние то кнопка нажата!
Задержки в прерываниях плохо потому что можете пропустить другие прерывания (представте что в будущем будет проект в котором будет задействовано 10 прерываний!!!).

Цитата
конструкция PWM_PORT &= (0<<PWM_PIN); что в протеусе, что в авр студии сбрасывается хорошо

Потому что всегда выполняется операция PWM_PORT&0x00 - потому и сбрасывается...
Подумайте над тем что значит выражение (0<<PWM_PIN).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.