mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-22 23:56:13 +01:00
Squashed commit of the following:
commitf13824164b
Author: Asbelos <asbelos@btinternet.com> Date: Thu Oct 10 16:07:42 2024 +0100 _s7 keyword generator commit8a7dc2643c
Author: Asbelos <asbelos@btinternet.com> Date: Mon Oct 7 10:54:05 2024 +0100 comments commit801cddfef7
Author: Asbelos <asbelos@btinternet.com> Date: Sun Oct 6 13:24:07 2024 +0100 simpler macro insert commit5883f474ee
Author: Asbelos <asbelos@btinternet.com> Date: Sun Oct 6 13:18:29 2024 +0100 Auto include commit312fc255e4
Author: Asbelos <asbelos@btinternet.com> Date: Sun Oct 6 13:12:51 2024 +0100 Cleanup to one class commit3094074349
Author: Asbelos <asbelos@btinternet.com> Date: Sun Oct 6 10:34:16 2024 +0100 peeled back commitaa2a6ad119
Author: Asbelos <asbelos@btinternet.com> Date: Sat Oct 5 18:27:43 2024 +0100 all fastpins commit931baf4b6d
Author: Asbelos <asbelos@btinternet.com> Date: Sat Oct 5 16:28:03 2024 +0100 Partial lib extract commit47bc3b55fc
Author: Asbelos <asbelos@btinternet.com> Date: Fri Oct 4 15:41:51 2024 +0100 fixes and SEG7 macro commit3f26ca2d1a
Author: Asbelos <asbelos@btinternet.com> Date: Fri Oct 4 14:33:23 2024 +0100 enums for exrail easy commit7e7c00594b
Author: Asbelos <asbelos@btinternet.com> Date: Fri Oct 4 13:16:57 2024 +0100 Working commitfc4df87848
Author: Asbelos <asbelos@btinternet.com> Date: Fri Oct 4 09:27:46 2024 +0100 leds and buttons
This commit is contained in:
parent
f5014f5595
commit
fa00e9e11b
|
@ -63,6 +63,10 @@
|
||||||
// playing sounds with IO_I2CDFPlayer
|
// playing sounds with IO_I2CDFPlayer
|
||||||
#define PLAYSOUND ANOUT
|
#define PLAYSOUND ANOUT
|
||||||
|
|
||||||
|
// SEG7 is a helper to create ANOUT from a 7-segment requets
|
||||||
|
#define SEG7(vpin,value,format) \
|
||||||
|
ANOUT(vpin,(value & 0xFFFF),TM1638::DF_##format,((uint32_t)value)>>16)
|
||||||
|
|
||||||
// helper macro to strip leading zeros off time inputs
|
// helper macro to strip leading zeros off time inputs
|
||||||
// (10#mins)%100)
|
// (10#mins)%100)
|
||||||
#define STRIP_ZERO(value) 10##value%100
|
#define STRIP_ZERO(value) 10##value%100
|
||||||
|
|
|
@ -570,6 +570,6 @@ protected:
|
||||||
#include "IO_EncoderThrottle.h"
|
#include "IO_EncoderThrottle.h"
|
||||||
#include "IO_TCA8418.h"
|
#include "IO_TCA8418.h"
|
||||||
#include "IO_NeoPixel.h"
|
#include "IO_NeoPixel.h"
|
||||||
|
#include "IO_TM1638.h"
|
||||||
|
|
||||||
#endif // iodevice_h
|
#endif // iodevice_h
|
||||||
|
|
217
IO_TM1638.cpp
Normal file
217
IO_TM1638.cpp
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
/*
|
||||||
|
* © 2024, Chris Harlow. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of DCC++EX API
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* It 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 CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Credit to https://github.com/dvarrel/TM1638 for the basic formulae.*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "IODevice.h"
|
||||||
|
#include "DIAG.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t HIGHFLASH _digits[16]={
|
||||||
|
0b00111111,0b00000110,0b01011011,0b01001111,
|
||||||
|
0b01100110,0b01101101,0b01111101,0b00000111,
|
||||||
|
0b01111111,0b01101111,0b01110111,0b01111100,
|
||||||
|
0b00111001,0b01011110,0b01111001,0b01110001
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
TM1638::TM1638(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin){
|
||||||
|
_firstVpin = firstVpin;
|
||||||
|
_nPins = 8;
|
||||||
|
_clk_pin = clk_pin;
|
||||||
|
_stb_pin = stb_pin;
|
||||||
|
_dio_pin = dio_pin;
|
||||||
|
pinMode(clk_pin,OUTPUT);
|
||||||
|
pinMode(stb_pin,OUTPUT);
|
||||||
|
pinMode(dio_pin,OUTPUT);
|
||||||
|
_pulse = PULSE1_16;
|
||||||
|
|
||||||
|
_buttons=0;
|
||||||
|
_leds=0;
|
||||||
|
_lastLoop=micros();
|
||||||
|
addDevice(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TM1638::create(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin) {
|
||||||
|
if (checkNoOverlap(firstVpin,8))
|
||||||
|
new TM1638(firstVpin, clk_pin,dio_pin,stb_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::_begin() {
|
||||||
|
displayClear();
|
||||||
|
test();
|
||||||
|
_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TM1638::_loop(unsigned long currentMicros) {
|
||||||
|
if (currentMicros - _lastLoop > (1000000UL/LoopHz)) {
|
||||||
|
_buttons=getButtons();// Read the buttons
|
||||||
|
_lastLoop=currentMicros;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::_display() {
|
||||||
|
DIAG(F("TM1638 Configured on Vpins:%u-%u"), _firstVpin, _firstVpin+_nPins-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// digital read gets button state
|
||||||
|
int TM1638::_read(VPIN vpin) {
|
||||||
|
byte pin=vpin - _firstVpin;
|
||||||
|
bool result=bitRead(_buttons,pin);
|
||||||
|
// DIAG(F("TM1638 read (%d) buttons %x = %d"),pin,_buttons,result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// digital write sets led state
|
||||||
|
void TM1638::_write(VPIN vpin, int value) {
|
||||||
|
// TODO.. skip if no state change
|
||||||
|
writeLed(vpin - _firstVpin + 1,value!=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analog write sets digit displays
|
||||||
|
|
||||||
|
void TM1638::_writeAnalogue(VPIN vpin, int lowBytes, uint8_t mode, uint16_t highBytes) {
|
||||||
|
// mode is in DataFormat defined above.
|
||||||
|
byte formatLength=mode & 0x0F; // last 4 bits
|
||||||
|
byte formatType=mode & 0xF0; //
|
||||||
|
int8_t leftDigit=vpin-_firstVpin; // 0..7 from left
|
||||||
|
int8_t rightDigit=leftDigit+formatLength-1; // 0..7 from left
|
||||||
|
|
||||||
|
// loading is done right to left startDigit first
|
||||||
|
int8_t startDigit=7-rightDigit; // reverse as 7 on left
|
||||||
|
int8_t lastDigit=7-leftDigit; // reverse as 7 on left
|
||||||
|
uint32_t value=highBytes;
|
||||||
|
value<<=16;
|
||||||
|
value |= (uint16_t)lowBytes;
|
||||||
|
|
||||||
|
//DIAG(F("TM1638 fl=%d ft=%x sd=%d ld=%d v=%l vx=%X"),
|
||||||
|
// formatLength,formatType,startDigit,lastDigit,value,value);
|
||||||
|
while(startDigit<=lastDigit) {
|
||||||
|
switch (formatType) {
|
||||||
|
case _DF_DECIMAL:// decimal (leading zeros)
|
||||||
|
displayDig(startDigit,GETHIGHFLASH(_digits,(value%10)));
|
||||||
|
value=value/10;
|
||||||
|
break;
|
||||||
|
case _DF_HEX:// HEX (leading zeros)
|
||||||
|
displayDig(startDigit,GETHIGHFLASH(_digits,(value & 0x0F)));
|
||||||
|
value>>=4;
|
||||||
|
break;
|
||||||
|
case _DF_RAW:// Raw 7-segment pattern
|
||||||
|
displayDig(startDigit,value & 0xFF);
|
||||||
|
value>>=8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DIAG(F("TM1368 invalid mode 0x%x"),mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
startDigit++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TM1638::getButtons(){
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, LOW);
|
||||||
|
writeData(INSTRUCTION_READ_KEY);
|
||||||
|
pinMode(_dio_pin, INPUT);
|
||||||
|
ArduinoPins::fastWriteDigital(_clk_pin, LOW);
|
||||||
|
uint8_t buttons=0;
|
||||||
|
for (uint8_t eachByte=0; eachByte<4;eachByte++) {
|
||||||
|
uint8_t value = 0;
|
||||||
|
for (uint8_t eachBit = 0; eachBit < 8; eachBit++) {
|
||||||
|
ArduinoPins::fastWriteDigital(_clk_pin, HIGH);
|
||||||
|
value |= ArduinoPins::fastReadDigital(_dio_pin) << eachBit;
|
||||||
|
ArduinoPins::fastWriteDigital(_clk_pin, LOW);
|
||||||
|
}
|
||||||
|
buttons |= value << eachByte;
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
pinMode(_dio_pin, OUTPUT);
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, HIGH);
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TM1638::displayDig(uint8_t digitId, uint8_t pgfedcba){
|
||||||
|
if (digitId>7) return;
|
||||||
|
setDataInstruction(DISPLAY_TURN_ON | _pulse);
|
||||||
|
setDataInstruction(INSTRUCTION_WRITE_DATA| INSTRUCTION_ADDRESS_FIXED);
|
||||||
|
writeDataAt(FIRST_DISPLAY_ADDRESS+14-(digitId*2), pgfedcba);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::displayClear(){
|
||||||
|
setDataInstruction(DISPLAY_TURN_ON | _pulse);
|
||||||
|
setDataInstruction(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
|
||||||
|
for (uint8_t i=0;i<15;i+=2){
|
||||||
|
writeDataAt(FIRST_DISPLAY_ADDRESS+i,0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::writeLed(uint8_t num,bool state){
|
||||||
|
if ((num<1) | (num>8)) return;
|
||||||
|
setDataInstruction(DISPLAY_TURN_ON | _pulse);
|
||||||
|
setDataInstruction(INSTRUCTION_WRITE_DATA | INSTRUCTION_ADDRESS_FIXED);
|
||||||
|
writeDataAt(FIRST_DISPLAY_ADDRESS + (num*2-1), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TM1638::writeData(uint8_t data){
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
ArduinoPins::fastWriteDigital(_dio_pin, data & 1);
|
||||||
|
data >>= 1;
|
||||||
|
ArduinoPins::fastWriteDigital(_clk_pin, HIGH);
|
||||||
|
ArduinoPins::fastWriteDigital(_clk_pin, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::writeDataAt(uint8_t displayAddress, uint8_t data){
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, LOW);
|
||||||
|
writeData(displayAddress);
|
||||||
|
writeData(data);
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, HIGH);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::setDataInstruction(uint8_t dataInstruction){
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, LOW);
|
||||||
|
writeData(dataInstruction);
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, HIGH);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638::test(){
|
||||||
|
DIAG(F("TM1638 test"));
|
||||||
|
uint8_t val=0;
|
||||||
|
for(uint8_t i=0;i<5;i++){
|
||||||
|
setDataInstruction(DISPLAY_TURN_ON | _pulse);
|
||||||
|
setDataInstruction(INSTRUCTION_WRITE_DATA| INSTRUCTION_ADDRESS_AUTO);
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, LOW);
|
||||||
|
writeData(FIRST_DISPLAY_ADDRESS);
|
||||||
|
for(uint8_t i=0;i<16;i++)
|
||||||
|
writeData(val);
|
||||||
|
ArduinoPins::fastWriteDigital(_stb_pin, HIGH);
|
||||||
|
delay(1000);
|
||||||
|
val = ~val;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
134
IO_TM1638.h
Normal file
134
IO_TM1638.h
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* © 2024, Chris Harlow. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of DCC++EX API
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* It 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 CommandStation. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IO_TM1638_h
|
||||||
|
#define IO_TM1638_h
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "IODevice.h"
|
||||||
|
#include "DIAG.h"
|
||||||
|
|
||||||
|
class TM1638 : public IODevice {
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t _buttons;
|
||||||
|
uint8_t _leds;
|
||||||
|
unsigned long _lastLoop;
|
||||||
|
static const int LoopHz=20;
|
||||||
|
|
||||||
|
static const byte
|
||||||
|
INSTRUCTION_WRITE_DATA=0x40,
|
||||||
|
INSTRUCTION_READ_KEY=0x42,
|
||||||
|
INSTRUCTION_ADDRESS_AUTO=0x40,
|
||||||
|
INSTRUCTION_ADDRESS_FIXED=0x44,
|
||||||
|
INSTRUCTION_NORMAL_MODE=0x40,
|
||||||
|
INSTRUCTION_TEST_MODE=0x48,
|
||||||
|
|
||||||
|
FIRST_DISPLAY_ADDRESS=0xC0,
|
||||||
|
|
||||||
|
DISPLAY_TURN_OFF=0x80,
|
||||||
|
DISPLAY_TURN_ON=0x88;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t _clk_pin;
|
||||||
|
uint8_t _stb_pin;
|
||||||
|
uint8_t _dio_pin;
|
||||||
|
uint8_t _pulse;
|
||||||
|
bool _isOn;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
TM1638(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum DigitFormat : byte {
|
||||||
|
// last 4 bits are length.
|
||||||
|
// DF_1.. DF_8 decimal
|
||||||
|
DF_1=0x01,DF_2=0x02,DF_3=0x03,DF_4=0x04,
|
||||||
|
DF_5=0x05,DF_6=0x06,DF_7=0x07,DF_8=0x08,
|
||||||
|
// DF_1X.. DF_8X HEX
|
||||||
|
DF_1X=0x11,DF_2X=0x12,DF_3X=0x13,DF_4X=0x14,
|
||||||
|
DF_5X=0x15,DF_6X=0x16,DF_7X=0x17,DF_8X=0x18,
|
||||||
|
// DF_1R .. DF_4R raw 7 segmnent data
|
||||||
|
// only 4 because HAL analogWrite only passes 4 bytes
|
||||||
|
DF_1R=0x21,DF_2R=0x22,DF_3R=0x23,DF_4R=0x24,
|
||||||
|
|
||||||
|
// bits of data conversion type (ored with length)
|
||||||
|
_DF_DECIMAL=0x00,// right adjusted decimal unsigned leading zeros
|
||||||
|
_DF_HEX=0x10, // right adjusted hex leading zeros
|
||||||
|
_DF_RAW=0x20 // bytes are raw 7-segment pattern (max length 4)
|
||||||
|
};
|
||||||
|
|
||||||
|
static void create(VPIN firstVpin, byte clk_pin,byte dio_pin,byte stb_pin);
|
||||||
|
|
||||||
|
// Functions overridden in IODevice
|
||||||
|
void _begin();
|
||||||
|
void _loop(unsigned long currentMicros) override ;
|
||||||
|
void _writeAnalogue(VPIN vpin, int value, uint8_t param1, uint16_t param2) override;
|
||||||
|
void _display() override ;
|
||||||
|
int _read(VPIN pin) override;
|
||||||
|
void _write(VPIN pin,int value) override;
|
||||||
|
|
||||||
|
// Device driving functions
|
||||||
|
private:
|
||||||
|
enum pulse_t {
|
||||||
|
PULSE1_16,
|
||||||
|
PULSE2_16,
|
||||||
|
PULSE4_16,
|
||||||
|
PULSE10_16,
|
||||||
|
PULSE11_16,
|
||||||
|
PULSE12_16,
|
||||||
|
PULSE13_16,
|
||||||
|
PULSE14_16
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn getButtons
|
||||||
|
* @return state of 8 buttons
|
||||||
|
*/
|
||||||
|
uint8_t getButtons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn writeLed
|
||||||
|
* @brief put led ON or OFF
|
||||||
|
* @param num num of led(1-8)
|
||||||
|
* @param state (true or false)
|
||||||
|
*/
|
||||||
|
void writeLed(uint8_t num, bool state);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn displayDig
|
||||||
|
* @brief set 7 segment display + dot
|
||||||
|
* @param digitId num of digit(0-7)
|
||||||
|
* @param val value 8 bits
|
||||||
|
*/
|
||||||
|
void displayDig(uint8_t digitId, uint8_t pgfedcba);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fn displayClear
|
||||||
|
* @brief switch off all leds and segment display
|
||||||
|
*/
|
||||||
|
void displayClear();
|
||||||
|
void test();
|
||||||
|
void writeData(uint8_t data);
|
||||||
|
void writeDataAt(uint8_t displayAddress, uint8_t data);
|
||||||
|
void setDisplayMode(uint8_t displayMode);
|
||||||
|
void setDataInstruction(uint8_t dataInstruction);
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -54,4 +54,43 @@ static_assert("MAIN"_hk == 11339,"Keyword hasher error");
|
||||||
static_assert("SLOW"_hk == -17209,"Keyword hasher error");
|
static_assert("SLOW"_hk == -17209,"Keyword hasher error");
|
||||||
static_assert("SPEED28"_hk == -17064,"Keyword hasher error");
|
static_assert("SPEED28"_hk == -17064,"Keyword hasher error");
|
||||||
static_assert("SPEED128"_hk == 25816,"Keyword hasher error");
|
static_assert("SPEED128"_hk == 25816,"Keyword hasher error");
|
||||||
|
|
||||||
|
// Compile time converter from "abcd"_s7 to the 7 segment nearest equivalent
|
||||||
|
|
||||||
|
constexpr uint8_t seg7Digits[]={
|
||||||
|
0b00111111,0b00000110,0b01011011,0b01001111, // 0..3
|
||||||
|
0b01100110,0b01101101,0b01111101,0b00000111, // 4..7
|
||||||
|
0b01111111,0b01101111 // 8..9
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint8_t seg7Letters[]={
|
||||||
|
0b01110111,0b01111100,0b00111001,0b01011110, // ABCD
|
||||||
|
0b01111001,0b01110001,0b00111101,0b01110110, // EFGH
|
||||||
|
0b00000100,0b00011110,0b01110010,0b00111000, //IJKL
|
||||||
|
0b01010101,0b01010100,0b01011100,0b01110011, // MNOP
|
||||||
|
0b10111111,0b01010000,0b01101101,0b01111000, // QRST
|
||||||
|
0b00111110,0b00011100,0b01101010,0b01001001, //UVWX
|
||||||
|
0b01100110,0b01011011 //YZ
|
||||||
|
};
|
||||||
|
constexpr uint8_t seg7Space=0b00000000;
|
||||||
|
constexpr uint8_t seg7Minus=0b01000000;
|
||||||
|
constexpr uint8_t seg7Equals=0b01001000;
|
||||||
|
|
||||||
|
|
||||||
|
constexpr uint32_t CompiletimeSeg7(const char * sv, uint32_t running, size_t rlen) {
|
||||||
|
return (*sv==0 || rlen==0) ? running << (8*rlen) : CompiletimeSeg7(sv+1,
|
||||||
|
(*sv >= '0' && *sv <= '9') ? (running<<8) | seg7Digits[*sv-'0'] :
|
||||||
|
(*sv >= 'A' && *sv <= 'Z') ? (running<<8) | seg7Letters[*sv-'A'] :
|
||||||
|
(*sv >= 'a' && *sv <= 'z') ? (running<<8) | seg7Letters[*sv-'a'] :
|
||||||
|
(*sv == '-') ? (running<<8) | seg7Minus :
|
||||||
|
(*sv == '=') ? (running<<8) | seg7Equals :
|
||||||
|
(running<<8) | seg7Space,
|
||||||
|
rlen-1
|
||||||
|
); //
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint32_t operator""_s7(const char * keyword, size_t len)
|
||||||
|
{
|
||||||
|
return CompiletimeSeg7(keyword,0*len,4);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
84
Release_Notes/TM1638.md
Normal file
84
Release_Notes/TM1638.md
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
## TM1638 ##
|
||||||
|
|
||||||
|
The TM1638 board provides a very cheap way of implementing 8 buttons, 8 leds and an 8 digit 7segment display in a package requiring just 5 Dupont wires (vcc, gnd + 3 GPIO pins) from the command station without soldering.
|
||||||
|
|
||||||
|
|
||||||
|
This is ideal for prototyping and testing, simulating sensors and signals, displaying states etc. For a built layout, this could provide a control for things that are not particularly suited to throttle 'route' buttons, perhaps lineside automations or fiddle yard lane selection.
|
||||||
|
|
||||||
|
By adding a simple HAL statement to myAutomation.h it creates 8 buttons/sensors and 8 leds.
|
||||||
|
|
||||||
|
`HAL(TM1638,500,29,31,33)`
|
||||||
|
Creates VPINs 500-507 And desscribes the GPIO pins used to connect the clk,dio,stb pins on the TM1638 board.
|
||||||
|
|
||||||
|
Setting each of the VPINs will control the associated LED (using for example SET, RESET or BLINK in Exrail or `<z 500> <z -501> from a command).
|
||||||
|
|
||||||
|
Unlike most pins, you can also read the same pin number and get the button state, using Exrail IF/AT/ONBUTTON etc.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
`
|
||||||
|
HAL(TM1638,500,29,31,33)
|
||||||
|
`
|
||||||
|
All the folowing examples assume you are using VPIN 500 as the first, leftmost, led/button on the TM1638 board.
|
||||||
|
|
||||||
|
|
||||||
|
`ONBUTTON(500)
|
||||||
|
SET(500) // light the first led
|
||||||
|
BLINK(501,500,500) // blink the second led
|
||||||
|
SETLOCO(3) FWD(50) // set a loco going
|
||||||
|
AT(501) STOP // press second button to stop
|
||||||
|
RESET(500) RESET(501) // turn leds off
|
||||||
|
DONE
|
||||||
|
`
|
||||||
|
|
||||||
|
Buttons behave like any other sensor, so using `<S 500 500 1>` will cause the command station to issue `<Q 500>` and `<q 500>` messages when the first button is pressed or released.
|
||||||
|
|
||||||
|
Exrail `JMRI_SENSOR(500,8)` will create `<S` commands for all 8 buttons.
|
||||||
|
|
||||||
|
## Using the 7 Segment display ##
|
||||||
|
|
||||||
|
The 8 digit display can be treated as 8 separate digits (left most being the same VPIN as the leftmost button and led) or be written to in sections of any length. Writing uses the existing analogue interface to the common HAL but is awkward to use directly. To make this easier from Exrail, a SEG7 macro provides a remapping to the ANOUT facility that makes more sense.
|
||||||
|
|
||||||
|
SEG7(vpin,value,format)
|
||||||
|
|
||||||
|
The vpin determins which digit to start writing at.
|
||||||
|
The value can be a 32bit unsigned integer but is interpreted differentlky according to the format.
|
||||||
|
|
||||||
|
Format values:
|
||||||
|
1..8 give the length (number of display digits) to fill, and defaults to decimal number with leading zeros.
|
||||||
|
|
||||||
|
1X..8X give the length but display in hex.
|
||||||
|
|
||||||
|
1R..4R treats each byte of the value as raw 7-segment patterns so that it can write letters and symbols using any compination of the 7segments and deciml point.
|
||||||
|
|
||||||
|
There is a useful description here:
|
||||||
|
https://jetpackacademy.com/wp-content/uploads/2018/06/TM1638_cheat_sheet_download.pdf
|
||||||
|
|
||||||
|
|
||||||
|
e.g. SEG7(500,3,4)
|
||||||
|
writes 0003 to first 4 digits of the display
|
||||||
|
SEG7(504,0xcafe,4X)
|
||||||
|
writes CAFE to the last 4 digits
|
||||||
|
SEG7(500,0xdeadbeef,8X)
|
||||||
|
writes dEAdbEEF to all 8 digits.
|
||||||
|
|
||||||
|
Writing raw segment patters requires knowledge of the bit pattern to segment relationship:
|
||||||
|
` 0
|
||||||
|
== 0 ==
|
||||||
|
5| | 1
|
||||||
|
== 6 ==
|
||||||
|
4 | | 2
|
||||||
|
== 3 ==
|
||||||
|
7=decimal point
|
||||||
|
|
||||||
|
Thus Letter A is segments 6 5 4 2 1 0, in bits that is (0 bit on right)
|
||||||
|
0b01110111 or 0x77
|
||||||
|
This is not easy to do my hand and thus a new string type suffix has been introduced to make simple text messages. Note that the HAL interface only has width for 32 bits which is only 4 symbols so writing 8 digits requires two calls.
|
||||||
|
|
||||||
|
e.g. SEG7(500,"Hell"_s7,4R) SEG7(504,"o"_s7,4R)
|
||||||
|
DELAY(1000)
|
||||||
|
SEG7(500,"Worl"_s7,4R) SEG7(504,"d"_s7,4R)
|
||||||
|
|
||||||
|
Note that some letters like k,m,v,x do not have particularly readable 7-segment representations.
|
||||||
|
|
||||||
|
Credit to https://github.com/dvarrel/TM1638 for the basic formulae.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user