Страница 1 из 1

ШИМ на любую ногу. Задержка.

Добавлено: Вс мар 25, 2012 14:28:47
Hedgehoguse
Доброго дня всем!
Пролог. Давно почитываю ваш сайт. Нравятся самоделки и проекты, порой интересно понаблюдать за созданием устройства. Самому тоже нравится поднапрячь мозги, но практического опыта все же не хватает.
Итак! Имеется контроллер ATmega16 на тестовой плате. Имеется очень большое желание плавного управления яркостью светодиода. Вполне логично, что для этого имеет смысл использования ШИМ, что я и делаю. Однако, если же хочу использовать не стандартную ногу OC1A, а любую на мой выбор, то придется изменить ШИМ. Отключаю ногу и ставлю два прерывания по сравнению и по переполнению. В одном случае устанавливаю нужную мне ногу, в другом сбрасываю. Однако, даже когда регистр OCR1A равен нулю, то все равно имеется некая задержка во времени, которая не дает моему светодиоду потухнуть полностью. Вот пример на COdeVision:

Код: Выделить всё

//Настройка таймера:
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000,000 kHz
// Mode: Fast PWM top=00FFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x01;
TCCR1B=0x09;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

//Включение прерываний:
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x14;

//Прерывания:
// Timer1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Place your code here
  PORTD.0=1;
}

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here
  PORTD.0=0;
}
Задержка ШИМ.png
(130.9 КБ) 464 скачивания
Собственно, вот и ситуация. А хотелось бы если не избавиться, то минимизировать эту задержку. Предполагаю, что это происходит в связи с обработкой прерывания, или нет? Возможно ли избавиться? Менять скорость ШИМ на более низкую не очень-то хотелось бы - а если не один светодиод решу сделать, а, допустим, 50. Тогда надо на максимальной скорости работать, чтобы успевать переключаться. Выходить на 10 битное разрешение тоже, наверное, будет неудобно.
Есть ли другие варианты решения? Гуру, подскажите! :-)

Re: ШИМ на любую ногу. Задержка.

Добавлено: Вс мар 25, 2012 15:32:19
Flasher

Re: ШИМ на любую ногу. Задержка.

Добавлено: Пн мар 26, 2012 06:04:51
Hedgehoguse
Спасибо большое! Удобная вещь :)
Только с кодом не совсем разберусь. Делаю так:

Код: Выделить всё

//Переменные:
char x;
char led_bit;

//Таймер:
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Fast PWM top=00FFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x01;
TCCR1B=0x0A;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

//Прерывания:
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x10;

//Сам код прерывания:
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here
  PORTD.7=(x<<led_bit) & 0x80;
  //led_val=led_val/2;
  OCR1AL=OCR1AL+2^(7-led_bit);//led_val;
  led_bit++;
  if(led_bit==8){led_bit=0;OCR1AL=0;PORTC.7=!PORTC.7;}
  PORTC.6=!PORTC.6;
}

По моему видению работа прерывания должна выглядеть где-то так (алгоритм):
BAM.png
(8.89 КБ) 362 скачивания
А работает вот так:
BAM_реальная работа.png
(8.97 КБ) 516 скачиваний
Т.е. ему глубоко до лампочки, что я меняю OCR1A. Работает все равно с одним шагом. Где затык? Что я не понимать?
Спасибо.

Re: ШИМ на любую ногу. Задержка.

Добавлено: Пн мар 26, 2012 19:13:37
Hedgehoguse
Прошу прощения, уже сказал себе - "Шарик, ты балбес".
Косяков было несколько.
1) Начнем с того, что режим неудобный выбрал - fast PWM, в итоге остановился на CTC, который сам обнуляется при сравнении.
2) Затем, выбрал таймер, который работает с разрешением 10 бит. В итоге максимальное значение OCR не 255, а 1023. Что неудобно, ибо придется все умножать на 8. Т.к. мну для светодиода нафиг не надо столько градаций
3) Пока не врубился, но почему-то число в степень никак не хотело возводиться, пришлось лепить вторую переменную и на каждом шаге умножать ее на два (1*2; 2*2; 4*2; ...).

Уже поздно, завтра дальше буду разбираться с кодом, т.к. косяков в нем еще больше, чем полезного. :facepalm: