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

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

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

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

CAPTCHA
*

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

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


Комментарии
  • Игорь: Все настроил, еще раз просмотрел видео и методом научного тыка все настроил и сохранил, все работает и обе...
  • 21h: Здравствуйте, Игорь! Я не знаю :) Думаю аналогично согласно инструкции к вашей радиостанции.
  • Игорь: Добрый день, просмотрел Ваше видео все доступно и ясно для 8 ми канальных радеек, но мне нада настроить 69...
  • Гоги: Есть инструкция к Моторолкам – она подходит к серии Motorola TLKR T4… Т8. В конце сетка частот и...
  • 21h: торчок давно уже не обновлял, как только закрыл сайт где он работал. да, это морда для opentracker. без...
  • Buter: Какова дальнейшая жизнь торчка? Он кстати веб-интерфейсом для OpenTracker выступает? Без OpenTracker работать...
  • 21h: понятия не имею. гуглите инструкцию к вашей радейке и сверяйтесь с ней.
  • Денис: хочу их подружить с uv5r
  • Денис: t-388 walkie talkie на эти шпаргалочек нет,или как приминить ваши к их настройке?
  • John: Стекла для электроник – техночас.ру