8-900-374-94-44
[email protected]
Slide Image
Меню

Микросхема tm1637 описание – Обзор дисплея на базе драйвера TM1637

Дисплей на TM1637, часы с синхронизацией по NTP и программирование "народных" WiFi в среде Ардуино

Сначала хотел посвятить свой «юбилейный» 50-й обзор ESP8266 ES07 купленных за очень «вкусную» цену вместе с платами-адаптерами. Но обзор этих модулей я уже делал. Здесь же хочу рассказать, как можно делать свои поделки, в частности часы на семисегментном индикаторе, программируя эти «народные» WiFi в популярное среде Arduino IDE

Начнем с модулей:
Для своих проектов я искал семисегментные индикаторы, яркие и компактные. Сделал ряд проектов на индикаторах с драйверами MAX7219

Недавно покупая на Алиэкспрессе всякую мелочевку наткнулся на эти индикаторы, на микросхеме TM1637. Мне понравилось компактное исполнение, невысокая цена и управление всего по двум проводам. Заказал парочку вместе с кучей других деталек.

Модули приехали запаянные в пакетики

Характеристики:

  • Питание 3.3 — 5.5В
  • Потребляемый ток 0.2 — 80мА (в зависимости от горящих сегментов)
  • Градаций яркости индикаторов — 8
  • Размеры платы: 42x24мм


Четыре штырьковых контакта для подключения:
VCC — питание, GND — земля и два управления CLK и DIO по аналогии с интерфейсом I2C. Большое спасибо, что контакты идут вбок, а не вверх, как на некоторых платах.

Вместе в посылке пришли и ESP8266 ES07, о которых упоминал в начале статьи. Подробно написал про них в своем блоге.

Последнее время много ковырялся с ESP-шками и решил опробовать индикаторы именно с ними. Особенностью данной реализации стало программирование из среды Arduino IDE.
Настройка Arduino IDE для работы с ESP8266 хорошо описана здесь

Хочу немного добавить, что купленные мною модули ESP-07 распаянные на платы-адаптеры уже практически готовы к использованию. Подключаем TX/RX и GND к TTL-USB конвертеру, например, такому. Подключаем питание 3.3В к VCC. Для загрузки прошивки GPIO0 присоединяем к земле. Собственно и все. Подключить GPIO0 и RESET к данному конвертеру у меня не получилось, но это оказалось не сильно нужно. При подсоединенном GPIO0 к земле ESP находится в режиме загрузки прошивки во флэш-память, но после загрузки происходит запуск программы без отсоединения данного GPIO. Это позволяет вполне комфортно отлаживать свою программу. Нужно перед загрузкой только перезагрузить модуль передергиванием питания или кратковременно подав на вывод RESET на землю. Для этого можно припаять специальную кнопку.

На фотке немного другой модуль ES12 из предыдущей партии. Конденсатор установлен для повышения стабильности работы. Последние модули использую без них.

Итак модуль подключен, среда настроена. Для ES07 все настройки ESP8266 ставятся «по умолчанию»:

Для работы с дисплеем на TM1637 я взял готовую библиотеку для Ардуино DigitalTube. «По умолчанию», дополнительные библиотеки устанавливаются в каталог: «Мои документы\Arduino\libraries\». Чтобы оправдать использование WiFi-модуля, эти часы буду синхронизировать время с NTP сервером в интернете.

Подключаем ESP, дисплей к CLK -> GPIO4, DIO ->GPIO5, стабилизатор 3.3В и USB-TTL конвертер макетными проводами

Грузим скетч, который можно взять здесь.
Настраиваем параметры своей точки доступа: AP_SSID и AP_PASS, свою таймзону TIMEZONE. У меня установлена для Перми/Екатеринбурга. Для Москвы будет 3.
Функцией tm1637.set(2) устанавливаем необходимую яркость индикатора от 0 до 7.
Компилируем:

Готово. Часы показывают часы и минуты, мигая двоеточием. Время точное из интернета, синхронизируется с NTP сервером. При длительном отсутствии соединения происходит перезагрузка ESP-шки.

В корпус все это делать не стал, так как это только прототип для будущего проекта.
Прочитать об этом можно будет в моем блоге

Полезные ссылки

А это помощник:


mysku.ru

TM1637 и AVR ASM - - блог Л е о н ы ч а

Намедни приблудился китайский дисплейный модуль на контроллере TM1637 (далее в тексте - контроллер, устройство) .

 

 

Вещь конечно, приятная во всех отношениях. По цене, сопоставим с ценой "голого" четырёхразрядного индикатора. Управляется всего по двум проводам, позволяя применять в качестве "ядра" дешевые маловыводные микроконтроллеры (далее в тексте - МК) вплоть до шестиногих букашек вроде Tiny10. Причём, от процессора не потребуется отвлекаться на динамическую индикацию,.достаточно отправить контроллеру посылку из нескольких байтов, и заниматься своими делами. "Выстрелил и забыл".

Но и это ещё не всё. К устройству можно подключить шестнадцатикнопочную клавиатуру, получив почти полноценный терминал (кстати, борьбу с дребезгом контроллер тоже берёт на себя. )) )

И все эти радости - по двум проводочкам... Вкусно.

 

Но не без ложки китайского дёгтя , ессно.

Ибо даташит, переведенный с китайского на английский, это... что-то. (Здесь должен быть абзац, составленный исключительно из матерных слов).

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

И вот с этим-то - самая засада. Поскольку посторонние источники крайне скудны. Существуют библиотеки под некоторые среды, в том числе - Ардуино (не к ночи будь помянута), но понимания работы ТМ1637 они не добавляют.

Примеров ассемблерного кода для AVR найти и вовсе не удалось, что сподвигло меня добавить в конце сего материала демонстрационную программульку, чтобы по мере способностей, восполнить этот пробел. На исчерпывающую полноту, абсолютную истину, и красоту кода не претендую. ))

 

Итак - "О контроллере ТМ1637 человеческим языком".

 

Начнём с "физики".

Последовательный интерфейс, разработанный для этого контроллера, является творческой переработкой широко известного "квадратного" I2C. Отличия состоят в других названиях линий, обратном порядке следования битов, и в отсутствии адреса устройства.

С чем связаны эти странности, с китайской ли самобытностью, или с патентными ограничениями, неведомо. (Памятуя о смешной цене устройства, логичнее предполагать второе))).

Конечно есть решения, позволяющие применять для обмена с устройством стандартные аппаратные интерфейсы USI, встроенные во многие современные МК. Но здесь мы их рассматривать не будем. Отчасти по той причине, что не у всех "букашек" есть встроенный USI, поэтому строить интерфейс программным путём всё равно когда-то, да придётся.

 

Обмен данными происходит по двум шинам - тактовой CLK, и данных DIO. При отсутствии передачи, на обеих шинах сохраняется высокий уровень.

Для передачи одного байта требуется девять импульсов синхронизации CLK. Биты передаются начиная с младшего.

Активной стороной всегда является МК. Контроллер TM1637 только принимает данные и отвечает на запросы.

Важно 1 - изменения состояния шины DIO должны происходить только при низком уровне на шине CLK.

Перед восходящим (передним) фронтом на CLK, на шине DIO уже должен быть установлен актуальный потенциал, соответствующий состоянию передаваемого бита.

Важно 2 - это правило нарушается лишь в начале и в конце посылки, (в пределах одной посылки может быть передано от одного до нескольких байтов). Маркером начала посылки является переход от высокого уровня к низкому на DIO при высоком CLK. Маркер окончания посылки - переход от низкого уровня к высокому на DIO при высоком CLK.

Эти два условия соответствуют стандартному протоколу I2C.

 

Сигнал подтверждения ACK тоже почти похож на аналогичный от I2C, и представляет собой низкий уровень на шине DIO, выставляемый устройством по заднему (спадающему) фронту восьмого импульса CLK (напомню, что по переднему фронту этого же импульса происходит запись последнего, восьмого бита передаваемого байта). Этот низкий уровень удерживается в течение одного такта синхронизации - до заднего фронта девятого импульса CLK. Если после этого не будет сформирован маркер окончания передачи, то следующий импульс CLK будет считаться первым синхроимпульсом следующего передаваемого байта.

 

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

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

 

С физикой вроде разобрались, теперь - СОФТ.

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

1. Даташит требует перво-наперво провести "инициализацию". Причём нигде в даташите не объяснено, что сие значит. В голову сразу лезут страшные воспоминания о громоздких процедурах для дисплеев на контроллере HD44780 и ему подобных...

Но здесь инициализация представляет собой всего лишь одну однобайтную команду, позволяющую включить дисплей и установить нужную пользователю яркость (да-да, и яркостью мы тоже можем управлять))). С помощью этой же команды можно и выключать дисплей. Например с целью энергосбережения.

Структура этого байта такова:

 

Bit 7 _ Всегда 1.

Bit 6 _ Всегда 0

Bit 5 _ 0 или безразлично

Bit 4 _ 0 или безразлично

Bit 3 _ 1 - включить дисплей, 0 - выключить дисплей

Bit 2, Bit 1,Bit 0 _ Три бита 0...2 задают 8 градаций яркости дисплея.

 

NB: Касаемо содержимого битов 4 и 5, даташит гласит: "Zero should be inserted for irrelevant items". Что по-видимому следует понимать как "Неиспользуемый бит. Рекомендуется записывать в него ноль". Однако при записи туда единиц, ровным счётом ничего не меняется.

 

z.B: Команда 0b10001000 (0х88) - включить дисплей на минимальной яркости. (см.Фиг.2)

 

 

2.Затем нужно передать ещё одну однобайтную команду конфигурации, определяющую последующие действия:

а. Включим ли мы дисплей в нормальный режим, или в тестовый. Что такое тестовый режим, даташит умалчивает.

б. Будем ли мы передавать данные пакетом в несколько знаков (с автоинкрементом адреса), или изменять данные в каждом знакоместе по отдельности (по фиксированному адресу).

в. Будем ли мы вообще передавать в устройство данные для отображения, или будем читать состояние подключенной клавиатуры.

 

Структура команды конфигурации

Bit 7 _ Всегда 0

Bit 6 _ Всегда 1.

Bit 5 _ 0 или безразлично

Bit 4 _ 0 или безразлично

Bit 3 _ 1 - тестовый режим, 0 - нормальный режим

Bit 2 _ 1 - с фиксированным адресом знакоместа, 0 - с автоинкрементом адреса

Bit 1 _ 1 - чтение клавиатуры, 0 - запись отображаемых данных

Bit 0 _ Всегда 0

 

z.B: Команда 0b01000000 - (0х40) будем записывать данные пакетом, в нормальном режиме.

 

3. И наконец, нужно передать в устройство адрес знакоместа, и данные которые мы хотим в нём увидеть.

Здесь вспоминаем пункт "2.б". Если выбран режим фиксированного адреса, то посылки будут двухбайтовыми: [адрес]+[передаваемые_данные] для каждого знакоместа.

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

Адреса знакомест начинаются с 0xC0 (крайне левое, оно же - первое), и заканчиваются на 0xC3 для четырёхзнакового индикатора, или на 0xC5 для шестизнакового.

 

z.B: Посылка (0хC2,0x73) - отобразит в третьем разряде букву "Р". (см.Фиг.3)

 

 

Если выбрана пакетная передача данных, то достаточно передать начальный адрес (например для первого знакоместа - 0xC0 ) а затем передать группу байтов данных. При этом адрес для каждого из байтов будет добавлен автоматически, и все они последовательно попадут на свои места. Всё это, и начальный адрес, и несколько байтов данных передаются за одну посылку.

z.B: Посылка контроллеру подряд пяти байтов (0xC0,0x06,0x5B,0x4F,0x66) - отобразит, начиная с первого знакоместа, число "1234".

 

Работа с клавиатурой

 

 

Её чтение происходит так:

1. Если инициализация не проведена ранее, проводим её.

2. Подаём команду конфигурации, которая в данном случае выглядит примерно так: 0b01000010 (0х42)

Это запрос текущего состояния клавиатуры.

3 Получив запрос, устройство переключается в режим передачи, и в ответ на каждый следующий передний фронт получаемых от МК импульсов CLK, выставляет на шину DIO уровень, соответствующий значению передаваемого бита.

Поэтому нам потребуется перевести шину DIO в режим чтения (переконфигурируя соответствующий порт МК как вход), чтобы снимать с неё данные.

Данные передаются в течение первых восьми тактов CLK. Девятый такт образует стоп-бит.

Всю процедуру чтения нужно производить одной двухбайтной посылкой [команда]+[чтение_данных].

Запрос клавиатуры при ненажатых кнопках, возвращает значение 0xFF.

 

В полученном байте состояния клавиатуры, интерес представляют первые (младшие) пять битов.

Биты 0...2 дают код нажатой кнопки в пределах одной группы (клавиатура организована как две группы по восемь кнопок. см.фиг.4)

Низкий уровень бита 3 указывает на активность в первой группе (К1).

Низкий уровень бита 4 указывает на активность во второй группе (К2).

Высокий уровень в обеих этих битах (Bit3,Bit4) указывает на отсутствие нажатых кнопок.

 

Чтение клавиатуры проиллюстрировано в документации картинкой (см.Фиг.5). Картинки - то немногое что ещё можно понять в даташите. )))

 

 

При работе с клавиатурой следует учитывать три особенности.

1. Клавиатура "не понимает" нажатия двух и более кнопок одновременно.

2. При изменении состояния клавиатуры, контроллер не проявляет никакой активности на интерфейсных шинах. Поэтому, вызывать от неё прерывания МК не получится. Клавиатуру придётся регулярно опрашивать с достаточной периодичностью.

3. Судя по осциллограммам, выход устройства в режиме передачи данных в МК представляет собой "открытый исток", хотя в даташите это нигде не упомянуто.

Поэтому скорость нарастания напряжения на шине DIO ограничена параметрами RC цепи, состоящей из резистора подтяжки (10 КОм) и конденсатора неведомой ёмкости, установленного параллельно шине. Это обстоятельство ограничивает скорость пересылки данных в режиме чтения клавиатуры. При попытках уменьшения периода импульсов CLK до 100...150 мкс и менее, моё устройство отказывалось читать клавиатуру правильно.

В примере кода, этот период составляет около 300 мкс (его можно изменять, модифицируя подпрограмму "pause:").

 

Быстродействие же устройства "на индикацию" может быть достаточно высоким. У меня оно бодро выводило символы на табло при периоде синхроимпульсов на шине CLK менее четырёх микросекунд. Работу при более высокой частоте, я не проверял.

 

И ещё.

Если планируется прошивка МК прямо в устройстве, старайтесь не использовать ISP выводы МК для линий DIO и SCK. Контроллер может принять активность на этих линиях за обмен с ним, и в неподходящий момент выставить на DIO свой ACK.

Впрочем, разъём между МК и устройством гарантированно позволит избежать коллизий. ))

 

Внизу выложен файл "ТМ1637.asm" - листинг демонстрационной программки на Ассемблере для ATtiny24 с тактовой частотой 8 МГц (писано в AVRStudio_4.14).

В ней присутствуют все четыре основных действия для работы с TM1637 - инициализация, передача данных с автоинкрементом адреса, передача данных по фиксированному адресу, и чтение клавиатуры.

Программка выводит на табло цифры "123" в старших разрядах, и "кракозябры" соответствующие необработанному коду чтения клавиатуры, в младшем разряде. Расшифровать код клавиатуры можно с помощью "весовых коэффициентов", показанных на фиг.6.

 

 

 

Приложение: TM1637.asm

(В более удобоваримом виде - тут: https://www.chipmake...les/file/16019/ )

;*****************************************

;

; TM1637 + Tiny24 8MHz

; CLK = PA3

; DIO = PA1

; Отображение в старших разрядах надписи "123"

; и необработанного байта состояния клавиатуры в 4-м разряде

;

;*******************************************

.include "tn24def.inc"

;****** РЕГИСТРЫ

.def tmp0 =r16

.def tmp1 =r17

.def tmp2 =r18

.def tmp3 =r19

;****** БИТЫ

.equ CLK =0x03 ;

.equ DIO =0x01 ;

 

rjmp RESET ; Reset Handler

rjmp EXINT ; IRQ0 Handler

rjmp PCIN0 ; PCINT0 Handler

rjmp PCIN1 ; PCINT1 Handler

rjmp WDT ; Watchdog Interrupt Handler

rjmp TIM1_CAPT ; Timer1 Capture Handler

rjmp TIM1_COMPA ; Timer1 Compare A Handler

rjmp TIM1_COMPB ; Timer1 Compare B Handler

rjmp TIM1_OVF ; Timer1 Overflow Handler

rjmp TIM0_COMPA ; Timer0 Compare A Handler

rjmp TIM0_COMPB ; Timer0 Compare B Handler

rjmp TIM0_OVF ; Timer0 Overflow Handler

rjmp ANA_COMP ; Analog Comparator Handler

rjmp ADCHN ; ADC Conversion Handler

rjmp EE_RDY ; EEPROM Ready Handler

rjmp USI_STR ; USI STart Handler

rjmp USI_OVF ; USI Overflow Handler

 

RESET: ldi tmp1, low(RAMEND)

out SPL,tmp1

 

ldi tmp0,0xFF ;

out ddra,tmp1 ;весь porta как выход

out porta,tmp1 ;всем 1

 

;***************************************************

;***************************************************

LOOP:

;инициализация

rcall start ;маркер начала посылки

ldi tmp0,0x88 ;включение дисплея. Яркость минимальная.

rcall outcom ;вывожу команду

rcall end ;маркер конца посылки

 

rcall pause ;пауза 100 мкс

;включение режима передачи данных с автоинкрементом адреса

rcall start ;маркер начала посылки

ldi tmp0,0x40 ;режим передачи данных с автоинкрементом адреса

rcall outcom ;вывожу команду

rcall end ;маркер конца посылки

 

rcall pause ;пауза 100 мкс

;вывод сообщения "123" на табло

rcall start ;маркер начала посылки

ldi tmp0,0xC0 ;УСТАНОВКА НАЧАЛЬНОГО АДРЕСА (0хC0 - крайнее левое знакоместо)

rcall outcom ;вывожу адрес

ldi tmp0,0x06 ;1 в первый разряд

rcall outcom ;вывожу данные

ldi tmp0,0x5b ;2 во второй разряд

rcall outcom ;вывожу данные

ldi tmp0,0x4f ;3 в третий разряд

rcall outcom ;вывожу данные

rcall end ;маркер конца посылки

rcall pause ;пауза 100 мкс

 

;чтение клавиатуры

rcall start ;маркер начала посылки

ldi tmp0,0x42 ;режим чтения клавиатуры

rcall outcom ;вывожу команду

rcall incom ;получаю данные

rcall end ;маркер конца посылки

 

mov tmp2,tmp0 ;сохраняю данные клавиатуры в tmp4

 

;включение режима передачи данных с фиксированным адресом

rcall start ;маркер начала посылки

ldi tmp0,0x44 ;режим передачи данных с фиксированным адресом

rcall outcom ;вывожу команду

rcall end ;маркер конца посылки

;вывод необработанного байта состояния клавиатуры в четвертый разряд табло

rcall pause ;пауза 100 мкс

rcall start ;маркер начала посылки

ldi tmp0,0xC3 ;УСТАНОВКА АДРЕСА (0хC3 - четвертое знакоместо)

rcall outcom ;вывожу адрес

mov tmp0,tmp2 ;восстанавливаю в tmp0 сохранённые данные клавиатуры

rcall outcom ;вывожу данные

rcall end ;маркер конца посылки

 

rjmp LOOP

;***********************************

start: ;маркер начала посылки

rcall pause ;пауза 100 мкс

sbi porta,clk ;

sbi porta,dio ;

rcall pause ;пауза 100 мкс

cbi porta,dio ;

rcall pause ;пауза 100 мкс

ret

;***********************************

end: ;маркер конца посылки

sbi porta,clk ;

rcall pause ;пауза 100 мкс

sbi porta,dio ;

rcall pause ;пауза 100 мкс

ret

;***********************************

outcom: ;последовательный вывод. выводимый байт должен находиться в tmp0

push tmp1

; вывод восьми битов регистра tmp0

ldi tmp1,0x08 ;

outc10: cbi porta,clk ;опускаю CLK

rcall pause ;пауза 100 мкс

 

lsr tmp0 ; \

brcc outc20 ; |

sbi porta,dio ; > младший бит tmp0 выставляю на DIO

rjmp outc30 ; |

outc20: cbi porta,dio ; /

 

outc30: rcall pause ;пауза 100 мкс

sbi porta,clk ;поднимаю CLK

rcall pause ;пауза 100 мкс

dec tmp1 ;

brne outc10 ;последовательно вывожу весь байт

; стоп-бит

cbi ddra,dio ;переключаю DIO как вход, чтобы исключить коллизию с ACK

cbi porta,clk ;опускаю CLK

rcall pause ;пауза 100 мкс

sbi porta,clk ;поднимаю clk

rcall pause ;пауза 100 мкс

cbi porta,clk ;опускаю CLK

cbi porta,dio ;

sbi ddra,dio ;окончание стоп-бита, переключаю DIO как выход

; (выхожу с нулями на обеих шинах)

rcall pause ;пауза 100 мкс

pop tmp1 ;

ret ;

 

;********************************

incom: ;Чтение кнопок. выходные данные будут в tmp0

push tmp1

clr tmp0 ;

;последовательный ввод восьми битов в tmp0

ldi tmp1,0x08 ;

inc10: cbi porta,clk ;опускаю CLK

cbi ddra,dio ;переключение линии DIO как входа

sbi porta,dio ;включаю подтяжку DIO

rcall pause ;пауза 100 мкс

sbi porta,clk ;поднимаю CLK

rcall pause ;пауза 100 мкс

lsr tmp0 ;

sbr tmp0,0x80 ;\

sbis pina,dio ; >перенос пина DIO в tmp0

cbr tmp0,0x80 ;/

dec tmp1 ;

brne inc10 ;последовательно ввожу весь байт

 

rcall pause ;пауза 100 мкс

cbi porta,clk ;

;стоп-бит

rcall pause ;пауза 100 мкс

sbi porta,clk ;девятый импульс CLK

rcall pause ;пауза 100 мкс

cbi porta,clk ;опускаю CLK

 

cbi porta,dio ;выключаю подтяжку DIO

sbi ddra,dio ;переключение линии DIO как выхода

; выход с нулями на обеих шинах

rcall pause ;пауза 100 мкс

pop tmp1

ret

;********************************

pause: ;пауза 100 мкс

push tmp3 ;

ldi tmp3,0xff

de10: dec tmp3

brne de10

pop tmp3

ret

;*****************************************************************

;*****************************************************************

EXINT: ; IRQ0 Handler

PCIN0: ; PCINT0 Handler

PCIN1: ; PCINT1 Handler

WDT: ; Watchdog Interrupt Handler

TIM1_CAPT: ; Timer1 Capture Handler

TIM1_COMPA: ; Timer1 Compare A Handler

TIM1_COMPB: ; Timer1 Compare B Handler

TIM1_OVF: ; Timer1 Overflow Handler

TIM0_COMPA: ; Timer0 Compare A Handler

TIM0_COMPB: ; Timer0 Compare B Handler

TIM0_OVF: ; Timer0 Overflow Handler

ANA_COMP: ; Analog Comparator Handler

ADCHN: ; ADC Conversion Handler

EE_RDY: ; EEPROM Ready Handler

USI_STR: ; USI STart Handler

USI_OVF: ; USI Overflow Handler

rjmp reset ;

www.chipmaker.ru

Подключаем к Arduino дисплей TM1637

Всем привет.
Сегодня для тестирования, подключаем к Arduino Nano, четырех значный, 7 х 4 сегментный, I2C дисплей TM1637.
Еще несколько лет назад подключить такой дисплей было не так просто и приходилось использовать все выводы платы Ардуино. Но сейчас благодаря микросхеме TM1637, преобразующей данные с шины I2C, в параллельные сигналы, эти дисплеи стало очень просто подключать к контроллерам. Так как для подключения этого дисплея нужно всего 4 провода, мама-мама или если использовать макетную плату, то 4 провода папа-папа. Из них 2 повода это питание +5 В, GND и оставшиеся 2 провода это шина I2C.
Вкратце расскажу про характеристики дисплея:
Микросхема драйвера дисплея TM1637
Логические уровни толерантные как к уровням напряжения 5 В и 3.3 В.
Четыре семи сегментные цифры плюс разделительные точки.
Сам дисплей с общим анодом.
Яркость дисплея можно регулировать и имеет 3 уровня.
Цвета свечения сегментов бывают разные красный, синий, желтый, белый и зеленый. Но самый популярный цвет красный. Я бы для себя предпочел бы белый, но как мне кажется белый при ярком дневном освещении будет плохо читаем. Наверно с этим и связана популярность красного.

И так, перейдем к подключению сегментного экрана к Arduino nano. Подключение занимает всего несколько секунд.

Схема подключения:

Принципиальная схема:

Для того что бы на экране индикатора появилась какая либо информация, нужно скачать и установить библиотеку TM1637, потом запустить Arduino IDE и выбрать «Файлы — примеры — TM1637» и после чего нажать кнопочку «Загрузка в контроллер», кнопку обозначил на изображении

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

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

Например нам нужно на экране получить цифру 4. Для этого нужно суммировать следующие значения 2 + 4 + 32 + 64 = 102. Переводим в шестнадцатеричную систему исчисления и  получаем 0x66.

Ну вот как бы и все, что я хотел Вам рассказать про этот замечательный I2C экранчик. Надеюсь ничего не упустил. Если будут вопросы. Не стесняйтесь задавайте. Я отвечаю всегда, но может не всегда быстро как многим хотелось бы.

И на последок видео демонстрация возможностей сегментного индикатора TM1637

duino.ru

Часы реального времени [Амперка / Вики]

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

Описание компонентов

В нашем проекте мы используем:

Часы реального времени

Мы используем модуль с часами реального времени от Seeed Studio. Они построены на базе микросхемы DS1307 от Maxim Integrated. Из элементов обвязки она требует три резистора, часовой кварц и батарейку, которые уже имеются на данном модуле. Модуль обладает следующими свойствами:

  • Подсчет времени (секунды, минуты, часы), даты (год, месяц, число), дня недели

  • Двухпроводной интерфейс I²C

Суть часов реального времени в том, что при наличии батарейки, они могут идти даже если основное устройство обесточено. Мы с такими часами сталкиваемся постоянно в ноутбуках или цифровых фотоаппаратах. Если достать из этих устройств аккумулятор, а через некоторое время вернуть их обратно, то время не сбросится. В этом заслуга часов реального времени, Real Time Clock (RTC).

Все необходимые библиотеки можно скачать с официального сайта.

Индикатор

Мы используем четырёхразрядный индикатор от Seeed Studio. Основное в индикаторе — микросхема TM1637, представляющая собой драйвер для отдельных 7-сегментных разрядов. В данном модуле используется 4 разряда. Модуль обладает следующими свойствами:

  • 8 градаций яркости

  • Двухпроводной интерфейс работы (CLK, DIO)

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

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

  • Статическая индикация: 4 цифры × 7 сегментов = 28 соединений.

  • Динамическая индикация: 7 сегментов + 4 общих анода или катода = 11 соединений.

  • Микросхема TM1637: 2 соединения.

Выгода очевидна.

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

Подключение

Модуль часов реального времени необходимо подключить к выводам SCL/SDA, относящимся к шине I²C. Также необходимо подключить линии питания (Vcc) и земли (GND).

Линии SDA/SCL имеют собственные отдельные пины на Arduino, однако внутри они так или иначе подключены к пинам общего назначения. Если рассмотреть Arduino Uno, линии SDA соответствует пин A4, а SCL — A5.

В комплекте с модулем поставляется шлейф с мама-контактами, которые удобнее подключать к Troyka Shield. Однако отдельные пины SDA и SCL на ней не выведены, поэтому мы осуществили подключение прямо через пины A5 и A4.

В плане подключения индикатора — все гораздо проще. Выводы CLK и DIO можно подключить к любым цифровым выводам. В данном случае используются 12-й и 11-й выводы соответственно.

Написание прошивки

Функция setup должна инициализировать часы реального времени и индикатор, а также записывать время компиляции во внутреннюю память часов реального времени. Все действие, а точнее, чтение времени из RTC и вывод его на индикатор, будет производиться в функции loop.

Код для этого выглядит следующим образом:

rtc.ino
#include <Wire.h>
#include <EEPROM.h>
#include "TM1637.h"
#include "DS1307.h"
 
 
//Массив, содержащий время компиляции
char compileTime[] = __TIME__;
 
 
//Номера пинов Arduino, к которым подключается индикатор
#define DISPLAY_CLK_PIN 12  
#define DISPLAY_DIO_PIN 13
 
//Для работы с микросхемой часов и индикатором мы используем библиотеки
//Классы TM1637 и DS1307 объявлены именно в них
TM1637 display(DISPLAY_CLK_PIN, DISPLAY_DIO_PIN);
DS1307 clock;
 
 
void setup()
{
 
  //Включаем и настраиваем индикатор
  display.set();
  display.init();
 
  //Запускаем часы реального времени
  clock.begin();
 
  //Получаем число из строки, зная номер первого символа
  byte hour = getInt(compileTime, 0);
  byte minute = getInt(compileTime, 3);
  byte second = getInt(compileTime, 6);
 
  //Готовим для записи в RTC часы, минуты, секунды
  clock.fillByHMS(hour, minute, second);
 
  //Записываем эти данные во внутреннюю память часов.
  //С этого момента они начинают считать нужное для нас время
  clock.setTime();
 
}
 
 
void loop()
{
  //Значения для отображения на каждом из 4 разрядов
  int8_t timeDisp[4];
 
  //Запрашиваем время с часов
  clock.getTime();
 
  //Получаем десятки часов с помощью целочисленного деления
  timeDisp[0] = clock.hour / 10;
 
  //Получаем единицы часов с помощью остатка от деления
  timeDisp[1] = clock.hour % 10;
 
  //Проделываем то же самое с минутами
  timeDisp[2] = clock.minute / 10;
  timeDisp[3] = clock.minute % 10;
 
  //... а затем выводим его на экран
  display.display(timeDisp);
 
  //у нас нет отдельных разрядов для секунд, поэтому
  //будем включать и выключать двоеточие каждую секунду
  display.point(clock.second % 2 ? POINT_ON : POINT_OFF);
 
}
 
//Содержимое функции объяснено ниже
char getInt(const char* string, int startIndex) {
  return int(string[startIndex] - '0') * 10 + int(string[startIndex+1]) - '0';
}

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

Объяснение функции getInt

Для начала необходимо понять, откуда же в массиве compileTime появляется время. Оно появляется в этой строчке:

unsigned char compileTime[] = __TIME__;

Компилятор вместо __TIME__ подставляет строку, содержащую время компиляции в виде __TIME__ = "hh:mm:ss", где hh - часы, mm - минуты, ss - секунды.

Вернемся к коду, который необходимо объяснить:

char getInt(const char* string, int startIndex) {
  return int(string[startIndex] - '0') * 10 + int(string[startIndex+1]) - '0';
}

В массиве string, передаваемом в качестве параметра в функцию getInt, мы получаем символ с индексом startIndex и следующий за ним, чтобы в итоге получить двухзначное целое число. Однако, изначально это не число, а пара символов. Чтобы получить число по символу, нам необходимо вычесть из этого символа символ нуля ('0'): ведь в таблице ASCII все символы цифр идут одна за другой, начиная с символа нуля. Поэтому код int(string[startIndex]) - '0'), дословно, делает следующее: «Берем символ номер startIndex, вычитаем из него символ нуля и переводим в целочисленный тип».

Проблемы

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

Это происходит потому что после включения питания, вновь исполняется код, находящийся в функции setup. А он записывает в часы реального времени старое значение времени.

Чтобы этого избежать, нам необходимо еще чуть-чуть модифицировать код. Каждый раз в функции setup будет происходить подсчет «хэша» времени компиляции — будет рассчитываться количество секунд, прошедшее с 00:00:00 до времени компиляции. И этот хэш будет сравниваться с хэшем в EEPROM. Напомним EEPROM — память, которая не обнуляется при отключении питания.

Если значения посчитанного и сохранённого ранее хэша совпадают, то это значит, что перезаписывать время в модуль часов нет необходимости: это уже было сделано. А вот если эта проверка не проходит, то происходит перезапись времени в RTC.

Для записи/чтения числа типа unsigned int в/из EEPROM написаны две дополнительные функции EEPROMWriteInt и EEPROMReadInt. Они добавлены потому что функции EEPROM.read и EEPROM.write могуть читать и писать только данные типа char.

rtc-eeprom.ino
#include <Wire.h>
#include <EEPROM.h>
#include "TM1637.h"
#include "DS1307.h"
 
//Массив, содержащий время компиляции
char compileTime[] = __TIME__;
 
//Номера пинов Arduino, к которым подключается индикатор
#define DISPLAY_CLK_PIN 12  
#define DISPLAY_DIO_PIN 13
 
//Для работы с микросхемой часов и индикатором мы используем библиотеки
TM1637 display(DISPLAY_CLK_PIN, DISPLAY_DIO_PIN);
DS1307 clock;
 
 
void setup()
{
 
  //Включаем и настраиваем индикатор
  display.set();
  display.init();
 
  //Запускаем часы реального времени
  clock.begin();
 
  //Получаем число из строки, зная номер первого символа
  byte hour = getInt(compileTime, 0);
  byte minute = getInt(compileTime, 3);
  byte second = getInt(compileTime, 6);
 
  //Импровизированный хэш времени
  //Содержит в себе количество секунд с начала дня
  unsigned int hash =  hour * 60 * 60 + minute  * 60 + second; 
 
  //Проверяем несовпадение нового хэша с хэшем в EEPROM
  if (EEPROMReadInt(0) != hash) {
 
    //Сохраняем новый хэш
    EEPROMWriteInt(0, hash);
 
    //Готовим для записи в RTC часы, минуты, секунды
    clock.fillByHMS(hour, minute, second);
 
    //Записываем эти данные во внутреннюю память часов.
    //С этого момента они начинают считать нужное для нас время
    clock.setTime();
  }
 
}
 
 
void loop()
{
  //Значения для отображения на каждом из 4 разрядов
  int8_t timeDisp[4];
 
  //Запрашиваем время с часов
  clock.getTime();
 
  //Получаем десятки часов с помощью целочисленного деления
  timeDisp[0] = clock.hour / 10;
 
  //Получаем единицы часов с помощью остатка от деления
  timeDisp[1] = clock.hour % 10;
 
  //Проделываем то же самое с минутами
  timeDisp[2] = clock.minute / 10;
  timeDisp[3] = clock.minute % 10;
 
  //... а затем выводим его на экран
  display.display(timeDisp);
 
  //у нас нет отдельных разрядов для секунд, поэтому
  //будем включать и выключать двоеточие каждую секунду
  display.point(clock.second % 2 ? POINT_ON : POINT_OFF);
 
}
 
char getInt(const char* string, int startIndex) {
  return int(string[startIndex] - '0') * 10 + int(string[startIndex+1]) - '0';
}
 
//Запись двухбайтового числа в память
void EEPROMWriteInt(int address, int value)
{
  EEPROM.write(address, lowByte(value));
  EEPROM.write(address + 1, highByte(value));
}
 
//Чтение числа из памяти
unsigned int EEPROMReadInt(int address)
{
  byte lowByte = EEPROM.read(address);
  byte highByte = EEPROM.read(address + 1);
 
  return (highByte << 8) | lowByte;
}

Заключение

В данной статье был показан пример работы с микросхемой часов реального времени RTC DS1307 и микросхемой-драйвером индикатора TM1637, также мы научились получать дату и время на этапе компиляции. Теперь, если выставить нужное время на часах, а потом отключить питание хоть на несколько часов, то после включения время вновь будет точным. Проверено!

wiki.amperka.ru

Подключение TM1367 к PIC (первый опыт)

РадиоКот >Статьи >

Подключение TM1367 к PIC (первый опыт)

Подключение TM1367 к PIC (первый опыт).

Недавно решил использовать в таймере четырехзначный семисегментный индикатор ТМ1637 вместо знакосинтезирующего ЖКИ на базе контроллера HD44780.
Конструкция получается дешевле, освобождаются четыре порта, меньше команд в программе .
Вспомнив, что знакомство с ЖКИ на HD44780 начиналось с просмотра в интернете простых примеров программ на ассемблере, набрал запрос в поисковике.
Но ответа на вопрос "как подключить TM1637 к PIC" не получил. Дейташит микросхемы и статьи с пояснениями ее работы многое прояснили, но следуя им, работоспособную программу написать не удалось- то путались знакоместа, отсутствовали символы или произвольно выключался индикатор. Видимо не все, кажущееся авторам элементарным, доходит до впервые обратившегося к этой микросхеме. Программы в библиотеке MPLAB я тоже не нашел (или не сумел ей воспользоваться).
Поэтому пришлось отложить изучение интерфейса ТМ1637 и выводить символы по-своему, руководствуясь принципами I2C , не пытаясь объяснять свои решения . Так написал программку на ассемблере и использовал ее в своем таймере. Может быть она кому-то пригодится для знакомства с ТМ1637 или для демонстрации физического уровня I2C. Буду краток, считая, что читающий знаком с материалами по ТМ1637 и уже пытался их использовать ))).
В программе данные на шину DIO ТМ1637 выводятся группами по 5 байт . Включается индикатор этой же процедурой- первый байт, команда включения .140, второй, конфигурация .64, третий, номер какого-либо знакоместа; два последних байта могут быть нолями (сегменты не зажигаются). Следующая группа из пяти байт содержит номер знакоместа первой цифры и коды четырех выводимых цифр. Вывод данных происходит синхронно с состоянием тактовой шины CLK- уровень на DIO переключается, когда на CLK ноль. Между информационными байтами выдерживается промежуток в один период CLK на время ответа ACK. Старт и стоп происходит при переключении DIO на высоком уровне CLK. Тактовые импульсы имеют скважинность 2 и период 300мкс. В перерывах передачи импульсы не формируются, на шинах устанавливают единицу подтягивающие резисторы по 10 Ком. Порты RA4 (CLK) и RA5 (DIO) подключены к ним через развязывающие диоды “на всякий случай”, вдруг какое-либо новое устройство по своему усмотрению выставит на шинах ноль и двухтактный выход порта сгорит. Хотя стабильность частоты CLK не требуется, предпочтительно запретить прерывания при выводе знаков. Порты контроллера назначены согласно рисунку 1.


Для демонстрации интерфейса предлагаю программу " Часы ".
Меню программы имеет три режима:
- установка часов на рисунке 2,


- установка минут на рисунке 3,


- индикация времени на рисунке 4.


Интерфейс ТМ1637 реализован в процедуре PWR. В ней создан стек из пяти байт BTR1 - BTR5, в которые предварительно записываются данные. Байты синхронно с CLK сдвигаются вправо и правый крайний бит определяет уровень на шине DIO. После восьми информационных бит устанавливается высокий уровень и не делается сдвиг во время одного такта CLK, отводимого на ACK.

В таблице ниже поясняется назначение некоторых процедур программы:

PWR Интерфейс ТМ1637. RA4- CLK, RA5- DIO.
CLOCK Часы, считающие переполнения TMR1
JK и PI9_ Переключение пунктов меню, увеличение или уменьшение параметра
BDPP Преобразование числа из двоичной формы в двоично-десятичную, подготовка к выводу на индикатор
RDEP2C и IND2C Преобразование полубайтов выводимого числа в коды символов, запись кодов в BTR1 – BTR5. Коды семисегментных цифр записаны в ЕЕР по адресам от 0 до 9 соответственно.
KTRI_ и C_IND Управление работой программы.

Поскольку программа вырезана из таймера (сам многорежимный таймер ничем не отличается от многих других и не достоин внимания Радиокотов), в ней много ‘’некрасивых” адресов и лишних переменных. Прошу не обращать на них внимания; цель статьи- предложить действующий вариант интерфейса для ТМ1637, например, в виде незамысловатых часов.

Освоив вывод на дисплей цифр, не трудно выводить и буквы в семисегментном алфавите, как показано на рис. 5.


К сожалению, в отличие от LCD1602 , в PROTEUS нет эмулятора ТМ1637.
Debugger I2C дает непонятные комментарии о работе интерфейса. Для отладки программы подходит логический анализатор.

На рис.6 показано начало передачи,- сначала команда "Старт", потом байт 00110001.Мы помним, что биты в интерфейсе передаются начиная с младшего, поэтому исходный байт "перевернут" и имеет вид 10001100, что соответствует .140, команде включения. Потом перерыв (единица на DIO) на время ответа ТМ.Этот же байт можно увидеть с помощью реального осциллографа (рисунок 7), только труднее добиться стабильной синхронизации. Хотя, если непременно нужна осциллограмма, можно использовать свободный порт микроконтроллера для формирования синхросигнала в нужном байте последовательности DIO.

К статье приложены проекты в MPLAB и PROTEUS’е.
Вот так я открыл для себя недорогой и удобный индикатор и поупражнялся в двоичном счете.

Файлы:
Проект в Proteus
Проект в MPLAB

Все вопросы в Форум.


Как вам эта статья?

Заработало ли это устройство у вас?

www.radiokot.ru

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

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