Свежие обсуждения
Микроконтроллеры

Output compare на ATMega8535 - не могу разобраться...

1 2

Приветствую участников форума! Столкнулся с непонятной проблемой, хотя, возможно, решение и лежит на поверхности - просто я не могу его увидеть. Суть вот в чем - в системе (мега8535) 16-битный таймер переполняется раз в секунду (идет отсчет времени). Параллельно я хочу организовать медленный ШИМ на выводе OC1A, загружая в регистр сравнения разные значения. Чтобы при совпадении значения регистров таймера и регистра сравнения на выводе появлялся высокий уровень, а при переполнении таймера - низкий. Но почему-то получается так, что в прерывании по таймеру перевести вывод в низкий уровень не получается, т.е. как он включается при сравнении, так в 1 и остается... Вот такой простой кусок кода:

#include <mega8535.h>

interrupt [TIM1_OVF] void timer1_ovf_isr(void) //прерывание по таймеру
{
TCCR1A=0b00000000; //в прерывании отключаем вывод OC1A - т.е. он должен стать просто выходом
PORTD.5=0; // принудительно переводим выход в 0 (вот эта строка и не работает)...
TCCR1A=0b11000000; // и возвращаем этот выход снова в режим output compare
}

void main(void)
{
PORTD=0x00;
DDRD=0x60; Пины 5 и 6 порта D - выходы

TCCR1A=0b11000000; //высокий уровень при совпадении TCNT1 и OCR1
TCCR1B=0x03; // Таймер тикает с предделителем 64

OCR1A=32000; //примерно на половине счета таймера - сравнение.

TIMSK=0x04; //прерывание по переполнению

#asm("sei");

while (1)
{
};
}

Реально получается, что по достижении таймером значения регистра сравнения выход становится в 1 и так и остается. Подскажите пожалуйста, в чем я не прав...
С уважением, Николай.

 

Николай, в даташите сказано, что изменение режима линий порта при настройке OCR должно произойти до того, как будет включен режим вывода на линии. Попробуйте в начале обработчика отключить линию в DDR, а в конце - снова включить ее на вывод. Если не поможет - не парьтесь, навешайте на прерывание по сравнению еще один обработчик и взводите линию там (режим OCR при этом, естественно, должен быть без вывода на линию).

 

Изменение режима и так происходит в функции main, еще до того, как произойдет первое прерывание. Ввод операции с DDR не помог, а проблему я решил именно так, как Вы посоветовали Дополнительным прерыванием по сравнению. Но желание разобраться в ситуации осталось.

Расследование показало: низкий уровень на ножке МК появляется, но снова становится высоким при подключении к Compare Output, хотя таймер-то уже обнулился! И совпадения быть не может...

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TCCR1A=0b00000000; //отключаем порт от Compare Output
PORTD.5=0; //выставляем на ножке низкий уровень (он реально выставляется!)
delay_ms(100); //и держится ровно до тех пор, пока мы...
TCCR1A=0b11000000; //...снова не подключим OCR1. Но в этот момент значение TCNT1 никак не равно OCR1A
}

С уважением, Николай.

 

Ув Николай, я, видимо не совсем ясно выразился. Вот что имелось в виду:

DDRD=0x40;
TCCR1A=0b00000000;
DDRD=0x60;
PORTD.5=0;
DDRD=0x40;
TCCR1A=0b11000000;
DDRD=0x60;

Или нечто подобное

 

Так я так и делал... Не помогает У меня самый главный вопрос - почему срабатывает сравнение тогда, когда значения регистров никак не могут быть равны... Т.е. таймер уже обнулился, в регистре сравнения - значение, явно отличное от нуля, а эффект получается как от совпадения...

 

Я думаю что если использовать этот счетчик не в pwm режиме то вообще невозможно добиться pwm такими средствами. Сбрасываться нога не будет поскольку не от чего ей сбрасываться. Предлагается в прерывании по сравнению Прибавлять к тому значению что было в регистре сравнения еще число и переводить счетчик в режим сброса ноги по сравнению. Следующий раз в прерывании сравнения прибавлять оставшийся интервал от периода и устанавливать взвод ножки по сравнению. Потом снова прибавить и установить на сброс по сравнению. Заодно можно обеспечит более быстрый pwm - быстрее периода. Только минимальный интервал срабатывания должен быть больше времени работы всех обработчиков прерываний.

 

В качестве критерия какой интервал прибавлять и как настраивать управление ногой можно использовать текущее значение выхода

 

ответ на главный вопрос - он не срабатывает а не сбрасывается после предыдущего срабатывания. Автоматический сброс только для pwm режима. А так только ручками все самому делать.

 

Это тоже вариант, но это тоже обходной путь. Сейчас сделано так - нога взводится в прерывании по сравнению и сбрасывается в прерывании по таймеру. Я пытаюсь для себя разобраться, почему при выполнении этого кода:
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
TCCR1A=0b00000000;
PORTD.5=0;
delay_ms(100);
TCCR1A=0b11000000; //вот на этой строке на ноге снова появляется высокий уровень...
}
Несмотря на явное несовпадение в этот момент регистров TCNT1 и OCR1 - вот я в чем разобраться пытаюсь...
С уважением, Николай.

 

Так я ручками и пытаюсь, в обработчике прерывания по переполнению...

Только сейчас мысль пришла - а если попробовать флаг прерывания скинуть??? Ручками??? Пойду попробую!!!