pi-tm1638  1.0
TM1638 library for Raspberry Pi
 All Data Structures Files Functions Variables Typedefs
tm1638.c
Go to the documentation of this file.
1 
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <stdint.h>
73 #include <stdbool.h>
74 
75 #include <bcm2835.h>
76 
77 #include "tm1638.h"
78 
85 struct tm1638_tag
86 {
87  uint8_t data;
88  uint8_t clock;
89  uint8_t strobe;
91  uint8_t intensity;
92  bool enable;
93 };
94 
95 static void tm1638_send_raw(const tm1638_p t, uint8_t x);
96 static uint8_t tm1638_receive_raw(const tm1638_p t);
97 static void tm1638_send_command(const tm1638_p t, uint8_t x);
98 static void tm1638_send_data(const tm1638_p t, uint8_t addr, uint8_t data);
99 static void tm1638_send_config(const tm1638_p t);
100 static uint8_t tm1638_calc_config(const tm1638_p t);
101 
102 /* See tm1638.h */
103 tm1638_p tm1638_alloc(uint8_t data, uint8_t clock, uint8_t strobe)
104 {
105  /* The delays in this code are somewhat arbitrary: they work for me
106  but I make no claims that they are optimal or robust */
107 
108  tm1638_p t = malloc(sizeof(tm1638));
109  if (!t)
110  return NULL;
111 
112  t->data = data;
113  t->clock = clock;
114  t->strobe = strobe;
115 
116  t->intensity = 7;
117  t->enable = true;
118 
119  bcm2835_gpio_fsel(t->data, BCM2835_GPIO_FSEL_OUTP);
120  bcm2835_gpio_fsel(t->clock, BCM2835_GPIO_FSEL_OUTP);
121  bcm2835_gpio_fsel(t->strobe, BCM2835_GPIO_FSEL_OUTP);
122 
123  bcm2835_gpio_write(t->strobe, HIGH);
124  bcm2835_gpio_write(t->clock, HIGH);
125  delayMicroseconds(1);
126 
128 
129  tm1638_send_cls(t);
130 
131  return t;
132 }
133 
134 /* See tm1638.h */
136 {
137  free(*t);
138  *t = NULL;
139 }
140 
141 /* See tm1638.h */
142 void tm1638_enable(tm1638_p t, bool enable)
143 {
144  t->enable = enable;
146 }
147 
148 /* See tm1638.h */
149 void tm1638_set_intensity(tm1638_p t, uint8_t intensity)
150 {
151  /* maximum intensity is 7 */
152  if (intensity > 7)
153  intensity = 7;
154 
155  t->intensity = intensity;
156 
158 }
159 
166 static void tm1638_send_config(const tm1638_p t)
167 {
169 }
170 
179 static uint8_t tm1638_calc_config(const tm1638_p t)
180 {
181  return 0x80 | (t->enable ? 8 : 0) | t->intensity;
182 }
183 
191 static void tm1638_send_raw(const tm1638_p t, uint8_t x)
192 {
193  /* The delays in this code are somewhat arbitrary: they work for me
194  but I make no claims that they are optimal or robust */
195  for(int i = 0; i < 8; i++)
196  {
197  bcm2835_gpio_write(t->clock, LOW);
198  delayMicroseconds(1);
199 
200  bcm2835_gpio_write(t->data, x & 1 ? HIGH : LOW);
201  delayMicroseconds(1);
202 
203  x >>= 1;
204  bcm2835_gpio_write(t->clock, HIGH);
205  delayMicroseconds(1);
206  }
207 }
208 
217 static uint8_t tm1638_receive_raw(const tm1638_p t)
218 {
219  /* The delays in this code are somewhat arbitrary: they work for me
220  but I make no claims that they are optimal or robust */
221 
222  uint8_t x = 0;
223 
224  /* Turn GPIO pin into an input */
225  bcm2835_gpio_fsel(t->data, BCM2835_GPIO_FSEL_INPT);
226 
227  for(int i = 0; i < 8; i++)
228  {
229  x <<= 1;
230 
231  bcm2835_gpio_write(t->clock, LOW);
232  delayMicroseconds(1);
233 
234  uint8_t y = bcm2835_gpio_lev(t->data);
235 
236  if (y & 1)
237  x |= 1;
238  delayMicroseconds(1);
239 
240  bcm2835_gpio_write(t->clock, HIGH);
241  delayMicroseconds(1);
242  }
243 
244  /* Turn GPIO pin back into an output */
245  bcm2835_gpio_fsel(t->data, BCM2835_GPIO_FSEL_OUTP);
246 
247  return x;
248 }
249 
257 static void tm1638_send_command(const tm1638_p t, uint8_t x)
258 {
259  /* The delays in this code are somewhat arbitrary: they work for me
260  but I make no claims that they are optimal or robust */
261  bcm2835_gpio_write(t->strobe, LOW);
262  delayMicroseconds(1);
263 
264  tm1638_send_raw(t, x);
265 
266  bcm2835_gpio_write(t->strobe, HIGH);
267  delayMicroseconds(1);
268 }
269 
278 static void tm1638_send_data(const tm1638_p t, uint8_t addr, uint8_t data)
279 {
280  /* The delays in this code are somewhat arbitrary: they work for me
281  but I make no claims that they are optimal or robust */
282  tm1638_send_command(t, 0x44);
283 
284  bcm2835_gpio_write(t->strobe, LOW);
285  delayMicroseconds(1);
286 
287  tm1638_send_raw(t, 0xc0 | addr);
288  tm1638_send_raw(t, data);
289 
290  bcm2835_gpio_write(t->strobe, HIGH);
291  delayMicroseconds(1);
292 }
293 
294 /* See tm1638.h */
295 void tm1638_set_7seg_raw(const tm1638_p t, uint8_t digit, uint8_t n)
296 {
297  tm1638_send_data(t, digit << 1, n);
298 }
299 
300 /* See tm1638.h */
301 void tm1638_set_7seg_text(const tm1638_p t, const char *str, uint8_t dots)
302 {
303  const char *p = str;
304 
305  for(int i = 0, j = 1; i < 8; i++, j <<= 1)
306  {
307  // We want the loop to finish, but don't walk over the end of the string
308  char c = *p;
309  if (c)
310  p++;
311 
312  uint8_t f = tm1638_font(c);
313 
314  if (dots & j)
315  f |= 128;
316 
317  tm1638_set_7seg_raw(t, i, f);
318  }
319 }
320 
321 /* See tm1638.h */
322 void tm1638_set_led(const tm1638_p t, uint8_t led, uint8_t cols)
323 {
324  tm1638_send_data(t, (led << 1) + 1, cols);
325 }
326 
327 /* See tm1638.h */
328 void tm1638_set_8leds(const tm1638_p t, uint8_t red, uint8_t green)
329 {
330  for(int i = 0, j = 128; i < 8; i++, j >>= 1)
331  tm1638_set_led(t, i, ((red & j) ? 1 : 0) + ((green & j) ? 2 : 0));
332 }
333 
334 /* See tm1638.h */
336 {
337  /* The delays in this code are somewhat arbitrary: they work for me
338  but I make no claims that they are optimal or robust */
339  tm1638_send_command(t, 0x40);
340 
341  bcm2835_gpio_write(t->strobe, LOW);
342  delayMicroseconds(1);
343 
344  tm1638_send_raw(t, 0xc0);
345  for(int i = 0; i < 16; i++)
346  tm1638_send_raw(t, 0x00);
347 
348  bcm2835_gpio_write(t->strobe, HIGH);
349  delayMicroseconds(1);
350 }
351 
352 /* See tm1638.h */
353 uint8_t tm1638_font(char c)
354 {
355  const uint8_t f[] = {
356  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360  0x00, 0x86, 0x22, 0x7e, 0x6d, 0x00, 0x00, 0x02,
361  0x30, 0x06, 0x63, 0x00, 0x04, 0x40, 0x80, 0x52,
362  0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x27,
363  0x7f, 0x6f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x53,
364  0x5f, 0x77, 0x7f, 0x39, 0x3f, 0x79, 0x71, 0x3d,
365  0x76, 0x06, 0x1f, 0x69, 0x38, 0x15, 0x37, 0x3f,
366  0x73, 0x67, 0x31, 0x6d, 0x78, 0x3e, 0x2a, 0x1d,
367  0x76, 0x6e, 0x5b, 0x39, 0x64, 0x0f, 0x00, 0x08,
368  0x20, 0x5f, 0x7c, 0x58, 0x5e, 0x7b, 0x31, 0x6f,
369  0x74, 0x04, 0x0e, 0x75, 0x30, 0x55, 0x54, 0x5c,
370  0x73, 0x67, 0x50, 0x6d, 0x78, 0x1c, 0x2a, 0x1d,
371  0x76, 0x6e, 0x47, 0x46, 0x06, 0x70, 0x01, 0x00
372  };
373 
374  return (c > 127) ? 0 : f[(unsigned char)c];
375 }
376 
377 /* See tm1638.h */
378 uint32_t tm1638_read_buttons(const tm1638_p t)
379 {
380  /* The delays in this code are somewhat arbitrary: they work for me
381  but I make no claims that they are optimal or robust */
382  bcm2835_gpio_write(t->strobe, LOW);
383  delayMicroseconds(1);
384 
385  tm1638_send_raw(t, 0x42);
386 
387  uint32_t x = 0;
388  for(int i = 0; i < 4; i++)
389  {
390  x <<= 8;
391  x |= tm1638_receive_raw(t);
392  }
393 
394  bcm2835_gpio_write(t->strobe, HIGH);
395  delayMicroseconds(1);
396 
397  return x;
398 }
399 
400 /* See tm1638.h */
402 {
403  uint32_t x = tm1638_read_buttons(t);
404  uint8_t y = 0;
405 
406  for(int i = 0; i < 4; i++)
407  {
408  y <<= 1;
409 
410  if (x & 0x80000000)
411  y |= 0x10;
412 
413  if (x & 0x08000000)
414  y |= 0x01;
415 
416  x <<= 8;
417  }
418 
419  return y;
420 }
421