Регулировка яркости семисегментного индикатораПри использовании семисегментных индикаторов часто возникает необходимость в регулировке их яркости свечения. Существуют несколько таких способов. Например, изменять номиналы токоограничительных резисторов, подключенных к сегментам индикатора, но опять нет возможности оперативно регулировать яркость. Также можно подключить к общему катоду(аноду) транзистор, который будет ограничивать ток протекающий через индикаторы. Мы же применим способ благодаря которому можно программно менять яркость - ШИМ регулирование.

В учебной статье про динамическую индикацию мы использовали таймер/счетчик 2, который работал в Нормальном режиме. Но обычно для реализации динамической индикации используют режим СТС (сброс при совпадении), это режим, при котором частота возникновения прерываний по совпадению значений счетчика таймера и регистра OCR2 определяется содержимым OCR2 и предделителем тактовой частоты таймера. При таком режиме работы таймера можно легко изменять частоту обновления разрядов, записывая в регистр сравнения OCR2 необходимое значение, предварительно расчитанное.

Сейчас же мы будем использовать режим FASTPWM и будем обрабатывать два прерывания - по совпадению и переполнению таймера. Режим FASTPWM отличается тем, что при равенстве регистра сравнения (OCR2) и счетчика таймера (TCNT2) возникает прерывание по совпадению, но счетчик не обнуляется (как в режиме СТС), а продолжает считать до переполнения, после чего возникает соответствующее прерывание. При этом прерывания по совпадению и переполнению таймера будут следовать с одинаковой частотой. Значение записанное в регистр OCR2 будет определять время прошедшее от переполнения до совпадения. В обработчике по совпадению мы будем обновлять показания индикаторов, а в обработчике прерывания по переполнению гасить все разряды индикатора при этом мы получим ШИМ регулирование яркостью индикатора.

На рисунках ниже показаны два графика, с большим и малым значением OCR2:

Установка в регистр OCR2 разных значений позволяет менять скважность импульсов проходящих через индикатор, а значит и яркость его свечения. Чем меньше значение OCR2, тем ярче горит индикатор. Так как регулировка может происходить только в сторону уменьшения тока, значения токоограничительных резисторов выбираются по максимальной яркости индикатора.

Напишем программу в которой значение регистра OCR2 будет выводиться на семисегментный индикатор. Меняться же это значение будет с помощью двух кнопок "+"(SB1) и "-"(SB2), которые подключены к выводам PC0 и PC1, также к этим выводам программно подключены внутренние подтягивающие резисторы.  Микроконтроллер Atmega8 работает от внутреннего генератора частотой 8MHz. Семисегментный индикатор трехразрядный с общим анодом. Схема на рисунке ниже:

Регулировка яркости семисегментного индикатора

Как было сказано выше, в программе используется два типа прерывания от таймера 2:

ISR (TIMER2_COMP_vect){} // Прерывание по совпадению

ISR (TIMER2_OVF_vect){} // Прерывание по переполнению

В прерывании по совпадению мы обновляем данные дисплея, поочередно включая каждый его разряд. В прерывании по переполнению мы выключаем сразу все разряды индикатора, таким образом осуществляя ШИМ регулирование.

/********** Использование динамической индикации ***********************/
/********** Регулировка яркости семисегментного индикатора *************/

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

//------------------0-----1-----2-----3-----4-----5-----6-----7-----8-----9---
char SEGMENT[ ] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

volatile unsigned char segcounter = 0;
volatile int display = 0;

// Обработчик прерывания по совпадению таймера2
ISR (TIMER2_COMP_vect)
{	
PORTD = 0xFF; // Гасим все сегменты
PORTB = (1 << segcounter); // Выбираем следующий разряд
	
switch (segcounter)
{	
case 0: // Раскладываем число на разряды
PORTD = ~(SEGMENT[display % 1000 / 100]);
break;	
case 1:
PORTD = ~(SEGMENT[display % 100 / 10]);
break;		
case 2:
PORTD = ~(SEGMENT[display % 10]);
break;
}
if ((segcounter++) > 1) segcounter = 0;	
}

// Обработчик прерывания по переполнению таймера 2
ISR (TIMER2_OVF_vect)
{
PORTB = 0x00; // Гасим все разряды
}

int main (void) 
{
// Настройка портов
DDRB |= (1 << PB2)|(1 << PB1)|(1 << PB0); // Разряды индикатора
PORTB = 0x00;

DDRC &= ~(1 << PC1)|(1 << PC0); // Кнопки
PORTC |= (1 << PC1)|(1 << PC0); // Вкл. внутренние резисторы

DDRD |= 0xFF; // Сегменты индикатора 
PORTD = 0x00;

// Настройка таймера 2
TCCR2 |= (1 << WGM21)|(1 << WGM20)|(1 << CS21); // Режим FASTPWM. Предделитель на 8
TIMSK |= (1 << TOIE2)|(1 << OCIE2); // Разрешение прерываний по таймеру 2
OCR2 = 50; // Начальное значение OCR2 

sei(); // Глобально разрешаем прерывания
 
while(1)
{		
if((PINC&(1 << PC0)) == 0) // Если нажали кнопку "+"
{
if(OCR2++ >= 255) // Увеличиваем значение OCR2
OCR2 = 255;
_delay_ms(100);
}

if((PINC&(1 << PC1)) == 0) // Если нажали кнопку "-"
{
if(OCR2-- <= 0) // Уменьшаем значение OCR2
OCR2 = 0;
_delay_ms(100);
}

display = OCR2; // Выводим значение OCR2 на индикатор

}
}