123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /**
- * ESP-32 IDF library for control TM1637 LED 7-Segment display
- *
- * Author: Petro <petro@petro.ws>
- *
- * Project homepage: https://github.com/petrows/esp-32-tm1637
- * Example: https://github.com/petrows/esp-32-tm1637-example
- *
- */
- #include "tm1637.h"
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <rom/ets_sys.h>
- #define TM1637_ADDR_AUTO 0x40
- #define TM1637_ADDR_FIXED 0x44
- #define MINUS_SIGN_IDX 16
- static const int8_t tm1637_symbols[] = {
- // XGFEDCBA
- 0x3f, // 0b00111111, // 0
- 0x06, // 0b00000110, // 1
- 0x5b, // 0b01011011, // 2
- 0x4f, // 0b01001111, // 3
- 0x66, // 0b01100110, // 4
- 0x6d, // 0b01101101, // 5
- 0x7d, // 0b01111101, // 6
- 0x07, // 0b00000111, // 7
- 0x7f, // 0b01111111, // 8
- 0x6f, // 0b01101111, // 9
- 0x77, // 0b01110111, // A
- 0x7c, // 0b01111100, // b
- 0x39, // 0b00111001, // C
- 0x5e, // 0b01011110, // d
- 0x79, // 0b01111001, // E
- 0x71, // 0b01110001 // F
- 0x40, // 0b01000000 // minus sign
- };
- static void tm1637_start(tm1637_led_t * led);
- static void tm1637_stop(tm1637_led_t * led);
- static void tm1637_send_byte(tm1637_led_t * led, uint8_t byte);
- static void tm1637_delay();
- static inline float nearestf(float val,int precision) {
- int scale = pow(10,precision);
- return roundf(val * scale) / scale;
- }
- void tm1637_start(tm1637_led_t * led)
- {
- // Send start bit to TM1637
- gpio_set_level(led->m_pin_clk, 1);
- gpio_set_level(led->m_pin_dta, 1);
- tm1637_delay();
- gpio_set_level(led->m_pin_dta, 0);
- tm1637_delay();
- gpio_set_level(led->m_pin_clk, 0);
- tm1637_delay();
- }
- void tm1637_stop(tm1637_led_t * led)
- {
- gpio_set_level(led->m_pin_clk, 0);
- gpio_set_level(led->m_pin_dta, 0);
- tm1637_delay();
- gpio_set_level(led->m_pin_clk, 1);
- gpio_set_level(led->m_pin_dta, 1);
- tm1637_delay();
- }
- void tm1637_send_byte(tm1637_led_t * led, uint8_t byte)
- {
- for (uint8_t i=0; i<8; ++i)
- {
- gpio_set_level(led->m_pin_clk, 0);
- tm1637_delay();
- gpio_set_level(led->m_pin_dta, byte & 0x01); // Send current bit
- gpio_set_level(led->m_pin_clk, 1);
- byte >>= 1;
- tm1637_delay();
- }
- gpio_set_level(led->m_pin_clk, 0); //wait for the ACK
- gpio_set_level(led->m_pin_dta, 1);
- tm1637_delay();
- gpio_set_level(led->m_pin_clk, 1);
- gpio_set_direction(led->m_pin_dta, GPIO_MODE_INPUT);
- tm1637_delay();
- uint8_t ack = gpio_get_level(led->m_pin_dta);
- if (ack == 0) {
- gpio_set_direction(led->m_pin_dta, GPIO_MODE_OUTPUT);
- gpio_set_level(led->m_pin_dta, 0);
- }
- tm1637_delay();
- gpio_set_direction(led->m_pin_dta, GPIO_MODE_OUTPUT);
- tm1637_delay();
- }
- void tm1637_delay()
- {
- ets_delay_us(50);
- }
- // PUBLIC PART:
- tm1637_led_t * tm1637_init(gpio_num_t pin_clk, gpio_num_t pin_data) {
- tm1637_led_t * led = malloc(sizeof(tm1637_led_t));
- led->m_pin_clk = pin_clk;
- led->m_pin_dta = pin_data;
- led->m_brightness = 0x07;
- gpio_set_direction(pin_clk, GPIO_MODE_OUTPUT);
- gpio_set_direction(pin_data, GPIO_MODE_OUTPUT);
- gpio_set_level(pin_clk, 0);
- gpio_set_level(pin_data, 0);
- return led;
- }
- void tm1637_set_brightness(tm1637_led_t * led, uint8_t level)
- {
- if (level > 0x07) { level = 0x07; } // Check max level
- led->m_brightness = level;
- }
- void tm1637_set_segment_number(tm1637_led_t * led, const uint8_t segment_idx, const uint8_t num, const bool dot)
- {
- uint8_t seg_data = 0x00;
- if (num < (sizeof(tm1637_symbols)/sizeof(tm1637_symbols[0]))) {
- seg_data = tm1637_symbols[num]; // Select proper segment image
- }
- if (dot) {
- seg_data |= 0x80; // Set DOT segment flag
- }
- tm1637_set_segment_raw(led, segment_idx, seg_data);
- }
- void tm1637_set_segment_raw(tm1637_led_t * led, const uint8_t segment_idx, const uint8_t data)
- {
- tm1637_start(led);
- tm1637_send_byte(led, TM1637_ADDR_FIXED);
- tm1637_stop(led);
- tm1637_start(led);
- tm1637_send_byte(led, segment_idx | 0xc0);
- tm1637_send_byte(led, data);
- tm1637_stop(led);
- tm1637_start(led);
- tm1637_send_byte(led, led->m_brightness | 0x88);
- tm1637_stop(led);
- }
- void tm1637_set_number(tm1637_led_t * led, uint16_t number)
- {
- tm1637_set_number_lead_dot(led, number, false, 0x00);
- }
- void tm1637_set_number_lead(tm1637_led_t * led, uint16_t number, const bool lead_zero)
- {
- tm1637_set_number_lead_dot(led, number, lead_zero, 0x00);
- }
- void tm1637_set_number_lead_dot(tm1637_led_t * led, uint16_t number, bool lead_zero, const uint8_t dot_mask)
- {
- uint8_t lead_number = lead_zero ? 0xFF : tm1637_symbols[0];
- if (number < 10) {
- tm1637_set_segment_number(led, 3, number, dot_mask & 0x01);
- tm1637_set_segment_number(led, 2, lead_number, dot_mask & 0x02);
- tm1637_set_segment_number(led, 1, lead_number, dot_mask & 0x04);
- tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
- } else if (number < 100) {
- tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
- tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
- tm1637_set_segment_number(led, 1, lead_number, dot_mask & 0x04);
- tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
- } else if (number < 1000) {
- tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
- tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
- tm1637_set_segment_number(led, 1, (number / 100) % 10, dot_mask & 0x04);
- tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
- } else {
- tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
- tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
- tm1637_set_segment_number(led, 1, (number / 100) % 10, dot_mask & 0x04);
- tm1637_set_segment_number(led, 0, (number / 1000) % 10, dot_mask & 0x08);
- }
- }
- void tm1637_set_float(tm1637_led_t * led, float n) {
- if( n < 0 ) {
- tm1637_set_segment_number(led, 0, MINUS_SIGN_IDX, 0);
- float absn = nearestf(fabs(n),1);
- int int_part = (int)absn;
- float fx_part = absn - int_part;
- if( absn < 10 ) {
- fx_part *= 100;
- tm1637_set_segment_number(led, 1, (int)(absn + 0.5), 1 );
- tm1637_set_segment_number(led, 2, ((int)fx_part/10) % 10, 0 );
- tm1637_set_segment_number(led, 3, ((int)fx_part) % 10, 0 );
- }
- else if( n < 100 ) {
- fx_part *= 100;
- uint8_t f = ((int)fx_part % 10);
-
- tm1637_set_segment_number(led, 1, (int_part/10) % 10, 0 );
- tm1637_set_segment_number(led, 2, int_part % 10, 1 );
- tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10 + ((f > 4)?1:0), 0 );
- }
- else if( n < 1000 ) {
- tm1637_set_segment_number(led, 1, (int_part/100) % 10, 0 );
- tm1637_set_segment_number(led, 2, (int_part/10) % 10, 0 );
- tm1637_set_segment_number(led, 3, (int_part % 10) + ((fx_part >= 0.5 )?1:0), 0 );
- }
- }
- else {
- // positive number
- int int_part = (int)n;
- float fx_part = n - int_part;
- if( n < 10 ) {
- n = nearestf(n,1);
- int_part = (int)n;
- fx_part = 10000 * (n - int_part);
-
- tm1637_set_segment_number(led, 0, int_part, 1);
- tm1637_set_segment_number(led, 1, ((int)fx_part/1000) % 10, 0 );
- tm1637_set_segment_number(led, 2, ((int)fx_part/100) % 10, 0 );
- tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10, 0 );
- }
- else if( n < 100 ) {
- n = nearestf(n,2);
- int_part = (int)n;
- fx_part = 1000 * (n - int_part);
-
- tm1637_set_segment_number(led, 0, (int_part/10) % 10, 0);
- tm1637_set_segment_number(led, 1, int_part % 10, 1 );
- tm1637_set_segment_number(led, 2, ((int)fx_part/100) % 10, 0 );
- tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10,0);
- }
- else if( n < 1000 ) {
- n = nearestf(n,2);
- int_part = (int)n;
- fx_part = 100 * (n - int_part);
-
- tm1637_set_segment_number(led, 0, (int_part/100) % 10, 0);
- tm1637_set_segment_number(led, 1, (int_part/10) % 10, 0 );
- tm1637_set_segment_number(led, 2, int_part % 10, 1 );
- tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10, 0 );
- }
- }
- }
|