Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

seglogoВ продолжение урока, рассмотрим динамическую индикацию. Если вы внимательно изучили статическую индикацию, то знаете, что сегментный индикатор это набор светодиодов. Для того, чтобы подключить индикатор, нужно 7 ножек микроконтроллера. Но, вдруг нам понадобилось использовать несколько индикаторов, например 2, 3, 4…

Тогда нам понадобится уже 14, 21, 28 ножек, а ножек итак мало… Тут нам на помощь приходит динамическая индикация. Основная задача динамической индикации — снизить количество используемых ножек микроконтроллера. Обратите внимание на схеме задействовано 9, а не 14 ножек. Ножки управления все подключены параллельно.
sch2

В общем смысле работает данная конструкция следующим образом: вначале выводится конфигурация первого числа на общую шину и включаем PB1. Первый индикатор загорается, с нужным числом. Затем его гасим, выводим конфигурацию второго числа на шину данных, зажигаем второй индикатор, выключаем.

Более детально. В первый момент времени все выключено PORTB=0x00; PORTD=0xFF; так как схема с общим «+», анодом. Далее на PORTD посылается конфигурация первого числа, например «0». Из статической индикации мы помним:

case 0:
{
  PORTD=0xC0; 
  break;
}

Но обратите внимание, «+» подключен к PORTB.1, т.е. чтобы зажечь сегмент нужно включить ножку PORTB.1=1; 

Во второй момент времени, снова все выключаем, посылаем конфигурацию второго числа и включаем, на этот раз, второй индикатор. Далее повторяем.

При высоких частотах, человеческий глаз не способен разглядеть эти переключения, и кажется что индикатор горит постоянно. Рекомендуется не использовать частоты кратные 50Гц. В своем тестовом проекте я использовал 120Гц. Таймер настроен на частоту 1МГц. Код обрабатывается в прерывании таймера1. Прерывание вызывается 240 раз в секунду, потому что индикаторов два, поэтому 1000 000/240=4166 или 0x1046 пихаем в регистр сравнения. Протеус подружить с динамическим индикатором не удалось, зато на железе заработало сразу.

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

Для схемы с общим анодом

sch4

Для схемы с общим катодом

sch3

В качестве тестовой прошивки использовал таймер из предыдущего проекта.

Видео работы прошивки

140 комментариев: Урок 6.2 Динамическая индикация в AVR микроконтроллерах

  • там же в прерывании

  • ….interrupt ….. // по прерыванию раз в секунду
    {
    if(sek < 5)
    {
    i[sek] = result;
    sek++;
    }
    else
    {
    mid = (i[0]+i[1]+i[2]+i[3]+i[4])/5;
    sek = 0;
    }
    }

    что означает i и mid 🙁

  • i это временная переменная ,которая хранит значение результатов за 1,2,3 секунду, сделано в виде массива. mid — среднее

  • Здравствуйте, так а а где прошивка к данному проекту

  • Здравствуйте. Я только учусь, и возник такой вопрос- можно использовать такую индикацию в качестве например часов без использования программного таймера? Или возникнут проблемы, например отставать будут

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

  • Ув. Автор,
    В коде прошивки на Си есть директива #asm(sei). Я раньше писал на ассемблере под 8086, и там, насколько я помню, эта инструкция была sti (от англ. reSTore Interrupts). Это опечатка, или же язык ассемблера для микроконтроллеров AVR от такового для 8086?
    Заранее спасибо за ответ

  • Простите, язык отличается. Пропустил слово, с кем не бывает.

  • Отличается, можно в даташите посмотреть набор команд

  • Спасибо

  • Мне нужно написать программу для этой схемы
    http://vk.com/photo274168004_360830925
    Смысл в том, что я должен нажатием кнопок +- уменьшать и увеличивать значения показываемые на индикаторе. Но эти значения фиксированные.
    Вы не могли бы сказать мне правильно ли сделана схема.
    И, если не тяжело пример программы для нее.

  • Здравствуйте уважаемый админ)Простой вопрос. А можно ли в протеусе увидеть прерывание?(в виде изменения на осцилоскопе состояния порта ,если например в прерывании поставить порт на единицу?).Буду рад если вы ответите))

  • можно

  • Огромное спасибо за ваш сайт с обучением.
    По теме в Протеусе нужно использовать 2-х сегментный, или 4-х сегментный индикатор, тогда все заработает.

  • Здравствуйте, возникла такая ситуация, реализовал динамическую индикацию на PORTB как в первом уроке, применяя для переключения PORTC.0, PORTC.1 в протеусе работает замечательно , а на железе нет, подаю питание, коротко мерцают разряды и потухают, тактировал от внутреннего на 8МГц, от чего это может быть? Заранее благодарен.

  • Вот листинг:

    #include
    #include
    #asm
    .equ __w1_port=0x12 ;PORTD
    .equ __w1_bit=0
    #endasm
    #include
    #include

    int temper;
    int number = 0;
    int number1 = 0;
    int number2 = 0;
    int i=0;
    eeprom int final=0;

    interrupt [EXT_INT0] void ext_int0_isr(void)
    {

    }

    interrupt [EXT_INT1] void ext_int1_isr(void)
    {

    }

    // Timer 1 output compare A interrupt service routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    PORTC.0=0;
    PORTC.1=0;
    if(i==0)
    {
    number=number1;
    PORTC.1=1;
    i++;
    }
    else
    {
    number=number2;
    PORTC.0=1;
    i=0;
    }

    switch(number)
    {
    case 0:{PORTB=0xC0; break;}
    case 1:{PORTB=0xF9; break;}
    case 2:{PORTB=0xA4; break;}
    case 3:{PORTB=0xB0; break;}
    case 4:{PORTB=0x99; break;}
    case 5:{PORTB=0x92; break;}
    case 6:{PORTB=0x82; break;}
    case 7:{PORTB=0xF8; break;}
    case 8:{PORTB=0x80; break;}
    case 9:{PORTB=0x90; break;}
    }
    }

    void main(void)
    {
    float dT = 1.2;
    PORTB=0xC0;
    DDRB=0xFF;

    PORTC=0xFF;
    DDRC=0xFF;

    PORTD = 0x0C;
    DDRD = 0x80;

    TCCR1A=0x00;
    TCCR1B=0x0A;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x10;
    OCR1AL=0x46;

    GICR|=0xC0;
    MCUCR=0x00;
    GIFR=0xC0;
    TIMSK=0x10;

    w1_init();
    // Global enable interrupts
    #asm(«sei»)

    while (1)
    {
    temper=ds18b20_temperature(0);
    if (temper>1000)
    {
    temper=4096.0-temper;
    temper=-temper;
    }

    number1= temper/10;
    number2= temper%10;
    delay_ms(1500);

    };
    }

  • это из за датчика температуры

  • Большое спасибо, буду разбираться…

  • Доброго дня ! Подскажите пожалуйста как быть с регистром сравнения если у меня задействовано 3 сегмента. С двумя по выше сказанным параметрам работает отлично, после добавления третьего индикаторы вообще не светятся, разве что в протеусе. Спасибо.

    третий сегмент добавил так :
    switch (i){
    case 0: number = n1; PORTC.0 = 1;i++;break;
    case 1: number = n2; PORTC.1 = 1;i++;break;
    case 2: number = n3; PORTC.2 = 1;i=0;break;
    }
    n1 = temper/100;
    n2 = (temper%100)/10;
    n3 = (temper%100)%10;

  • посчитайте частоту может недостаточно чтобы светилось, пройдитесь отладчиком

  • Здравствуйте! Вот решил попробывать себя в микроконторолерах. Решил собрать устройтво которое считает количество нажатий кнопок, одна кнопка инкрементирует другая декрементирует. вывожу на симесигментник. проблема вот в чем: как связать внешнее прерывание по нажатию кнопки и вывод на симесигментик с моей програмой?
    код:
    #include
    #include // for putsf
    #include
    #define ISC10 2
    #define ISC11 3
    #define INT1 7
    unsigned char int1 = 0;

    int i=0;
    int k=0;
    int l=0;
    int m=0;
    int rezUHH=0;
    int rezUH=0;
    int rezUL=0;
    int rezULL=0;

    //##########################################################
    //# Подпрограммы
    //##########################################################

    void display(int ind_tabl, int point)
    {
    if (point==0)
    {
    switch (ind_tabl)
    {
    case 0 : PORTD = 0b11111010; break;
    case 1 : PORTD = 0b10000010; break;
    case 2 : PORTD = 0b10111001; break;
    case 3 : PORTD = 0b10101011; break;
    case 4 : PORTD = 0b11000011; break;
    case 5 : PORTD = 0b01101011; break;
    case 6 : PORTD = 0b01111011; break;
    case 7 : PORTD = 0b10100010; break;
    case 8 : PORTD = 0b11111011; break;
    case 9 : PORTD = 0b11101011; break;
    }
    }
    if (point==1)
    {
    switch (ind_tabl)
    {
    case 0 : PORTD = 0b11111110; break;
    case 1 : PORTD = 0b10000110; break;
    case 2 : PORTD = 0b10111101; break;
    case 3 : PORTD = 0b10101111; break;
    case 4 : PORTD = 0b11000111; break;
    case 5 : PORTD = 0b01101111; break;
    case 6 : PORTD = 0b01111111; break;
    case 7 : PORTD = 0b10100110; break;
    case 8 : PORTD = 0b11111111; break;
    case 9 : PORTD = 0b11101111; break;
    }
    }
    }

    //##########################################################
    //# Обработка прерываний
    //##########################################################

    // Прерывание по совпадению T1 с OCR1A f=300 Hz (75 Hz)
    interrupt [TIM1_COMPA] void T1_CompareA (void)
    { int rez=0;
    i++;
    if (i==1)
    {
    PORTB.7 = 0;
    PORTB.2 = 1;
    display(rezUHH, 0);
    }
    if (i==2)
    {
    PORTB.2 = 0;
    PORTB.1 = 1;
    display(rezUH, 1);
    }
    if (i==3)
    {
    PORTB.1 = 0;
    PORTB.0 = 1;
    display(rezUL, 0);
    }
    if (i==4)
    {
    PORTB.0 = 0;
    PORTB.7 = 1;
    display(rezULL, 0);
    i = 0;
    }

    {}
    rez = (ADCW*5)/2;

    rezUHH = rez/1000;
    rezUH = (rez/100)%10;
    rezUL = (rez/10)%10;
    rezULL = rez%10;
    }

    //##########################################################
    //# Инициализация
    //##########################################################

    void initialization(void)
    {

    // Ин-ция таймеров
    TCNT0=0x00;
    // T1:
    TCCR1A=0b00000000; // Включаем перывй тамер с предделителем на
    TCCR1B=0b00001010; // 8 (f T1 = 8 000 000 / 8 = 1 000 000 Hz)
    TCNT1H=0x00; // Обнуляем содержимое таймера
    TCNT1L=0x00; // Обнуляем содержимое таймера
    OCR1AH=0x0D; // Устанавливаем OCR1A в 0x0D04 (2 222 — 1)
    OCR1AL=0x04;
    OCR1BH=0x00;
    OCR1BL=0x00;
    TIMSK=0b00010000;
    // T3:
    ASSR=0x00;
    //определяем биты регистров
    // Внешие прерывания
    //INT0;
    //INT1;
    MCUCR=0x00;

    // Ин-ция портов
    DDRB=0xFF; // Порт В — выход
    PORTB=0x00;
    DDRC=0b11111110; // Порт С — выход
    PORTC=0x00;
    DDRD=0xFF; // Порт D — выход
    PORTD=0x00;

    #asm(«sei»)
    }

    //##########################################################
    //# Тело основной программы
    //##########################################################

    void main (void)
    {

    initialization();
    sei();//устанавливаем бит глобального разрешения прерывани
    // Бесконечный цикл
    Идея в том что: при нажатии одной кнопки ждем вторую кнопку и потом инкрементируем а при нажатии второй ждем первую и декриментируем. Часть кода в вайл(ниже) просто как пример идеи вместо портов должны каак я понимаю быть внешние прерывания. Но блин! Я ничего стоящего не нашел по инфе .как это все обьединить . Помогите новичку! Извиняюсь если вопрос уж шибко большой.
    while (1){
    M1:
    if (PORTB.3==1)

    { while(1)

    if(PORTB.4==1)

    {k++;
    goto M1; }
    if(l=2000){l=0; goto M1;}}}
    if (PORTB.4==1)
    { while(1)
    {m++;
    if(PORTB.3==1)

    {k++;
    m=0; goto M1; }
    if(m=2000){m=0; goto M1;}}}}

  • не увидел обработчика внешнего прерывания

  • а ,все я сделал по другому) но теперь другой вопрос обратно не декрекрементирует, а как обратно сделать я докумекать немогу. тоесть вычитание. в идеале это будет датчик количества людей в помещении на кухню поставить там чтоб при выходе последнего свет гас или при входе загорался вместо кнопок будут ик излучатели с фото транзисторами

    /*****************************************************
    Автор программы :

    Project : Реализация шины I2C (TWI)_Master
    Version :
    Date :
    Author :
    Company :
    Comments:

    Chip type : ATmega8
    Program type : Application
    AVR Core Clock frequency: 8,000000 MHz
    Memory model : Small
    External RAM size : 0
    Program size : x bytes
    *****************************************************/

    #include
    #include // for putsf
    #include
    #include

    unsigned int i=0;
    unsigned int k=0;
    unsigned int l=0;
    unsigned int m=0;

    //##########################################################
    //# Подпрограммы
    //##########################################################

    void display(unsigned int ind_tabl)
    {
    switch (ind_tabl)
    {
    case 0 : PORTD = 0b11111010; break;
    case 1 : PORTD = 0b10000010; break;
    case 2 : PORTD = 0b10111001; break;
    case 3 : PORTD = 0b10101011; break;
    case 4 : PORTD = 0b11000011; break;
    case 5 : PORTD = 0b01101011; break;
    case 6 : PORTD = 0b01111011; break;
    case 7 : PORTD = 0b10100010; break;
    case 8 : PORTD = 0b11111011; break;
    case 9 : PORTD = 0b11101011; break;
    }
    }

    //##########################################################
    //# Обработка прерываний
    //##########################################################

    // Прерывание по совпадению T1 с OCR1A f=300 Hz (75 Hz)
    interrupt [TIM1_COMPA] void T1_CompareA (void)
    { unsigned int rez=0;
    i++;
    if (i==1)
    {
    PORTB.0 = 0;
    PORTB.2 = 1;
    display(0);
    }
    if (i==2)
    {
    PORTB.2 = 0;
    PORTB.1 = 1;
    rez = k/10;
    display(rez);
    }
    if (i==3)
    {
    PORTB.1 = 0;
    PORTB.0 = 1;
    rez = k%10;
    display(rez);
    i = 0;
    }

    }

    //##########################################################
    //# Инициализация
    //##########################################################

    void initialization(void)
    {

    // Ин-ция таймеров
    TCNT0=0x00;
    // T1:
    TCCR1A=0b00000000; // Включаем перывй тамер с предделителем на
    TCCR1B=0b00001010; // 8 (f T1 = 8 000 000 / 8 = 1 000 000 Hz)
    TCNT1H=0x00; // Обнуляем содержимое таймера
    TCNT1L=0x00; // Обнуляем содержимое таймера
    OCR1AH=0x0D; // Устанавливаем OCR1A в 0x0D04 (2 222 — 1)
    OCR1AL=0x04;
    OCR1BH=0x00;
    OCR1BL=0x00;
    TIMSK=0b00010000;
    // T3:
    ASSR=0x00;
    //определяем биты регистров

    // Внешие прерывания
    //INT0;
    //INT1;
    MCUCR=0x00;

    // Ин-ция портов
    DDRB=0xFF; // Порт В — выход
    PORTB=0x00;
    DDRC=0b11111001; // Порт С — выход
    PORTC=0x00;
    DDRD=0xFF; // Порт D — выход
    PORTD=0x00;

    #asm(«sei»)
    }

    //##########################################################
    //# Тело основной программы
    //##########################################################

    void main (void)
    {

    initialization();

    while (1)
    {
    M1:
    if (PINC.1==1)
    {while(1)
    {
    if(PINC.2==1)
    {
    if (k0) k—;
    goto M1;
    }
    //if(m=2000) { m=0; goto M1;}
    }
    }
    }

    извиняюсь если забиваю коменты) 😳

  • void main (void)
    {

    initialization();

    while (1)
    {
    M1:
    if (PINC.1==1)
    {while(1)
    {
    if(PINC.2==1)
    {
    if (k0) k—;
    goto M1;
    }
    //if(m=2000) { m=0; goto M1;}
    }
    }
    }

    обрезало)

  • https://drive.google.com/file/d/0B6Jn0dae8wjbd1pHRTZuMmR2V0U/view?usp=sharing

    извиняюсь раньше не додумался 😳 в коментах режет последнею часть

  • Я не понял вообще логики, по идее есть 2 датчика, логично разместить их один у самого выхода, другой чуть вглубь кухни. Тогда появится 2 основных возможных варианта: вначале размыкается датчик 1, потом датчик 2 — это когда кто то вошел в кухню. Вариант 2 сначала размыкается датчик 2, а потом датчик 1 — значит кто то ушел. Собственно остается обработать эти 2 состояния. Для этого нужно 2 флага, для каждого датчика и одна переменная, которая по этим флагам изменяется.

  • описано выше вами правильно, но есть одно но ! я сколько не мучился , ничего не получается как вы сказали 2 состояния не обрабатываются, обрабатывается только одно: когда ктото вошел он считает все впорядке + , а на выход тобишь -минус 1, шишь ! уж как хочешь я этот код переделывал с флагами без флагов . Если есть пример похожий или где почитать о подобном, буду благодарен , я сам только начал изучать си. Вот и спрашиваю. Примеров просто не нашел, сам по логике пытаюсь докумекать(

  • Первое что в голову пришло

    ext_interrupt1()
    {
    if(flag2 == 1)
    {
    peoples++;
    flag1 = 0;
    flag2 = 0;
    }
    else
    flag1 = 1;
    }

    ext_interrupt2()
    {
    if(flag1 == 1)
    {
    peoples--;
    flag1 = 0;
    flag2 = 0;
    }
    else
    flag2 = 1;
    }

  • спасибо 😉

  • Здравствуйте! При написании программы для вольтметра-амперметра, столкнулся с тем, что не отображаются единицы ампер на втором дисплее, Скриншот в Proteus.
    Быть может таймер в этом виноват?

  • лучше проект целиком с протеусом

  • как увеличиваете ток?

  • Изменяя сопротивление лампочки.

  • посмотрел Ваш проект, у Вас подцеплен внешний кварц к ноге PB6 и эта же нога пытается управлять индикацией. Ставишь на внутренний генератор и все ок.

  • Таки проглядел) Благодарю!

  • админ подскажите что не так,к тини2313 подключил 4 семисег. индикатора, частототу для них выбрал 120гц, таймер работает на 4мгц, 4.000.000/480=8333 или 208D, записал в регистр OCR1BH=0x20
    OCR1BL=0x8D
    фьюзы стоят
    CKSEL0, CKSEL2,CKSEL3, SUT0, но они все равно очень сильно мерцают, как можно исправить?

  • OCR1BH=0x02

  • Здравствуйте, помогите пожалуйста советом, если можно хоть как-то предположить от чего так происходит и в каком направлении мыслить, при включении датчик прерывисто возвращает не те значения, показания скачут то 999 то вообще сбрасывается в 0 потом текущая температура, и так по кругу, помех шины никаких нет.Поменял 2 датчика, разницы никакой. Всю голову «сломал». 😐

  • Извиняюсь, если не в ту тему написал (индикация динамическая, датчик DS18b20)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика