управление регистрами 74hc595 и 4094 с 7 сегментными индикаторами

Февраль 21, 2010

proteus_register

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

В данной статье разбираются 2 регистра, управление которыми отличается немного, хотя они по своему назначению совпадают. Эти регистры относятся к регистрам с последовательной загрузкой и параллельным выходом с выходом переноса, который обозначается QS или Q7’. При помощи этого выхода можно задействовать следущий разряд регистра, но это будет в следущем уроке.

Разберем самый простой индикатор 4094. Он использует всего 2 входа. Вход STB (строб) подтянут к лог1 и при каждом такте производит вывод данных на параллельную шину.
Работает это так.
На входе данных D выставляется 1 или 0, потом тактовый вход CLK из 0 переходит в 1 и потом снова в 0. При этом на выходе происходит моментальное изменение состояния. Далее на входе данных снова выставляется нужный уровень и дергается клок.

Для надежности перед записью данных в регистр его надо инициализировать. Инициализация проходит так же в регистрах самого мк и означает запись в него нулей по длине его памяти. В данном случае это 8 бит. Всеразличная периферия типа синтезаторов частот так же имеет в себе сдвиговые регистры и они так же требуют инициализации, что обычно указывается в даташитах. Однако там регистры могут быть и по 10,12,15 и более бит.

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

Из предыдущих статей понятно, что конструкция var|=1<<n; выставляет бит с номером n в лог1.
Конструкция var & = ~(1<<n); выставляет сначала на нужном месте n лог1, потом весь байт инвертируется и на этом месте остается 0. Потом происходит логическое И с содержимым регистра. Где есть 0, в том месте в порту и будет 0.

   1: #define CD4094_PORT           PORTD
   2: #define CD4094_DDR            DDRD
   3: #define CD4094_PIN_DATA       0
   4: #define CD4094_PIN_CLK        1
   5:  
   6: #define CD4094_DATA_ON        CD4094_PORT|=1<<CD4094_PIN_DATA;
   7: #define CD4094_DATA_OFF       CD4094_PORT&=~(1<<CD4094_PIN_DATA);
   8: #define CD4094_CLK            {CD4094_PORT|=1<<CD4094_PIN_CLK;CD4094_PORT&=~(1<<CD4094_PIN_CLK);}


Использование обозначения PIN говорит о том, что речь идет конкретно о выводе, который мы определили. В нашем случае регистр 4094 подключен к порту D с выводами 0 и 1.

В строках 6 и 7 идет определение действия по выставлению вывода данных в 1 или 0.

В последней строке один макрос определяет сразу 2 действия. Т.к. Скорость работы мк всего 1мгц, то между операциями пауза не требуется и для экономии кода можно не ставить макрос задержки.

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

Для начала сконфигурируем регистр направления CD4094_DDR на выход, записав в нужные места по единице.

CD4094_DDR = (1<<CD4094_PIN_DATA)|(1<<CD4094_PIN_CLK);

   1: dig = cathode[0];
   2:  
   3: for(i=8;i>0;i--){
   4:     
   5:     if(dig & 0x80){ CD4094_DATA_ON } else {CD4094_DATA_OFF}
   6:         
   7:        dig <<=1;
   8:        CD4094_CLK
   9: }

Строка 0 - записываем во временную переменную dig код цифры 0. Это необходимо, т.к. массив только для чтения, а операция сдвига будет менять содержимое.

Строка 3 - организуем очередь от 0 до 8, т.к. бит 8.

Напомню, что код цифры 0 в двоичной системе выглядит как 0011 1111, где сегмент а будет самый правый бит. Биты нумеруются слева направо 76543210. Тут используется принцип первый ушел, первый и пришел. Операция AND служит для получения логического условия для работы оператора if, который срабатывает тогда, когда там не 0. Код 0х80 в двоичной системе выглядит как 1000 0000.

Получается

0 0111111

1 0000000

------------

0

Т.к. в if - 0, то макрос CD4094_DATA_ON не сработает. В этом случае сработает else { CD4094_DATA_OFF}. Это нужно для того, чтобы сбросить в 0 пин, если следущий бит в переменной dig будет 0. Если же не сбросить, то этот бит будет засчитан как 1, т.к. с предыдущего бита состояние вывода не изменилось. В результате этого цифрф будут неправильно показываться, что усложнит отладку. Или же вместо цифр будет набор горящих сегментов.

Строка 7 dig <<=1; сдвигает на 1 разряд влево.

В оригинале было

0011 1111 и при сдвиге влево на 1 мы получаем

0111 1110 - этот 0 добавляется автоматом, чтобы байт всегда состоял из 8 бит.

При следущем проходе цикла у нас будет уже 1111 1100.

Прогнав цикл 8 раз, в переменной dig будет число 0000 0000. При повторном вызове процедуры эти нули будут снова переписаны на код какой-то цифры.

Теперь напишем 2 функции: инициализацию регистра и отправку цифры.

   1: oid cd4094(char tmp){
   2: char i, dig;
   3:  
   4: dig = cathode[tmp];
   5: for(i=8;i>0;i--){
   6:     
   7:     if(dig & 0x80){ CD4094_DATA_ON } else {CD4094_DATA_OFF}
   8:         
   9:         dig <<=1;
  10:         CD4094_CLK
  11:     }    
  12:  
  13: }
  14:  
  15: void cd4094_init(void){
  16: char i;
  17:  
  18:     for(i=0;i<8;i++){ CD4094_DATA_OFF; CD4094_CLK }
  19: }

 

Теперь рассмотрим второй регистр 74hc595. Этот регистр хорош тем, что у него почти все выходы на одной стороне корпуса, что облегчает разводку платы под светодиоды или реле. Однако этот регистр управляется немного сложнее. В нем задействуется 3й вход стробирования и еще этот регистр можно сбрасывать подачей лог0 на вход /MR и при этом дернуть строб.

Вот мы это все и напишем.

Для начала определим порт и пины.

   1: //74hc595
   2: #define HC595_PORT       PORTC
   3: #define    HC595_DDR     DDRC
   4: #define HC595_PIN_DATA   1
   5: #define HC595_PIN_CLK    0
   6: #define HC595_PIN_STROBE 2
   7: #define HC595_PIN_RESET  3
   8:  
   9: #define HC595_DATA_ON    HC595_PORT|=1<<HC595_PIN_DATA;
  10: #define HC595_DATA_OFF   HC595_PORT&=~(1<<HC595_PIN_DATA);
  11: #define HC595_CLK       {HC595_PORT|=1<<HC595_PIN_CLK;HC595_PORT&=~(1<<HC595_PIN_CLK);}
  12: #define HC595_STROBE    {HC595_PORT|=1<<HC595_PIN_STROBE;HC595_PORT&=~(1<<HC595_PIN_STROBE);}
  13: #define HC595_RESET     {HC595_PORT&=~(1<<HC595_PIN_RESET); HC595_STROBE; HC595_PORT|=1<<HC595_PIN_RESET;}

Теперь напишем всю функцию. Она на 95% копирует предыдущую, только теперь добавляется макрос стробирования после полного окончания очереди.

   1: void hc595(char tmp){
   2: char dig, i;
   3:  
   4: dig = cathode[tmp];
   5:  
   6:     for(i=8;i>0;i--){
   7:     
   8:         if(dig & 0x80){ HC595_DATA_ON } else {HC595_DATA_OFF}
   9:        
  10:             dig <<=1;
  11:             HC595_CLK
  12:         
  13:     }    
  14:     HC595_STROBE//  вот этот макрос
  15:  
  16: }

Под конец для проверки всех этих функций напишем код для зажигания цифр с паузой и потом выключим индикаторы.

   1: int main(void){
   2:  
   3: CD4094_DDR = (1<<CD4094_PIN_DATA)|(1<<CD4094_PIN_CLK);
   4: CD4094_PORT = 0x00;
   5:  
   6: HC595_DDR = (1<<HC595_PIN_DATA)|(1<<HC595_PIN_CLK)|(1<<HC595_PIN_STROBE)|(1<<HC595_PIN_RESET);
   7: HC595_PORT = 1<<HC595_PIN_RESET;// вывод сброса нужно выставить в 1
   8:  
   9:  
  10: cd4094_init();
  11: cd4094(0);
  12:  
  13: _delay_ms(1000);
  14:  
  15: hc595(2);
  16:  
  17: _delay_ms(1000);
  18: HC595_RESET
  19:  
  20: _delay_ms(1000);
  21: cd4094_init();
  22:  
  23: return 0;    
  24:  
  25: }

Исходник и файл протеуса.

Tags: , ,

категория: учим мк avr

Comments (3)

 

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

  2. Некропост, понимаю. Но он открыл мне 4094, который дешевле 595, а это сейчас важно.

    В статье написано:

    Разберем самый простой индикатор 4094. Он использует всего 2 входа. Вход STB (строб) подтянут к лог1 и при каждом такте производит вывод данных на параллельную шину.

    Сначала напрягся, но заглянув в даташит, понял, что 4094 аналогичен 595 по логике работы. У обоих есть возможность перекидывать данные из регистра сдвига в регистр хранения. Просто у 595 быстродействие покруче.

    Спасибо за статью.

ответить

Авторизация только через loginza.

Yandex Google Вконтакте Mail.ru Twitter Loginza MyOpenID OpenID