Записки программиста
Благодаря заметке Два способа мультиплексирования светодиодов на примере микроконтроллеров AVR мы с вами знаем, что можно управлять сотней светодиодов, используя всего лишь 11 пинов микроконтроллера. Но что делать, если нужно управлять двумястами или, скажем, тысячью светодиодами? Оказывается, что изученные способы мультиплексирования могут быть улучшены, да так, что используя всего лишь три пина микроконтроллера можно управлять абсолютно любым количеством светодиодов! И в этом нам помогут следующие микросхемы.
Примечание: Если вы пропустили предыдущий пост, посвященный микросхемам 74xx, вот он — Интегральные схемы: чипы стандартной логики 74xx. Впрочем, тот пост был посвящен логическим вентилям, и для понимания представленного далее материала читать его не требуется.
SIPO сдвиговый регистр 74HC595
Сдвиговые регистры — это микросхемы, позволяющие, очень грубо говоря, добавить пинов вашему микроконтроллеру. Для добавления пинов на запись, используются SIPO сдвиговые регистры. SIPO означает «последовательный вход, параллельный выход». Если же нужно больше пинов на чтение, используются сдвиговые регистры PISO, «параллельный вход, последовательный выход». В данном разделе мы познакомимся с типичным SIPO сдвиговым регистром, 74HC595.
Какой пин 74HC595 для чего предназначен, можно узнать из даташита [PDF]:
Если коротко, то:
- VCC, GND — это питание.
- OE — разрешение вывода. Чтобы вывод был всегда разрешен, можно подключить этот пин напрямую к минусу.
- SRCLR — сброс. Если не используется, то нужно подключить напрямую к плюсу.
- SER, SRCLK — используются для передачи данных. При подаче высокого напряжения на SRCLK происходит считывание одного бита данных с пина SER.
- RCLK — при подаче сюда высокого напряжения происходит одновременный вывод принятых данных на параллельные выходы.
- Qa-Qh — параллельные выходы. Сюда происходит вывод последних восьми полученных бит при подаче высокого напряжения на SRCLK.
- Qh’ — при получении очередного бита информации и смещении значений по параллельным выходам бит Qh на самом деле не отбрасывается, а поступает на этот пин. Подключив его к пину SER другого сдвигового регистра, а также соединив выходы RCLK и SRCLK обоих сдвиговых регистров, можно получить 16-разрядный сдвиговый регистр. Второй сдвиговый регистр в свою очередь можно соединить с третьим и так далее, получив сколь угодно разрядный регистр сдвига.
Надеюсь, идея ясна — мы последовательно передаем на сдвиговый регистр восемь бит информации по одному биту. Затем сдвиговый регистр параллельно выводит полученные биты на восемь пинов. Отсюда и «последовательный вход, параллельный выход».
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
void loop ( )
{
/* . */
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
/* . */
delay ( 100 ) ;
}
Нам даже не нужно писать никаких циклов. В Arduino уже предусмотрена готовая процедура shiftOut , которая делает все за нас.
В итоге три пина микроконтроллера эффективно превратились в восемь пинов. Если соединить несколько сдвиговых регистров, как это было описано выше, то можно вместо восьми пинов получить сколько угодно. При этом в микроконтроллере все так же будет задействовано только три пина.
Существует похожий чип 74HC164, который имеет 14 пинов вместо 16-и. В нем отсутствует пин переноса (аналог Qh’). Даташит 74HC164 доступен здесь [PDF].
PISO сдвиговый регистр 74HC165
Типичным представителем PISO сдвиговых регистров является 74HC165.
- VCC, GND — питание.
- A-H — входы сдвигового регистра.
- SH — когда на этом пине низкое напряжение, происходит считывание данных с пинов A-H.
- CLK INH — что-то делает только при высоком напряжении на SH. Низкое напряжение означает разрешить использование часов (пин CLK). На практике можно подключить напрямую к земле.
- CLK — когда на SH высокое напряжение и на CLK INH низкое, при подаче на CLK низкого напряжения происходит сдвиг данных.
- Qh — выход сдвигового регистра. Одноименный выход с чертой — это инвертированный выход.
- SER — при очередном сдвиге освободившийся бит принимает значение, поданное на этот пин. Пин может быть задействован при одновременном использовании нескольких сдвиговых регистров. Или можно просто подключить к земле.
Пример кода, считывающего состояние восьми кнопок, используя всего лишь три пина:
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
= digitalRead ( dataPin ) else
value
void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;
hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;
Встроенная процедура shiftIn для работы с 74HC165, к сожалению, не годится, так в ней используется обратный порядок подачи сигналов LOW и HIGH на clockPin. Поэтому в приведенном коде используется собственная реализация с правильным порядком.
Декодер / демультиплексор 74HC138
В данном контексте было бы большим упущением не рассказать про демультиплексоры, так как они могут быть использованы для управления светодиодными матрицами, так же, как и сдвиговые регистры. Грубо говоря, демультиплексоры занимаются тем, что декодируют числа из бинарного представления в унарное. Типичным представителем демультиплексоров является 74HC138.
Вот иллюстрация из его даташита [PDF]:
- VCC, GND — питание.
- A, B, C — три бита входа.
- Y0-Y7 — выход. Если на вход подан ноль в бинарном представлении, на Y0 будет подано низкое напряжение, а на все остальные выходы высокое. Если подана единица в бинарном представлении, на Y1 будет низкое напряжение, а на всех остальных выходах высокое, и так далее.
- G1, G2A, G2B — разрешение вывода. Чтобы на выходах Y0-Y7 было что-то осмысленное, на G1 должно быть подано высокое напряжение, а на G2A и G2B — низкое. Иначе на всех выходах Y0-Y7 будет высокое напряжение независимо от входов A, B и C. Пины G2A и G2B можно просто подключить к земле.
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
uint8_t hc138_out = 0 ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
74HC138 может быть использован в бегущей строке. При использовании матричной схемы мультиплексирования светодиодов с его помощью можно выбирать строку светодиодной матрицы.
Существует также чип 74HC154. Он аналогичен по функциональности, но более громоздок и является четырехбитным. Его даташит можно полистать здесь [PDF].
Как несложно догадаться, если есть демультиплексоры, значит бывают и мультиплексоры. Они в каком-то смысле аналогичны PISO сдвиговым регистрам, так как позволяют увеличить количество читающих пинов микроконтроллера. В качестве примеров можно привести чипы 74HC151 и 74HC153. Их даташиты доступны, соответственно, здесь [PDF] и здесь [PDF].
Fun fact! При помощи мультиплексора можно реализовать произвольную логическую функцию, подключив его входы напрямую к питанию или земле в соответствии с таблицей истинности и используя управляющие сигналы, как входные данные.
Полная версия кода
Вы, конечно же, поняли, что приведенные выше отрывки кода являются частью одной программы. Вот ее полный исходный код:
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
uint8_t hc595_out = 0 ;
uint8_t hc138_out = 0 ;
void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
= digitalRead ( dataPin ) else
value
void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;
hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
Фотография соответствующего прототипа на макетной плате:
Используемые чипы слева направо — микроконтроллер ATmega328P, SIPO сдвиговый регистр 74HC595, демультиплексор 74HC138, PISO сдвиговый регистр 74HC165. Состояние восьми кнопок считывается через 74HC165. Светодиоды слева, соответствующие нажатым кнопкам, не горят, а отпущенным — горят. Состояние этих светодиодов контролируется через 74HC595. На фото я зажал три правые кнопки карандашом и потому три соответствующих им светодиода не горят. Еще восемь светодиодов справа контролируются демультиплексором 74HC138. Их состояние зависит только от времени, по очереди гаснет один светодиод.
Заключение
Еще из интересных чипов стоит упомянуть шинный формирователь 74HC244. Это штука, которая может как бы отрезать одну часть цепи от другой. Если добавить в цепь 74HC04 (логическое НЕ), то при помощи 74HC244 можно будет использовать одни и те же пины для работы с SIPO и PISO сдвиговыми регистрами, плюс один пин для переключения между ними. Итого, если микроконтроллер имеет четыре пина, он может работать с любым количеством кнопок и светодиодов. У самого маленького известного мне микроконтроллера ATtiny13 целых пять свободных пинов, что позволяет обойтись и без 74HC04. Подробности о 74HC244 ищите в даташите [PDF], там все очень просто.
Также заслуживает внимания чип 74HC4051. Эта штука позволяет соединить аналоговый канал с любым из 8 других аналогвых каналов, или разъединить их все. Мне нравится думать о 74HC4051, как о переключателе, управляемом программного. Подробности — в даташите [PDF].
В контексте увеличения числа пинов микроконтроллера стоит также упомянуть чипы MCP23017 / MCP23S17 [PDF] и специализированные чипы для управления светодиодными матрицами вроде MAX7221 [PDF]. Интересны они тем, что предлагая функциональность, аналогичную функциональности сдвиговых регистров и декодеров, могут занимать меньше места на плате. Если же вы хотите увеличить числ ШИМ-пинов, обратите внимание на микросхему TLC5940 (видеообзор, библиотека). Однако обсуждение данных микросхем уже сильно выходит за рамки данного поста. Вы без труда сможете изучить их самостоятельно в качестве домашнего задания.
Итак, теперь вы знаете все необходимое, чтобы делать при помощи светодиодов потрясающие вещи, вроде таких или даже таких. Полную версию исходников к посту вы найдете в этом репозитории на GitHub.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.
Управление семисегментным дисплеем с помощью ПЛИС
Привет, Хабр! Хочу внести свою посильную лепту в продвижение ПЛИС. В этой статье я постараюсь объяснить, как на языке VHDL описать устройство, управляющее семисегментным дисплеем. Но перед тем как начать, хочу кратко рассказать о том как я пришел к ПЛИС и почему я выбрал язык VHDL.
Где-то пол года назад решил попробывать свои силы в программировании ПЛИС. До этого со схемотехникой никогда не сталкивался. Был небольшой опыт использования микроконтроллеров (Atmega328p, STM32). Сразу после решения освоиться с ПЛИС, встал вопрос выбора языка, который я буду использовать. Выбор пал на VHDL из-за его строгой типизации. Мне, как новичку, хотелось как можно больше возможных проблем отловить на этапе синтеза, а не на рабочем устройстве.
Почему именно семисегментный дисплей? Мигать светодиодом уже надоело, да и логика мигания им не представляет из себя ничего интересного. Логика управления дисплеем с одной стороны сложнее, чем мигание светодиодом (т. е. писать ее интереснее), а с другой достаточно простая в реализации.
Что я использовал в процессе создания устройства:
- ПЛИС Altera Cyclone II (знаю, что он безнадежно устарел, зато у китайцев его можно купить за копейки)
- Quartus II версии 13.0.0 (на сколько я знаю это последняя версия поддерживающая Cyclone II)
- Симулятор ModelSim
- Семисегментный дисплей со сдвиговым регистром
Задача
Создать устройство, которое будет в цикле показывать числа 0 — 9. Раз в секунду отображаемое на дисплее значение должно увеличиваться на 1.
Реализовать данную логику можно по-разному. Я разделю данное устройство на модули, каждый из которых будет выполнять какое-то действие и результат этого действия будет передаваться следующему модулю.
Модули
- Данное устройство должно уметь отсчитывать время. Для подсчета времени я создал модуль «delay». Этот модуль имеет 1 входящий и 1 исходящий сигнал. Модуль принимает частотный сигнал ПЛИС и, через указанное количество периодов входящего сигнала, меняет значение исходящего сигнала на противоположное.
- Устройство должно считать от 0 до 9. Для этого будет использоваться модуль bcd_counter.
- Для того, чтобы зажечь сегмент на дисплее, нужно выставить в сдвиговом регистре дисплея соответствующий сегменту бит в 0, а для того, чтобы погасить сегмент в бит нужно записать 1 (мой дисплей имеет инвертированную логику). Установкой и сбросом нужных битов будет заниматься декодер bcd_2_7seg.
- За передачу данных будет отвечать модуль transmitter.
Для наглядности, привожу схему данного устройства
Как видно из схемы устройство имеет 1 входящий сигнал (clk) и 3 исходящих сигнала (sclk, dio, rclk). Сигнал clk приходит в 2 делителя сигнала (sec_delay и transfer_delay). Из устройства sec_delay выходит исходящий сигнал с периодом 1с. По переднему фронту этого сигнала счетчик (bcd_counter1) начинает генерировать следующее число для отображения на дисплее. После того, как число сгенерировано, декодер (bcd_2_7seg1) преобразует двоичное представление числа в горящие и не горящие сегменты на дисплее. Которые, с помощью передатчика (transmitter1), передаются на дисплей. Тактирование передатчика осуществляется с помощью устройства transfer_delay.
Код
Для создания устройства в VHDL используется конструкция из двух составляющих entity и architecture. В entity декларируется интерфейс для работы с устройством. В architecture описывается логика работы устройства.
Вот как выглядит entity устройства delay
entity delay is -- При объявлении entity, поле generic не является обязательным generic (delay_cnt: integer); -- Описываем входные и выходные сигналы устройства port(clk: in std_logic; out_s: out std_logic := '0'); end entity delay;
Через поле generic мы можем задать устройству нужную задержку. А в поле ports описываем входящие и исходящие сигналы устройства.
Архитектура устройства delay выглядит следующим образом
-- В секции architecture описывается то, как устройство будет работать -- С одной entity может быть связано 0 или более архитектур architecture delay_arch of delay is begin delay_proc: process(clk) variable clk_cnt: integer range 0 to delay_cnt := 0; variable out_v: std_logic := '0'; begin -- Если имеем дело с передним фронтом сигнала if(rising_edge(clk)) then clk_cnt := clk_cnt + 1; if(clk_cnt >= delay_cnt) then -- switch/case в языке VHDL case out_v is when '0' => out_v := '1'; when others => out_v := '0'; end case; clk_cnt := 0; -- Устанавливаем в сигнал out_s значение переменной out_v out_s
Код внутри секции process исполняется последовательно, любой другой код исполняется параллельно. В скобках, после ключевого слова process указываются сигналы, по изменению которых данный процесс будет запускаться (sensivity list).
Устройство bcd_counter в плане логики выполнения идентично устройству delay. Поэтому на нем я подробно останавливаться не буду.
Вот как выглядит entity и architecture декодера
entity bcd_to_7seg is port(bcd: in std_logic_vector(3 downto 0) := X"0"; disp_out: out std_logic_vector(7 downto 0) := X"00"); end entity bcd_to_7seg; architecture bcd_to_7seg_arch of bcd_to_7seg is signal not_bcd_s: std_logic_vector(3 downto 0) := X"0"; begin not_bcd_s
Вся логика данного устройства выполняется параллельно. О том как получить формулы для данного устройства я рассказывал в одном из видео на своем канале. Кому интересно, вот ссылка на видео.
В устройстве transmitter я комбинирую последовательную и параллельную логику
entity transmitter is port(enable: in boolean; clk: in std_logic; digit_pos: in std_logic_vector(7 downto 0) := X"00"; digit: in std_logic_vector(7 downto 0) := X"00"; sclk, dio: out std_logic := '0'; ready: buffer boolean := true); end entity transmitter; architecture transmitter_arch of transmitter is constant max_int: integer := 16; begin sclk
В сигнал sclk я перенаправляю значение входящего в передатчик сигнала clk, но только в том случае, если устройство в данный момент выполняет передачу данных (сигнал ready = false). В противном случае значение сигнала sclk будет равно 0. В начале передачи данных (сигнал enable = true), я объединяю данные из двух входящих в устройство 8-и битных векторов (digit_pos и digit) в 16-и битный вектор (data_v) и передаю данные из этого вектора по одному биту за такт, устанавливая значение передаваемого бита в исходящий сигнал dio. Из интересного в этом устройстве хочу отметить то, что данные в dio устанавливаются на задний фронт сигнала clk, а в сдвиговый регистр дисплея данные с пина dio будут записаны по приходу переднего фронта сигнала sclk. По завершению передачи, установкой сигнала ready
Вот как выглядит entity и architecture устройства display
entity display is port(clk: in std_logic; sclk, rclk, dio: out std_logic := '0'); end entity display; architecture display_arch of display is component delay is generic (delay_cnt: integer); port(clk: in std_logic; out_s: out std_logic := '0'); end component; component bcd_counter is port(clk: in std_logic; bcd: out std_logic_vector(3 downto 0)); end component; component bcd_to_7seg is port(bcd: in std_logic_vector(3 downto 0); disp_out: out std_logic_vector(7 downto 0)); end component; component transmitter is port(enable: in boolean; clk: in std_logic; digit_pos: in std_logic_vector(7 downto 0); digit: in std_logic_vector(7 downto 0); sclk, dio: out std_logic; ready: buffer boolean); end component; signal sec_s: std_logic := '0'; signal bcd_counter_s: std_logic_vector(3 downto 0) := X"0"; signal disp_out_s: std_logic_vector(7 downto 0) := X"00"; signal tr_enable_s: boolean; signal tr_ready_s: boolean; signal tr_data_s: std_logic_vector(7 downto 0) := X"00"; -- Этот флаг, совместно с tr_ready_s контролирует -- установку и сброс rclk сигнала signal disp_refresh_s: boolean; signal transfer_clk: std_logic := '0'; begin sec_delay: delay generic map(25_000_000) port map(clk, sec_s); transfer_delay: delay generic map(10) port map(clk, transfer_clk); bcd_counter1: bcd_counter port map(sec_s, bcd_counter_s); bcd_to_7seg1: bcd_to_7seg port map(bcd_counter_s, disp_out_s); transmitter1: transmitter port map(tr_enable_s, transfer_clk, X"10", tr_data_s, sclk, dio, tr_ready_s); tr_proc: process(transfer_clk) variable prev_disp: std_logic_vector(7 downto 0); variable rclk_v: std_logic := '0'; begin if(rising_edge(transfer_clk)) then -- Если передатчик готов к передаче следующей порции данных if(tr_ready_s) then -- Если передаваемые данные не были только что переданы if(not (prev_disp = disp_out_s)) then prev_disp := disp_out_s; -- Помещаем передаваемые данные в шину данных передатчика tr_data_s
Это устройство управляет другими устройствами. Здесь, перед объявлением вспомогательных сигналов, я объявляю компоненты которые буду использовать. В самой архитектуре (после ключевого слова begin) я создаю экземпляры устройств:
- sec_delay — экземпляр компонента delay. Исходящий сигнал направляется в сигнал sec_s.
- transfer_delay — экземпляр компонента delay. Исходящий сигнал направляется в сигнал transfer_clk.
- bcd_counter1 — экземпляр компонента bcd_counter. Исходящий сигнал направляется в сигнал bcd_counter_s.
- bcd_to_7seg1 — экземпляр компонента bcd_to_7seg. Исходящий сигнал направляется в сигнал disp_out_s.
- transmitter1 — экземпляр компонента transmitter. Исходящие сигналы направляются в сигналы sclk, dio, tr_ready_s.
Если передатчик не занят, то процесс инициализирует начало передачи данных
if(tr_ready_s) then if(not (prev_disp = disp_out_s)) then prev_disp := disp_out_s; -- Помещаем передаваемые данные в -- шину данных передатчика tr_data_s
Устанавливает и сбрасывает сигнал rclk после завершения передачи данных
if(rclk_v = '1') then disp_refresh_s
Временная диаграмма
Вот как выглядит временная диаграмма передачи числа 1 на первую позицию дисплея
Сначала передаются данные “10011111“. Затем передается позиция числа на дисплее “00010000“ (этот параметр приходит в передатчик, как константа X”10”). В обоих случаях первым передается крайний правый бит (lsb).
Весь код можно посмотреть на github. Файлы с припиской *_tb.vhd — это отладочные файлы для соответствующих компонентов (например transmitter_tb.vhd — отладочный файл для передатчика). Их я на всякий случай тоже залил на github. Данный код был загружен и работал на реальной плате. Кому интересно, иллюстрацию работы кода можно посмотреть вот тут (начиная с 15:30). Спасибо за внимание.
Rclk на схеме что это
Благодаря заметке Два способа мультиплексирования светодиодов на примере микроконтроллеров AVR мы с вами знаем, что можно управлять сотней светодиодов, используя всего лишь 11 пинов микроконтроллера. Но что делать, если нужно управлять двумястами или, скажем, тысячью светодиодами? Оказывается, что изученные способы мультиплексирования могут быть улучшены, да так, что используя всего лишь три пина микроконтроллера можно управлять абсолютно любым количеством светодиодов! И в этом нам помогут следующие микросхемы.
Примечание: Если вы пропустили предыдущий пост, посвященный микросхемам 74xx, вот он — Интегральные схемы: чипы стандартной логики 74xx. Впрочем, тот пост был посвящен логическим вентилям, и для понимания представленного далее материала читать его не требуется.
SIPO сдвиговый регистр 74HC595
Сдвиговые регистры — это микросхемы, позволяющие, очень грубо говоря, добавить пинов вашему микроконтроллеру. Для добавления пинов на запись, используются SIPO сдвиговые регистры. SIPO означает «последовательный вход, параллельный выход». Если же нужно больше пинов на чтение, используются сдвиговые регистры PISO, «параллельный вход, последовательный выход». В данном разделе мы познакомимся с типичным SIPO сдвиговым регистром, 74HC595.
Какой пин 74HC595 для чего предназначен, можно узнать из даташита [PDF]:
Если коротко, то:
- VCC, GND — это питание.
- OE — разрешение вывода. Чтобы вывод был всегда разрешен, можно подключить этот пин напрямую к минусу.
- SRCLR — сброс. Если не используется, то нужно подключить напрямую к плюсу.
- SER, SRCLK — используются для передачи данных. При подаче высокого напряжения на SRCLK происходит считывание одного бита данных с пина SER.
- RCLK — при подаче сюда высокого напряжения происходит одновременный вывод принятых данных на параллельные выходы.
- Qa-Qh — параллельные выходы. Сюда происходит вывод последних восьми полученных бит при подаче высокого напряжения на SRCLK.
- Qh’ — при получении очередного бита информации и смещении значений по параллельным выходам бит Qh на самом деле не отбрасывается, а поступает на этот пин. Подключив его к пину SER другого сдвигового регистра, а также соединив выходы RCLK и SRCLK обоих сдвиговых регистров, можно получить 16-разрядный сдвиговый регистр. Второй сдвиговый регистр в свою очередь можно соединить с третьим и так далее, получив сколь угодно разрядный регистр сдвига.
Надеюсь, идея ясна — мы последовательно передаем на сдвиговый регистр восемь бит информации по одному биту. Затем сдвиговый регистр параллельно выводит полученные биты на восемь пинов. Отсюда и «последовательный вход, параллельный выход».
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
void loop ( )
{
/* . */
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
/* . */
delay ( 100 ) ;
}
Нам даже не нужно писать никаких циклов. В Arduino уже предусмотрена готовая процедура shiftOut , которая делает все за нас.
В итоге три пина микроконтроллера эффективно превратились в восемь пинов. Если соединить несколько сдвиговых регистров, как это было описано выше, то можно вместо восьми пинов получить сколько угодно. При этом в микроконтроллере все так же будет задействовано только три пина.
Существует похожий чип 74HC164, который имеет 14 пинов вместо 16-и. В нем отсутствует пин переноса (аналог Qh’). Даташит 74HC164 доступен здесь [PDF].
PISO сдвиговый регистр 74HC165
Типичным представителем PISO сдвиговых регистров является 74HC165.
- VCC, GND — питание.
- A-H — входы сдвигового регистра.
- SH — когда на этом пине низкое напряжение, происходит считывание данных с пинов A-H.
- CLK INH — что-то делает только при высоком напряжении на SH. Низкое напряжение означает разрешить использование часов (пин CLK). На практике можно подключить напрямую к земле.
- CLK — когда на SH высокое напряжение и на CLK INH низкое, при подаче на CLK низкого напряжения происходит сдвиг данных.
- Qh — выход сдвигового регистра. Одноименный выход с чертой — это инвертированный выход.
- SER — при очередном сдвиге освободившийся бит принимает значение, поданное на этот пин. Пин может быть задействован при одновременном использовании нескольких сдвиговых регистров. Или можно просто подключить к земле.
Пример кода, считывающего состояние восьми кнопок, используя всего лишь три пина:
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
= digitalRead ( dataPin ) else
value
void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;
hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;
Встроенная процедура shiftIn для работы с 74HC165, к сожалению, не годится, так в ней используется обратный порядок подачи сигналов LOW и HIGH на clockPin. Поэтому в приведенном коде используется собственная реализация с правильным порядком.
Декодер / демультиплексор 74HC138
В данном контексте было бы большим упущением не рассказать про демультиплексоры, так как они могут быть использованы для управления светодиодными матрицами, так же, как и сдвиговые регистры. Грубо говоря, демультиплексоры занимаются тем, что декодируют числа из бинарного представления в унарное. Типичным представителем демультиплексоров является 74HC138.
Вот иллюстрация из его даташита [PDF]:
- VCC, GND — питание.
- A, B, C — три бита входа.
- Y0-Y7 — выход. Если на вход подан ноль в бинарном представлении, на Y0 будет подано низкое напряжение, а на все остальные выходы высокое. Если подана единица в бинарном представлении, на Y1 будет низкое напряжение, а на всех остальных выходах высокое, и так далее.
- G1, G2A, G2B — разрешение вывода. Чтобы на выходах Y0-Y7 было что-то осмысленное, на G1 должно быть подано высокое напряжение, а на G2A и G2B — низкое. Иначе на всех выходах Y0-Y7 будет высокое напряжение независимо от входов A, B и C. Пины G2A и G2B можно просто подключить к земле.
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
uint8_t hc138_out = 0 ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
74HC138 может быть использован в бегущей строке. При использовании матричной схемы мультиплексирования светодиодов с его помощью можно выбирать строку светодиодной матрицы.
Существует также чип 74HC154. Он аналогичен по функциональности, но более громоздок и является четырехбитным. Его даташит можно полистать здесь [PDF].
Как несложно догадаться, если есть демультиплексоры, значит бывают и мультиплексоры. Они в каком-то смысле аналогичны PISO сдвиговым регистрам, так как позволяют увеличить количество читающих пинов микроконтроллера. В качестве примеров можно привести чипы 74HC151 и 74HC153. Их даташиты доступны, соответственно, здесь [PDF] и здесь [PDF].
Fun fact! При помощи мультиплексора можно реализовать произвольную логическую функцию, подключив его входы напрямую к питанию или земле в соответствии с таблицей истинности и используя управляющие сигналы, как входные данные.
Полная версия кода
Вы, конечно же, поняли, что приведенные выше отрывки кода являются частью одной программы. Вот ее полный исходный код:
const uint8_t hc595_data = 6 ; /* SER */
const uint8_t hc595_latch = 7 ; /* RCLK */
const uint8_t hc595_clock = 8 ; /* SRCLK */
const uint8_t hc138_a = 5 ;
const uint8_t hc138_b = 4 ;
const uint8_t hc138_c = 3 ;
const uint8_t hc138_enable = 9 ;
const uint8_t hc165_data = A5 ; /* QH */
const uint8_t hc165_latch = A4 ; /* SH */
const uint8_t hc165_clock = A3 ; /* CLK */
uint8_t hc595_out = 0 ;
uint8_t hc138_out = 0 ;
void setup ( )
{
pinMode ( hc595_data, OUTPUT ) ;
pinMode ( hc595_latch, OUTPUT ) ;
pinMode ( hc595_clock, OUTPUT ) ;
pinMode ( hc138_a, OUTPUT ) ;
pinMode ( hc138_b, OUTPUT ) ;
pinMode ( hc138_c, OUTPUT ) ;
pinMode ( hc138_enable, OUTPUT ) ;
pinMode ( hc165_data, INPUT ) ;
pinMode ( hc165_clock, OUTPUT ) ;
pinMode ( hc165_latch, OUTPUT ) ;
}
uint8_t shiftIn165 ( uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder )
= digitalRead ( dataPin ) else
value
void loop ( )
{
digitalWrite ( hc165_latch, LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( hc165_latch, HIGH ) ;
delayMicroseconds ( 5 ) ;
hc595_out = shiftIn165 ( hc165_data, hc165_clock, MSBFIRST ) ;
digitalWrite ( hc595_latch, LOW ) ;
shiftOut ( hc595_data, hc595_clock, MSBFIRST, hc595_out ) ;
digitalWrite ( hc595_latch, HIGH ) ;
Фотография соответствующего прототипа на макетной плате:
Используемые чипы слева направо — микроконтроллер ATmega328P, SIPO сдвиговый регистр 74HC595, демультиплексор 74HC138, PISO сдвиговый регистр 74HC165. Состояние восьми кнопок считывается через 74HC165. Светодиоды слева, соответствующие нажатым кнопкам, не горят, а отпущенным — горят. Состояние этих светодиодов контролируется через 74HC595. На фото я зажал три правые кнопки карандашом и потому три соответствующих им светодиода не горят. Еще восемь светодиодов справа контролируются демультиплексором 74HC138. Их состояние зависит только от времени, по очереди гаснет один светодиод.
Заключение
Еще из интересных чипов стоит упомянуть шинный формирователь 74HC244. Это штука, которая может как бы отрезать одну часть цепи от другой. Если добавить в цепь 74HC04 (логическое НЕ), то при помощи 74HC244 можно будет использовать одни и те же пины для работы с SIPO и PISO сдвиговыми регистрами, плюс один пин для переключения между ними. Итого, если микроконтроллер имеет четыре пина, он может работать с любым количеством кнопок и светодиодов. У самого маленького известного мне микроконтроллера ATtiny13 целых пять свободных пинов, что позволяет обойтись и без 74HC04. Подробности о 74HC244 ищите в даташите [PDF], там все очень просто.
Также заслуживает внимания чип 74HC4051. Эта штука позволяет соединить аналоговый канал с любым из 8 других аналогвых каналов, или разъединить их все. Мне нравится думать о 74HC4051, как о переключателе, управляемом программного. Подробности — в даташите [PDF].
В контексте увеличения числа пинов микроконтроллера стоит также упомянуть чипы MCP23017 / MCP23S17 [PDF] и специализированные чипы для управления светодиодными матрицами вроде MAX7221 [PDF]. Интересны они тем, что предлагая функциональность, аналогичную функциональности сдвиговых регистров и декодеров, могут занимать меньше места на плате. Если же вы хотите увеличить числ ШИМ-пинов, обратите внимание на микросхему TLC5940 (видеообзор, библиотека). Однако обсуждение данных микросхем уже сильно выходит за рамки данного поста. Вы без труда сможете изучить их самостоятельно в качестве домашнего задания.
Итак, теперь вы знаете все необходимое, чтобы делать при помощи светодиодов потрясающие вещи, вроде таких или даже таких. Полную версию исходников к посту вы найдете в этом репозитории на GitHub. Как обычно, буду весьма рад вашим вопросам и дополнениям.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.
Знакомство с микросхемой регистра сдвига 74HC595 — управление 16 светодиодами
Из этого руководства вы узнаете, как управлять 16 светодиодами используя всего 3 линии управления. Мы осуществим это путем последовательной передачи данных в сдвиговые регистры 74HC595.
Микросхема 74HC595 содержит 8 битный регистр хранения и 8 битный сдвиговый регистр. Данные последовательно передаются в сдвиговый регистр, затем фиксируются в регистре хранения. К регистру хранения подключены 8 выходных линий. На картинке ниже показано расположение выводов микросхемы 74HC595.
Вывод 14 (DS) это вывод данных. В некоторых описаниях он обозначается как «SER».
Когда уровень на выводе 11 (SH_CP, иногда обозначается как SRCLK) переходит из низкого в высокий, значение на выводе DS сохраняется в сдвиговом регистре, при этом данные сдвигаются на один разряд, чтобы предоставить место для нового бита.
Пока на выводе 12 (ST_CP, иногда обозначается как RCLK) низкий уровень, данные записываются в регистр сдвига. Когда уровень переходит в высокий, данные из сдвигового регистра фиксируются в регистре хранения, из которого поступают на выводы Q0…Q7.
На представленной ниже временная диаграмме, показано, каким образом можно установить на выходах Q0…Q7 микросхемы значение 11000011, учитывая что изначально там было значение 00000000.
Ниже показана схема, которую мы соберем в несколько шагов.
Мы используем перфорированную макетную плату с контроллером Atmega8, которую использовали во многих наших проектах. Добавим еще 2 пустых макетных платы и подведем к ним питание.
Установим микросхему регистра сдвига и подключим к ней питание +5 В и общий провод.
Теперь проведем 3 линии управления между микроконтроллером и регистром сдвига, для чего подсоединим:
- PC0 к DS
- PC1 к ST_CP
- PC2 к SH_CP
Этими линиями являются 3 синих провода на картинке ниже.
Затем подключим светодиоды и резисторы. Я использовал резисторы сопротивлением 510 Ом, но допустимы и другие номиналы.
Для демонстрации работы схемы я написал небольшую программу, которая выводит перемещающийся из стороны в сторону огонек на 8 светодиодах.
Все это конечно впечатляет, но разве я не говорил, что мы будем управлять 16 светодиодами? Чтобы сделать это, нам потребуется еще один сдвиговый регистр 74HC595, больше светодиодов, больше резисторов и больше оранжевых и голубых проводов.
Мы используем вывод Q7, чтобы соединить регистры сдвига в одну цепочку.
Модифицированная схема показана ниже.
Мы остановились на 16 светодиодах, но можно соединить в одну цепочку еще больше регистров сдвига. Эта методика конечно не ограничивается управлением светодиодами, ее можно использовать для увеличения числа портов вывода, чтобы управлять другими видами устройств.
Одно предупреждение касательно этой методики. Когда вы включаете схему, на выходах регистров наблюдаются некоторое произвольное значение. Для того чтобы записать требуемое значение, требуется меньше микросекунды, но для некоторых схем это может стать причиной проблем. В этом случае вы должны использовать выводы MR и OE, для сброса регистров хранения.
Динамическая индикация и 7 сегментный индикатор, модуль на двух 74HC595, код из видео
4bit Digital Tube LED Display Module — Обзор модуля с семисегментным индикатором и двумя сдвиговыми регистрами 74HC595. разберем работу с динамической индикацией.
Особенности модуля:
Модуль базируется на двух сдвиговых регистрах TM74HC595 к которым подключен 4х разрядный 7 сегментный индикатор ZS3641BS. Схема похожего модуля, с двумя индикаторами ZS3641BS и 8 сегментами ниже, отличие только в дополнительном индикаторе.
Один TM74HC595 управляет сегментами, причем всеми разом, ибо они все параллельны, а второй управляет разрядами. Если на один регистр отправить байт, в котором будет символ, он будет на всех четырех разрядах, но отобразится на том, который будет включен вторым регистром, и соответственно для этого, на него нужно отправить второй байт.
Динамическая индикация:
Для отображения всех разрядов применяется динамическая индикация, что это и как работает показано в видео ниже.
Подключение модуля к Arduino:
Подключать индикатор можно на любые свободные выходы Arduino, питание у модуля 5 вольт.
Для работы с модулем можно использовать код выше, можно использовать библиотеки, например эту.
ФОРМИРОВАТЕЛЬ СИГНАЛА —
RAWR
Самый, простой вариант — во-
обще обойтись без формирователя
(рис.5). Здесь сигнал -RDDATA "по
совместительству" является и сигна-
лом -RAWR, проходя напрямую че-
рез интерфейсный разъем Х1.
Резистор R1
служит нагрузкой
открытого коллек-
тора микросхемы
DD1. Его наличие
обязательно для
всех последующих
схем. Номинал
R1 обычно колеблется в пределах
от 150. 330 Ом (желательно) до 10
кОм. При низких номиналах R1 улуч-
шается согласование волнового со-
противления ленточного кабеля, ко-
торый находится между дисководом
и контроллером. При этом увеличи-
вается крутизна фронта сигнала —
RDDATA.
(Продолжение. Начало в N4/99)
Схема, показанная на рис.5 бу-
дет работать, если имеется полная
уверенность в том, что в конкрет-
ном дисководе длительность сигна-
ла -RDDATA (а значит, и -RAWR) не
превышает 600 нс. Однако дисковод
дисководу рознь. К примеру, соглас-
но техническим данным на НГМД
"Электроника МС5305" [3], макси-
мальная длительность -RDDATA со-
ставляет 1,5 мкс.
Понятно, что приведенная про-
стейшая схема в контроллерах не
прижилась. Очередной шаг напра-
шивается сам собой — сделать
длительность сигнала -RDDATA пос-
тоянной. С этим может справиться
од-новибратор (рис.6).
Длительность выходных импуль-
сов од-новибратора DD2 рассчиты-
вается по приближенной формуле
Ти = 0,45*R1*C1. В схемах обычно
добиваются значения Ти в пре-
делах 200. 300 нс.
Иногда одновибратор стро-
ится по схеме формирователя с
RC-задержкой (рис.7, [5]).
Сигнал RDD (вывод 23 БИС
i8272A) функционально экви-
валентен сигналу -RAWR ВГ93. Его
длительность определяется цепоч-
кой задержки R1, С1. "Необычный"
логический элемент DD1 образован
Следует заметить,
что в схемах рис. 6, 7
импульсы одновибра-
тора никак не связаны
с тактовыми сигнала-
ми контроллера. Это
вносит дополнитель-
ную погрешность в
к импульсам синхронизации FCLK
(рис.8). Поясняющие временные
диаграммы приведены на рис.9.
Длительность сигнала -RAWR
строго нормирована величиной 250
нс независимо от периода (4; 6 или
8 мкс). Тактовые импульсы FCLK
частотой 4 МГц поступают от внут-
реннего кварцевого генератора конт-
роллера. Их период определяет дли-
тельность сигнала -RAWR.
Сдвиг во времени переднего
фронта сигналов -RDDATA и -RAWR
(рис.9) не носит принципиального
характера, поскольку основная ин-
формация переносится периодом
следования сигнала.
Существует несколько разновид-
ностей данной схемы, отличающих-
ся типом применяемого логического
элемента DD2, вплоть до замены его
диодом и резистором. Общим клас-
сифицирующим признаком является
подача сигнала -RDDATA на D-вход
триггера DD1.1.
прошивкой программируемой матри-
цы.
процесс выделения информации.
Как следствие, во многих контролле-
рах схемы были усовершенствова-
ны. В частности, изменить ситуацию
помогает привязка сигнала -RDDATA
В схеме на рис.10 сигнал чтения
подается на С-вход триггера DD2.1.
Логика работы (рис.11) и возмож-
ности схемы от этого не меняются.
Новизна заключается в применении
сигнала WF/DE, блокирующего вы-
дачу импульсов -RAWR в режиме
записи информации. Это может по-
надобиться для корректной работы
некоторых схем формирователя сиг-
нала RCLK.
Еще один нюанс, который заслу-
живает внимания — можно ли "сэ-
кономить" на буферном элементе
DD1.1? Не секрет, что D-триггеры
ТТЛ-серий ТМ2 очень чувствитель-
ны к крутизне фронта импульса на
синхровходе. К примеру, согласно
техническим условиям,
на вход С микросхемы
К555ТМ2 желательно
подавать сигналы с
длительностью фрон-
та и среза не более 15
нс.
Учитывая это, эле-
мент DD1.1 нужен, а
вот устанавливаемый в некоторых
схемах конденсатор С1 (отмечен
пунктиром) — под вопросом. Если
С1 удаляет "иголки" сигнала, то сто-
ит вначале попытаться уменьшить
номинал резистора R2.
Схемы на рис.8, 10 относятся к
разряду "четырехмегагерцовых"^
CLK). В некоторых контроллерах
имеется дополнительно частота 8
МГц. Разработчики не преминули
воспользоваться такой возможнос-
тью, что позволило уменьшить дли-
тельность сигнала -RAWR до 125 нс
(рис.12, [6]).
Микросхема DD2 содержит син-
хронно тактируемые D-триггеры.
Временные диаграммы (рис.13) по-
казаны для случая WF/DE=0, т.е. для
режима чтения.
Закономерен вопрос, а зачем
вообще нужно уменьшать длитель-
ность сигнала -RAWR? Ответ дает
рис.14, на котором показаны вре-
менные соотношения в "окне детек-
тирования" согласно техническим
данным на ВГ93 [4].
Запас "окна детектирования"
(ЗП) определяется по формуле
ЗП = ±(Т/2 — х1 — т2 — Ти)/2.
Ти — это не что иное как дли-
тельность сигнала -RAWR. Если
принять т1 = т2 = 40 нс, то для Ти
= 125 нс значение ЗП равно +897
мкс (+0.224Т), а для Ти — 250 нс
ЗП равно ±835 мкс (+0.209Т).
Следовательно, схема на рис.12
теоретически имеет на 7,4% боль-
ший запас "окна детектирования",
чем схемы на рис.8,10, что позволя-
ет ближе подойти к пределу +0.25Т.
Нередко встречаются "гибрид-
ные" схемы, у которых -RAWR рас-
щепляется на два сигнала: один из
них, длительностью 250 нс, подается
на вывод 27 ВГ93; другой, длитель-
ностью 125 нс — на схему выделе-
ния синхросерии. К чему это приво-
дит, станет ясно при рассмотрении
схемотехники формирования сигна-
ла RCLK.
ФОРМИРОВАТЕЛЬ СИГНАЛА
RCLK
Изложение данного материала в
радиолюбительских статьях обычно
сопровождается кратким описанием
принципа работы, иногда — графом
переходов [6]. Думается, этого недо-
статочно, ведь за общими фразами
не видно физики процесса, а вузов-
ская подготовка имеется далеко не у
каждого. Отсюда путаница в поняти-
ях, отсутствие какой-либо классифи-
кации.
Похожие публикации:
- 30 rpm что это
- Как проверить кварцевые часы
- Сколько стоит зарядка для гироскутера
- Sanyuan 250v 10a где можно купить
Статическая индикация на семисегментниках с использованием 74hc595
Я думаю, у многих при использовании динамической индикации на семисегментных индикаторах возникали проблемы с яркостью индикаторов.
А всё потому, что сегменты постоянно подключаются – отключаются и получается некое подобие ШИМ. Чтобы этого не происходило, следует использовать статическую индикацию. При таком принципе сегменты зажигаются один раз и переключаются только при изменении цифры. Это и программно удобно: не нужно постоянно вызывать из программы функции или подпрограммы, отвечающие за динамическую индикацию. Нужно только при изменении данных повторно вывести их на дисплей и всё.
Но возникает проблема: для этого нужно много выводов микроконтроллера. К примеру, если у нас 4 цифры, то нужно 8х4=32 вывода, у у Меги16 их всего 32. Поэтому для реализации статической индикации необходимо использовать сдвиговые регистры или расширители портов.
Расширители портов, как правило, подключаются к микроконтроллеру через SPI/I2C и представляют из себя полноценный порт ввода-вывода, который можно настроить на вход/выход и перевести в высокоомное Hi-Z сотояние(это когда вывод как-бы ни к чему не подключен).
А сдвиговые регистры(я рассматриваю именно 74hc595) дают нам совокупность ножек, которые являются выходами и их также можно перевести в состояние Hi-Z. Управляются они через последовательный интерфейс. В данном случае это подобие SPI. Конечно, существуют и регистры с параллельным входом – последовательным выходом и другие, но мы не будем их рассматривать в рамках данной статьи.
Как Вы уже догадались, для реализации статической индикации нам достаточно сдвиговых регистров. Наверное, самые популярные из них – 74hc595. Это регистры-защёлки с последовательным входом – параллельным выходом. Защёлками они называются потому, что после того, как мы запишем в них данные, их необходимо “защёлкнуть” – перевести на некоторое время состояние одного из пинов в логическую единицу. Только после этого будет изменено состояние выходов.
Вот распиновка регистра:
Распишу выводы по порядку:
- VCC и GND – питание, оно может быть в пределах от 2 до 6 Вольт.
- Qa – Qh – выходы регистра, каждый из них тянет до 6 мА тока при питании 5 Вольт.
- Qh’ – вывод для объединения нескольких регистров. Он подключается к входу данных следующего регистра, ещё расскажу об этом.
- SER – вход данных регистра.
- SRCLK – вход для тактовых импульсов.
- RCLK — Защелка. Подаём на него единицу и данные защёлкиваются.
- OE – Если подать на этот вывод 1, то выходы передут в высокоомное стостояние, если 0 – в рабочее сотояние(0 или 1).
- SRCLR – сброс регистра.
Для реализации статической индикации на понадобятся выводы питания, выходы регистра и выводы SER, SRCLK, RCLK. Если больше одного регистра – можно соединить их цепочкой: вывод Qh’ предыдущего регистра с выводом SER следующего. Вот общая схема включения(подтяжка RESET у МК не нарисована, но подразумевается; картинка кликабельна):
Порядок записи в регитр такой: сначала устанавливаем нужный уровель на SER, который должен соответствовать требуемому биту, потом устанавливаем в единицу SRCLK и потом сразу-же устанавливаем его в ноль. Произойдёт вывод 1 бита, следующий бит будет сдвигать предыдущий. Повторяем такой цикл 8 раз(или 32 раза с 4-мя разрядами индикатора), после всех действий устанавливаем в единицу защёлку, потом обнуляем, и данные будут обработына и выведены. Более подробно расписано в комментариях к коду примера. Скачать можно в конце статьи.
Для реализации статической индикации я написал недольшую библиотеку. Она изначально поддерживает Дисплей с 4-мя цифрами. При желании можете сократить/увеличить количество цифр. В комментариях к коду всё подробно расписано. Пользоваться библиотекой просто. Для начала добавьте файл 74hc595segment.asm в папку с проектом, подключите библиотеку к проекту где-нибудь в конце программы, там, где находятся подпрограммы :
.include "74hc595segment.asm"
После, там, где у Вас инициализация, добавьте строку с инициальзацией(скорее, настройкой портов):
rcall display_init
Дальше пропишите порты ввода-вывода, на которых будут висеть регистры, определения находятся в начале файла с библиотекой:
;========================================================================== ;Указываем выводы, на которых будет сидеть шина данных ;Сначала порты и DDR .equ DS_PORT = PORTA .equ DS_DDR = DDRA; Данные .equ TAKT_PORT = PORTA .equ TAKT_DDR = DDRA;Вход тактировки 74hc595 .equ ZAS_PORT = PORTA .equ ZAS_DDR = DDRA;Защёлка ;А дальше указываем конкретные выводы .equ ZAS = PA2; Защёлка .equ TAKT =PA1; Вход тактировки 74hc595 .equ DS = PA0; Данные ;=========================================================================
Теперь можно пользоваться. Загружем в переменные цифры и выводим их на дисплей:
ldi r16,1;Загружем цифорки в соответствующие ячейки памяти. sts digits,r16 ldi r16,2 sts digits+1,r16 ldi r16,3 sts digits+2,r16 ldi r16,4 sts digits+3,r16 ldi r16,0b00001000; Установка точки. sts digits+4,r16 ;Младшие 4 бита соответствуют четырём точкам(слева-направо). rcall display;Выводим на дисплей данные
Полный текст программы:
;========================================================================= ;Тестовая программа для проверки библитеки, предназначеной ;Для реализации статической индикации на семисегментниках с ;Использованием сдвиговых регистров 74hc595 ; ©LPA, 2012 ; http://radioelektr.ru ;========================================================================= .include "m16Adef.inc" ;========================================================================= ldi r16,low(ramend) out spl,r16 ldi r16,high(ramend) out sph,r16 ;Стек rcall display_init ;Настройка портов ввода-вывода, к которым подключены регистры ;========================================================================= ldi r16,1;Загружем цифорки в соответствующие ячейки памяти. sts digits,r16 ldi r16,2 sts digits+1,r16 ldi r16,3 sts digits+2,r16 ldi r16,4 sts digits+3,r16 ldi r16,0b00001000; Установка точки. sts digits+4,r16 ;Младшие 4 бита соответствуют четырём точкам(слева-направо). rcall display;Выводим на дисплей данные main:;Главный цикл пуст rjmp main ;========================================================================= .include "74hc595segment.asm";Подключение библиотеки
А вот что из этого получилось:
Если хотите изменить библиотеку под свои индикаторы – никаких проблем, в конце библиотеки есть таблица символов. Её можно расширить, сократить, можно задать состояние каждого вывода регистра для определённой цифры. Код прокомментирован, поятому, я думаю, проблем не будет.
Также я сделал ещё один пример: простые часы с использованием статической индикации и DS1307. В симуляторе они выглядят так:
В архиве есть две прошивки с исходниками и модели в протеусе(v 7.7 SP2). Исходники прокомментированы.