123
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
Модератор форума: nightmare, Huntswarrior, Aleks_Crow 
Форум » Программирование микроконтроллеров AVR, PIC » Вопросы по програмированию » BAM-PWM-ШИМ (*icon-0*)
BAM-PWM-ШИМ
Отправлено 10.08.2011 - 12:371
Администраторы
3318 сообщений
Мужчина


Наверняка, каждому попадалась задача, в которой нужно управлять яркостью огромного количества светодиодов. Аппаратных ШИМ-каналов никак не хватает, а если посчитать, сколько нужно вычислительных мощностей для программного ШИМ’а, то отпадает всякое желание с этим всем связываться.



Выход из этой ситуации называется BAM (Binary Angle Modulation).



image





Смысл очень прост – яркость кодируется двоичным числом, каждый бит которого соответствует
включенному состоянию светодиода. Чем старше бит числа, тем больше у него "вес".

 

положение бита вес
0 1
1 2
2 4
3 8
4 16
5 32
6 64
7 128

 



“Вес” соответствует длительности включения светодиода. К примеру, если мы хотим зажечь диод с яркостью 0b00101111, то нужно будет пропустить промежутки в 128 и 64, потом включить диод на промежуток 32 тика, потом снова отключить на 16 тиков и включить на 8, 4, 2, 1. Надеюсь, следующая картинка расставит все на свои места:



image





Чем BAM лучше, чем  ШИМ ?

  • Для его реализации нужно значительно меньше вычислительной мощности, чем для реализации ШИМ’а.

    Если для одного прохода 8битного ШИМ’а должно произойти 256 прерываний (для 100Гц ШИМ’а по прерыванию каждые 39мкс), то для BAM той-же глубины и частоты нужно всего 8 прерываний: каждые 5000мкс, 2500мкс, 1250мкс, 625мкс, 312мкс, 156мкс, 78мкс, 39мкс.
  • Мерцание диодов, модулированных BAM немного менее заметно, так как включения и выключения диодов происходят с большей чем несущая частотой. (исключение – ровно половина яркости, при таком положении, BAM и ШИМ будут одинаковы).




Почему такое хитрое название? Каждый бит занимает некий кусок фазы включённого состояния светодиода – отсюда слово Angle. Эти куски распределены как степени двойки, вот и получается слово Binary. Ну, то, что это вид модуляции догадаться не сложно. Вот и получается Binare Angle Modulation.



Используя такой подход, народ делает совершенно сумасшедшие вещи, к примеру – http://www.elcojacobs.com/shiftpwm/ Вы только вдумайтесь – регулировать яркость у 768 светодиодов на обычной атмеге! Потрясающе!







Источник: http://bsvi.ru
Источник: http://www.elcojacobs.com/shiftpwm/

Программа на С,
Автор Nigel Batten:

Code
#include <avr/io.h>
#include <avr/interrupt.h>

// define the processor speed if it's not been defined at the compilers command line.
#ifndef F_CPU
#define F_CPU 1000000
#endif

volatile uint8_t g_timeslice[8] ; // one byte for each bit-position being displayed on a port.
volatile uint8_t g_tick = 0;
volatile uint8_t g_bitpos = 0; // which bit position is currently being shown

void led_init( void ) ;
void led_encode_timeslices( uint8_t a[] );

__attribute((OS_main)) int main(void)
{
uint8_t brightness[8]; // brightness for each LED on port D.

led_init();
led_encode_timeslices( brightness ) ;
sei();

// now a (simple) demonstration...
// In the real-world, you'd probably want to decouple the
// animation speed from the LED flicker-rate.
uint8_t slowtick = 30;
uint8_t position = 0 ;
while(1)
{
while(g_tick==0){ /*wait for g_tick to be non-zero*/ }
g_tick = 0 ; //consume the tick
// make each of the LEDs slightly dimmer...
for ( uint8_t index = 0 ; index < 8 ; index++ )
{
if (brightness[ index ] > 0) brightness[ index ]-- ;
}
// once every 50 ticks, advance the head of the sweep...
slowtick-- ;
if (slowtick==0)
{
slowtick = 30;
position++ ;
position &= 7 ;
brightness[ position ] = 100 ;
}
// and now re-encode all the timeslices...
led_encode_timeslices( brightness ) ;
}
return(0);
}

// simple initialisation of the port and timer
void led_init( void )
{
PORTD = 0x00 ; // All outputs to 0.
DDRD = 0xff ; // All outputs.

TCCR2 |= (1<<WGM21) ; // set the timer to CTC mode.
TCCR2 |= ((1<<CS21)|(1<<CS20)) ; // use clock/32 tickrate
g_bitpos = 0 ;
OCR2 = 1 ; // initial delay.
TIMSK |= (1 << OCIE2) ; // Enable the Compare Match interrupt
}

// encode an array of 8 LED brightness bytes into the pattern
// to be shown on the port for each of the 8 timeslices.
void led_encode_timeslices( uint8_t intensity[] )
{
uint8_t portbits = 0;
uint8_t bitvalue ;

for ( uint8_t bitpos = 0 ; bitpos < 8 ; bitpos++ )
{
portbits = 0;
bitvalue = 1 ;
for ( uint8_t ledpos = 0 ; ledpos < 8 ; ledpos++ )
{
if (intensity[ ledpos ] & (1 << bitpos)) portbits |= bitvalue ;
bitvalue = bitvalue << 1 ;
}
g_timeslice[ bitpos ] = portbits ;
}
}

// Timer interrupt handler - called once per bit position.
ISR( TIMER2_COMP_vect )
{
g_bitpos ++ ;
g_bitpos &= 7;
PORTD = g_timeslice[ g_bitpos ] ;
// now set the delay...
TCNT2 = 0;
OCR2 <<= 1 ;
if (g_bitpos == 0) OCR2 = 1 ; // reset the compare match value.
if (g_bitpos == 7) g_tick = 1 ; // give the main loop a kick.
}


Файлы для загрузки:

Code
http://www.batsocks.co.uk/downloads/index_downloads.htm


Только дурак нуждается в порядке-гений господствует над хаосом...
Онлайн ЧАТ по робототехнике ! Заходи и общайся без регистрации =)
Профиль Личное сообщение Дом. страница icq Skype
31
Форум » Программирование микроконтроллеров AVR, PIC » Вопросы по програмированию » BAM-PWM-ШИМ (*icon-0*)
Страница 1 из 11
Поиск: