tm1637.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /**
  2. * ESP-32 IDF library for control TM1637 LED 7-Segment display
  3. *
  4. * Author: Petro <petro@petro.ws>
  5. *
  6. * Project homepage: https://github.com/petrows/esp-32-tm1637
  7. * Example: https://github.com/petrows/esp-32-tm1637-example
  8. *
  9. */
  10. #include "tm1637.h"
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #include <rom/ets_sys.h>
  15. #define TM1637_ADDR_AUTO 0x40
  16. #define TM1637_ADDR_FIXED 0x44
  17. #define MINUS_SIGN_IDX 16
  18. static const int8_t tm1637_symbols[] = {
  19. // XGFEDCBA
  20. 0x3f, // 0b00111111, // 0
  21. 0x06, // 0b00000110, // 1
  22. 0x5b, // 0b01011011, // 2
  23. 0x4f, // 0b01001111, // 3
  24. 0x66, // 0b01100110, // 4
  25. 0x6d, // 0b01101101, // 5
  26. 0x7d, // 0b01111101, // 6
  27. 0x07, // 0b00000111, // 7
  28. 0x7f, // 0b01111111, // 8
  29. 0x6f, // 0b01101111, // 9
  30. 0x77, // 0b01110111, // A
  31. 0x7c, // 0b01111100, // b
  32. 0x39, // 0b00111001, // C
  33. 0x5e, // 0b01011110, // d
  34. 0x79, // 0b01111001, // E
  35. 0x71, // 0b01110001 // F
  36. 0x40, // 0b01000000 // minus sign
  37. };
  38. static void tm1637_start(tm1637_led_t * led);
  39. static void tm1637_stop(tm1637_led_t * led);
  40. static void tm1637_send_byte(tm1637_led_t * led, uint8_t byte);
  41. static void tm1637_delay();
  42. static inline float nearestf(float val,int precision) {
  43. int scale = pow(10,precision);
  44. return roundf(val * scale) / scale;
  45. }
  46. void tm1637_start(tm1637_led_t * led)
  47. {
  48. // Send start bit to TM1637
  49. gpio_set_level(led->m_pin_clk, 1);
  50. gpio_set_level(led->m_pin_dta, 1);
  51. tm1637_delay();
  52. gpio_set_level(led->m_pin_dta, 0);
  53. tm1637_delay();
  54. gpio_set_level(led->m_pin_clk, 0);
  55. tm1637_delay();
  56. }
  57. void tm1637_stop(tm1637_led_t * led)
  58. {
  59. gpio_set_level(led->m_pin_clk, 0);
  60. gpio_set_level(led->m_pin_dta, 0);
  61. tm1637_delay();
  62. gpio_set_level(led->m_pin_clk, 1);
  63. gpio_set_level(led->m_pin_dta, 1);
  64. tm1637_delay();
  65. }
  66. void tm1637_send_byte(tm1637_led_t * led, uint8_t byte)
  67. {
  68. for (uint8_t i=0; i<8; ++i)
  69. {
  70. gpio_set_level(led->m_pin_clk, 0);
  71. tm1637_delay();
  72. gpio_set_level(led->m_pin_dta, byte & 0x01); // Send current bit
  73. gpio_set_level(led->m_pin_clk, 1);
  74. byte >>= 1;
  75. tm1637_delay();
  76. }
  77. gpio_set_level(led->m_pin_clk, 0); //wait for the ACK
  78. gpio_set_level(led->m_pin_dta, 1);
  79. tm1637_delay();
  80. gpio_set_level(led->m_pin_clk, 1);
  81. gpio_set_direction(led->m_pin_dta, GPIO_MODE_INPUT);
  82. tm1637_delay();
  83. uint8_t ack = gpio_get_level(led->m_pin_dta);
  84. if (ack == 0) {
  85. gpio_set_direction(led->m_pin_dta, GPIO_MODE_OUTPUT);
  86. gpio_set_level(led->m_pin_dta, 0);
  87. }
  88. tm1637_delay();
  89. gpio_set_direction(led->m_pin_dta, GPIO_MODE_OUTPUT);
  90. tm1637_delay();
  91. }
  92. void tm1637_delay()
  93. {
  94. ets_delay_us(50);
  95. }
  96. // PUBLIC PART:
  97. tm1637_led_t * tm1637_init(gpio_num_t pin_clk, gpio_num_t pin_data) {
  98. tm1637_led_t * led = malloc(sizeof(tm1637_led_t));
  99. led->m_pin_clk = pin_clk;
  100. led->m_pin_dta = pin_data;
  101. led->m_brightness = 0x07;
  102. gpio_set_direction(pin_clk, GPIO_MODE_OUTPUT);
  103. gpio_set_direction(pin_data, GPIO_MODE_OUTPUT);
  104. gpio_set_level(pin_clk, 0);
  105. gpio_set_level(pin_data, 0);
  106. return led;
  107. }
  108. void tm1637_set_brightness(tm1637_led_t * led, uint8_t level)
  109. {
  110. if (level > 0x07) { level = 0x07; } // Check max level
  111. led->m_brightness = level;
  112. }
  113. void tm1637_set_segment_number(tm1637_led_t * led, const uint8_t segment_idx, const uint8_t num, const bool dot)
  114. {
  115. uint8_t seg_data = 0x00;
  116. if (num < (sizeof(tm1637_symbols)/sizeof(tm1637_symbols[0]))) {
  117. seg_data = tm1637_symbols[num]; // Select proper segment image
  118. }
  119. if (dot) {
  120. seg_data |= 0x80; // Set DOT segment flag
  121. }
  122. tm1637_set_segment_raw(led, segment_idx, seg_data);
  123. }
  124. void tm1637_set_segment_raw(tm1637_led_t * led, const uint8_t segment_idx, const uint8_t data)
  125. {
  126. tm1637_start(led);
  127. tm1637_send_byte(led, TM1637_ADDR_FIXED);
  128. tm1637_stop(led);
  129. tm1637_start(led);
  130. tm1637_send_byte(led, segment_idx | 0xc0);
  131. tm1637_send_byte(led, data);
  132. tm1637_stop(led);
  133. tm1637_start(led);
  134. tm1637_send_byte(led, led->m_brightness | 0x88);
  135. tm1637_stop(led);
  136. }
  137. void tm1637_set_number(tm1637_led_t * led, uint16_t number)
  138. {
  139. tm1637_set_number_lead_dot(led, number, false, 0x00);
  140. }
  141. void tm1637_set_number_lead(tm1637_led_t * led, uint16_t number, const bool lead_zero)
  142. {
  143. tm1637_set_number_lead_dot(led, number, lead_zero, 0x00);
  144. }
  145. void tm1637_set_number_lead_dot(tm1637_led_t * led, uint16_t number, bool lead_zero, const uint8_t dot_mask)
  146. {
  147. uint8_t lead_number = lead_zero ? 0xFF : tm1637_symbols[0];
  148. if (number < 10) {
  149. tm1637_set_segment_number(led, 3, number, dot_mask & 0x01);
  150. tm1637_set_segment_number(led, 2, lead_number, dot_mask & 0x02);
  151. tm1637_set_segment_number(led, 1, lead_number, dot_mask & 0x04);
  152. tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
  153. } else if (number < 100) {
  154. tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
  155. tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
  156. tm1637_set_segment_number(led, 1, lead_number, dot_mask & 0x04);
  157. tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
  158. } else if (number < 1000) {
  159. tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
  160. tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
  161. tm1637_set_segment_number(led, 1, (number / 100) % 10, dot_mask & 0x04);
  162. tm1637_set_segment_number(led, 0, lead_number, dot_mask & 0x08);
  163. } else {
  164. tm1637_set_segment_number(led, 3, number % 10, dot_mask & 0x01);
  165. tm1637_set_segment_number(led, 2, (number / 10) % 10, dot_mask & 0x02);
  166. tm1637_set_segment_number(led, 1, (number / 100) % 10, dot_mask & 0x04);
  167. tm1637_set_segment_number(led, 0, (number / 1000) % 10, dot_mask & 0x08);
  168. }
  169. }
  170. void tm1637_set_float(tm1637_led_t * led, float n) {
  171. if( n < 0 ) {
  172. tm1637_set_segment_number(led, 0, MINUS_SIGN_IDX, 0);
  173. float absn = nearestf(fabs(n),1);
  174. int int_part = (int)absn;
  175. float fx_part = absn - int_part;
  176. if( absn < 10 ) {
  177. fx_part *= 100;
  178. tm1637_set_segment_number(led, 1, (int)(absn + 0.5), 1 );
  179. tm1637_set_segment_number(led, 2, ((int)fx_part/10) % 10, 0 );
  180. tm1637_set_segment_number(led, 3, ((int)fx_part) % 10, 0 );
  181. }
  182. else if( n < 100 ) {
  183. fx_part *= 100;
  184. uint8_t f = ((int)fx_part % 10);
  185. tm1637_set_segment_number(led, 1, (int_part/10) % 10, 0 );
  186. tm1637_set_segment_number(led, 2, int_part % 10, 1 );
  187. tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10 + ((f > 4)?1:0), 0 );
  188. }
  189. else if( n < 1000 ) {
  190. tm1637_set_segment_number(led, 1, (int_part/100) % 10, 0 );
  191. tm1637_set_segment_number(led, 2, (int_part/10) % 10, 0 );
  192. tm1637_set_segment_number(led, 3, (int_part % 10) + ((fx_part >= 0.5 )?1:0), 0 );
  193. }
  194. }
  195. else {
  196. // positive number
  197. int int_part = (int)n;
  198. float fx_part = n - int_part;
  199. if( n < 10 ) {
  200. n = nearestf(n,1);
  201. int_part = (int)n;
  202. fx_part = 10000 * (n - int_part);
  203. tm1637_set_segment_number(led, 0, int_part, 1);
  204. tm1637_set_segment_number(led, 1, ((int)fx_part/1000) % 10, 0 );
  205. tm1637_set_segment_number(led, 2, ((int)fx_part/100) % 10, 0 );
  206. tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10, 0 );
  207. }
  208. else if( n < 100 ) {
  209. n = nearestf(n,2);
  210. int_part = (int)n;
  211. fx_part = 1000 * (n - int_part);
  212. tm1637_set_segment_number(led, 0, (int_part/10) % 10, 0);
  213. tm1637_set_segment_number(led, 1, int_part % 10, 1 );
  214. tm1637_set_segment_number(led, 2, ((int)fx_part/100) % 10, 0 );
  215. tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10,0);
  216. }
  217. else if( n < 1000 ) {
  218. n = nearestf(n,2);
  219. int_part = (int)n;
  220. fx_part = 100 * (n - int_part);
  221. tm1637_set_segment_number(led, 0, (int_part/100) % 10, 0);
  222. tm1637_set_segment_number(led, 1, (int_part/10) % 10, 0 );
  223. tm1637_set_segment_number(led, 2, int_part % 10, 1 );
  224. tm1637_set_segment_number(led, 3, ((int)fx_part/10) % 10, 0 );
  225. }
  226. }
  227. }