Применённая в ПБлоке библиотека функционально позволяет и первое и второе и кое-что другое (в общем 20 ф-й), а также нуждается в небольшой коррекции по требованию компилятора более поздних Arduino IDE. ПБлок LED&KEY (TM1638) и так выглядит слишком монструозным, потому пихать к имеющимся 8-ми ещё 16 булевых (байтовых) переменных для кнопок и 8-м для Bi-LED слишком расточительно для ресурсов МК, что является платой за графическое представление в FLProg и отсутствие переменной типа Word. Т.н. "костыли" - добавят ещё пару байт. Опишите более подробно необходимый Вам функционал и у Вас будет больше шансов после выходных получить желаемый тест ПБлока. Удачи!dizzyy писал(а): 13 июн 2018, 09:44в сети есть фото с двухцветными светодиодами или 16 кнопками , но на форуме нету таких блоков ..
может кто уже делал такое ...
TM1638 LED&KEY
TM1638 LED&KEY
TM1638 LED&KEY
а если поделить отдельно кнопки, светодиоды и сегменты (или как то светоды+сегменты)
хотел уйти от 1602 в сторону облегчения, а вижу что наоборот ..
вообще то этот блок изначально придумали для пивоваров , но ним же можно варить сусло под самогон для вискаря, можно организовать сушку солода , сушильные камеры ....
так как я использовал алгоритм Грачика , то многое боком вылазит...вот и хочу "спростить" .например - все задано в меню , и во время работы читается с еепром и чтоб изменить надо остановить , и в меню корректировать.. а мне будет проще разбить на платы , и после завершения платы переменной задать значение еепром один раз, тогда во время работы можно менять значение ..
интересует самый простой способ вывода светодиодов и опрос кнопок(аналог я так понял не самый лучший выбор)
TM1638 LED&KEY
Неужели булевые переменные 24-х кнопок, 16-и светодиодов и 8-и позиций десятичных/разделительных точек перестанут занимать 48 байт от этого? Хотя отчасти Вы правы, не всем всё это нужно, но кажется не в Вашем случае.
По теме.
Извините за длительное молчание, не был готов предметно говорить, и оказалась, что применяемая библиотека, ко всем warning-ам компилятора, ещё неправильно «общается» с ТМ1638. Если интересует этот вопрос,- обратите внимание на принудительные (IMHO) переключения состояния пинов Ардуино в High, при наличии подтяжек к Vcc сигнальных линий Data, Clock, Strobe, которые и предназначены для формирования этого уровня. К сожаленью не нашлось альтернативы и на github-е. Впрочем это касается всей линейки ТМ16хх, что у некоторых устройств (ТМ1628, ТМ1637, ТМ1651 и т.д. с эрзац-TWI/I2C) неизбежно приведёт к выгоранию вывода Ардуино и/или самого драйвера при удержании линии DIO в LOW (ACK или response ) подчинённым устройством. Вероятно виноваты Chinese GoogleTranslated Datasheets. К слову, предпочтительным считается втекание тока в МК, а не вытекание (см. нагрузочные ха-ки по документации).
dizzyy, ОК. Вообще-то я спрашивал об функционале «некоего устройства по отображению буквенно-числовой на 7-ми сегментном индикаторе, другой информации на одиночных светодиодах, а также сканирования кнопочной клавиатуры», которое Вы хотите создать на базе передней панели ТРМ251 применив мс ТМ1638 (или один из модулей на ТМ1638 ?). По приложеной Вами фотографии корпуса ТРМ251 я догадываюсь, что Вам нужно управлять 4-х разрядным 7-и сегментным индикатором, 19-ю ( ? ) одиночными светодиодами и 13-ю ( ? ) кнопками.
Указанная библиотека предназначена (см. описание) для промышленно выпускаемых модулей:
- LED&KEY- 8 одиночных светодиодов, клавиатура- «матрица» 1х8 кнопок (pin3 TM1638-K3), 8-разрядный 7-сегм. индикатор с общим катодом (СС);
- JY-LKM1638– 8 одиночных 2-полярных светодиодов с общим анодом (то-же, что 16- одноцветных), клавиатура- «матрица» 1х8 кнопок (pin3- TM1638_K3) 8-разрядный 7-сегм. индикатор с общим катодом (СС);
- QYF-TM1638- клавиатура- «матрица» 2х8 кнопок (pins1,2- TM1638_К1,K2- неуточн.инф.) 8-разрядный 7-сегм. индикатор с общим анодом (СА);
- ТМ1640- 16-разрядный 7-сегм. индикатор с общим катодом (СС).
[spoiler title= Так это выглядит] [/spoiler]
Наверное, ни одна из конфигураций полностью не удовлетворяет Ваших потребностей. Отсюда и вытекал мой вопрос. Тем не менее, если использовать возможности самого драйвера, заложенные производителем, то при дописании функций:
- setBinaryToLEDs(0bxxxxxxxx, positionToStart), вместо ненужных(?) для ваших задач 4-х старших разрядов из 8-и присутствующих, можно выводить состояние до 24-х одиночных светодиодов дополнительно к 16-ти имеющимся функции setLEDs(word led). Это если Вам не хватает (в чем сомневаюсь, потому не делал);
-get24Buttons()- поддержка "хитро" подключенных/кодированных 24 кнопок (готово).
Тест и новую библиотеку могу (при желании/актуальности и ответах на вопросы с пометкой-(?)) предоставить в личке (!- поддержку QYF-TM1638 пришлось пока отложить). Извините, в паблик больше тесты не выкладываю- безполезно.
Удачи!
У вас нет необходимых прав для просмотра вложений в этом сообщении.
TM1638 LED&KEY
Здравствуйте Ув.[ref]Dobwchin[/ref]!
Давайте попробуем разобраться с Вашими нюансами.
Что касается обсуждаемого блока- то в нём много лишнего для сторонних пользователей и ничего лишнего для меня на момент его создания- таковы были мои запросы тогда. Если есть достаточно навыков- "лишнее" лучше удалить из кода.
Давайте попробуем разобраться с Вашими нюансами.
Хорошим тоном при написании кода считается инициализация переменных при их объявлении. [spoiler= Откроем сгенерированный скетч проекта в Arduino IDE] Объявление переменных (входы/выходы) ПБ ТМ1638 происходит в секции Declare, их первая инициализация- в Loop и это происходит не по прихоти авторов пользовательских блоков. Если же выходы ПБлоков- являются физическими выходами МКонтроллера- то нужно озаботиться их начальной инициализацией, как писал выше, и/или в секции Setup безопасным значением для подключенного оборудования, т.е до первого цикла.[/spoiler]
Если они (выходы) не подключены, то кому/чему угрожают самые неожиданные значения на них?Dobwchin писал(а): 16 авг 2018, 05:51 как быть с логическими, выводами блока, если они в тексте программы не использованы
Разрешите маленький совет, (для несогласных не буду оспаривать,- просто проигнорируйте это пожалуйста) если не помните где читали, и в каких случаях применяется что-либо- забудьте. Это касалось входов неиспользуемых логических элементов в МС КМОП и ОУ для защиты от статики.Dobwchin писал(а): 16 авг 2018, 05:51где-то читал что неиспользуемые физические ноги нужно логически притягивать к земле
Что касается обсуждаемого блока- то в нём много лишнего для сторонних пользователей и ничего лишнего для меня на момент его создания- таковы были мои запросы тогда. Если есть достаточно навыков- "лишнее" лучше удалить из кода.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Последний раз редактировалось Labu559 27 сен 2019, 22:24, всего редактировалось 2 раза.
-
- Лейтенант
- Сообщения: 391
- Зарегистрирован: 09 апр 2016, 12:17
- Откуда: Кременчуг
- Имя: Сергей
TM1638 LED&KEY
Прошу помощи в создании блока для чтения состояния кнопок, подключенных к ТМ1638 (не модуль, а микросхема, позволяет считывать состояние 24 кнопок, причём при любом количестве одновременно нажатых). Мне нужен блок с тремя байтовыми переменными на выходе. Сейчас я могу сделать блок, используя 32-битную переменную состояния кнопок, но тогда внутри блока придётся раскладывать её на байты, в то же время я понимаю, что в самой библиотеке заложено побитовое считывание, зачем же грузить контроллер двойным преобразованием из uint8_t в uint32_t и обратно?
В приведённом скетче функция dwButtons = buttons.tick(); возвращает 32-битную переменную состояния кнопок. Мне же нужна конструкция типа
dwButton1 = ........();
dwButton2 = ........();
dwButton3 = ........();
Скетч примера:
[spoiler][/spoiler]
Ниже привожу содержимое библиотеки (а она состоит из 25 библиотек!) для тех, кто может помочь, но не хочет скачивать.
TM16xxButtons.cpp, здесь находится искомая tick
[spoiler][/spoiler]
TM16xx.cpp, здесь находится getButtons()
[spoiler][/spoiler]
Ну и TM1638.cpp, здесь ищем снова getButtons()
[spoiler][/spoiler]
Полная библиотека от Ricardo Batista для 1637, 1638, 1640 и т. д. с примерами и прочими плюшками.
[spoiler] [/spoiler]
В приведённом скетче функция dwButtons = buttons.tick(); возвращает 32-битную переменную состояния кнопок. Мне же нужна конструкция типа
dwButton1 = ........();
dwButton2 = ........();
dwButton3 = ........();
Скетч примера:
[spoiler]
Код: Выделить всё
#include <TM1638.h>
#include <TM16xxDisplay.h>
#include <TM16xxButtons.h>
uint32_t dwButtons;
TM1638 module(8, 9, 7); // DIO=8, CLK=9, STB=7
TM16xxButtons buttons(&module); // TM16xx button
TM16xxDisplay display(&module, 8); // TM16xx object, 8 digits
void setup()
{
Serial.begin(115200);
module.clearDisplay(); // clear display
module.setupDisplay(true, 1); // set intensity 0-7, 7=highest
delay(50);
module.setDisplayToString("o-HELLO-");
delay(900);
module.clearDisplay();
}
void loop()
{
dwButtons = buttons.tick();
display.setDisplayToHexNumber(dwButtons, 0, false);
Serial.print(F("Button "));
Serial.println(dwButtons, HEX);
}
Ниже привожу содержимое библиотеки (а она состоит из 25 библиотек!) для тех, кто может помочь, но не хочет скачивать.
TM16xxButtons.cpp, здесь находится искомая tick
[spoiler]
Код: Выделить всё
/*
TM16xxButtons.cpp - Buttons class for TM16xx.
The TM16xxButtons class supports the key-scanning features of TM16xx chips, such as TM1637 or TM1638.
It extends the getButtons() function of the base class and provides these features:
- setting callback functions
- multi-state keys (similar to OneButton): Press, LongPress, Click, Doubleclick
These are some TM16xx chips that support key-scanning:
TM1637 8 x 2 single DIO/CLK
TM1638 8 x 3 multi DIO/CLK/STB
TM1668 10 x 2 multi DIO/CLK/STB
Made by Maxint R&D. See https://github.com/maxint-rd/
Partially based on OneButton library by Matthias Hertel. See https://github.com/mathertel/OneButton
*/
//#define TM16XX_DEBUG 1
#include "TM16xxButtons.h"
// constructor
TM16xxButtons::TM16xxButtons(TM16xx *pTM16xx, byte nNumButtons) : _nNumButtons(nNumButtons), _pTM16xx(pTM16xx)
{
// TODO: reduce memory by using dynamic memory allocation instead of static arrays for button states
// requires additional constructor parameter to allow less than TM16XX_BUTTONS_MAXBUTTONS
//_pTM16xx=pTM16xx;
#if(TM16XX_OPT_BUTTONS_MALLOC)
_state=malloc(_nNumButtons*sizeof(byte));
_startTime=malloc(_nNumButtons*sizeof(unsigned long));
_stopTime=malloc(_nNumButtons*sizeof(unsigned long));
#endif
reset();
}
// explicitly set the number of millisec that have to pass by before a click is
// detected.
void TM16xxButtons::setClickTicks(int ticks)
{
_clickTicks = ticks;
} // setClickTicks
// explicitly set the number of millisec that have to pass by before a long
// button press is detected.
void TM16xxButtons::setLongPressTicks(int ticks)
{
_longPressTicks = ticks;
} // setLongPressTicks
#if(TM16XX_OPT_BUTTONS_EVENT)
// set function for release event
void TM16xxButtons::attachEventHandler(callbackTM16xxButtonsEvent newFunction)
{
_eventFunc = newFunction;
} // attachEventHandler
#else
void TM16xxButtons::attachRelease(callbackTM16xxButtons newFunction)
{
_releaseFunc = newFunction;
} // attachRelease
// set function for click event
void TM16xxButtons::attachClick(callbackTM16xxButtons newFunction)
{
_clickFunc = newFunction;
} // attachClick
// set function for doubleClick event
void TM16xxButtons::attachDoubleClick(callbackTM16xxButtons newFunction)
{
_doubleClickFunc = newFunction;
} // attachDoubleClick
// set function for longPressStart event
void TM16xxButtons::attachLongPressStart(callbackTM16xxButtons newFunction)
{
_longPressStartFunc = newFunction;
} // attachLongPressStart
// set function for longPressStop event
void TM16xxButtons::attachLongPressStop(callbackTM16xxButtons newFunction)
{
_longPressStopFunc = newFunction;
} // attachLongPressStop
// set function for during longPress event
void TM16xxButtons::attachDuringLongPress(callbackTM16xxButtons newFunction)
{
_duringLongPressFunc = newFunction;
} // attachDuringLongPress
#endif
// function to get the current long pressed state
bool TM16xxButtons::isPressed(byte nButton)
{
if(nButton>=_nNumButtons) return(false);
return(_state[nButton]==TM16XX_BUTTONS_STATE_PRESSED || _state[nButton]==TM16XX_BUTTONS_STATE_DBLPRESS || _state[nButton]==TM16XX_BUTTONS_STATE_LPRESS);
}
// function to get the current long pressed state
bool TM16xxButtons::isLongPressed(byte nButton)
{
if(nButton>=_nNumButtons) return(false);
return(_state[nButton]==TM16XX_BUTTONS_STATE_LPRESS);
}
int TM16xxButtons::getPressedTicks(byte nButton)
{
if(nButton>=_nNumButtons) return(0);
return((_stopTime[nButton] - _startTime[nButton])); // uint16_t subtraction may overflow, but is still fine 0x01 - 0xFC = 0x05
}
void TM16xxButtons::reset(void)
{
for(byte n=0; n<_nNumButtons; n++)
{
_state[n] = TM16XX_BUTTONS_STATE_START; // restart.
_startTime[n] = 0;
_stopTime[n] = 0;
}
}
/**
* @brief Check input of the configured pin and then advance the finite state
* machine (FSM).
*/
uint32_t TM16xxButtons::tick(void)
{ // update the state of each button and call callback functions as needed
uint32_t dwButtons=_pTM16xx->getButtons();
#ifdef TM16XX_DEBUG
Serial.print(F("TM16xxButtons: "));
Serial.print(dwButtons, HEX);
Serial.print(F(", state: "));
for(byte n=0; n<_nNumButtons; n++)
{
tick(n, (dwButtons&bit(n))>0); // MMOLE 181103: _BV only works on 16-bit values!
Serial.print(_state[n]);
}
Serial.print(F(" "));
#else
for(byte n=0; n<_nNumButtons; n++)
tick(n, dwButtons&bit(n)); // MMOLE 181103: _BV only works on 16-bit values!
#endif
return(dwButtons);
}
/**
* @brief Advance the finite state machine (FSM) using the given level.
*/
void TM16xxButtons::tick(byte nButton, bool activeLevel)
{
//unsigned long now = millis(); // current (relative) time in msecs.
uint16_t now = (uint16_t) millis(); // current (relative) time in msecs. To safe RAM we only use the bottom word (16 bits for instead of 32 for approx. 50 days)
// Implementation of the state machine
switch(_state[nButton])
{
case TM16XX_BUTTONS_STATE_START: // waiting for button being pressed.
if (activeLevel)
{
_state[nButton] = TM16XX_BUTTONS_STATE_PRESSED; // step to pressed state
_startTime[nButton] = now; // remember starting time
} // if
break;
case TM16XX_BUTTONS_STATE_PRESSED: // waiting for button being released.
if (!activeLevel)
{
_state[nButton] = TM16XX_BUTTONS_STATE_RELEASED; // step to released state
_stopTime[nButton] = now; // remember stopping time
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
_eventFunc(TM16XX_BUTTONS_EVENT_RELEASE, nButton);
#else
if (_releaseFunc)
_releaseFunc(nButton);
#endif
}
else if ((activeLevel) && ((unsigned long)(now - _startTime[nButton]) > _longPressTicks))
{
_state[nButton] = TM16XX_BUTTONS_STATE_LPRESS; // step to long press state
_stopTime[nButton] = now; // remember stopping time
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
{
_eventFunc(TM16XX_BUTTONS_EVENT_LONGPRESSSTART, nButton);
_eventFunc(TM16XX_BUTTONS_EVENT_LONGPRESSBUSY, nButton);
}
#else
if (_longPressStartFunc)
_longPressStartFunc(nButton);
if (_duringLongPressFunc)
_duringLongPressFunc(nButton);
#endif
} else {
// wait. Stay in this state.
} // if
break;
case TM16XX_BUTTONS_STATE_RELEASED: // waiting for button being pressed the second time or timeout.
#if(TM16XX_OPT_BUTTONS_EVENT)
if ((unsigned long)(now - _startTime[nButton]) > _clickTicks)
#else
if (_doubleClickFunc == NULL || (unsigned long)(now - _startTime[nButton]) > _clickTicks)
#endif
{
// this was only a single short click
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
_eventFunc(TM16XX_BUTTONS_EVENT_CLICK, nButton);
#else
if (_clickFunc)
_clickFunc(nButton);
#endif
_state[nButton] = TM16XX_BUTTONS_STATE_START; // restart.
}
else if ((activeLevel))
{
_state[nButton] = TM16XX_BUTTONS_STATE_DBLPRESS; // step to doubleclick state
_startTime[nButton] = now; // remember starting time
} // if
break;
case TM16XX_BUTTONS_STATE_DBLPRESS: // waiting for button being released finally.
if ((!activeLevel))
{
// this was a 2 click sequence.
_state[nButton] = TM16XX_BUTTONS_STATE_START; // restart.
_stopTime[nButton] = now; // remember stopping time
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
{
_eventFunc(TM16XX_BUTTONS_EVENT_RELEASE, nButton);
_eventFunc(TM16XX_BUTTONS_EVENT_DOUBLECLICK, nButton);
}
#else
if (_releaseFunc)
_releaseFunc(nButton);
if (_doubleClickFunc)
_doubleClickFunc(nButton);
#endif
} // if
break;
case TM16XX_BUTTONS_STATE_LPRESS: // waiting for button being release after long press.
if (!activeLevel)
{
_state[nButton] = TM16XX_BUTTONS_STATE_START; // restart.
_stopTime[nButton] = now; // remember stopping time
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
{
_eventFunc(TM16XX_BUTTONS_EVENT_RELEASE, nButton);
_eventFunc(TM16XX_BUTTONS_EVENT_LONGPRESSSTOP, nButton);
}
#else
if (_releaseFunc)
_releaseFunc(nButton);
if (_longPressStopFunc)
_longPressStopFunc(nButton);
#endif
}
else
{
// button is being long pressed
#if(TM16XX_OPT_BUTTONS_EVENT)
if (_eventFunc)
_eventFunc(TM16XX_BUTTONS_EVENT_LONGPRESSBUSY, nButton);
#else
if (_duringLongPressFunc)
_duringLongPressFunc(nButton);
#endif
} // if
break;
} // switch
} // TM16xxButtons.tick(nButton)
TM16xx.cpp, здесь находится getButtons()
[spoiler]
Код: Выделить всё
/*
TM16xx.h - Library for TM1637, TM1638 and similar chips.
Modified by Maxint R&D. See https://github.com/maxint-rd/
Copyright (C) 2011 Ricardo Batista (rjbatista <at> gmail <dot> com)
This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "TM16xx.h"
//#include "string.h"
TM16xx::TM16xx(byte dataPin, byte clockPin, byte strobePin, byte maxDisplays, byte digits, boolean activateDisplay, byte intensity)
{
this->dataPin = dataPin;
this->clockPin = clockPin;
this->strobePin = strobePin;
this->_maxDisplays = maxDisplays;
this->digits = digits;
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(strobePin, OUTPUT);
digitalWrite(strobePin, HIGH);
digitalWrite(clockPin, HIGH);
//sendCommand(TM16XX_CMD_DISPLAY | (activateDisplay ? 8 : 0) | min(7, intensity)); // display command: on or intensity
/*
sendCommand(TM16XX_CMD_DATA_AUTO); // data command: set data mode to auto-increment write mode
start();
send(TM16XX_CMD_ADDRESS); // address command + address C0H
for (int i = 0; i < 16; i++) { // TM1638 and TM1640 have 16 data addresses, TM1637 and TM1668 have less, but will wrap.
send(0x00);
}
stop();
*/
// Note: calling these methods should be done in constructor of derived class in order to use properly initialized members!
/*
clearDisplay();
setupDisplay(activateDisplay, intensity);
/**/
}
void TM16xx::setupDisplay(boolean active, byte intensity)
{
sendCommand(TM16XX_CMD_DISPLAY | (active ? 8 : 0) | min(7, intensity));
}
void TM16xx::clearDisplay()
{ // Clear all data registers. The number of registers depends on the chip.
// TM1638 (10x8): 10 segments per grid, stored in two bytes. The first byte contains the first 8 display segments, second byte has seg9+seg10 => 16 bytes
// TM1640 (8x16): one byte per grid => 16 bytes
// TM1637 (8x6): one byte per grid => 6 bytes
// TM1668 (10x7 - 14x3): two bytes per grid => 14 bytes
sendCommand(TM16XX_CMD_DATA_AUTO); // set auto increment addressing mode
// send the address followed by bulk-sending of the data to clear the display memory
start();
send(TM16XX_CMD_ADDRESS);
for (int i = 0; i < _maxDisplays; i++) {
send(0x00);
if(_maxSegments>8)
send(0x00); // send second byte (applicable to TM1638 and TM1668)
}
stop();
}
void TM16xx::setSegments(byte segments, byte position)
{ // set 8 leds on common grd as specified
// TODO: support 10-14 segments on chips like TM1638/TM1668
if(position<_maxDisplays)
sendData(position, segments);
//sendData(TM16XX_CMD_ADDRESS | position, segments);
}
void TM16xx::sendChar(byte pos, byte data, boolean dot)
{
/*
if(pos<_maxDisplays)
sendData(pos, data | (dot ? 0b10000000 : 0));
*/
setSegments(data | (dot ? 0b10000000 : 0), pos);
}
void TM16xx::setDisplayDigit(byte digit, byte pos, boolean dot, const byte numberFont[])
{
sendChar(pos, pgm_read_byte_near(numberFont + (digit & 0xF)), dot);
}
void TM16xx::setDisplayToDecNumber(int nNumber, byte bDots) // byte bDots=0
{ // Function to display a decimal number on a n-digit clock display.
// Kept simple to fit in ATtiny44A
// For extended display features use the TM16xxDisplay class
// TODO: support large displays such as 8segx16 on TM1640
for(byte nPos=1; nPos<=digits; nPos++)
{
setDisplayDigit(nNumber % 10, digits - nPos, bDots&_BV(nPos));
nNumber/=10;
}
}
void TM16xx::clearDisplayDigit(byte pos, boolean dot)
{
sendChar(pos, 0, dot);
}
void TM16xx::setDisplay(const byte values[], byte size)
{ // send an array of values to the display
for (byte i = 0; i < size; i++) {
sendChar(i, pgm_read_byte_near(values+i), 0);
}
}
void TM16xx::setDisplayToString(const char* string, const word dots, const byte pos, const byte font[])
{
for (int i = 0; i < digits - pos; i++) {
if (string[i] != '\0') {
sendChar(i + pos, pgm_read_byte_near(font+(string[i] - 32)), (dots & (1 << (digits - i - 1))) != 0);
} else {
break;
}
}
}
// key-scanning method, implemented in chip specific derived class
uint32_t TM16xx::getButtons()
{ // return state of up to 32 keys.
return(0);
}
//
// Protected methods
//
void TM16xx::bitDelay()
{ // if needed derived classes can add a delay (eg. for TM1637)
//delayMicroseconds(50);
}
void TM16xx::start()
{ // if needed derived classes can use different patterns to start a command (eg. for TM1637)
digitalWrite(strobePin, LOW);
bitDelay();
}
void TM16xx::stop()
{ // if needed derived classes can use different patterns to stop a command (eg. for TM1637)
digitalWrite(strobePin, HIGH);
bitDelay();
}
void TM16xx::send(byte data)
{
// MMOLE 180203: shiftout does something, but is not okay (tested on TM1668)
//shiftOut(dataPin, clockPin, LSBFIRST, data);
for (int i = 0; i < 8; i++) {
digitalWrite(clockPin, LOW);
bitDelay();
digitalWrite(dataPin, data & 1 ? HIGH : LOW);
bitDelay();
data >>= 1;
digitalWrite(clockPin, HIGH);
bitDelay();
}
bitDelay(); // NOTE: TM1638 specifies a Twait between bytes of minimal 1us.
}
void TM16xx::sendCommand(byte cmd)
{
start();
send(cmd);
stop();
}
void TM16xx::sendData(byte address, byte data)
{
sendCommand(TM16XX_CMD_DATA_FIXED); // use fixed addressing for data
start();
send(TM16XX_CMD_ADDRESS | address); // address command + address
send(data);
stop();
}
byte TM16xx::receive()
{
byte temp = 0;
// Pull-up on
pinMode(dataPin, INPUT);
digitalWrite(dataPin, HIGH);
for (int i = 0; i < 8; i++) {
temp >>= 1;
digitalWrite(clockPin, LOW);
bitDelay(); // NOTE: on TM1637 reading keys should be slower than 250Khz (see datasheet p3)
if (digitalRead(dataPin)) {
temp |= 0x80;
}
digitalWrite(clockPin, HIGH);
bitDelay();
}
// Pull-up off
pinMode(dataPin, OUTPUT);
digitalWrite(dataPin, LOW);
return temp;
}
Ну и TM1638.cpp, здесь ищем снова getButtons()
[spoiler]
Код: Выделить всё
/*
TM1638.cpp - Library implementation for TM1638.
Copyright (C) 2011 Ricardo Batista (rjbatista <at> gmail <dot> com)
Rewrite for TM16xx library by Maxint R&D. See https://github.com/maxint-rd/
This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "TM1638.h"
TM1638::TM1638(byte dataPin, byte clockPin, byte strobePin, byte numDigits, boolean activateDisplay, byte intensity)
: TM16xx(dataPin, clockPin, strobePin, TM1638_MAX_POS, numDigits, activateDisplay, intensity)
{
_maxSegments=10; // on the LED & KEY modules the extra segments are used to drive individual red or red/green LEDs
clearDisplay();
setupDisplay(activateDisplay, intensity);
}
void TM1638::setSegments(byte segments, byte position)
{ // set 8 leds on common grd as specified
// TODO: support 10-14 segments on chips like TM1638/TM1668
// TM1638 uses 10 segments in two bytes, similar to TM1668
// for the digit displays only the first byte (containing seg1-seg8) is sent
// Only the LSB (SEG1-8) is sent to the display
if(position<_maxDisplays)
sendData(position << 1, segments);
}
void TM1638::setSegments16(uint16_t segments, byte position)
{ // method to send more than 8 segments (10 max for TM1638)
// TM1638 uses 10 segments in two bytes, similar to TM1668
// segments 0-7 are in bits 0-7 of position bytes 0,2,4,6,8,10,12,14
// segments 8-9 are in bits 0-1 of position bytes 1,3,5,7,9,11,13,15
if(position<_maxDisplays)
{
sendData(position << 1, (byte)segments&0xFF);
sendData((position << 1) | 1, (byte)(segments>>8)&0x03);
}
}
void TM1638::setLED(byte color, byte pos)
{ // TM1638 uses 10 segments in two bytes, for the LEDs only the second byte (containing seg9-seg10) is send
sendData((pos << 1) + 1, color);
}
void TM1638::setLEDs(word leds)
{
for (int i = 0; i < digits; i++) {
byte color = 0;
if ((leds & (1 << i)) != 0) {
color |= TM1638_COLOR_RED;
}
if ((leds & (1 << (i + 8))) != 0) {
color |= TM1638_COLOR_GREEN;
}
setLED(color, i);
}
}
uint32_t TM1638::getButtons(void)
{
// TM1638 returns 4 bytes/8 nibbles for keyscan. Each byte has K3, K2 and K1 status in lower bits of each nibble for KS1-KS8
// NOTE: K1/K2 are implemented for this class, but the TM1638 LED&KEY module only uses K3.
// Also note that the buttons are wired in odd sequence: S1=KS1, S5=KS2, S2=KS3, S6=KS4, S3=KS5, S7=KS6, S4=KS7, S8=KS8
byte keys_K1 = 0;
byte keys_K2 = 0;
byte keys_K3 = 0;
start();
send(TM16XX_CMD_DATA_READ); // B01000010 Read the key scan data
for (int i = 0; i < 4; i++)
{
byte rec = receive();
keys_K1 |= ((rec&_BV(2))>>2 | (rec&_BV(6))>>5) << (2*i); // bits 2 and 6 for K1/KS1 and K1/KS2
keys_K2 |= ((rec&_BV(1))>>1 | (rec&_BV(5))>>4) << (2*i); // bits 1 and 5 for K2/KS1 and K2/KS2
keys_K3 |= ((rec&_BV(0)) | (rec&_BV(4))>>3) << (2*i); // bits 0 and 4 for K3/KS1 and K3/KS2
}
stop();
return((uint32_t)keys_K3<<16 | (uint32_t)keys_K2<<8 | (uint32_t)keys_K1);
}
Полная библиотека от Ricardo Batista для 1637, 1638, 1640 и т. д. с примерами и прочими плюшками.
[spoiler] [/spoiler]
У вас нет необходимых прав для просмотра вложений в этом сообщении.
TM1638 LED&KEY
Может на биты? или я не так понялseri0shka писал(а): 25 сен 2019, 22:05 32-битную переменную состояния кнопок, но тогда внутри блока придётся раскладывать её на байты
раскладывание и преобразование числа это для МК ,грубо говоря, несколько тактов.
dwButton1 = dwButton & 1 ;seri0shka писал(а): 25 сен 2019, 22:05 Мне же нужна конструкция типа
dwButton1 = ........();
dwButton2 = ........();
dwButton2 = dwButton & 1<<1 ;
dwButton3 = dwButton & 1<<2 ;
dwButton4 = dwButton & 1<<3 ;
и так далее.
- Sancho
- Полковник
- Сообщения: 4066
- Зарегистрирован: 25 дек 2015, 17:32
- Откуда: Ярославль.
- Имя: Александр
- Поблагодарили: 5 раз
- Контактная информация:
TM1638 LED&KEY
[ref]seri0shka[/ref], В данном случае я согласен с Алексеем - получение байта - несколько тактов, при этом бибка вообще не меняется. И может обновляться, скачиваться из первоисточника другим пользователем.
Вы же никаких новых плюшек не добавите.
Пример:
dwButton1= byte_button((buttons.tick()), 0); // 0,1,2 - байт который хотим получить
// сама функция
byte byte_button(uint32_t a, uint8_t b)
{
byte с = a>>(8*b) & 0xFF;
return c;
}
Как-то так...
Отправлено спустя 4 минуты 2 секунды:
версия 2
dwButton1=(buttons.tick()) & 0xFF;
dwButton2=(buttons.tick())>>8 & 0xFF;
dwButton3=(buttons.tick())>>16 & 0xFF;
Вы же никаких новых плюшек не добавите.
Пример:
dwButton1= byte_button((buttons.tick()), 0); // 0,1,2 - байт который хотим получить
// сама функция
byte byte_button(uint32_t a, uint8_t b)
{
byte с = a>>(8*b) & 0xFF;
return c;
}
Как-то так...
Отправлено спустя 4 минуты 2 секунды:
версия 2
dwButton1=(buttons.tick()) & 0xFF;
dwButton2=(buttons.tick())>>8 & 0xFF;
dwButton3=(buttons.tick())>>16 & 0xFF;
мой ник в нете и почте omelchuk890, если что. запомните на всякий. многие знают номер тлф.
-
- Лейтенант
- Сообщения: 391
- Зарегистрирован: 09 апр 2016, 12:17
- Откуда: Кременчуг
- Имя: Сергей
TM1638 LED&KEY
[ref=#ff8000]Sancho[/ref], спасибо, попробую. И всё же, кто меня ткнёт носом, в каком месте в библиотеках "первичная" функция считывания? В функции отображения я смог найти, что искал, в результате сэкономил сотню-две байт, для меня имеет значение, так как в основном пользуюсь Атмега8. При этом переделывать саму библиотеку не пришлось.
[ref=#ff8000]pan[/ref], мне таки байты нужны. В конечном итоге мне нужен блок с байтами на входах для управления светодиодами, и с байтами на выходах от кнопок и тумблеров. И ничего лишнего. Развитие этой темы: Матрица кнопок и светодиодов
[ref=#ff8000]pan[/ref], мне таки байты нужны. В конечном итоге мне нужен блок с байтами на входах для управления светодиодами, и с байтами на выходах от кнопок и тумблеров. И ничего лишнего. Развитие этой темы: Матрица кнопок и светодиодов
TM1638 LED&KEY
Уважаемый [ref]seri0shka[/ref], функция в С возвращает (ссылка return) единственную переменную (без манипуляций со ссылками и указателями). То есть [spoiler title=получить отдельных три байта состояния 3 групп по 8 кнопок]Для того чтобы считать состояние кнопок нужно отослать микросхеме соответствующую key reading Command- 0b01000010(см. таблицу 5.1 Setting of Data Command стр.3). В ответ Вы получите четыре байта key data (диаграмма [3] Timing for key reading, стр.10). При этом в каждом байте будут незначащими каждый 3-й и 7-й биты (см. таблицу Figure (4) стр.7). При чем в первом байте 0-й бит(первый) это состояние кнопки на выводах МС SEG1/KS1 и K3, второй бит – кнопка на SEG1/KS1 и K2, третий бит - SEG1/KS1 и K1 и т.д. Т.о. Вы можете за раз считать всё 32-х битное число в котором только 24 бита несут полезную информацию или прервать считывание после 1 байта, 2-го или 3-го досрочным дёрганьем ножки Strobe в High. Смотрим приложенный Datasheet[/spoiler] Вы можете только получением из функции 32-х битного значения, извлечением каждого кратного 4-ке незначащего бита, таким образом получить 24-х битное и разбить его на 3 байта состояния кнопок, что Вам правильно подсказали ув.[ref=#ff8000]Sancho[/ref], [ref=#ff8000]pan[/ref]. Извините, при всём уважении к с.Батиста разбирался не с его очередной библиотекой, а с [spoiler title=документацией от производителя,] [/spoiler]и написал свою библиотеку, чего и всем желаю. [spoiler title= функция считывания состояния 24-х кнопок у меня выглядит так]seri0shka писал(а): 26 сен 2019, 19:19 И всё же, кто меня ткнёт носом, в каком месте в библиотеках "первичная" функция считывания
#define DIO_HIGH pinMode(dataPin, INPUT) // External pullup
#define DIO_LOW pinMode(dataPin, OUTPUT)
#define DIO_READ digitalRead(dataPin)
#define DIO_WRITE digitalWrite(dataPin,LOW)
#define CLK_HIGH pinMode(clockPin, INPUT) // External pullup
#define CLK_LOW pinMode(clockPin, OUTPUT)
#define CLK_WRITE digitalWrite(clockPin,LOW)
#define STB_HIGH pinMode(strobePin, INPUT) // External pullup
#define STB_LOW pinMode(strobePin, OUTPUT)
unsigned long TM16XX::getButtons_24(void)
{
unsigned long keys_24 = 0;
STB_LOW;
send(0x42);
keys_24 = fullReceive();
STB_HIGH;
return keys_24;
}
// Вспомогательные функции
void TM16XX::send(byte data)
{
for (byte i = 0; i < 8; i++) {
CLK_LOW;
digitalWrite(dataPin, data & 1 ? HIGH : LOW);
data >>= 1;
CLK_HIGH;
}
}
unsigned long TM16XX::fullReceive()
// For matrix keyboard 3x8 buttons on K1, K2, K3 pins of IC TM1638 connected
{
unsigned long temp = 0;
DIO_HIGH;
for (byte i = 0; i < 31; i++)
{
CLK_LOW;
if((i&0b1)&&(i&0b10)) //3,7,11,15,19,23,27 bits excluded
{
CLK_HIGH;
continue;
}
else
{
temp <<= 1;
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
CLK_HIGH;
}
}
DIO_LOW;
return temp;
Дальше разбивайте результат из getButtons_24() как Вам подсказали выше.
unsigned long read24keys= getButtons_24();
byte keys1_8= (read24keys)&0xFF;
byte keys9_16= (read24keys>>8)&0xFF;
byte keys17_24= (read24keys>>16)&0xFF;
[/spoiler ]
Удачи!
У вас нет необходимых прав для просмотра вложений в этом сообщении.
-
- Лейтенант
- Сообщения: 391
- Зарегистрирован: 09 апр 2016, 12:17
- Откуда: Кременчуг
- Имя: Сергей
TM1638 LED&KEY
[ref]Labu559[/ref], спасибо за столь подробное и доходчивое объяснение. Попробовал сделать тестовый скетч на основе Вашей библиотеки. Выводит нули вместо кодов кнопок. Посмотрите, что я делаю не так?
[spoiler][/spoiler]
[spoiler]
Код: Выделить всё
#define dataPin 8
#define clockPin 9
#define strobePin 7
#define DIO_HIGH pinMode(dataPin, INPUT)
#define DIO_LOW pinMode(dataPin, OUTPUT)
#define DIO_READ digitalRead(dataPin)
#define DIO_WRITE digitalWrite(dataPin,LOW)
#define CLK_HIGH pinMode(clockPin, INPUT)
#define CLK_LOW pinMode(clockPin, OUTPUT)
#define CLK_WRITE digitalWrite(clockPin,LOW)
#define STB_HIGH pinMode(strobePin, INPUT)
#define STB_LOW pinMode(strobePin, OUTPUT)
void setup()
{
Serial.begin(115200);
delay(50);
}
void loop()
{
unsigned long read24keys = getButtons_24();
byte keys1_8 = (read24keys) & 0xFF;
byte keys9_16 = (read24keys >> 8) & 0xFF;
byte keys17_24 = (read24keys >> 16) & 0xFF;
Serial.print(F("Button "));
Serial.print(keys1_8, HEX); // здесь получаю 0
Serial.print(F("-- "));
Serial.print(keys9_16, HEX); // и здесь
Serial.print(F("-- "));
Serial.println(keys17_24, HEX); // эдесь тоже 0, с библой от Батиста всё выводит нормально
}
unsigned long getButtons_24(void)
{
unsigned long keys_24 = 0;
STB_LOW;
send(0x42);
keys_24 = fullReceive();
STB_HIGH;
delay(5);
return keys_24;
}
// Вспомогательные функции
void send(byte data)
{
for (byte i = 0; i < 8; i++) {
CLK_LOW;
digitalWrite(dataPin, data & 1 ? HIGH : LOW);
data >>= 1;
CLK_HIGH;
}
}
unsigned long fullReceive()
// For matrix keyboard 3x8 buttons on K1, K2, K3 pins of IC TM1638 connected
{
unsigned long temp = 0;
DIO_HIGH;
for (byte i = 0; i < 31; i++)
{
CLK_LOW;
if ((i & 0b1) && (i & 0b10)) //3,7,11,15,19,23,27 bits excluded
{
CLK_HIGH;
continue;
}
else
{
temp <<= 1;
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
CLK_HIGH;
}
}
DIO_LOW;
return temp;
}
- Sancho
- Полковник
- Сообщения: 4066
- Зарегистрирован: 25 дек 2015, 17:32
- Откуда: Ярославль.
- Имя: Александр
- Поблагодарили: 5 раз
- Контактная информация:
TM1638 LED&KEY
Вторая строчка лишняя, на мой взгляд. Там и так 0.
Но это не относится к ответу - почему не работает.
мой ник в нете и почте omelchuk890, если что. запомните на всякий. многие знают номер тлф.
TM1638 LED&KEY
Я подразумевал, что нужно вставить функции в библиотеку Батисты, ведь Вам нужно ещё выводить текст, состояние 2х8 (16-ти) светодиодов, и...
... и сделаете инициализацию- добавите строки :
#include <TM1638.h>
byte Bright = 1;//Яркость дисплея
TM1638 module(8, 9, 7, true, Bright);
Дайте немного времени на подготовку теста, следите за сообщениями в личном разделе.
[spoiler] [/spoiler]
Александр, конечно ты прав, в этом случае это локальная переменная. В свете программы (если глобальная переменная) - это универсальный вариант.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
- Sancho
- Полковник
- Сообщения: 4066
- Зарегистрирован: 25 дек 2015, 17:32
- Откуда: Ярославль.
- Имя: Александр
- Поблагодарили: 5 раз
- Контактная информация:
TM1638 LED&KEY
Labu559 писал(а): 29 сен 2019, 08:13 это локальная переменная. В свете программы (если глобальная переменная) - это универсальный вариант.
После сдвига влево в этом месте 0.seri0shka писал(а): 27 сен 2019, 22:59 temp <<= 1;
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
Заново его устанавливать - зачем?
мой ник в нете и почте omelchuk890, если что. запомните на всякий. многие знают номер тлф.
-
- Лейтенант
- Сообщения: 391
- Зарегистрирован: 09 апр 2016, 12:17
- Откуда: Кременчуг
- Имя: Сергей
TM1638 LED&KEY
Всё оказалось просто, хотя на поиски я потратил больше 6 часов.

Вдвойне обидно, что я ведь уже встречался с точно такой же проблемой при использовании блока для 1617 от [ref]Labu559[/ref]. Так что сам виноват.

[ref]Labu559[/ref] делал блоки и библиотеки для модулей на 1637 и 1638, а в модулях уже установлены резисторы подтяжки. Я же использовал голые микросхемы, и подключал без резисторов. В библиотеках Батисты задействована внутренняя подтяжка контроллера, поэтому с его библиотекой у меня всё работало сразу.
Так что нужно или ставить резисторы, или править библиотеку. Скетч из поста 91 рабочий при подключенных резисторах. Учитесь на моих ошибках.

Компилятор с вами согласен, при удалении этой строчки не меняется ни результат, ни размер использованной памяти.Sancho писал(а): 28 сен 2019, 15:06 if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
Вторая строчка лишняя, на мой взгляд. Там и так 0.
TM1638 LED&KEY
Ув.[ref]seri0shka[/ref]! Приятно общаться с людьми, которым чужд потребительский подход, пытаются разобраться и помочь другим "не наступать на те же грабли". Спасибо Вам! Позвольте кое-что дополнить:
Этого можно было избежать. Ну что же, прийдётся повториться и указать где описал уже особенности работы с ТМ16хх.
...резисторы подтяжки, которые по протоколу I2C/TWI должны формировать высокий уровень на линиях, когда МК отпускает эти линии. Во всех остальных блоках здесь на форуме, скетчах и библиотеках TM1637 на github (за исключением на С++ от автора avishorp и на С от dhog1) делается это принудительным переключением выводов МК в HIGH. Другими словами подтяжка Clock (CLK) и Data (DIO) резисторами к Vcc, при таких делах, вообще становится лишней. См. описание протокола I2C/TWI и анализируем что будет с выходом МК или ведомого устройства в свете выдержки из описания протокола: "Генерация синхросигнала (ACK) - это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Сигнал синхронизации может быть изменен только если он “вытягивается” медленным ведомым устройством (путем удержания линии в низком состоянии)...". А если в этот момент МК переключается принудительно в HIGH? Чей вывод сгорит первым от КЗ?[/spoiler] и настоятельно рекомендую начав с этого все сообщения ув. dhog1 до конца обсуждения. [spoiler title=цитирование] - на "подтянутых" линиях (которые соединены с питанием через подтягивающие резисторы) используют две операции: освободить линию (перейти в высокоимпедансное состояние, т.е. отключиться от линии, и тогда резисторы подтянут ее в состояние логической единицы), и прижать линию к земле, установив на ней логический ноль. Что-либо писать в подтянутую линию (устанавливая бит порта в "1") смысла не имеет...
На линиях "с подтяжкой к питанию" (pullup) используют операции:
- освободить линию (перейти в высокоимпедансное состояние, т.е. отключиться от линии), что приводит к установлению на линии логической единицы (работают подтягивающие к питанию резисторы). Это означает перевод пина МК в состояние (input, low), т.е. DDR(PIN) -> 0, PORT(PIN) -> 0...
- Включив внутреннюю подтяжку (DDRx->0, PORTx->1), вы определяете "1" на линии. Если "с другой стороны" прижмут линию к земле, от вас потечет ток, чего "другая сторона" может не ожидать. (Pxn will source current if ext. pulled low. из даташита).
- прижать линию к земле (установить на линии логический ноль). Это означает перевод пина МК в состояние (output, low), т.е DDR(PIN) -> 1, PORT(PIN) -> 0
Линии данных и синхроимпульсов для TM163x подтягиваются внешними резисторами, их нормальное состояние "1". Именно они (резисторы) вытягивают линии к "1", когда вы со своей стороны перестаете их прижимать к земле ("0"). Состояние линии данных после сгенерированного восходящего фронта синхроимпульса считывается через соответствующий пин регистра PINx.
- ...при считывании байта командой scan_key выдать ACK прийдется...[/spoiler]
external pull-up resistor should be provided to connect 1K-10K. The Company recommends a
10K pull up resistor. At falling edge of the clock, DIO controls the operation of NMOS, at which point, the
reading is unstable until rising edge of the clock.[/spoiler] или схемах которыя я публиковал выше.
такой фокус (вместо подтягивающих резисторов используется источник тока) проходит безболезненно, то с TM1637 (I2C или 2-Wire) будет пшик при задержке ACK
Желаю всем удачи и большего внимания при чтении описаний!
Этого можно было избежать. Ну что же, прийдётся повториться и указать где описал уже особенности работы с ТМ16хх.
Нет, в этом загвоздка, Батиста не использует подтяжку, он просто переключает интерфейсные ноги МК в состояние LOW/HIGH (см. функции его библиотеки TM16xx.cpp- TM16xx::start(); void TM16xx::stop(); void TM16xx::send(byte data) и др.). А после прочитайте пж.второй абзац сообщения №83, это сообщение №21 [spoiler title= выборка]...обратите внимание на принудительные (IMHO) переключения состояния пинов Ардуино в High, при наличии подтяжек к Vcc сигнальных линий Data, Clock, Strobe, которые и предназначены для формирования этого уровня. К сожаленью не нашлось альтернативы и на github-е. Впрочем это касается всей линейки ТМ16хх, что у некоторых устройств (ТМ1636, ТМ1637, ТМ1640, ТМ1650, ТМ1651 и т.д. с эрзац-TWI/I2C) неизбежно приведёт к выгоранию вывода Ардуино и/или самого драйвера при удержании линии DIO в LOW (ACK, ACKnowledge буквально из английского- "подтверждаю получение") подчинённым устройством...(редакт. при потере данных),seri0shka писал(а): 01 окт 2019, 18:34 В библиотеках Батисты задействована внутренняя подтяжка контроллера
...резисторы подтяжки, которые по протоколу I2C/TWI должны формировать высокий уровень на линиях, когда МК отпускает эти линии. Во всех остальных блоках здесь на форуме, скетчах и библиотеках TM1637 на github (за исключением на С++ от автора avishorp и на С от dhog1) делается это принудительным переключением выводов МК в HIGH. Другими словами подтяжка Clock (CLK) и Data (DIO) резисторами к Vcc, при таких делах, вообще становится лишней. См. описание протокола I2C/TWI и анализируем что будет с выходом МК или ведомого устройства в свете выдержки из описания протокола: "Генерация синхросигнала (ACK) - это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Сигнал синхронизации может быть изменен только если он “вытягивается” медленным ведомым устройством (путем удержания линии в низком состоянии)...". А если в этот момент МК переключается принудительно в HIGH? Чей вывод сгорит первым от КЗ?[/spoiler] и настоятельно рекомендую начав с этого все сообщения ув. dhog1 до конца обсуждения. [spoiler title=цитирование] - на "подтянутых" линиях (которые соединены с питанием через подтягивающие резисторы) используют две операции: освободить линию (перейти в высокоимпедансное состояние, т.е. отключиться от линии, и тогда резисторы подтянут ее в состояние логической единицы), и прижать линию к земле, установив на ней логический ноль. Что-либо писать в подтянутую линию (устанавливая бит порта в "1") смысла не имеет...
На линиях "с подтяжкой к питанию" (pullup) используют операции:
- освободить линию (перейти в высокоимпедансное состояние, т.е. отключиться от линии), что приводит к установлению на линии логической единицы (работают подтягивающие к питанию резисторы). Это означает перевод пина МК в состояние (input, low), т.е. DDR(PIN) -> 0, PORT(PIN) -> 0...
- Включив внутреннюю подтяжку (DDRx->0, PORTx->1), вы определяете "1" на линии. Если "с другой стороны" прижмут линию к земле, от вас потечет ток, чего "другая сторона" может не ожидать. (Pxn will source current if ext. pulled low. из даташита).
- прижать линию к земле (установить на линии логический ноль). Это означает перевод пина МК в состояние (output, low), т.е DDR(PIN) -> 1, PORT(PIN) -> 0
Линии данных и синхроимпульсов для TM163x подтягиваются внешними резисторами, их нормальное состояние "1". Именно они (резисторы) вытягивают линии к "1", когда вы со своей стороны перестаете их прижимать к земле ("0"). Состояние линии данных после сгенерированного восходящего фронта синхроимпульса считывается через соответствующий пин регистра PINx.
- ...при считывании байта командой scan_key выдать ACK прийдется...[/spoiler]
- это указано в даташите без альтернативы (без "или") [spoiler title=последний абзац стр.2]▲ Note: When DIO outputs data, it is an NMOS open drain output. To read the keypad, an
external pull-up resistor should be provided to connect 1K-10K. The Company recommends a
10K pull up resistor. At falling edge of the clock, DIO controls the operation of NMOS, at which point, the
reading is unstable until rising edge of the clock.[/spoiler] или схемах которыя я публиковал выше.
- Да, увы, сеньйор Батиста заблуждается уже много лет. Но если с ТМ1638 и др. MC (SPI или 3-Wire протокол)
такой фокус (вместо подтягивающих резисторов используется источник тока) проходит безболезненно, то с TM1637 (I2C или 2-Wire) будет пшик при задержке ACK
Желаю всем удачи и большего внимания при чтении описаний!

Последний раз редактировалось Labu559 03 окт 2019, 23:40, всего редактировалось 1 раз.
-
- Лейтенант
- Сообщения: 391
- Зарегистрирован: 09 апр 2016, 12:17
- Откуда: Кременчуг
- Имя: Сергей
TM1638 LED&KEY
Спасибо за столько полезных ссылок (добавляйте номер поста, при переходе по ссылкам страница сдвигается в произвольном направлении). Более-менее переварил информацию, почти понятно.
Одно не пойму: как можно сделать пшик, если не устанавливать на ноге контроллера высокий уровень при низкоимпедансном состоянии? Если всё же установить, то внешние подтягивающие резисторы никак не спасут от выгорания. Я считаю, что стоит присмотреться в сторону применения внутренней подтяжки вместо внешней, хотя номинал внутренних резисторов в 2 раза превышает максимально рекомендуемый даташитом. Для того, чтоб не сжечь ТМ1637, 1638, можно на время экспериментов поставить последовательно (между ногой МК и ТМ...) резистор на 100...200 ом, он не помешает работе в нормальном режиме, но спасёт ТМ... в случае неправильно написанной библиотеки.
Отправлено спустя 8 часов 2 минуты 39 секунд:
В результате поисков наткнулся на вариант использования тм1668 без библиотек: http://arduino.ru/forum/proekty/korpus- ... -proektakh Попробовал с ТМ1638, сходу заработало.
После обработки получил то, что мне нужно (пост 376), осталось преобразовать это дело в блок пользователя, что у меня проблемы не составляет.
Пробный скетч, на основе которого буду делать блок (посмотрите, может будут замечания):
Зачем так намудрено в функции setBrightness (установка яркости)? Можно проще?
Одно не пойму: как можно сделать пшик, если не устанавливать на ноге контроллера высокий уровень при низкоимпедансном состоянии? Если всё же установить, то внешние подтягивающие резисторы никак не спасут от выгорания. Я считаю, что стоит присмотреться в сторону применения внутренней подтяжки вместо внешней, хотя номинал внутренних резисторов в 2 раза превышает максимально рекомендуемый даташитом. Для того, чтоб не сжечь ТМ1637, 1638, можно на время экспериментов поставить последовательно (между ногой МК и ТМ...) резистор на 100...200 ом, он не помешает работе в нормальном режиме, но спасёт ТМ... в случае неправильно написанной библиотеки.
Отправлено спустя 8 часов 2 минуты 39 секунд:
В результате поисков наткнулся на вариант использования тм1668 без библиотек: http://arduino.ru/forum/proekty/korpus- ... -proektakh Попробовал с ТМ1638, сходу заработало.
После обработки получил то, что мне нужно (пост 376), осталось преобразовать это дело в блок пользователя, что у меня проблемы не составляет.
Пробный скетч, на основе которого буду делать блок (посмотрите, может будут замечания):
Код: Выделить всё
#define PIN_DIO 8
#define PIN_CLK 9
#define PIN_STB 10
///////////// ТИПА "библиотека" ДЛЯ TM1668 ////////////
#define LED_DATA_LENGTH 16 // достаточно 16 байтов на светодиоды и 2 на кнопки
// Глобальные переменные
static uint16_t ledGRID[LED_DATA_LENGTH / 2]; // текущее состояние экрана
static uint16_t saveGRID[LED_DATA_LENGTH / 2]; // нужно для сохранения состояния экрана на время теста
static uint8_t currentBrightness = 1; // текущая яркость
// Запись одиночной команды в TM1668
void writeSingleCommand(const uint8_t command) {
digitalWrite(PIN_STB, LOW);
shiftOut(PIN_DIO, PIN_CLK, LSBFIRST, command);
digitalWrite(PIN_STB, HIGH);
delayMicroseconds(1); // Пауза до следующей команды
}
// Запись состояния дисплея в TM1668
void updateDisplay(void) {
writeSingleCommand(0x40); // запись данных, автоматический адрес
digitalWrite(PIN_STB, LOW);
shiftOut(PIN_DIO, PIN_CLK, LSBFIRST, 0xC0); // Установка адреса в 0
uint8_t * p = (uint8_t *) ledGRID;
for (int8_t i = 0; i < LED_DATA_LENGTH; i++, p++) shiftOut(PIN_DIO, PIN_CLK, LSBFIRST, *p); // запись данных
digitalWrite(PIN_STB, HIGH);
delayMicroseconds(1); // Пауза до следующей команды
}
// Чтение состояния кнопок с TM1668
uint32_t getButtons_24(void)
{
uint32_t keys_24 = 0;
digitalWrite(PIN_STB, LOW);//STB_LOW;
shiftOut(PIN_DIO, PIN_CLK, LSBFIRST, 0x42); // чтение данных //send(0x42);
pinMode(PIN_DIO, INPUT_PULLUP);//DIO_HIGH;
delayMicroseconds(1);
for (byte i = 0; i < 31; i++)
{
digitalWrite(PIN_CLK, LOW);//CLK_LOW;
keys_24 <<= 1;
if (digitalRead(PIN_DIO)) bitSet(keys_24, 0);
//else bitClear(keys_24, 0);
digitalWrite(PIN_CLK, HIGH);//CLK_HIGH;
}
pinMode(PIN_DIO, OUTPUT);//DIO_LOW;
digitalWrite(PIN_STB, HIGH);//STB_HIGH;
return keys_24;
}
// Установить яркость от 0 (выключено) до 8
// (возвращает старую яркость)
static inline uint8_t setBrightness(const uint8_t newBrighness) {
const uint8_t res = currentBrightness;
currentBrightness = (newBrighness > 8) ? 8 : newBrighness;
if (currentBrightness == 0) writeSingleCommand(0x80); // Выключить дисплей
else writeSingleCommand(0x88 + (currentBrightness - 1)); // Установить яркость
return res;
}
// Зажечь произвольные символы
void matrix(byte leds_0, byte leds_1, byte leds_2, byte leds_3, byte leds_4, byte leds_5, byte leds_6, byte leds_7, byte Brightness)
{
memcpy(saveGRID, ledGRID, sizeof(saveGRID));
ledGRID[0] = leds_0;
ledGRID[1] = leds_1;
ledGRID[2] = leds_2;
ledGRID[3] = leds_3;
ledGRID[4] = leds_4;
ledGRID[5] = leds_5;
ledGRID[6] = leds_6;
ledGRID[7] = leds_7;
setBrightness(Brightness);
updateDisplay();
}
void setup(void) {
Serial.begin(115200);
// Инициализация пинов
pinMode(PIN_CLK, OUTPUT);
pinMode(PIN_DIO, OUTPUT);
pinMode(PIN_STB, OUTPUT);
digitalWrite(PIN_STB, HIGH);
digitalWrite(PIN_CLK, HIGH);
// Инициализация экрана
writeSingleCommand(0x03); // Режим отображения (1 и 2 - ничего не меняется)
}
void loop(void) {
matrix(1, 127, 4, 8, 16, 33, 64, 128, 7);
delay(50);
// Читаем состояние кнопок
// и отрабатываем команды
uint32_t read24keys = getButtons_24();
byte keys1 = (read24keys) & 0xFF;
byte keys2 = (read24keys >> 8) & 0xFF;
byte keys3 = (read24keys >> 16) & 0xFF;
byte keys4 = (read24keys >> 24) & 0xFF;
Serial.print(F("Button "));
Serial.print(keys1);
Serial.print(F("-- "));
Serial.print(keys2);
Serial.print(F("-- "));
Serial.print(keys3);
Serial.print(F("-- "));
Serial.println(keys4);
}
TM1638 LED&KEY
А что там сложного? Даже для меня, не знающего С, там всё просто. Можно оставить две строчки, если вы уверены, что newBrighness будет в пределах от 0 до 8 и вам не нужно возвращать старую яркость.seri0shka писал(а): 02 окт 2019, 23:50Зачем так намудрено в функции setBrightness (установка яркости)? Можно проще?
TM1638 LED&KEY
Поправил, добавил, сделал выборки и цитирования в 96-м сообщении.
Внешние подтягивающие резисторы ничего не спасают, они формируют высокий уровень на линии, когда МК отключается (Hi-Z) от этой линии и позволяют безопасно прижимать линию к земле, как мастеру, так и слейвам без КЗ.seri0shka писал(а): 02 окт 2019, 23:50 как можно сделать пшик, если не устанавливать на ноге контроллера высокий уровень при низкоимпедансном состоянии? Если всё же установить, то внешние подтягивающие резисторы никак не спасут от выгорания.
А я не ставлю под сомнение рекоммендации производителя. Для слабо помехоустойчивых интерфейсных линий зачастую 4,7кОм слишком много. Высокоомная внутренняя подтяжка (50-60кОм) не позволит работать шине (RC-контур) на высоких скоростях (частота тактирования драйвера до 450кГц) .seri0shka писал(а): 02 окт 2019, 23:50 Я считаю, что стоит присмотреться в сторону применения внутренней подтяжки вместо внешней
прочитайте пж. ещё раз новую редакцию сообщения №96, не отвлекаясь на ссылки. Если не поможет- не берите в голову, для Вашей текущей задачи-ТМ1638 не особо актуально (я описал общий принцип, рекоммендованный производителем. В Ардуино почти всё "работает" как бы как).
Автор сделал перезапись уровня яркости только при его изменении по сравнению с предыдущим значением, а не в каждом цикле


Последний раз редактировалось Labu559 13 май 2021, 07:59, всего редактировалось 3 раза.
TM1638 LED&KEY
Можете показать в каких строчках это реализовано?Labu559 писал(а): 04 окт 2019, 00:16Автор сделал перезапись уровня яркости только при его изменении по сравнению с предыдущим значением, а не в каждом цикле.
TM1638 LED&KEY
Не могу, я ошибся, это в моей библиотеке так реализовано. Исправил сообщение (убрали кнопку зачёркнутого текста?

Вообще то нужно смотреть на весь код первоисточника, а не на избранные куски. В комплексе там есть ф-и увеличения и уменьшения яркости на 1 кнопками.

По Батисте можно так:
Код: Выделить всё
void loop() {
if (currentBrightness != newBrightness){
currentBrightness = newBrightness ;
setBright(currentBrightness);}
}
void TM16xx::setBright(byte newBrightness)
{
byte intensity = 0x80; // display OFF mode, 0x88- ON mode
if (newBrightness) intensity += (newBrightness + 7);
// или то же с защитой от превышения диапазона (отсекаем 4,5,6 биты)
// if (newBrightness) intensity += ((newBrightness&0xF)+ 7);
send(intensity);
// ф-я от Батисты
void TM16XX::send(byte data)
{
for (byte i = 0; i < 8; i++) {
CLK_LOW;
digitalWrite(dataPin, data & 1 ? HIGH : LOW);
data >>= 1;
CLK_HIGH;
}
}
Последний раз редактировалось Labu559 13 май 2021, 08:07, всего редактировалось 4 раза.
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя