· 5 years ago · Dec 11, 2020, 10:20 AM
1/*
2 SevenSegmentTM1637 - class to control a 4 digit seven segment display with a TM1636 or TM1637 driver IC
3 Created by Bram Harmsen, September 25, 2015
4 Released into the public domain.
5 Licence: GNU GENERAL PUBLIC LICENSE V2.0
6
7 # Changelog
8
9 v1.0 25-10-2015
10 v1.1 04-07-2020
11
12*/
13
14#ifndef SevenSegmentTM1637_H
15#define SevenSegmentTM1637_H
16
17#include <Arduino.h>
18#include "SevenSegmentAsciiMap.h"
19
20// COMPILE TIME USER CONFIG ////////////////////////////////////////////////////
21#define TM1637_DEBUG false // true for serial debugging
22#define TM1637_BEGIN_DELAY 500 // ms
23#define TM1637_PRINT_BUFFER_SIZE 128 // lower if you don't need it
24
25// Default values //////////////////////////////////////////////////////////////
26#define TM1637_DEFAULT_PRINT_DELAY 300 // 300 ms delay between characters
27#define TM1637_DEFAULT_BLINK_DELAY 50 // ms
28#define TM1637_DEFAULT_CLOCK_BLINK_DELAY 500 // the default delay for when using printTime
29#define TM1637_DEFAULT_BLINK_REPEAT 10
30#define TM1637_DEFAULT_CURSOR_POS 0 // 0-MAX-1 (e.g 3)
31#define TM1637_DEFAULT_COLON_ON false //
32#define TM1637_DEFAULT_BACKLIGHT 100 // 0..100
33
34#define TM1637_MAX_LINES 1 // number of display lines
35#define TM1637_MAX_COLOM 4 // number of coloms (digits)
36#define TM1637_MAX_CHARS 128
37
38// PROGRAM CONFIG (ONLY CHANGE WHEN YOU KNOW WHAT YOU RE DOING:)////////////////
39#define TM1637_CLK_DELAY_US 5 // clock delay for communication
40// mine works with 1us, perhaps increase if display does not function ( tested upto 1ms)
41
42
43// COMMANDS ////////////////////////////////////////////////////////////////////
44#define TM1637_COM_SET_DATA B01000000 // 0x40 (1) Data set
45#define TM1637_COM_SET_ADR B11000000 // 0xC0 (2) Address command set
46#define TM1637_COM_SET_DISPLAY B10000000 // 0x80 (3) Display control command set
47
48// Data set (1) (use logical OR to contruct complete command)
49#define TM1637_SET_DATA_WRITE B00000000 // Write data to the display register
50#define TM1637_SET_DATA_READ B00000010 // Read the key scan data
51#define TM1637_SET_DATA_A_ADDR B00000000 // Automatic address increment
52#define TM1637_SET_DATA_F_ADDR B00000100 // Fixed address
53#define TM1637_SET_DATA_M_NORM B00000000 // Normal mode
54#define TM1637_SET_DATA_M_TEST B00100000 // Test mode
55
56// Address settings (2) (use logical OR to contruct complete command)
57#define TM1637_SET_ADR_00H B0000000 // addr 00
58#define TM1637_SET_ADR_01H B0000001 // addr 01
59#define TM1637_SET_ADR_02H B0000010 // addr 02
60#define TM1637_SET_ADR_03H B0000011 // addr 03
61#define TM1637_SET_ADR_04H B0000100 // addr 04 (only TM1637)
62#define TM1637_SET_ADR_05H B0000101 // addr 05 (only TM1637)
63// The command is used to set the display register address; if the address is set to 0C4H or higher, the data is ignored, until the effective address is set; when the power is on, the default is set to 00H address.
64
65// Display control command set (use logical OR to consruct complete command)
66#define TM1637_SET_DISPLAY_1 B0000000 // Pulse width 1/16 (0.0625) (0)
67#define TM1637_SET_DISPLAY_2 B0000001 // Pulse width 2/16 (0.0625) (1)
68#define TM1637_SET_DISPLAY_4 B0000010 // Pulse width 4/16 (0.0625) (2)
69#define TM1637_SET_DISPLAY_10 B0000011 // Pulse width 10/16 (0.0625) (3)
70#define TM1637_SET_DISPLAY_11 B0000100 // Pulse width 11/16 (0.0625) (4)
71#define TM1637_SET_DISPLAY_12 B0000101 // Pulse width 12/16 (0.0625) (5)
72#define TM1637_SET_DISPLAY_13 B0000110 // Pulse width 13/16 (0.0625) (6)
73#define TM1637_SET_DISPLAY_14 B0000111 // Pulse width 14/16 (0.0625) (7)
74#define TM1637_SET_DISPLAY_OFF B0000000 // OFF
75#define TM1637_SET_DISPLAY_ON B0001000 // ON
76// there are a total of 8 brighness values, plus off
77
78// PROTOCOL SPECIFICATION
79/*
80* Structure
81* START COMMAND ACK STOP set config or display
82* START ADR_CMD DATA ACK STOP sets single digit
83* START ADR_CMD DATA0 .. DATAN ACK STOP sets multiple digits when in auto mode
84*
85* There are basicly three things you can do:
86* 1. Set some configuration values
87* - read/write mode, auto/manual address, normal/test mode
88* 2. Set a (starting) address followed by 1 or N data bytes
89* 3. Set the display brightness (pwm) 0-7 and on or off
90*
91* From the datasheet it might seem that you always have to perform all three commands; setting configuration, setting address and data bytes and display. I'v tested this and this is not true. You can just set only one of these three. But ofcourse you have to make sure that your configuration is set properly. For example if you haven't set the configuration to automatic addresses, you can't just send out 4 data bytes, it won't work. Simlilair, if your display is off and you write some data to it, it won't display. On the other hand most default setting are what you want most of the time.
92
93*/
94
95class SevenSegmentTM1637 : public Print {
96
97public:
98 // LIQUID CRISTAL API ///////////////////////////////////////////////////////
99 // See http://playground.arduino.cc/Code/LCDAPI for more details.
100
101 /* Constructor
102 @param [in] pinClk clock pin (any digital pin)
103 @param [in] pinDIO digital output pin (any digital pin)
104 */
105 SevenSegmentTM1637(uint8_t pinClk, uint8_t pinDIO);
106 /* Initializes the display
107 * Initializes the display, sets some text and blinks the display
108
109 @param [in] cols optional: number of coloms (digits)
110 @param [in] rows optional: number of rows
111 */
112 void init(uint8_t cols = TM1637_MAX_COLOM, uint8_t rows = TM1637_MAX_LINES);
113 /* Implemented for compatibility, see begin() above */
114 void begin(uint8_t cols = TM1637_MAX_COLOM, uint8_t rows = TM1637_MAX_LINES);
115 // Print class inheritance ///////////////////////////////////////////////////
116 // See https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/Print.h for more details
117 /* This library inherent the Print class, this means that all regular print function can be used. For example:
118 * printing a number: print(78)
119 * printint a number in BIN, OCT, HEX..: print(78, BIN)
120 * printing a float: print(2.85)
121 * printing a PROGMEM c string: print(F("Arduino"))
122 *
123 * Also the more low level write() function can be used. (Actually all print function eventually call one of these write methods, every class that wants to inherent from the Print class needs to implement these)
124 */
125 size_t write(uint8_t byte);
126 size_t write(const char* str);
127 size_t write(const uint8_t* buffer, size_t size);
128
129 /* Clears the display
130 * Writes zero to all digits and segments, display off.
131 */
132 void clear(void);
133 /* Sets the cursor position to zero
134 */
135 void home(void);
136 /* Sets the cursor position to a specfic position
137 *
138 @param [in] col colomn (position)
139 */
140 void setCursor(uint8_t row, uint8_t col);
141 // Liquid cristal optional //////////////////////////////////////////////////
142 /* Sets the display backlight
143 * The display has 8 PWM modes and an off mode. The function accepts a value from 0 to 100, where 80-100 are the same; full brighness.
144
145 @param [in] value brightness value (0..80(100))
146 */
147 void setBacklight(uint8_t value);
148 /* Sets the display contrast (identical to brightness)
149 * This function is mainly for compatibility with the LCD API
150 */
151 void setContrast(uint8_t value);
152
153 /* Turns the display ON
154 * Identical to setting the brightness to the default value.
155 */
156 void on(void);
157 /* Turns the display ON
158 * Identical to setting the brightness to zero and clearing the display.
159 */
160 void off(void);
161
162 // SevenSegmentTM1637 METHODS ///////////////////////////////////////////////
163 /* Blink the last printed text
164 *
165 @param [in] blinkDelay optional: blink delay in ms
166 @param [in] repeats optional: number of blink repeats
167 */
168 void blink(uint8_t blinkDelay = TM1637_DEFAULT_BLINK_DELAY, uint8_t repeats = TM1637_DEFAULT_BLINK_REPEAT, uint8_t maxBacklight=100, uint8_t minBacklight=0);
169
170 // getters and setters ///////////////////////////////////////////////////////
171 /* Turn the colon on or off
172 * When turing the colon on, the next displayed text/numbers will have a colon
173 @param [in] setToOn sets the colon to on or off
174 */
175 void setColonOn(bool setToOn);
176 /* Get the currrent colon setting
177 */
178 bool getColonOn(void);
179 /* Sets the delay for scrolling text
180 * When printing more than four characters/ the display will scroll, this setting determines the scrolling speed in ms
181 @param [in] printDelay the print delay in ms
182 */
183 void setPrintDelay(uint16_t printDelay);
184
185 // helpers //////////////////////////////////////////////////////////////////
186 /* Encodes a character to sevensegment binairy
187 *
188 @param [in] c a character to encode
189 */
190 uint8_t encode(char c);
191 /* Encodes a single digit to sevensegment binairy
192 *
193 @param [in] d a digit to encode
194 */
195 uint8_t encode(int16_t d);
196 /* Encodes a null terminated c string (char array) to sevensegment binairy
197 *
198 @param [out] buffer holds the encodes char array
199 @param [in] str the c string to encode
200 @param [in] bufferSize the size/length of the buffer
201 */
202 size_t encode(uint8_t* buffer, const char* str, size_t bufferSize);
203 /* Encodes a byte array to sevensegment binairy
204 *
205 @param [out] buffer holds the encodes char array
206 @param [in] byteArr the byte array to encode
207 @param [in] bufferSize the size/length of the buffer
208 */
209 size_t encode(uint8_t* buffer, const uint8_t* byteArr, size_t arrSize);
210 /* Shift an array one position to the left
211 @param [out] buffer the buffer to be shifted
212 @param [in] length the length to the buffer
213 */
214 void shiftLeft(uint8_t* buffer, size_t length);
215
216 // SevenSegmentTM1637 low level methods (use when you know what you're doing)
217 /* Prints raw (encoded) bytes to the display
218 * A
219 * ___
220 * * F | | B
221 * X -G-
222 * * E | | C
223 * ___
224 * D
225 * Bit: 76543210
226 * Segment: XGFEDCBA
227 *
228 * For example to print an H, you would set bits BCEFG, this gives B01110110 in binary or 118 in decimal or 0x76 in HEX.
229 * Bit 7 (X) only applies to the second digit and sets the colon
230 */
231 /* Print raw (binary encodes) bytes to the display
232 @param [in] rawBytes Array of raw bytes
233 @param [in] length optional: length to print to display
234 @param [in] position optional: Start position
235 */
236 void printRaw(const uint8_t* rawBytes, size_t length = 4, uint8_t position = 0);
237 /* Print raw (binary encodes) bytes to the display
238 @param [in] rawByte Raw byte
239 @param [in] position optional: Start position
240 */
241 void printRaw(uint8_t rawByte, uint8_t position);
242 /* Write command to IC TM1637
243 @param [in] cmd command to send
244 @return acknowledged? command was (successful) acknowledged
245 */
246 bool command(uint8_t cmd) const;
247 bool command(const uint8_t* command, uint8_t length) const;
248 /* Read bytes from IC TM1637
249 * The IC also can read the state of a keypad? TODO untested
250 */
251 uint8_t comReadByte(void) const;
252 /* Write a single command to the display
253 @param [in] cmd command to send
254 */
255 void comWriteByte(uint8_t command) const;
256 /* Send start signal
257 * Send the start signal for serial communication
258 */
259 void comStart(void) const;
260 /* Send stop signal
261 * Send the stop signal for serial communication
262 */
263 void comStop(void) const;
264 /* Get command acknowledged
265 * Get acknowledge signal (command was succesful received)
266 */
267 bool comAck(void) const;
268
269 /* Static version of low level function
270 * If using more than one display, this saves some space since these methods will be shared among all instances/objects of the class
271 */
272 static bool command(uint8_t pinClk, uint8_t pinDIO, uint8_t cmd);
273 static bool command(uint8_t pinClk, uint8_t pinDIO, const uint8_t* command, uint8_t length);
274 static void comStart(uint8_t pinClk, uint8_t pinDIO);
275 static void comWriteByte(uint8_t pinClk, uint8_t pinDIO, uint8_t command);
276 static bool comAck(uint8_t pinClk, uint8_t pinDIO);
277 static void comStop(uint8_t pinClk, uint8_t pinDIO);
278protected:
279 const uint8_t _pinClk; // clock pin
280 const uint8_t _pinDIO; // digital out pin
281 uint8_t _numCols; // number of columns
282 uint8_t _numRows; // number of rows
283
284 uint8_t _backLightValue; // brightness of the display (0..100)
285 uint8_t _cursorPos; // current cursor position
286 uint16_t _printDelay; // print delay in ms (multiple chars)
287 uint8_t _colonOn; // colon bit if set
288 uint8_t _rawBuffer[TM1637_MAX_COLOM];// hold the last chars printed to display
289};
290
291
292#define TM1637_COLON_BIT B10000000
293
294// debug macros for debugging
295#if TM1637_DEBUG
296 #define TM1637_DEBUG_BEGIN(x) Serial.begin(x)
297 #define TM1637_DEBUG_PRINT(...) Serial.print(__VA_ARGS__)
298 #define TM1637_DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
299 #define TM1637_DEBUG_WRITE(x) Serial.write(x)
300 #define TM1637_DEBUG_MESSAGE(...) \
301 Serial.print(millis()); \
302 Serial.print(F("\t")); \
303 Serial.print(__VA_ARGS__);
304 #define TM1637_DEBUG_MESSAGELN(...) \
305 TM1637_DEBUG_MESSAGE(__VA_ARGS__) \
306 Serial.println();
307#else
308 #define TM1637_DEBUG_BEGIN(x)
309 #define TM1637_DEBUG_PRINT(...)
310 #define TM1637_DEBUG_PRINTLN(...)
311 #define TM1637_DEBUG_WRITE(x)
312 #define TM1637_DEBUG_MESSAGE(x)
313 #define TM1637_DEBUG_MESSAGELN(x)
314#endif
315
316// arduino:standard variant direct port access macros for more speed ( communication is ~us)
317#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8A__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168PA__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
318 #define portOfPin(P) \
319 ( ((P) >= 0 && (P) < 8)? &PORTD:( ((P) > 7 && (P) < 14) ? &PORTB: &PORTC ) )
320 #define ddrOfPin(P) \
321 ( ((P) >= 0 && (P) < 8)? &DDRD: ( ((P) > 7 && (P) < 14) ? &DDRB: &DDRC ) )
322 #define pinOfPin(P) \
323 ( ((P) >= 0 && (P) < 8)? &PIND: ( ((P) > 7 && (P) < 14) ? &PINB: &PINC ) )
324
325 #define pinIndex(P) ( (uint8_t)( P > 13 ? P-14: P&7 ) )
326 #define pinMask(P) ( (uint8_t)( 1 << pinIndex(P) ) )
327
328 #define pinAsInput(P) *(ddrOfPin(P) ) &= ~pinMask(P)
329 #define pinAsInputPullUp(P) *(ddrOfPin(P) ) &= ~pinMask(P);digitalHigh(P)
330 #define pinAsOutput(P) *(ddrOfPin(P) ) |= pinMask(P)
331 #define digitalLow(P) *(portOfPin(P)) &= ~pinMask(P)
332 #define digitalHigh(P) *(portOfPin(P)) |= pinMask(P)
333 #define isHigh(P) ( ( *( pinOfPin(P) ) & pinMask(P) ) > 0 )
334 #define isLow(P) ( ( *( pinOfPin(P) ) & pinMask(P) ) == 0 )
335 #define digitalState(P) ((uint8_t)isHigh(P))
336#else
337 #define pinAsOutput(P) pinMode(P, OUTPUT)
338 #define pinAsInput(P) pinMode(P, INPUT)
339 #define pinAsInputPullUp(P) pinMode(P, INPUT_PULLUP)
340 #define digitalLow(P) digitalWrite(P, LOW)
341 #define digitalHigh(P) digitalWrite(P, HIGH)
342 #define isHigh(P) (digitalRead(P) == 1)
343 #define isLow(P) (digitalRead(P) == 0)
344 #define digitalState(P) digitalRead(P)
345#endif
346
347#endif
348