Китайцы на aliexpress и других Интернет-площадках торгуют классными часами, которые стоят недорого ($6.5 с бесплатной доставкой, см. [1, 2]), легко собираются в домашних условиях и при этом красиво выглядят. Также приятный бонус - схема открыта, и в интернете можно легко найти исходный код микроконтроллера часов [3], так что при желании можно разобраться как все работает и внести свои изменения в алгоритм. Я купил себе такие часы, собрал за 1 вечер, и здесь решил выложить перевод инструкции к часам, которая в оригинале поставляется на английском языке.
Часы работают на дешевом микроконтроллере STC15W404AS, который можно купить на сайте aliexpress по цене 0.6..1.5 доллара.
Здесь приведена краткая информация по микроконтроллеру STC15W404AS. Подробные данные см. в даташите STC15-English.pdf из архива [3].
STC15W404AS относится к серии STC15W401AS семейства STC15 микроконтроллеров компании STC MCU Limited. Микроконтроллер имеет усовершенствованное ядро MSC51 (система команд и архитектура популярного некогда семейства микроконтроллеров Intel 8051). Это новое ядро, отличающееся высоким быстродействием (скорость работы в 8..12 раз быстрее традиционного ядра 8051 на той же тактовой частоте), широким рабочим диапазоном напряжений питания, низким энергопотреблением и устойчивостью к помехам. Код программы может быть защищен от несанкционированного доступа при перепрошивке с помощью специальной технологии шифрования STC. Поставляется в различных вариантах корпусов на 16, 20 и 28 выводов. STC15W404AS полностью совместим по системе команд с традиционным ядром 8051, и реализует его все аппаратные функции. Дополнительно в нем имеется два указателя DPTR вместо одного, порт UART можно использовать как 3 последовательных порта путем сдвига его данных на 3 группы выводов. Также имеется интерфейс SPI, и 8-канальный АЦП, которых нет в традиционных микроконтроллерах Intel 8051/8052/8751. Порты GPIO могут работать точно так же, как и оригинальные, и их также можно использовать в расширенных режимах (есть 4 режима работы: квази-двунаправленный со слабым pull-up, мощный двухтактный с усиленным pull-up, только вход с высоким сопротивлением и открытый сток). Каждый выход может коммутировать ток до 20 мА, однако общий коммутируемый ток не должен превышать 120 мА на корпус для 40-выводного корпуса и 90 мА для 16-выводного корпуса. В таблице ниже сведены основные параметры микроконтроллера.
Параметр
Описание
Рабочее напряжение
2.4V..5V
Память программ (FLASH)
4 килобайта, с поддержкой ISP/IAP (IAP расшифровывается как In-Application Programming, т. е. перепрограммирование в программе), количество перезаписей не менее 100 тысяч раз.
ОЗУ (SRAM)
512 байт: 256 байт традиционное регистровое ОЗУ (scratch-pad RAM) и 256 байт расширенное ОЗУ (auxiliary RAM).
UART
1 шт., его можно по выбору использовать на 3 группах выводов (P3.0/P3.1, или P3.6/P3.7 или P1.6/P1.7).
SPI
1 шт.
Таймеры
3 таймера разрядностью 16 бит T0, T1, T2 (T0 и T1 совместимы с традиционными Timer/Counter 0 и Timer/Counter 1 архитектуры 8051).
Захват и генерация сигнала
CCP, PCA, PWM: 3 канала, которые можно использовать как 3 таймера или 3 ЦАП.
Специальные режимы энергопотребления, таймер пробуждения
Есть
Стандартные внешние прерывания
5 каналов: INT0, INT1, ~INT2, ~INT3, ~INT4.
АЦП
8 каналов, 10 бит
Компаратор
Есть
EEPROM
9 килобайт с поддержкой IAP (In-Application Programming), количество перезаписей не менее 100 тысяч раз.
Прерывание при детектировании низкого напряжения
Есть
Сторожевой таймер (WDT)
Есть
Внутренняя система сброса
Есть, порог напряжения сброса опционально настраивается.
Система шифрования кода. С применением ключа шифрования, прошитого в MCU, имеется возможность обновлять программное обеспечение с помощью кнопки update. Для этого в системе программирования выбираются опции "encryption" download и "release project", когда требуется обновить программное обеспечение микроконтроллера. Из-за того, что в памяти программ последние 7 байт используются для хранения глобального идентификатора (global ID), то пространство памяти FLASH, доступное для программы пользователя, уменьшается на эти 7 байт.
Система сброса. В микроконтроллер встроена очень удобная система сброса, так что можно полностью исключить внешние цепочки, формирующие сигнал RESET. По умолчанию вывод P5.4/RST/MCLKO используется как порт ввода/вывода (GPIO), но его можно переконфигурировать как ножку сброса RST с активным уровнем лог. 1, это делается программатором STC-ISP. Порог сброса можно запрограммировать по 16 различным уровням.
Тактирование. В кристалл встроен точный R/C генератор (точность установки частоты ±0.3%). Уход частоты в зависимости от температуры в диапазоне -40..+80°C составляет 1%, в диапазоне -20..+65°C составляет 0.6%. Это позволяет отказаться от подключения дорогого внешнего кварцевого резонатора. Тактовая частота может быть установлена в диапазоне 5..35 МГц (предпочтительные частоты 5.5296, 11.0592, 22.1184, 33.1776 МГц).
Цоколевка и назначение выводов микроконтроллера для 28-выводного корпуса показана в таблице ниже.
№
Мнемоника
Описание/функция
1
P2.6
Порт ввода/вывода (GPIO).
2
P2.7
3
P1.0
4
P1.1
5
P1.2/SS/CMPO
P1.2
Порт ввода/вывода (GPIO).
SS
Slave Selection, сигнал выборки подчиненного устройства интерфейса SPI.
CMPO
Выходной порт результата сравнения компаратора.
6
P1.3/MOSI
P1.3
Порт ввода/вывода (GPIO).
MOSI
Master Output Slave Input, сигнал данных интерфейса SPI.
7
P1.4/MISO
P1.4
Порт ввода/вывода (GPIO).
MISO
Master Input Slave Output, сигнал данных интерфейса SPI.
8
P1.5/SCLK
P1.5
Порт ввода/вывода (GPIO).
SCLK
Тактовый сигнал интерфейса SPI.
9
P1.6/RXD_3/MCLKO_2
P1.6
Порт ввода/вывода (GPIO).
RXD_3
Вход данных UART1
MCLKO_3
Выход инвертирующего усилителя внутренней схемы тактирования. Когда используется внешний генератор тактов, этот вывод должен оставаться не подключенным.
10
P1.7/TXD_3
P1.7
Порт ввода/вывода (GPIO).
TXD_3
Выход данных UART1.
11
P5.4/RST/MCLKO/CMP-
P5.4
Порт ввода/вывода (GPIO).
RST
Вход для сигнала сброса. Уровень лог. 1 на этом выводе длительностью не менее 2 машинных такта приводит к сбросу устройства.
MCLKO
Master clock output, главный выход тактов. Выходная частота может быть равна MCLK, MCLK/2 и MCLK/4. Эта частота может вырабатываться от внутреннего R/C генератора, или от внешнего генератора, или с помощью использования внешнего кварцевого резонатора.
CMP-
Инверсный вход компаратора.
12
VCC
Плюс напряжения питания.
13
P5.5/CMP+
P5.5
Порт ввода/вывода (GPIO).
CMP+
Прямой (без инверсии) вход компаратора.
14
GND
Минус напряжения питания, общий провод.
15
P3.0/RXD/~INT4/T2CLKO
P3.0
Порт ввода/вывода (GPIO).
RXD
Вход данных UART1.
~INT4
Внешнее прервание 4, которое может сработать только по спаду логического уровня (от лог. 1 к лог. 0). Этот сигнал поддерживает функцию пробуждения из режима пониженного энергопотребления/выключения (power-down wake-up).
T2CLKO
T2 Clock Output, выход тактов T2. Эта ножка может быть сконфигурирована для вывода тактовой частоты путем установки бита INT_CLKO[2] /T2CLKO.
16
P3.1/TXD/T2
P3.1
Порт ввода/вывода (GPIO).
TXD
Выход данных UART1.
T2
Внешний вход тактов для Timer/Counter 2.
17
P3.2/INT0
P3.2
Порт ввода/вывода (GPIO).
INT0
Внешнее прервание 0, которое может сработать как по нарастанию, так и по спаду уровня, что определяется настройкой бита IT0 (TCON.0).
18
P3.3/INT1
P3.3
Порт ввода/вывода (GPIO).
INT1
Внешнее прервание 1, которое может сработать как по нарастанию, так и по спаду уровня, что определяется настройкой бита IT1 (TCON.2). INT1 поддерживает функцию пробуждения из режима пониженного энергопотребления/выключения (power-down wake-up).
19
P3.4/T0/T1CLKO
P3.4
Порт ввода/вывода (GPIO).
T0
Внешний вход тактов для Timer/Counter 0.
T1CLKO
T1 Clock Output, выход тактов T1. Эта ножка может быть сконфигурирована для вывода тактовой частоты путем установки бита INT_CLKO[1] /T1CLKO.
20
P3.5/T1/T0CLKO
P3.5
Порт ввода/вывода (GPIO).
T1
Внешний вход тактов для Timer/Counter 1.
T0CLKO
T0 Clock Output, выход тактов T0. Эта ножка может быть сконфигурирована для вывода тактовой частоты путем установки бита INT_CLKO[0] /T0CLKO.
21
P3.6/~INT2/RXD_2
P3.6
Порт ввода/вывода (GPIO).
~INT2
Внешнее прерывание 2, которое может срабатывать только по спаду уровня (при переходе от лог. 1 к лог. 0). ~INT2 поддерживает функцию пробуждения из режима пониженного энергопотребления/выключения (power-down wake-up).
RXD_2
Вход данных UART1.
22
P3.7/~INT3/TXD_2
P3.7
Порт ввода/вывода (GPIO).
~INT3
Внешнее прерывание 2, которое может срабатывать только по спаду уровня (при переходе от лог. 1 к лог. 0). ~INT3 поддерживает функцию пробуждения из режима пониженного энергопотребления/выключения (power-down wake-up).
TXD_2
Выход данных UART1.
23
P2.0/RSTOUT_LOW
P2.0
Порт ввода/вывода (GPIO).
RSTOUT_LOW
Выход, который аппаратно генерирует лог. 0 после включения питания и во время сброса, и его можно программно установить в лог. 1.
24
P2.1/SCLK_2
P2.1
Порт ввода/вывода (GPIO).
SCLK_2
Сигнал тактов интерфейса SPI.
25
P2.2/MISO_2
P2.2
Порт ввода/вывода (GPIO).
MISO_2
Master Input Slave Output, сигнал данных интерфейса SPI.
26
P2.3/MOSI_2
P2.3
Порт ввода/вывода (GPIO).
MOSI_2
Master Output Slave Input, сигнал данных интерфейса SPI.
27
P2.4/SS_2
P2.4
Порт ввода/вывода (GPIO).
SS_2
Slave Selection, сигнал выборки подчиненного устройства интерфейса SPI.
28
P2.5
P2.5
Порт ввода/вывода (GPIO).
Таблица выбора микроконтроллеров из серии STC15W408AS (STC15W401AS, STC15W402AS, STC15W404AS, STC15W408AS, IAP15W413AS, IRC15W415AS):
Можно использовать компилятор Keil C или любой другой компилятор, рассчитанный на семейство MCS-51. Также можно использовать бесплатный инструментарий SDCC (см. папку compiler архива [3]). В опциях проекта следует выбрать ядро Intel 8052, и в качестве заголочного файла определения регистров нужно подключить хедер reg51.h (можете в качестве него использовать файл stc_diyclock-master\src\stc15.h из исходного кода архива [3]).
Программа может быть загружена с помощью порта UART через ножки GPIO P3.0 и P3.1. Для этого нужен простой переходничок USB-TTL который можно купить на aliexpress (прогуглите запрос stc-isp programmer site:aliexpress.com). Также можно купить специальный программатор STC-ISP40PIN, U8 или U8-mini (прогуглите STC-ISP40PIN site:aliexpress.com). Но можно ничего не покупать, для перепрошивки достаточно иметь любой переходик USB-TTL-UART. Итак, процесс перепрошивки по шагам.
1. Вбейте ключевые слова для поиска 6, откройте страничку загрузки на сайте STC, и выберите там последнюю версию утилиты программирования (я скачал stc-isp6.85.rar). На иероглифы не обращайте внимания. Распакуйте из-архива exe-файл, запустите.
2. Из выпадающего списка MCU Type выберите тип Вашего микроконтроллера. Этот список представляет собой дерево, в котором на верхнем уровне перечислены не сами типы микроконтроллеров, а их серии (разделы, список которых можно дополнительно развернуть). Например, чтобы выбрать микроконтроллер STC15W1K24S, нужно сначала в списке выбрать раздел STC15W1K16S Series, и уже в этом разделе выбрать микроконтроллер STC15W1K24S.
3. Подключите через USB Ваш переходничок USB-TTL-UART (я использовал дешевый USB-SERIAL CH340), выберите его по номеру COM-порта в выпадающем списке COM Port.
4. Отключите питание от платы, где установлен прошиваемый Вами микроконтроллер STC (микроконтроллер STC должен быть обесточен). Соедините провода GND, TXD и RXD переходничка соответственно с ножками GND, P3.0, P3.1 микроконтроллера.
5. Теперь проверьте, работает ли соединение с программируемым микроконтроллером, следующим образом: нажмите кнопку Check MCU, после чего подайте питание на программируемый микроконтроллер STC. В результате этой операции в консоль утилиты stc-isp будет выдано текст наподобие следующего (это пример проверки STC15W1K24S):
Current H/W Option:
. Current system clock source is internal IRC oscillator
. IRC frequency: 18.443MHz
. Wakeup Timer frequency: 36.727KHz
. Do not detect the level of P3.2 and P3.3 next download
. Power-on reset, use the extra power-on delay
. RESET pin behaves as I/O pin
. Reset while detect a Low-Voltage
. Thresh voltage level of the built-in LVD : 2.62 V
. Inhibit EEPROM operation under Low-Voltage
. CPU-Core supply level : 2.81 V
. Hardware do not enable Watch-Dog-Timer
. Watch-Dog-Timer pre-scalar : 256
. Watch-Dog-Timer stop count in idle mode
. Program can modify the Watch-Dog-Timer scalar
. Do not erase user EEPROM area at next download
. Do not control 485 at next download
. Do not check user password next download
. TXD is independent IO
. TXD pin as quasi-bidirectional mode after reset
. P2.0 output HIGH level after reset
. MCU type: STC15W1K24S
F/W version: 7.2.5T
Complete !(2017-03-11 15:53:59)
Если увидели этот текст, значит программирование работает, и Вы можете прошить в микроконтроллер свою программу. Если же нет, то где-то в подключении допустили ошибку, проверяйте все соединения.
Рекомендуется сначала запаивать короткие, невысокие компоненты - резисторы и конденсаторы. Если начнете с высоких компонентов, то в принципе ничего страшного, однако высокие компоненты будут слегка мешать запаивать низкие. Я сначала запаял резисторы, потом конденсаторы, потом транзисторы, потом коннекторы, потом панельки для микроконтроллера и микросхемы RTC, потом фоторезистор и терморезистор, потом кнопки и держатель батарейки. Само собой, 7-сегментные индикаторы следует запаивать последними, предварительно аккуратно промыв плату спиртом. Промывка нужна не только для эстетики, а чтобы тщательно визуально просмотреть качество монтажа. Также советую перед запайкой индикаторов прозвонить цепи питания на отсутствие коротких замыканий. После того, как запаяли индикаторы и еще раз смыли остатки флюса, можно установить в кроватки микроконтроллер и чип RTC.
Внимание: держатель батарейки советую запаивать только после того, как найдете подходящую батарейку на 3V, потому что возможно его придется немного приподнять над платой (в зависимости от толщины батарейки). Подойдут батарейки типов CR1216 (5034LC), CR1220 (5012LC) толщиной 1.6 и 2 мм соответственно и диаметром 12.5 мм (в комплекте батарейки нет). В крайнем случае можно поставить батарейку CR1025 (5033LC), но она толстовата (2.5 мм), так что держатель батарейки немного выгнется, если его не приподнять над платой при пайке.
Внимание: перед тем, как запаивать семисегментные индикаторы часов, установите и припаяйте все другие компоненты схемы, и тщательно проверьте монтаж. Понятно почему - индикаторы закрывают точки пайки, так что если допустили ошибку, то при смонтированных индикаторах трудно будет что-то исправить.
Внимание: индикаторы следует устанавливать с определенной ориентировкой в разных разрядах, см. картинку ниже.
Резисторы, конденсаторы и часовой кварц не имеют полярности, поэтому их установка проста. Но будьте внимательны с полярностью выводов, когда запаиваете транзисторы и бипер. При установке микросхем в кроватки будьте внимательны с ориентировкой корпусов микросхем.
Последней следует установить литиевую батарейку 3V. Без батарейки часы не могут хранить время и настройки при выключении питания.
Ниже в таблице приведен список деталей в том порядке, в каком их следует запаивать на плату.
Микросхема RTC (Real Time Clock, часы реального времени).
U2
STC15W404AS
Управляющий микроконтроллер.
BT1
Держатель для 3V литиевой батарейки.
DS1..DS4
Светодиодные 7-сегментные индикаторы.
В комплекте набора идет светофильтр, стенки пластикового корпуса и винты с гайками для его сборки. Для улучшения отображения наклейте на дисплей светофильтр. Поместите конструкцию в корпус.
[Настройка времени и основных функций]
После первого включения часы не идут, их необходимо сбросить длительным удержанием обоих кнопок управления в в течение 5 секунд. После этого часы покажут время 7:59. Через 5 секунд сброс завершится, время станет равным 8:00, на некоторое время запищит будильник. Дальше часы покажут текущую температуру в градусах Цельсия и текущую дату. Настроить время, будильник и работу часов можно в нижеуказанном порядке с помощью кнопок "F" ("функция", верхняя кнопка) и "+" (нижняя кнопка).
1. Установка часов. Для того, чтобы установить разряды часов, коротко нажмите на кнопку F. Цифры часов начнут мигать. Нажимайте кнопку + нужное количество раз для установки часов.
2. Установка минут. После установки часов снова коротко нажмите на кнопку F. Начнут мигать цифры минут. Точно так же, как устанавливали часы, установите кнопкой + количество минут. После завершения установки секунды установленной минуты будут отсчитываться от 0.
3. Установка часов будильника. Еще раз нажмите на кнопку F. Будут выведены и начнут мигать цифры часов настройки будильника, но точки в такт секундам при этом мигать не будут. Установите час будильника кнопкой +.
4. Установка минут будильника. Еще раз нажмите на кнопку F. Будут выведены и начнут мигать цифры минут настройки будильника, но точки в такт секундам при этом мигать не будут. Установите разряды минут будильника кнопкой +.
5. Проверка, активен ли будильник. Еще раз нажмите на кнопку F. Цифры на дисплее при этом не поменяются, но светящаяся точка в последнем разряде покажет активность будильника. Нажатия на кнопку + будут переключать работу будильника: если в последнем разряде точка горит, значит будильник активен и сработает в установленное время, а если не горит, то будильник отключен.
6. Настройка почасового бикания. Нажмите кнопку F, разряды часов начнут мигать. Нажимайте кнопку + для изменения начального времени будильника. Например, если установили на 9, то бикания начнутся с 9 часов. Снова нажмите на кнопку F, начнут мигать разряды минут. Кнопка + будет устанавливать время часов, когда ежечасное пищание прекращается. Например, если Вы установили начальное время 9, и конечное время 23, то часы будут бикать каждый час днем, и не будут беспокоить во время сна.
7. Проверка, активна ли функция почасового бикания. Еще раз нажмите на кнопку F. Цифры на дисплее при этом не поменяются, но светящаяся точка в разряде 3 (точка сверху) покажет активность этой функции. Нажатия на кнопку + будут циклически переключать работу функции: если точка в разряде 3 горит, то функция почасового бикания работает, а если не горит, то не работает.
8. Завершение настройки. Нажмите кнопку F последний раз, это завершит настройку часов.
[Подстройка показаний температуры и настройка даты]
1. Подстройка температуры. Нажмите кнопку +, часы покажут температуру. Нажимайте кнопку F для коррекции температуры, и для завершения коррекции температуры нажмите кнопку +.
2. Установка даты производится после подстройки температуры. Нажмите кнопку F, будут мигать цифры месяца, настраивайте их кнопкой +. Нажмите кнопку F еще раз, это подтвердит настройку месяца. После этого будут мигать цифры дней, настройте их кнопкой +. Нажатие кнопки F еще раз подтвердит настройку дней и переведет часы в настройку дня недели. Будет мигать цифра дня недели, кнопкой + её можно настроить. Нажмите кнопку F еще раз, чтобы подтвердить настройку недели, и нажмите кнопку + для завершения настройки.
[Работа часов]
45 секунд отображается текущее время, 5 секунд отображается температура, 5 секунд отображается дата, и еще 5 секунд отображается день недели. Далее по циклу процесс повторяется.
Ночью, когда освещение падает, яркость часов автоматически уменьшается.
Порт P1.4 может использоваться для управления реле (в зависимости от залитой прошивки).
Коннектор P1 может использоваться для подключения адаптера USB-UART с целью загрузки программного обеспечения. Назначение коннектора P3 мне неизвестно.
[Недостатки часов]
Китайцы постарались максимально удешевить конструкцию. По этой причине имеются недостатки, которые можно исправить либо корректировкой прошивки, либо с небольшой модификацией схемы.
1. При затемнении датчика освещенности (фоторезистор R16) яркость регулируется ступенчато, не плавно.
2. Немного удивило то, что по питанию стоит единственный фильтрующий конденсатор C1 емкостью 0.1 мкф. Это означает, что для питания можно применять стабилизированный источник питания, желательно с низкими пульсациями по питанию. В комплекте прилагается USB-кабель с джеком, которым можно подать питание на часы от компьютера или ноутбука.
3. В качестве датчика применяется терморезистор. Вместо терморезистора можно подключить датчик температуры типа DS18S20 или DS18B20 с интерфейсом 1-Wire, после этого коррекция измерения температуры не потребуется.
4. Нет возможности отключения будильника в определенные дни недели. Например, чтобы он не срабатывал в субботу и воскресенье.
[Исходный код (автор Jens Jensen, github.com/zerog2k/stc_diyclock)]
voidds_ram_config_init()
{
uint8_t i,j;
// проверка magic-байтов, чтобы определить, была ли ранее записана ramif ( (ds_readbyte( DS_CMD_RAM >>1|0x00) != MAGIC_LO
|| ds_readbyte( DS_CMD_RAM >>1|0x01) != MAGIC_HI) )
{
// если нет, то нужно инициализировать конфигурацию ram значениями// по умолчанию
ds_writebyte( DS_CMD_RAM >>1|0x00, MAGIC_LO);
ds_writebyte( DS_CMD_RAM >>1|0x01, MAGIC_HI);
// ОПТИМИЗАЦИЯ: генерировать ljmp в ds_ram_config_write
ds_ram_config_write();
return;
}
// чтение конфигурации ram// ОПТИМИЗАЦИЯ: условие завершения цикла !=4 даст код меньше, чем < 4 // ОПТИМИЗАЦИЯ: было cfg_table[i] = ds_readbyte(DS_CMD_RAM >> 1 | (i+2));// использование второй переменной вместо DS_CMD_RAM>>1 | (i+2)// дает код меньшего размера
j=DS_CMD_RAM>>1|2;
for (i=0; i!=4; i++)
cfg_table[i] = ds_readbyte(j++);
}
void_delay_ms(uint8_t ms)
{
// i,j выбраны для тактовой частоты fosc=11.0592 МГц с помощью осциллографа.// Инструментарий stc-isp дает неточные результаты (может быть, для C51 // в отличие sdcc?).// max 255 мсuint8_t i, j;
do
{
i =4;
j =240;
do
{
while (--j);
} while (--i);
} while (--ms);
}
// Глобальные переменные:
uint8_t count; // раньше было uint16, но 8 бит достаточно
uint16_t temp; // значение сенсора температуры
uint8_t lightval; // значение сенсора освещенности
volatileuint8_t displaycounter;
volatileuint8_t _100us_count;
volatileuint8_t _10ms_count;
uint8_t dmode = M_NORMAL; // состояние режима дисплея
uint8_t kmode = K_NORMAL; // состояние режима клавиатуры
void timer0_isr() __interrupt 1 __using 1
{
// Обработчик прервания (ISR) обновления дисплея.// За 1 проход обрабатывается одна цифра.uint8_t digit = displaycounter %4;
// Выключение всех цифр, установка уровней лог. 1.
P3 |=0x3C;
// Автоподстройка яркости: пропускается несколько тактовif (displaycounter % lightval <4 )
{
// заполнение цифр
P2 = dbuf[digit];
// включение выбранной цифры установкой лог. 0
P3 &=~(0x4<< digit);
}
displaycounter++;
// делитель: для получения интервалов 10 мсif (++_100us_count ==100)
{
_100us_count =0;
_10ms_count++;
// код для мигания двоеточия, 500 мсif (_10ms_count ==50)
{
display_colon =!display_colon;
_10ms_count =0;
}
// чтение кнопок с подавлением дребезга:// инкремент счетчика, если контакты замкнутыif ((debounce[0]) ==0x00)
{
// удержание как минимум на 8 тиков
S1_PRESSED =1;
switchcount[0]++;
}
else
{
// кнопка отпущена, или дребезг, сброс состояния
S1_PRESSED =0;
switchcount[0] =0;
}
if ((debounce[1]) ==0x00)
{
// удержание как минимум на 8 тиков
S2_PRESSED =1;
switchcount[1]++;
}
else
{
// кнопка отпущена, или дребезг, сброс состояния
S2_PRESSED =0;
switchcount[1] =0;
}
// код подавления дребезгаif (switchcount[0] > SW_CNTMAX)
{switchcount[0] = SW_CNTMAX; S1_LONG=1;}
if (switchcount[1] > SW_CNTMAX)
{switchcount[1] = SW_CNTMAX; S2_LONG=1;}
// чтение состояния кнопок в смещающееся 8-битное окно
debounce[0] = (debounce[0] <<1) | SW1;
debounce[1] = (debounce[1] <<1) | SW2;
}
}
//Интервал таймера 100 мкс на частоте 11.0592 МГц
void Timer0Init(void)
{
TL0 =0xA4;TH0 =0xFF; //Начальное значение таймера
TF0 =0; //Очистка флага TF0
TR0 =1; //Запуск в работу Timer0
ET0 =1; //Разрешение прерывания от Timer0
EA =1; //Глобальное разрешение прерываний
}
#define getkeypress(a) a##_PRESSED
int8_t gettemp(uint16_t raw) {
// Формула для преобразования значения АЦП, подключенного// к терморезистору ntc (Negative Temperature Coeff,// терморезистор с отрицательным коэффициентом)// в приблизительное значение градусов Цельсия:return76- raw *64/637;
}
/*********************************************/
int main()
{
// НАСТРОЙКА// установка выводов фоторезистора и терморезистора в режим выхода// с открытым коллектором:
P1M1 |= (1<<6) | (1<<7);
P1M0 |= (1<<6) | (1<<7);
// инициализация RTC (микросхема часов реального времени DS1302):
ds_init();
// инициализация/чтение конфигурации ram:
ds_ram_config_init();
// Раскомментируйте, чтобы сбросить минуты и часы в 0.// Использовалось для отладки, сейчас это не нужно.//ds_reset_clock();
Timer0Init(); // настройка таймера для обновления дисплея и чтения кнопок// ГЛАВНЫЙ ЦИКЛwhile(1)
{
RELAY =0;
_delay_ms(100);
RELAY =1;
// Часто запускаемый опрос АЦП:if ((count %4) ==0)
{
// автоподстройка яркости цифр путем деления диапазона АЦП на 8 шагов:
lightval = getADCResult8(ADC_LIGHT) >>3;
temp = gettemp(getADCResult(ADC_TEMP))
+ (cfg_table[CFG_TEMP_BYTE]&CFG_TEMP_MASK)
-4;
// установка нижнего порога подстройки яркости индикатора:if (lightval <4)
lightval =4;
}
ds_readburst(); // чтение RTC// Дерево принятия решений при опросе клавиатуры:switch (kmode)
{
case K_SET_HOUR:
flash_01 =!flash_01;
if (! flash_01)
{
if (getkeypress(S2)) ds_hours_incr();
if (getkeypress(S1)) kmode = K_SET_MINUTE;
}
break;
case K_SET_MINUTE:
flash_01 =0;
flash_23 =!flash_23;
if (! flash_23)
{
if (getkeypress(S2)) ds_minutes_incr();
if (getkeypress(S1)) kmode = K_SET_HOUR_12_24;
}
break;
case K_SET_HOUR_12_24:
dmode=M_SET_HOUR_12_24;
if (getkeypress(S2)) ds_hours_12_24_toggle();
if (getkeypress(S1)) kmode = K_NORMAL;
break;
case K_TEMP_DISP:
dmode=M_TEMP_DISP;
if (getkeypress(S1))
{
uint8_t offset=cfg_table[CFG_TEMP_BYTE]&CFG_TEMP_MASK;
offset++; offset&=CFG_TEMP_MASK;
cfg_table[CFG_TEMP_BYTE]=(cfg_table[CFG_TEMP_BYTE]&~CFG_TEMP_MASK)|offset;
}
if (getkeypress(S2)) kmode = K_DATE_DISP;
break;
case K_DATE_DISP:
dmode=M_DATE_DISP;
if (getkeypress(S1))
{
kmode=K_WAIT_S1;
lmode=CONF_SW_MMDD?K_SET_DAY:K_SET_MONTH;
smode=K_DATE_SWDISP;
}
if (getkeypress(S2)) kmode = K_WEEKDAY_DISP;
break;
case K_DATE_SWDISP:
CONF_SW_MMDD=!CONF_SW_MMDD;
kmode=K_DATE_DISP;
break;
case K_SET_MONTH:
flash_01 =!flash_01;
if (! flash_01)
{
if (getkeypress(S2))
{
ds_month_incr();
}
if (getkeypress(S1))
{
flash_01 =0; kmode = CONF_SW_MMDD?K_DATE_DISP:K_SET_DAY;
}
}
break;
case K_SET_DAY:
flash_23 =!flash_23;
if (! flash_23)
{
if (getkeypress(S2))
{
ds_day_incr();
}
if (getkeypress(S1))
{
flash_23 =0; kmode = CONF_SW_MMDD?K_SET_MONTH:K_DATE_DISP;
}
}
break;
case K_WEEKDAY_DISP:
dmode=M_WEEKDAY_DISP;
if (getkeypress(S1)) ds_weekday_incr();
if (getkeypress(S2)) kmode = K_NORMAL;
break;
case K_DEBUG:
dmode=M_DEBUG;
if (count>100) kmode = K_NORMAL;
if (S1_PRESSED||S2_PRESSED) count=0;
break;
case K_SEC_DISP:
dmode=M_SEC_DISP;
if (getkeypress(S1) || (count>100)) { kmode = K_NORMAL; }
if (getkeypress(S2)) { ds_sec_zero(); }
break;
case K_WAIT_S1:
count=0;
if (!S1_PRESSED)
{
if (S1_LONG) {S1_LONG=0; kmode=lmode;}
else {kmode=smode;}
}
break;
case K_WAIT_S2:
count=0;
if (!S2_PRESSED)
{
if (S2_LONG) {S2_LONG=0; kmode=lmode;}
else {kmode=smode;}
}
break;
case K_NORMAL:
default:
flash_01 =0;
flash_23 =0;
dmode=M_NORMAL;
if (S1_PRESSED)
{
kmode = K_WAIT_S1; lmode=K_SET_HOUR; smode=K_SEC_DISP;
}
//if (S2_PRESSED)//{// kmode = K_WAIT_S2; lmode=K_DEBUG;smode=K_TEMP_DISP;//}if (S2_PRESSED) { kmode = K_TEMP_DISP; }
};
// Выполнение дерева отображения:
clearTmpDisplay();
switch (dmode)
{
case M_NORMAL:
if (flash_01)
{
dotdisplay(1,display_colon);
}
else
{
if (!H12_24)
{
// десятки часов
filldisplay(0,
(rtc_table[DS_ADDR_HOUR]>>4)&(DS_MASK_HOUR24_TENS>>4),
0);
}
else
{
// десятки часов для случая включенного режима AMPM,// когда '1' только когда включено H12_THif (H12_TH)
filldisplay(0, 1, 0);
}
filldisplay(1,
rtc_table[DS_ADDR_HOUR]&DS_MASK_HOUR_UNITS,
display_colon);
}
if (flash_23)
{
// точка в разряде 3, если режим AMPM и PM=1
dotdisplay(2,display_colon);
dotdisplay(3,H12_24&H12_PM);
}
else
{
// десятки минут
filldisplay(2,
(rtc_table[DS_ADDR_MINUTES]>>4)&(DS_MASK_MINUTES_TENS>>4),
display_colon);
// минуты
filldisplay(3,
rtc_table[DS_ADDR_MINUTES]&DS_MASK_MINUTES_UNITS,
H12_24 & H12_PM);
}
break;
case M_SET_HOUR_12_24:
if (!H12_24)
{
filldisplay(1, 2, 0);
filldisplay(2, 4, 0);
}
else
{
filldisplay(1, 1, 0);
filldisplay( 2, 2, 0);
}
filldisplay(3, LED_h, 0);
break;
case M_SEC_DISP:
dotdisplay(0,display_colon);
dotdisplay(1,display_colon);
filldisplay(2,(rtc_table[DS_ADDR_SECONDS]>>4)&(DS_MASK_SECONDS_TENS>>4),0);
filldisplay(3,rtc_table[DS_ADDR_SECONDS]&DS_MASK_SECONDS_UNITS,0);
break;
case M_DATE_DISP:
if (flash_01)
{
dotdisplay(1,1);
}
else
{
if (!CONF_SW_MMDD)
{
// десятки месяца (операция &MASK_TENS бесполезна, поскольку// старшие биты читаются как '0')
filldisplay(0, rtc_table[DS_ADDR_MONTH]>>4, 0);
filldisplay(1, rtc_table[DS_ADDR_MONTH]&DS_MASK_MONTH_UNITS, 1);
}
else
{
// десятки месяца (операция &MASK_TENS бесполезна, поскольку// старшие биты читаются как '0')
filldisplay(2, rtc_table[DS_ADDR_MONTH]>>4, 0);
filldisplay( 3, rtc_table[DS_ADDR_MONTH]&DS_MASK_MONTH_UNITS, 0);
}
}
if (!flash_23)
{
if (!CONF_SW_MMDD)
{
// десятки дней (операция &MASK_TENS бесполезна)
filldisplay(2, rtc_table[DS_ADDR_DAY]>>4, 0);
// дни
filldisplay(3, rtc_table[DS_ADDR_DAY]&DS_MASK_DAY_UNITS, 0);
}
else
{
// десятки дней (операция &MASK_TENS бесполезна)
filldisplay( 0, rtc_table[DS_ADDR_DAY]>>4, 0);
// дни
filldisplay( 1, rtc_table[DS_ADDR_DAY]&DS_MASK_DAY_UNITS, 1);
}
}
break;
case M_WEEKDAY_DISP:
filldisplay(1, LED_DASH, 0);
// день недели (операция &MASK_UNITS бесполезна, потому что// старшие биты читаются как '0')
filldisplay(2, rtc_table[DS_ADDR_WEEKDAY], 0);
filldisplay(3, LED_DASH, 0);
break;
case M_TEMP_DISP:
filldisplay(0, ds_int2bcd_tens(temp), 0);
filldisplay(1, ds_int2bcd_ones(temp), 0);
filldisplay(2, CONF_C_F ? LED_f : LED_c, 1);
// -- температура определена как uint16, она не может быть < 0// if (temp < 0) filldisplay( 3, LED_DASH, 0);break;
case M_DEBUG:
filldisplay( 0, switchcount[0]>>4, S1_LONG);
filldisplay( 1, switchcount[0]&15, S1_PRESSED);
filldisplay( 2, switchcount[1]>>4, S2_LONG);
filldisplay( 3, switchcount[1]&15, S2_PRESSED);
break;
}
__critical { updateTmpDisplay(); }
// сохранение конфигурации ram
ds_ram_config_write();
if (S1_PRESSED || S2_PRESSED &&! (S1_LONG || S2_LONG))
{
// попытка ослабить чрезмерно длинное нажатие кнопок
_delay_ms(100);
}
// сброс при долгом нажатии кнопок, когда кнопка отпущенаif (! S1_PRESSED && S1_LONG)
{
S1_LONG =0;
}
if (! S2_PRESSED && S2_LONG)
{
S2_LONG =0;
}
count++;
WDT_CLEAR();
}
}
Как компилировать исходный код [2] под Windows, процесс по шагам:
1. Установите SDCC в папку, которую инсталлятор предлагает по умолчанию (C:\Program Files). Компилятор SDCC можно скачать из архива 170301stc15w404as-clock.zip по ссылке [3] из статьи "Цифровые часы на микроконтроллере STC15W404AS" (см. в архиве папку compiler, там 2 запускаемых инсталлятора, один для 32-битной Windows, другой для 64-битной Windows).
2. Распакуйте архив stc_diyclock-master.zip, он находится в папке srccode архива 170301stc15w404as-clock.zip (см. пункт 1), или можно скачать с сайта автора.
3. Перейдите в корневую папку распакованного проекта stc_diyclock-master (где находится файл Makefile), откройте интерпретатор командной строки cmd.exe, и выполните в этой папке 2 команды, одну за другой:
make clean
make
После успешного выполнения этих команд в корневой папке проекта окажется файл прошивки main.hex.
[UPD180317]
Внимание, исходный код по ссылке [3] использует не только память FLASH, но и EEPROM, поэтому прошивки просто кода main.hex недостаточно, нужно прошить еще и файл eeprom.hex. Если eeprom.hex не прошить, то цифры отображаться не будут, будут только мигать точки.
К сожалению, у меня не получилось получить файл eeprom.hex из-за непонятной проблемы с sed:
c:\temp\stc_diyclock-master>make eeprom
sed -ne '/:..1/ { s/1/0/2; p }' main.hex > eeprom.hex
sed: -e expression #2, char 21: Extra characters after command
Было лень разбираться, что тут неправильно в командной строке sed, поэтому я поступил проще: по ссылке [6] нашел готовый исходный код и готовую прошику, которая не использует EEPROM. Кстати, там же можно найти и готовый файл eeprom.hex.
Дополнительно прошивку, которая не использует EEPROM, я выложил в исправленной ссылке [5].
[Ссылки]
1. Compact 4-digit DIY Digital LED Clock Kit Light Control Temperature Date Time Display with Transparent Case site:aliexpress.com. 2. Geekcreit® DIY 4 Digit LED Electronic Clock Kit Temperature Light Control Version site:banggood.com. 3. 170301stc15w404as-clock.zip - документация, исходный код. 4. Цифровые часы на микроконтроллере STC15W1K24S. 5. 180301STC15W404AS-main-OK-no-need-EEPROM.hex - готовая прошивка, которая не использует EEPROM. 6. zerog2k/stc_diyclock site:github.com.
Нашел на Али часы на контроллере STC15F204EA. Нужен был для замены ИВЛ. Не посмотрел, что под него нет нормальной прошивки. На форуме radiokot нашел обсуждение (Zhuk72) и исходники (alex0732), всё прекрасно, но разводка другая. Те же компоненты, но назначены на другие порты. Компилятор Keil v3. Прочитал ваши статьи. Очень подробно, но в микроконтроллерах своя кухня и не совсем в теме. Если переназначить порты в библиотеке скажем с sbit P12=P1^2 на sbit P12=P1^4, а sbit P14=P1^4 на sbit P14=P1^2 будет ли это корректно?
Несколько лет занимаюсь STC-шками, но пока ни одного вируса в ПО не наблюдал. То, что некоторые антивирусники якобы "находят" троянов и т.д. и т.п. - это бывает. Но, как потом оказывается, всё это - ложная тревога. Лично у меня нет никаких претензий к ПО для STC (и не было).
В stc-isp6.85.rar сидит троян. На сайте производителя все подряд утилиты тоже с троянами. Детектируется Доктором Вэбом на раз.
microsin: пользуйтесь сервисом VirusTotal, ошибки и у антивирусов бывают.
Проверил. 15 из 72 антивирусов подтвердили трояна. Собственно и на сайте производителя данных чипов, где выложены всякие ехешники, такая же картина. Завирусовано всё напрочь.
Часы собрал, вроде все корректно припаял. Батарейка вставлена, внешнее питание подключено. Все светится и настраивается, но при этом часы "не идут". Если выдернуть внешнее питание, то часы "идут" (без отображения, конечно). Стоит подключить внешнее питание, отображают корректное время (которое успело "натикать" за время работы от батарейки), но время опять не идет... Есть идеи, куда копать?
microsin: 1. Проверьте тщательно монтаж микросхемы часов DS1302 и всех её компонентов и цепей (батарейка, кварц, и т. д.). 2. Если не помогло, поменяйте кварц. 3. Если не помогло, поменяйте микросхему DS1302.
Александр, все ваши хотелки из поста от 17.06.2020 16:17 точно есть в прошивке от zerog2k. Даже режим цикличного отображения температуры, даты, дня недели.
Это может зависеть от многих факторов. Но самый распространенный способ поправить ход часов, это замена кварца. Я взял кварц со старой материнской платы. Точность хода стала +2 сек в неделю.
microsin: если часы спешат, то можно увеличить точность, поставив между ножками кварца и землей конденсаторы порядка 5 - 20 пФ. Еще лучше - поставить подстроечные конденсаторы, и подбором емкости добиться максимальной точности хода. Еще лучше - применить другую микросхему часов, наподобие DS3231, для неё даже кварц не нужен. Подводить тогда часы придется раз в год или реже. Однако придется поправить немного код часов.
Комментарии
microsin: все должно нормально работать.
microsin: мой лицензионный антивирус Касперского почему-то не ругался. А вообще грустно это, не способствует популярности чипов STC.
Проверил. 15 из 72 антивирусов подтвердили трояна. Собственно и на сайте производителя данных чипов, где выложены всякие ехешники, такая же картина. Завирусовано всё напрочь.
microsin: пользуйтесь сервисом VirusTotal, ошибки и у антивирусов бывают.
microsin: проблема скорее всего в ошибке монтажа, замыканиях или непропаях.
microsin: 1. Проверьте тщательно монтаж микросхемы часов DS1302 и всех её компонентов и цепей (батарейка, кварц, и т. д.). 2. Если не помогло, поменяйте кварц. 3. Если не помогло, поменяйте микросхему DS1302.
microsin: если часы спешат, то можно увеличить точность, поставив между ножками кварца и землей конденсаторы порядка 5 - 20 пФ. Еще лучше - поставить подстроечные конденсаторы, и подбором емкости добиться максимальной точности хода. Еще лучше - применить другую микросхему часов, наподобие DS3231, для неё даже кварц не нужен. Подводить тогда часы придется раз в год или реже. Однако придется поправить немного код часов.
RSS лента комментариев этой записи