TM1638 LED&KEY

Использование дисплеев и обсуждение пользовательских блоков к ним
Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#81

Сообщение Labu559 » 13.06.2018{, 12:06}

dizzyy писал(а):
13.06.2018{, 09:44}
в сети есть фото с двухцветными светодиодами или 16 кнопками , но на форуме нету таких блоков ..
может кто уже делал такое ...
Применённая в ПБлоке библиотека функционально позволяет и первое и второе и кое-что другое (в общем 20 ф-й), а также нуждается в небольшой коррекции по требованию компилятора более поздних Arduino IDE. ПБлок LED&KEY (TM1638) и так выглядит слишком монструозным, потому пихать к имеющимся 8-ми ещё 16 булевых (байтовых) переменных для кнопок и 8-м для Bi-LED слишком расточительно для ресурсов МК, что является платой за графическое представление в FLProg и отсутствие переменной типа Word. Т.н. "костыли" - добавят ещё пару байт. Опишите более подробно необходимый Вам функционал и у Вас будет больше шансов после выходных получить желаемый тест ПБлока. Удачи!

Аватара пользователя
dizzyy
Капитан
Сообщения: 752
Зарегистрирован: 24.11.2017{, 16:25}
Репутация: 37
Откуда: Червоноград
Имя: Марьян

TM1638 LED&KEY

#82

Сообщение dizzyy » 13.06.2018{, 12:46}

Labu559 писал(а):
13.06.2018{, 12:06}
выглядит слишком монструозным
а если поделить отдельно кнопки, светодиоды и сегменты (или как то светоды+сегменты)

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

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#83

Сообщение Labu559 » 22.07.2018{, 00:22}

dizzyy писал(а):
13.06.2018{, 12:46}
а если поделить отдельно кнопки, светодиоды и сегменты
Неужели булевые переменные 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-сегм. индикатор с общим катодом (СС).
Так это выглядитПоказать
Modules_TM1638.jpg
Наверное, ни одна из конфигураций полностью не удовлетворяет Ваших потребностей. Отсюда и вытекал мой вопрос. Тем не менее, если использовать возможности самого драйвера, заложенные производителем, то при дописании функций:
- setBinaryToLEDs(0bxxxxxxxx, positionToStart), вместо ненужных(?) для ваших задач 4-х старших разрядов из 8-и присутствующих, можно выводить состояние до 24-х одиночных светодиодов дополнительно к 16-ти имеющимся функции setLEDs(word led). Это если Вам не хватает (в чем сомневаюсь, потому не делал);
-get24Buttons()- поддержка "хитро" подключенных/кодированных 24 кнопок (готово).
Тест и новую библиотеку могу (при желании/актуальности и ответах на вопросы с пометкой-(?)) предоставить в личке (!- поддержку QYF-TM1638 пришлось пока отложить). Извините, в паблик больше тесты не выкладываю- безполезно.
Удачи!

Dobwchin
Рядовой
Сообщения: 2
Зарегистрирован: 07.08.2018{, 10:20}
Репутация: 0
Откуда: Екатеринбург
Имя: Иван

TM1638 LED&KEY

#84

Сообщение Dobwchin » 16.08.2018{, 05:51}

Доброго времени суток! Остаются два ньюанса. Первый неиспользуемые "ноги" блока tm1638. Думаю вопрос больше к автору блока. Уважаемые, нужно ли ставить на них переменные типа false? где-то читал что неиспользуемые физические ноги нужно логически притягивать к земле. А как быть с логическими, выводами блока, если они в тексте программы не использованы?
Использую модуль Led&Key (на первом скриншоте вашего сообщения выше)
СпойлерПоказать
Изображение

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#85

Сообщение Labu559 » 27.08.2018{, 00:41}

Здравствуйте Ув.Dobwchin!
Давайте попробуем разобраться с Вашими нюансами.
Dobwchin писал(а):
16.08.2018{, 05:51}
нужно ли ставить на них переменные типа false
Хорошим тоном при написании кода считается инициализация переменных при их объявлении.
Откроем сгенерированный скетч проекта в Arduino IDEПоказать
Init.png
Объявление переменных (входы/выходы) ПБ ТМ1638 происходит в секции Declare, их первая инициализация- в Loop и это происходит не по прихоти авторов пользовательских блоков. Если же выходы ПБлоков- являются физическими выходами МКонтроллера- то нужно озаботиться их начальной инициализацией, как писал выше, и/или в секции Setup безопасным значением для подключенного оборудования, т.е до первого цикла.
Dobwchin писал(а):
16.08.2018{, 05:51}
как быть с логическими, выводами блока, если они в тексте программы не использованы
Если они (выходы) не подключены, то кому/чему угрожают самые неожиданные значения на них?
Dobwchin писал(а):
16.08.2018{, 05:51}
где-то читал что неиспользуемые физические ноги нужно логически притягивать к земле
Разрешите маленький совет, (для несогласных не буду оспаривать,- просто проигнорируйте это пожалуйста) если не помните где читали, и в каких случаях применяется что-либо- забудьте. Это касалось входов неиспользуемых логических элементов в МС КМОП и ОУ для защиты от статики.
Что касается обсуждаемого блока- то в нём много лишнего для сторонних пользователей и ничего лишнего для меня на момент его создания- таковы были мои запросы тогда. Если есть достаточно навыков- "лишнее" лучше удалить из кода.
Последний раз редактировалось Labu559 27.09.2019{, 22:24}, всего редактировалось 2 раза.

seri0shka
Лейтенант
Сообщения: 391
Зарегистрирован: 09.04.2016{, 12:17}
Репутация: 22
Откуда: Кременчуг
Имя: Сергей

TM1638 LED&KEY

#86

Сообщение seri0shka » 25.09.2019{, 22:05}

Прошу помощи в создании блока для чтения состояния кнопок, подключенных к ТМ1638 (не модуль, а микросхема, позволяет считывать состояние 24 кнопок, причём при любом количестве одновременно нажатых). Мне нужен блок с тремя байтовыми переменными на выходе. Сейчас я могу сделать блок, используя 32-битную переменную состояния кнопок, но тогда внутри блока придётся раскладывать её на байты, в то же время я понимаю, что в самой библиотеке заложено побитовое считывание, зачем же грузить контроллер двойным преобразованием из uint8_t в uint32_t и обратно?
В приведённом скетче функция dwButtons = buttons.tick(); возвращает 32-битную переменную состояния кнопок. Мне же нужна конструкция типа
dwButton1 = ........();
dwButton2 = ........();
dwButton3 = ........();

Скетч примера:
СпойлерПоказать

Код: Выделить всё

#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
СпойлерПоказать

Код: Выделить всё

/*
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()
СпойлерПоказать

Код: Выделить всё

/*
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()
СпойлерПоказать

Код: Выделить всё

/*
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 и т. д. с примерами и прочими плюшками.
СпойлерПоказать
TM16xx-master.rar
(3.39 МБ) 85 скачиваний

pan
Полковник
Сообщения: 2860
Зарегистрирован: 13.04.2017{, 11:57}
Репутация: 204
Имя: noname

TM1638 LED&KEY

#87

Сообщение pan » 26.09.2019{, 08:28}

seri0shka писал(а):
25.09.2019{, 22:05}
32-битную переменную состояния кнопок, но тогда внутри блока придётся раскладывать её на байты
Может на биты? или я не так понял
seri0shka писал(а):
25.09.2019{, 22:05}
зачем же грузить контроллер двойным преобразованием
раскладывание и преобразование числа это для МК ,грубо говоря, несколько тактов.
seri0shka писал(а):
25.09.2019{, 22:05}
Мне же нужна конструкция типа
dwButton1 = ........();
dwButton2 = ........();
dwButton1 = dwButton & 1 ;
dwButton2 = dwButton & 1<<1 ;
dwButton3 = dwButton & 1<<2 ;
dwButton4 = dwButton & 1<<3 ;

и так далее.

Аватара пользователя
Sancho
Полковник
Сообщения: 4066
Зарегистрирован: 25.12.2015{, 17:32}
Репутация: 590
Откуда: Ярославль.
Имя: Александр
Контактная информация:

TM1638 LED&KEY

#88

Сообщение Sancho » 26.09.2019{, 08:57}

seri0shka, В данном случае я согласен с Алексеем - получение байта - несколько тактов, при этом бибка вообще не меняется. И может обновляться, скачиваться из первоисточника другим пользователем.
Вы же никаких новых плюшек не добавите.
Пример:
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, если что. запомните на всякий. многие знают номер тлф.

seri0shka
Лейтенант
Сообщения: 391
Зарегистрирован: 09.04.2016{, 12:17}
Репутация: 22
Откуда: Кременчуг
Имя: Сергей

TM1638 LED&KEY

#89

Сообщение seri0shka » 26.09.2019{, 19:19}

Sancho, спасибо, попробую. И всё же, кто меня ткнёт носом, в каком месте в библиотеках "первичная" функция считывания? В функции отображения я смог найти, что искал, в результате сэкономил сотню-две байт, для меня имеет значение, так как в основном пользуюсь Атмега8. При этом переделывать саму библиотеку не пришлось.
pan, мне таки байты нужны. В конечном итоге мне нужен блок с байтами на входах для управления светодиодами, и с байтами на выходах от кнопок и тумблеров. И ничего лишнего. Развитие этой темы: Матрица кнопок и светодиодов

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#90

Сообщение Labu559 » 27.09.2019{, 17:29}

seri0shka писал(а):
26.09.2019{, 19:19}
И всё же, кто меня ткнёт носом, в каком месте в библиотеках "первичная" функция считывания
Уважаемый seri0shka, функция в С возвращает (ссылка return) единственную переменную (без манипуляций со ссылками и указателями). То есть
получить отдельных три байта состояния 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
Вы можете только получением из функции 32-х битного значения, извлечением каждого кратного 4-ке незначащего бита, таким образом получить 24-х битное и разбить его на 3 байта состояния кнопок, что Вам правильно подсказали ув.Sancho, pan. Извините, при всём уважении к с.Батиста разбирался не с его очередной библиотекой, а с
документацией от производителя,Показать
TM1638_v1.3(EN).pdf
(1.59 МБ) 72 скачивания
и написал свою библиотеку, чего и всем желаю.
функция считывания состояния 24-х кнопок у меня выглядит такПоказать

#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 ]
Удачи!

seri0shka
Лейтенант
Сообщения: 391
Зарегистрирован: 09.04.2016{, 12:17}
Репутация: 22
Откуда: Кременчуг
Имя: Сергей

TM1638 LED&KEY

#91

Сообщение seri0shka » 27.09.2019{, 22:59}

Labu559, спасибо за столь подробное и доходчивое объяснение. Попробовал сделать тестовый скетч на основе Вашей библиотеки. Выводит нули вместо кодов кнопок. Посмотрите, что я делаю не так?
СпойлерПоказать

Код: Выделить всё

#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.12.2015{, 17:32}
Репутация: 590
Откуда: Ярославль.
Имя: Александр
Контактная информация:

TM1638 LED&KEY

#92

Сообщение Sancho » 28.09.2019{, 15:06}

seri0shka писал(а):
27.09.2019{, 22:59}
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
Вторая строчка лишняя, на мой взгляд. Там и так 0.
Но это не относится к ответу - почему не работает.
мой ник в нете и почте omelchuk890, если что. запомните на всякий. многие знают номер тлф.

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#93

Сообщение Labu559 » 29.09.2019{, 08:13}

seri0shka писал(а):
27.09.2019{, 22:59}
тестовый скетч на основе Вашей библиотеки
Я подразумевал, что нужно вставить функции в библиотеку Батисты, ведь Вам нужно ещё выводить текст, состояние 2х8 (16-ти) светодиодов, и...
seri0shka писал(а):
27.09.2019{, 22:59}
Посмотрите, что я делаю не так?
... и сделаете инициализацию- добавите строки :
#include <TM1638.h>
byte Bright = 1;//Яркость дисплея
TM1638 module(8, 9, 7, true, Bright);
Дайте немного времени на подготовку теста, следите за сообщениями в личном разделе.
СпойлерПоказать
serioshkaTM1638.png
Test24keys_.flp.jpg
Sancho писал(а):
28.09.2019{, 15:06}
Вторая строчка лишняя, на мой взгляд.
Александр, конечно ты прав, в этом случае это локальная переменная. В свете программы (если глобальная переменная) - это универсальный вариант.

Аватара пользователя
Sancho
Полковник
Сообщения: 4066
Зарегистрирован: 25.12.2015{, 17:32}
Репутация: 590
Откуда: Ярославль.
Имя: Александр
Контактная информация:

TM1638 LED&KEY

#94

Сообщение Sancho » 30.09.2019{, 09:59}

Labu559 писал(а):
29.09.2019{, 08:13}
это локальная переменная. В свете программы (если глобальная переменная) - это универсальный вариант.
seri0shka писал(а):
27.09.2019{, 22:59}
temp <<= 1;
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);
После сдвига влево в этом месте 0.
Заново его устанавливать - зачем?
мой ник в нете и почте omelchuk890, если что. запомните на всякий. многие знают номер тлф.

seri0shka
Лейтенант
Сообщения: 391
Зарегистрирован: 09.04.2016{, 12:17}
Репутация: 22
Откуда: Кременчуг
Имя: Сергей

TM1638 LED&KEY

#95

Сообщение seri0shka » 01.10.2019{, 18:34}

seri0shka писал(а):
27.09.2019{, 22:59}
Посмотрите, что я делаю не так?
Всё оказалось просто, хотя на поиски я потратил больше 6 часов. :smile37:
Вдвойне обидно, что я ведь уже встречался с точно такой же проблемой при использовании блока для 1617 от Labu559. Так что сам виноват. :smile390:
Labu559 делал блоки и библиотеки для модулей на 1637 и 1638, а в модулях уже установлены резисторы подтяжки. Я же использовал голые микросхемы, и подключал без резисторов. В библиотеках Батисты задействована внутренняя подтяжка контроллера, поэтому с его библиотекой у меня всё работало сразу.
Так что нужно или ставить резисторы, или править библиотеку. Скетч из поста 91 рабочий при подключенных резисторах. Учитесь на моих ошибках. :yes:
Sancho писал(а):
28.09.2019{, 15:06}
if (DIO_READ) bitSet(temp, 0);
else bitClear(temp, 0);

Вторая строчка лишняя, на мой взгляд. Там и так 0.
Компилятор с вами согласен, при удалении этой строчки не меняется ни результат, ни размер использованной памяти.

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#96

Сообщение Labu559 » 02.10.2019{, 12:49}

Ув.seri0shka! Приятно общаться с людьми, которым чужд потребительский подход, пытаются разобраться и помочь другим "не наступать на те же грабли". Спасибо Вам! Позвольте кое-что дополнить:
seri0shka писал(а):
01.10.2019{, 18:34}
на поиски я потратил больше 6 часов.

Этого можно было избежать. Ну что же, прийдётся повториться и указать где описал уже особенности работы с ТМ16хх.
seri0shka писал(а):
01.10.2019{, 18:34}
В библиотеках Батисты задействована внутренняя подтяжка контроллера
Нет, в этом загвоздка, Батиста не использует подтяжку, он просто переключает интерфейсные ноги МК в состояние LOW/HIGH (см. функции его библиотеки TM16xx.cpp- TM16xx::start(); void TM16xx::stop(); void TM16xx::send(byte data) и др.). А после прочитайте пж.второй абзац сообщения №83, это сообщение №21
выборкаПоказать
...обратите внимание на принудительные (IMHO) переключения состояния пинов Ардуино в High, при наличии подтяжек к Vcc сигнальных линий Data, Clock, Strobe, которые и предназначены для формирования этого уровня. К сожаленью не нашлось альтернативы и на github-е. Впрочем это касается всей линейки ТМ16хх, что у некоторых устройств (ТМ1636, ТМ1637, ТМ1640, ТМ1650, ТМ1651 и т.д. с эрзац-TWI/I2C) неизбежно приведёт к выгоранию вывода Ардуино и/или самого драйвера при удержании линии DIO в LOW (ACK, ACKnowledge буквально из английского- "подтверждаю получение") подчинённым устройством...(редакт. при потере данных),
...резисторы подтяжки, которые по протоколу I2C/TWI должны формировать высокий уровень на линиях, когда МК отпускает эти линии. Во всех остальных блоках здесь на форуме, скетчах и библиотеках TM1637 на github (за исключением на С++ от автора avishorp и на С от dhog1) делается это принудительным переключением выводов МК в HIGH. Другими словами подтяжка Clock (CLK) и Data (DIO) резисторами к Vcc, при таких делах, вообще становится лишней. См. описание протокола I2C/TWI и анализируем что будет с выходом МК или ведомого устройства в свете выдержки из описания протокола: "Генерация синхросигнала (ACK) - это всегда обязанность ведущего; каждый ведущий генерирует свой собственный сигнал синхронизации при пересылке данных по шине. Сигнал синхронизации может быть изменен только если он “вытягивается” медленным ведомым устройством (путем удержания линии в низком состоянии)...". А если в этот момент МК переключается принудительно в HIGH? Чей вывод сгорит первым от КЗ?
и настоятельно рекомендую начав с этого все сообщения ув. dhog1 до конца обсуждения.
цитированиеПоказать
- на "подтянутых" линиях (которые соединены с питанием через подтягивающие резисторы) используют две операции: освободить линию (перейти в высокоимпедансное состояние, т.е. отключиться от линии, и тогда резисторы подтянут ее в состояние логической единицы), и прижать линию к земле, установив на ней логический ноль. Что-либо писать в подтянутую линию (устанавливая бит порта в "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 прийдется...
seri0shka писал(а):
01.10.2019{, 18:34}
Так что нужно или ставить резисторы,
- это указано в даташите без альтернативы (без "или")
последний абзац стр.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.
или схемах которыя я публиковал выше.
seri0shka писал(а):
01.10.2019{, 18:34}
или править библиотеку
- Да, увы, сеньйор Батиста заблуждается уже много лет. Но если с ТМ1638 и др. MC (SPI или 3-Wire протокол)
такой фокус (вместо подтягивающих резисторов используется источник тока) проходит безболезненно, то с TM1637 (I2C или 2-Wire) будет пшик при задержке ACK
Желаю всем удачи и большего внимания при чтении описаний! :)
Последний раз редактировалось Labu559 03.10.2019{, 23:40}, всего редактировалось 1 раз.

seri0shka
Лейтенант
Сообщения: 391
Зарегистрирован: 09.04.2016{, 12:17}
Репутация: 22
Откуда: Кременчуг
Имя: Сергей

TM1638 LED&KEY

#97

Сообщение seri0shka » 02.10.2019{, 15:48}

Спасибо за столько полезных ссылок (добавляйте номер поста, при переходе по ссылкам страница сдвигается в произвольном направлении). Более-менее переварил информацию, почти понятно.
Одно не пойму: как можно сделать пшик, если не устанавливать на ноге контроллера высокий уровень при низкоимпедансном состоянии? Если всё же установить, то внешние подтягивающие резисторы никак не спасут от выгорания. Я считаю, что стоит присмотреться в сторону применения внутренней подтяжки вместо внешней, хотя номинал внутренних резисторов в 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);
}
Зачем так намудрено в функции setBrightness (установка яркости)? Можно проще?

edyapd
Капитан
Сообщения: 768
Зарегистрирован: 20.09.2019{, 11:38}
Репутация: 65
Имя: Эдуард

TM1638 LED&KEY

#98

Сообщение edyapd » 03.10.2019{, 05:38}

seri0shka писал(а):
02.10.2019{, 23:50}
Зачем так намудрено в функции setBrightness (установка яркости)? Можно проще?
А что там сложного? Даже для меня, не знающего С, там всё просто. Можно оставить две строчки, если вы уверены, что newBrighness будет в пределах от 0 до 8 и вам не нужно возвращать старую яркость.

Labu559
Лейтенант
Сообщения: 359
Зарегистрирован: 25.01.2018{, 22:23}
Репутация: 95
Откуда: Bukovyna
Имя: Василий

TM1638 LED&KEY

#99

Сообщение Labu559 » 04.10.2019{, 00:16}

seri0shka писал(а):
02.10.2019{, 23:50}
добавляйте номер поста
Поправил, добавил, сделал выборки и цитирования в 96-м сообщении.
seri0shka писал(а):
02.10.2019{, 23:50}
как можно сделать пшик, если не устанавливать на ноге контроллера высокий уровень при низкоимпедансном состоянии? Если всё же установить, то внешние подтягивающие резисторы никак не спасут от выгорания.
Внешние подтягивающие резисторы ничего не спасают, они формируют высокий уровень на линии, когда МК отключается (Hi-Z) от этой линии и позволяют безопасно прижимать линию к земле, как мастеру, так и слейвам без КЗ.
seri0shka писал(а):
02.10.2019{, 23:50}
Я считаю, что стоит присмотреться в сторону применения внутренней подтяжки вместо внешней
А я не ставлю под сомнение рекоммендации производителя. Для слабо помехоустойчивых интерфейсных линий зачастую 4,7кОм слишком много. Высокоомная внутренняя подтяжка (50-60кОм) не позволит работать шине (RC-контур) на высоких скоростях (частота тактирования драйвера до 450кГц) .
seri0shka писал(а):
02.10.2019{, 23:50}
не пойму: как можно сделать пшик
прочитайте пж. ещё раз новую редакцию сообщения №96, не отвлекаясь на ссылки. Если не поможет- не берите в голову, для Вашей текущей задачи-ТМ1638 не особо актуально (я описал общий принцип, рекоммендованный производителем. В Ардуино почти всё "работает" как бы как).
seri0shka писал(а):
02.10.2019{, 23:50}
Зачем так намудрено в функции setBrightness
Автор сделал перезапись уровня яркости только при его изменении по сравнению с предыдущим значением, а не в каждом цикле :no: гашение и инкремент/декремент кнопками яркости дисплея, потому использует для сравнения старое значение яркости. :yes: ТМ1638 умеет отключать индикацию- регистры данных обновляются, но данные не выводятся на дисплей. Что бы не заморачиваться с отдельной функцией отключения, автор объединил её с регулировкой яркости сдвинув диапазон уровней из 0-7 к 1-8 (0- погасить дисплей) - хорошее решение IMHO.
Последний раз редактировалось Labu559 13.05.2021{, 07:59}, всего редактировалось 3 раза.

edyapd
Капитан
Сообщения: 768
Зарегистрирован: 20.09.2019{, 11:38}
Репутация: 65
Имя: Эдуард

TM1638 LED&KEY

#100

Сообщение edyapd » 04.10.2019{, 05:49}

Labu559 писал(а):
04.10.2019{, 00:16}
Автор сделал перезапись уровня яркости только при его изменении по сравнению с предыдущим значением, а не в каждом цикле.
Можете показать в каких строчках это реализовано?

Ответить

Вернуться в «Дисплеи и индикаторы»