I'm going to use the details section to contain the code used
There are three main modules, and these are all placed in the standard user directory that the ESP 8266 SDK uses for building code.
tm1638.h
#include "c_types.h"
#include "user_interface.h"
#include "ets_sys.h"
#include "gpio.h"
//You will have to os_intr_lock(); os_intr_unlock();
void tm1638OutBuffer( uint8_t * buffer, uint16_t length );
void tm1638OutByte( uint8_t data );
// 7 segment BITMAP for hex numbers
const uint16_t NUMBER_FONT[] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111, // 9
0b01110111, // A
0b01111100, // B
0b00111001, // C
0b01011110, // D
0b01111001, // E
0b01110001 // F
};
const uint16_t MINUS = 0b01000000;
// Bitmap for an Error String
const uint16_t ERROR_DATA[] = {
0b01111001, // E
0b01010000, // r
0b01010000, // r
0b01011100, // o
0b01010000, // r
0,
0,
0
};
// 7 Segment Bitmap for the ASCI Character set.. Note that this starts at ascii position 32, but
// the array starts at 0 so you need to subtract the difference from the key.
const uint16_t FONT_DEFAULT[] = {
0b00000000, // (32) <space>
0b10000110, // (33) !
0b00100010, // (34) "
0b01111110, // (35) #
0b01101101, // (36) $
0b00000000, // (37) %
0b00000000, // (38) &
0b00000010, // (39) '
0b00110000, // (40) (
0b00000110, // (41) )
0b01100011, // (42) *
0b00000000, // (43) +
0b00000100, // (44) ,
0b01000000, // (45) -
0b10000000, // (46) .
0b01010010, // (47) /
0b00111111, // (48) 0
0b00000110, // (49) 1
0b01011011, // (50) 2
0b01001111, // (51) 3
0b01100110, // (52) 4
0b01101101, // (53) 5
0b01111101, // (54) 6
0b00100111, // (55) 7
0b01111111, // (56) 8
0b01101111, // (57) 9
0b00000000, // (58) :
0b00000000, // (59) ;
0b00000000, // (60) <
0b01001000, // (61) =
0b00000000, // (62) >
0b01010011, // (63) ?
0b01011111, // (64) @
0b01110111, // (65) A
0b01111111, // (66) B
0b00111001, // (67) C
0b00111111, // (68) D
0b01111001, // (69) E
0b01110001, // (70) F
0b00111101, // (71) G
0b01110110, // (72) H
0b00000110, // (73) I
0b00011111, // (74) J
0b01101001, // (75) K
0b00111000, // (76) L
0b00010101, // (77) M
0b00110111, // (78) N
0b00111111, // (79) O
0b01110011, // (80) P
0b01100111, // (81) Q
0b00110001, // (82) R
0b01101101, // (83) S
0b01111000, // (84) T
0b00111110, // (85) U
0b00101010, // (86) V
0b00011101, // (87) W
0b01110110, // (88) X
0b01101110, // (89) Y
0b01011011, // (90) Z
0b00111001, // (91) [
0b01100100, // (92) \
0b00001111, // (93) ]
0b00000000, // (94) ^
0b00001000, // (95) _
0b00100000, // (96) `
0b01011111, // (97) a
0b01111100, // (98) b
0b01011000, // (99) c
0b01011110, // (100) d
0b01111011, // (101) e
0b00110001, // (102) f
0b01101111, // (103) g
0b01110100, // (104) h
0b00000100, // (105) i
0b00001110, // (106) j
0b01110101, // (107) k
0b00110000, // (108) l
0b01010101, // (109) m
0b01010100, // (110) n
0b01011100, // (111) o
0b01110011, // (112) p
0b01100111, // (113) q
0b01010000, // (114) r
0b01101101, // (115) s
0b01111000, // (116) t
0b00011100, // (117) u
0b00101010, // (118) v
0b00011101, // (119) w
0b01110110, // (120) x
0b01101110, // (121) y
0b01000111, // (122) z
0b01000110, // (123) {
0b00000110, // (124) |
0b01110000, // (125) }
0b00000001, // (126) ~
};
tm1636.c
#include "tm1638.h"
#include "ets_sys.h"
#include "osapi.h"
// These defines create simple shortcuts to switching IO pins on and off.
#define Set16_1 gpio_output_set(BIT16, 0, BIT16, 0);
#define Set16_0 gpio_output_set(0, BIT16, BIT16, 0);
#define Set14_1 gpio_output_set(BIT14, 0, BIT14, 0);
#define Set14_0 gpio_output_set(0, BIT14, BIT14, 0);
#define Set13_1 gpio_output_set(BIT13, 0, BIT13, 0);
#define Set13_0 gpio_output_set(0, BIT13, BIT13, 0);
#define Set12_1 gpio_output_set(BIT12, 0, BIT12, 0); // STR
#define Set12_0 gpio_output_set(0, BIT12, BIT12, 0);
#define DEBUG
// SEND_tm1638_stb_0 : Set the strobe pin which in this case is IO pin 12 to 0
void SEND_tm1638_stb_0()
{
#ifdef DEBUG
os_printf("s");
#endif
uint8_t time = 20;
while(time--)
{
Set12_0;
}
}
// SEND_tm1638_stb_0 : Set the strobe pin which in this case is IO pin 12 to 1
void SEND_tm1638_stb_1()
{
#ifdef DEBUG
os_printf("S");
#endif
uint8_t time = 20;
while(time--)
{
Set12_1;
}
}
// SEND_tm1638_stb_pulse : Send a pulse down the strobe line
void SEND_tm1638_stb_pulse()
{
uint8_t time = 20;
#ifdef DEBUG
os_printf("C");
#endif
while(time--)
{
Set12_1;
}
time = 10;
while(time--)
{
Set12_0;
}
}
// SEND_tm1638_clk_pulse : Send a pulse down the CLOCK line (pin 13)
void SEND_tm1638_clk_pulse()
{
// Configure a delay counter - All delays calculated using a Logic Analyser
uint8_t time = 20;
#ifdef DEBUG
os_printf("C");
#endif
while(time--)
{
Set13_0;
}
time = 10;
while(time--)
{
Set13_1;
}
}
// SEND_tm1638_data_1 : Set the data line to 1
void SEND_tm1638_data_1()
{
#ifdef DEBUG
os_printf("D");
#endif
Set14_1;
// Now send a clock pulse to send the data
SEND_tm1638_clk_pulse();
}
// SEND_tm1638_data_0 : Set the data line to 0
void SEND_tm1638_data_0()
{
#ifdef DEBUG
os_printf("d");
#endif
Set14_0
SEND_tm1638_clk_pulse();
}
// This routine outputs a single BYTE to the TM1638
void tm1638OutByte( uint8_t data )
{
SEND_tm1638_stb_pulse();
#ifdef DEBUG
os_printf("<");
#endif
// Send Data
if( data & 0x01 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x02 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x04 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x08 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x10 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x20 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x40 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( data & 0x80 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
#ifdef DEBUG
os_printf(">");
#endif
}
// This routine sends an ASCI string to the display
void tm1638OutBuffer( uint8_t * buffer, uint16_t length )
{
uint16_t i;
tm1638OutByte(0x02); // Set Display Mode
tm1638OutByte(0x40); // Set Data Instruction
tm1638OutByte(0xC0); // Set Display Address
SEND_tm1638_stb_0();
for( i = 0; i < length; i++ )
{
// Convert the string into a bitmap for the 7 seg displays using a predefined lookup.
uint8_t byte = FONT_DEFAULT[buffer[i]-32];
#ifdef DEBUG
os_printf("[");
#endif
// Send Data to the LED above the display. Just cheating here until I can work out
// an alternative way of handling them
if( byte & 0x01 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x02 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x04 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x08 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x10 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x20 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x40 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x80 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
// Send Data to the actual 7 seg display
if( byte & 0x01 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x02 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x04 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x08 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x10 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x20 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x40 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
if( byte & 0x80 ) SEND_tm1638_data_1(); else SEND_tm1638_data_0();
#ifdef DEBUG
os_printf("]");
#endif
}
// Send the final command 4 which enables the display
tm1638OutByte(0x8A);
// Send the strobe high
SEND_tm1638_stb_1();
}
// Routine to fetch the button presses back as a single byte with each bit representing a
// button in order.
uint16_t TM1638getButtons(void)
{
uint16_t keys = 0;
uint16_t time = 20;
uint16_t i=0;
uint16_t pinvalue=0;
#ifdef DEBUG
os_printf("in: TM1638getButtons");
#endif
// Send Command 1 - Which tells the TM1638 to send the button presses over the next set
// of clock pulses
tm1638OutByte(0x42);
// Keep the strobe low
SEND_tm1638_stb_0;
// The data line was configured as an OUTPUT, now switch to INPUT mode
gpio_output_set(0, 0, 0, BIT14); // Set GPIO14 as input
// Read all 4 bytes. the TM1638 can handle many buttons, this display unit
// only uses 8 buttons, but these are spread over the 32 bits returned
for ( i = 0; i < 31; i++ ) {
// Set Clock Low
time=20;
while(time--)
{
// Wait for stabilisation
Set13_0; //13 clock
}
// Now check the data line high or low
pinvalue=GPIO_INPUT_GET(GPIO_ID_PIN(14));
#ifdef DEBUG
os_printf("%u",pinvalue);
#endif
// Read input value on the Data Pin (14)
// Buttons are mapped across 4 bytes, at positions
// 1,5,9,13,17,21,25,29 Hence the various shift operations
if( i == 28 ) keys |= pinvalue << 0;
if( i == 20 ) keys |= pinvalue << 1;
if( i == 12 ) keys |= pinvalue << 2;
if( i == 4 ) keys |= pinvalue << 3;
if( i == 24 ) keys |= pinvalue << 4;
if( i == 16 ) keys |= pinvalue << 5;
if( i == 8 ) keys |= pinvalue << 6;
if( i == 0 ) keys |= pinvalue << 7;
// Set Clock High
time=20;
while(time--)
{
// Wait for stabilisation
Set13_1;
}
}
SEND_tm1638_stb_1();
// Reset 13 to be an output again
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO14);
return keys;
}
void tm1638Init()
{
gpio_init(); // Initialize the GPIO subsystem.
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO14);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO12);
Set14_0; // DATA
Set12_1; // CLOCK
Set13_1; // STROBE
os_printf("TM1638: Init Complete /n/r");
}
user_main.c
// Stuart Goggin March 2015
// ESP8266 and TM1638 LEDDisplayButton Demo
// - Initial experiments driving and reading from a el cheapo TM1638 display unit
#include "c_types.h"
#include "ip_addr.h"
#include "ets_sys.h"
#include "espconn.h"
#include "osapi.h"
#include "mem.h"
#include "gpio.h"
#include "os_type.h"
#include "user_config.h"
#include "user_interface.h"
#include "driver/uart.h"
#define user_procTaskPrio 0
#define user_procTaskQueueLen 1
void ICACHE_FLASH_ATTR network_init();
os_event_t user_procTaskQueue[user_procTaskQueueLen];
static void user_procTask(os_event_t *events);
LOCAL os_timer_t network_timer;
LOCAL os_timer_t key_timer;
static esp_udp global_udp; // UDP connect var (see espconn.h)
static struct espconn global_udp_connect; // Connection struct (see espconn.h)
static uint8_t udp_conn_ok = FALSE; // Bool to know if udp connection set
static void ICACHE_FLASH_ATTR udpNetworkRecvCb(void *arg, char *data, unsigned short len)
{
struct espconn *udpconn=(struct espconn *)arg;
// Diagnostic output via the FTDI USB port
os_printf("UDP RECV [");
os_printf(data,"%d");
os_printf("] ");
// We have received an UDP packet - so let's dump it to the TM1638 LED display as ASCII
// data.
// Disable the watchdog timer to prevent reboots during the data send operation
ets_wdt_disable();
os_intr_lock();
tm1638OutBuffer( data, len );
os_intr_unlock();
os_printf("\n\r");
}
void ICACHE_FLASH_ATTR network_start(void)
{
global_udp_connect.type=ESPCONN_UDP; // UDP Connection
global_udp_connect.state=ESPCONN_NONE; //
global_udp_connect.proto.udp=&global_udp; //
global_udp_connect.proto.udp->local_port=2222; // Set local port to 2222
if(espconn_create(&global_udp_connect) == 0) // IF Correctly setup
{
espconn_regist_recvcb(&global_udp_connect, udpNetworkRecvCb);
os_printf("UDP connection set\n\r");
udp_conn_ok = TRUE;
}
}
void ICACHE_FLASH_ATTR network_check_ip(void)
{
struct ip_info ipconfig;
os_timer_disarm(&network_timer); // Disarm timer
wifi_get_ip_info(STATION_IF, &ipconfig); // Get Wifi info
if (wifi_station_get_connect_status() == STATION_GOT_IP && ipconfig.ip.addr != 0)
{
network_start(); // Everything in order
}
else
{
os_printf("Waiting for IP...\n\r");
os_timer_setfn(&network_timer, (os_timer_func_t *)network_check_ip, NULL);
os_timer_arm(&network_timer, 1000, 0); // Check again in 1 second
}
}
// tobinstr: Integer to Binary
// Convert an integer in to a STRING containing the BINARY equivalent.
void tobinstr(int value, int bitsCount, char* output)
{
int i;
output[bitsCount] = '\0';
for (i = bitsCount - 1; i >= 0; --i, value >>= 1)
{
output[i] = (value & 1) + '0';
}
}
// key_check: Poll the keyboard and check for keypresses
// This routine is driven by a timer that operates periodically.
void ICACHE_FLASH_ATTR key_check(void)
{
uint8_t data;
char buffer[10]="....";
// Bring back a 8 bit value representing keypresses. 1 button per BIT
// This routine also decodes the odd bit vs button mapping of this unit.
data = TM1638getButtons();
// Convert the value into a displayable Binary value
// 0000 0000 - No buttons pressed
// 0101 1010 - four buttons pressed
tobinstr(data, 8, buffer);
os_printf("READ %u\n\r",data);
// Send the Binary string to the display
tm1638OutBuffer( buffer, 8);
}
//Do nothing function
static void ICACHE_FLASH_ATTR user_procTask(os_event_t *events)
{
os_delay_us(10);
}
// network init function
void ICACHE_FLASH_ATTR network_init()
{
os_timer_disarm(&network_timer);
os_timer_setfn(&network_timer, (os_timer_func_t *)network_check_ip, NULL);
os_timer_arm(&network_timer, 1000, 0);
}
//Init function
void ICACHE_FLASH_ATTR user_init()
{
uart_init(BIT_RATE_57600, BIT_RATE_57600); // Init UART @ 57600 bps
network_init(); // Init network timer
char ssid[32] = "SSID"; // Wifi SSID
char password[64] = "PASSWD"; // Wifi Password
//char ssid[32] = "B-LINK-MP01"; // Wifi SSID
//char password[64] = ""; // Wifi Password
struct station_config stationConf; // Station conf struct
wifi_set_opmode(0x1); // Set station mode
os_memcpy(&stationConf.ssid, ssid, 32); // Set settings
os_memcpy(&stationConf.password, password, 64); // Set settings
wifi_station_set_config(&stationConf); // Set wifi conf
// Init the driver for the tm1638 - just sets up the io pins
tm1638Init();
// Set up a repeating timer that checks for key presses periodically
os_timer_disarm(&key_timer);
os_timer_setfn(&key_timer, (os_timer_func_t *)key_check, NULL);
os_timer_arm(&key_timer, 500, 1);
//Start os task
system_os_task(user_procTask, user_procTaskPrio,user_procTaskQueue, user_procTaskQueueLen);
os_printf("\n\rStartup done\n\r"); // Startup done
}