INT 21h

Домашняя страница самого страшного прерывания

Bit Angle Modulation (BAM) – аналог ШИМ (PWM)

№ 3772 В разделах: Программирование Электроника от October 31st, 2011,

Прошляпил я как-то параметры купленного микроконтроллера AtTiny461. Думал там 6 шимов, а оказалось 3 + 3 инверсных выхода. Но ZiB подсказал клевый выход – сделать программный ШИМ. Этот МК работает на частоте 20 МГц, поэтому можно сделать все 12 необходимых мне ШИМов всего лишь на 1 чипе.

Принцип оказался проще некуда. Допустим, нам надо светить светодиодом с яркостью 00110010b (50d). В этом байте 8 бит. Проход начинаем с самого левого бита до самого правого. Длительность задержки таймера зависит от текущей позиции обрабатываемого бита. На самом левом задержка должна быть 128 тактов, на самом правом 1, т.е. мы делим задержку предыдущего бита на 2 и полученную задержку применяем к текущему биту. Знаю, сразу не вкурили. Сейчас объясню:

  1. программа запустилась, установилась самая первая задержка OCR = 128, таймер запустился
  2. сработал таймер
  3. берем самый левый бит. если он 0, то зажигаем диодик, если 1, то гасим. устанавливаем задержку таймера OCR = OCR / 2
  4. сделали инкремент переменной с текущей позицией обрабатываемого бита, делаем сдвиг всех битов влево
  5. проверили не являлся ли обработанный бит последним
  6. если бит последний, сбрасываем счетчик позиций и берем значение в служебную переменную из переменной с яркостью светодиода
  7. конец работы обработчика таймера
  8. переход к шагу 2


Прежде всего нужно инициализировать таймер:

void init_timer()
{
    TCCR1A = (0 << WGM10) | (0 << WGM11);
    TCCR1B = (0 << CS12) | (1 << CS11) | (1 << CS10) | (1 << WGM12) | (0 << WGM13);
    OCR1A = 128;
    TIMSK |= _BV(OCIE1A);
    sei();
}

Обработчик таймера должен выглядеть примерно так:

static volatile uint8_t arr_value = 128,
                led_value = 0,
                led_value_bit = 0;

ISR(TIMER1_COMPA_vect)
{
    // изменение задержки
    OCR1A = (uint16_t) arr_value;
    arr_value = arr_value / 2;

    // проверяем первый бит яркости
    if (led_value & 0x80)
        LED_PORT &= ~LED_BIT;   // 0 - выкл диод
    else
        LED_PORT |= LED_BIT;    // 1 - вкл диод

    led_value <<= 1;            // сдвиг значения яркости на бит влево 
    led_value_bit++;            // запоминаем текущий бит

    // если посмотрели все 8 битов, то сбрасываемся и берем значение яркости заново
    if (led_value_bit > 7) {
        led_value = led_brightness;
        led_value_bit = 0;
        arr_value = 128;
    }
}

А теперь основная программа

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

#define LED_PORT    PORTB
#define LED_DDR        DDRB
#define LED_BIT        (1<<PB4)
#define LED_GREEN    (1<<PB3)

void main()
{
    LED_DDR |= LED_BIT | LED_GREEN;
    init_timer();

    while (1) {
        _delay_ms(20);
        LED_PORT ^= LED_GREEN;  // моргаю зеленым. так, для красоты.
        led_brightness = 1;
        led_value = led_brightness;     // делаем копию для прерывания

        /*
        //медленно изменяем яркость туда-сюда
        if (led_direction > 0) { led_brightness++; } else { led_brightness--; } 
        if (led_brightness == 255) led_direction = 0; 
        if (led_brightness == 0) led_direction = 1; 
        */
    }
    return 0;
}

В конце бесконечного цикла есть закомментированный кусок кода. Чтобы светодиод медленно разгорался и гаснул, раскомментируйте его, а строку с led_brightness = 1; вообще уберите.

2 комментариев »

2 комментариев »

Comment by Hammer | November 18, 2011 @ 01:06:57

А как же печально известный переход 0x7f 0x80? Когда получается то слишком длинный 0, то слишком длинная 1 и, как следствие, мерцание.

Comment by 21h | November 20, 2011 @ 05:50:06

ну мерцает, да. только программно исправлять такие недостатки.

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

Форма отправки комментария

*

Разрешенные HTML-теги:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

RSS RSS Feed только для этого поста |


Комментарии
  • 21h: нене ) без меня )
  • Серегй: Не совсем грабить)) если грабить можно и без рации, есть более благие цели, вы просто ответьте на мой вопрос,...
  • 21h: магазин грабить собрались? ) не, тут я не помощник ;)
  • Серегй: А что бы мне поймать чужую волну, что мне для этого нужно сделать? Допустим я купил данную рацию себе, мне...
  • 21h: слушать никто не запрещает. нет закона, который запрещает слушать. те, кто говорит иначе нагло врут. а если...
  • Серегй: Я хотел узнать могу ли я просто прийти с данной рацией baofeng uv-5r, допустим на объект, ну или вообще...
  • 21h: У меня есть только эти 2. По другим ничего не знаю. В интернете можно скачать инструкцию к вашей модели рации,...
  • Серегй: Добрый день! Хотелось бы задать пару вопросов по поводу раций, у Вас есть куда можно обратиться ТАТ.
  • 21h: потому, что нейросетью проще. яркость светофора меняется в зависимости от времени суток от маленькой красной...
  • Михаил: А зачем нейросеть? Почему цвет светофора определить без нейросетей?