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

В целом реализация алгоритма в данном случае простая, поэтому жирный камень тут явно не нужен. За исключением одной проблемы, даже если использовать динамическую индикацию, то на один индикатор 7+4 выводов, очевидно что с ножками все плохо. Первая мысль — сдвиговый регистр. В целом идея рабочая и наверно так бы с стал делать, если бы мне не показали такой модуль:
max7219_module

Он содержит в себе микросхему MAX7219 и семисегментный дисплей на 4 разряда. Для его подключения к микроконтроллеру, нужно питание и 3 управляющих SPI линии CS, CLK, MOSI. Дисплей с общим катодом.
max7219

Ключевая здесь управляющая микросхема MAX7219, достаточно передать ей один раз данные, и она сама будет выводить нужные числа в нужный разряд и сама по себе будет крутить динамическую индикацию. Т.е. если вам нужно обновлять информацию на дисплее 1 раз в секунду, то микроконтроллер будет делать что то только в моменты передачи все остальное время он будет не загружен.

Работа с самой микросхемой довольно таки не сложная. Есть регистр куда задвигаются данные, адрес и данные.
register

Поэтому вся работа сводится к простой функции:

void write(char data, char adress)
{    
       unsigned char i;
       //опускаем CS
       _soft_latch=0;  
       #asm("nop") //latch
 
       //задвигаем адрес
       for(i=0;i<8;i++)
       {        
       if(adress & 0x80)
       {
       _soft_data = 1;
       }
       else
       {
       _soft_data = 0;
       }
         #asm("nop") //shift
         _soft_shift=1;
         #asm("nop")
         _soft_shift=0;  
         adress <<= 1;   
       }  
 
       //задвигаем данные     
       for(i=0;i<8;i++)
       {        
       if(data & 0x80)
       {
       _soft_data = 1;
       }
       else
       {
       _soft_data = 0;
       }
         #asm("nop") //shift
         _soft_shift=1;
         #asm("nop")
         _soft_shift=0;  
         data <<= 1;   
      }               
       _soft_latch=1;   
}

Данные уходят по восходящему фронту CS (latch).

После подачи напряжения ничего работать не будет, пока не будет записана единица по адресу 0x0c:

write(1, 0x0c);

shutdown_register

Max7219 поддерживает до 8 семисегментников подключенных одновременно, у меня было задействовано только 4 выхода, поэтому в регистр количества сканируемых линий можно поставить ограничение 4. Для этого по адресу 0x0b, нужно записать 0x04.
scan_format

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

Т.е. чтобы записать в 0 семисегментник, число 5 нужно отправить 0x05 по адресу 0x01;

write(5, 0x01);

Только надо не забывать про перекодировку числа в сегменты. В принципе можно посмотреть как это сделано в прошивке. Для желающих можно поковырять окончательный вариант схемы в протеусе
max7219_proteus

14 комментариев: Управление микросхемой MAX7219

  • Здравствуйте.Огромное спасибо давно я искал как работать с MAX7219 и на других сайтах но я с этого сайта начинал и здесь она появилась.Вот пытаюсь разобраться в CodeVisionAVR выдаёт ошибку строчка
    char temp_digits[3] = {0,0,0};

  • вы хоть пишите что за ошибка.

  • Так я и написал компилятор ругается при компиляции на строчку char temp_digits[3] = {0,0,0};

  • #include
    #include

    #define _soft_data PORTC.1
    #define _soft_shift PORTC.0
    #define _soft_latch1 PORTC.2
    #define _soft_latch2 PORTC.3
    #define _soft_latch3 PORTC.4
    #define _soft_enable3 PORTC.5

    char temp_digits[3] = {0x00,0x00,0x00};
    char sek_1=0;
    char min_1=50;

    char ust_min=1;

    char sek_2=0;
    char min_2=0;

    char sek_3=0;
    char min_3=0;

    char sek_flag=0;

    char mode = 0;

    // Timer1 output compare A interrupt service routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    sek_flag=1;
    }
    void write(char data, char adress, char n_display)
    {
    unsigned char i;

    if(n_display == 0)
    {
    _soft_latch1=0;
    #asm(«nop») //latch
    }
    if(n_display == 1)
    {
    _soft_latch2=0;
    #asm(«nop») //latch
    }
    if(n_display == 2)
    {
    _soft_latch3=0;
    #asm(«nop») //latch
    }

    for(i=0;i<8;i++)
    {
    if(adress & 0x80)
    {
    _soft_data = 1;
    }
    else
    {
    _soft_data = 0;
    }
    #asm("nop") //shift
    _soft_shift=1;
    #asm("nop")
    _soft_shift=0;
    adress <<= 1;
    }

    for(i=0;i<8;i++)
    {
    if(data & 0x80)
    {
    _soft_data = 1;
    }
    else
    {
    _soft_data = 0;
    }
    #asm("nop") //shift
    _soft_shift=1;
    #asm("nop")
    _soft_shift=0;
    data < 99)
    {
    min_1 = 0;
    }
    delay_ms(200);
    }
    if(PINB.1 == 0)
    {
    if(min_1 == 0)
    {
    min_1 = 60;
    }
    delay_ms(500);
    break;
    }
    write(bin_to_digit(min_1/10),0x01,0);
    write(bin_to_digit(min_1%10),0x02,0);
    write(bin_to_digit(sek_1/10),0x03,0);
    write(bin_to_digit(sek_1%10),0x04,0);
    }

    while(1)
    {
    if(PINB.0 == 0)
    {
    ust_min++;
    if(ust_min >= min_1)
    {
    ust_min = 0;
    }
    delay_ms(200);
    }
    if(PINB.1 == 0)
    {
    if(ust_min == 0)
    {
    ust_min = min_1/2;
    }
    break;
    delay_ms(500);
    }
    write(bin_to_digit(ust_min/10),0x01,0);
    write(bin_to_digit(ust_min%10),0x02,0);
    }

    while (1)
    {
    if(PINB.0 == 0)mode=0;
    if(PINB.1 == 0)mode=1;
    if(sek_flag == 1)
    {
    if(sek_1 == 0)
    {
    sek_1 = 59;
    min_1—;
    if(min_1==0)
    {
    #asm(«cli»);
    }
    }
    sek_1—;

    if(mode == 0)
    {
    sek_2++;
    if(sek_2>59)
    {
    sek_2=0;
    min_2++;
    }
    }
    else
    {
    sek_3++;
    if(sek_3>59)
    {
    sek_3=0;
    min_3++;
    }
    }

    write(bin_to_digit(min_1/10),0x01,0);
    write(bin_to_digit(min_1%10),0x02,0);
    write(bin_to_digit(sek_1/10),0x03,0);
    write(bin_to_digit(sek_1%10),0x04,0);

    write(bin_to_digit(min_2/10),0x01,1);
    write(bin_to_digit(min_2%10),0x02,1);
    write(bin_to_digit(sek_2/10),0x03,1);
    write(bin_to_digit(sek_2%10),0x04,1);

    write(bin_to_digit(min_3/10),0x01,2);
    write(bin_to_digit(min_3%10),0x02,2);
    write(bin_to_digit(sek_3/10),0x03,2);
    write(bin_to_digit(sek_3%10),0x04,2);

    if(min_2 == ust_min)
    {
    PORTB.2=1;
    #asm(«cli»)
    }
    if(min_3 == ust_min)
    {
    PORTB.3=1;
    #asm(«cli»)
    }

    sek_flag = 0;
    }
    }
    }

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

  • ПРИВЕТСТВУЮ.
    ВОТ ЭТА СТРОКА : char temp_digits[3] = {0x00,0x00,0x00};

  • Для 4 сегментов 0х03 надо записать, учитываем нулевой

  • IseMan, приведите полный текст ошибки

  • а вот мне например не нужна здоровенная мега 8)с её ЭсП И) а е меня есть прекрасное 2313 ) В котором какой то уси))по трем прорвода. В принципе для max7219 Больше и не надо.
    C какой то надстройкой для Clock еще. Его реально использовать?

  • если вы обратите внимание, то в статье используются обычные ножки, так что spi не обязателен

  • не знаю будет ли вставка работать)хостинг изображений

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

  • А как сделать каскад этих микросхем в avr через DIN->DOUT?

  • вроде просто соединить din-dout, clk общий и cs общий, но сам не пробовал

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

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

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