809 lines
14 KiB
C
809 lines
14 KiB
C
#include <avr/io.h>
|
|
#include <avr/interrupt.h>
|
|
#include <avr/pgmspace.h>
|
|
|
|
#ifdef ENABLE_OLED
|
|
# include "i2c_master.h"
|
|
#endif
|
|
|
|
// Port A0 - A3 -> LED Data
|
|
// Port A5 -> Select Output
|
|
// Port A4, A6 -> I2C Display
|
|
// Port A7 -> Enable Output
|
|
// Port B2 -> Button Input (Pulled-Up)
|
|
|
|
// Button Press Times
|
|
#define BTN_LONG_PRESS_MS 1000
|
|
#define BTN_DEBOUNCE_MS 50
|
|
|
|
// Size of each strip
|
|
#define LED0_COUNT 12
|
|
#define LED1_COUNT 12
|
|
#define LED2_COUNT 12
|
|
#define LED3_COUNT 15
|
|
|
|
// ms per frame
|
|
#define LED0_MS 500
|
|
#define LED1_MS 500
|
|
#define LED2_MS 500
|
|
#define LED3_MS 400
|
|
|
|
// ms offset
|
|
#define LED0_MS_OFFSET 0
|
|
#define LED1_MS_OFFSET 0
|
|
#define LED2_MS_OFFSET 0
|
|
#define LED3_MS_OFFSET 0
|
|
|
|
#define LED0_PORT PORTA
|
|
#define LED1_PORT PORTA
|
|
#define LED2_PORT PORTA
|
|
#define LED3_PORT PORTA
|
|
|
|
#define LED0_BIT 0
|
|
#define LED1_BIT 1
|
|
#define LED2_BIT 2
|
|
#define LED3_BIT 3
|
|
|
|
// NeoPixel Defines
|
|
#define T1H 900 // Width of a 1 bit in ns
|
|
#define T1L 600 // Width of a 1 bit in ns
|
|
#define T0H 400 // Width of a 0 bit in ns
|
|
#define T0L 900 // Width of a 0 bit in ns
|
|
#define RES 6000
|
|
#define RES_HALF RES / 2
|
|
#define NS_PER_SEC (1000000000L)
|
|
#define CYCLES_PER_SEC (F_CPU)
|
|
#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
|
|
#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
|
|
|
|
// ms counter
|
|
uint64_t ms = 0;
|
|
|
|
// Led update times
|
|
uint64_t led_ms_update[4] = {LED0_MS_OFFSET, LED1_MS_OFFSET, LED2_MS_OFFSET,
|
|
LED3_MS_OFFSET};
|
|
|
|
#ifdef ENABLE_OLED
|
|
// I2C Display Address
|
|
uint8_t display_address = 0x78;
|
|
|
|
// Draw only changed digits
|
|
uint8_t old_time[7] = {0, 0, 0, 0, 0, 0, 0};
|
|
|
|
uint64_t old_time_ms = 0;
|
|
#endif
|
|
|
|
// ms Counter Func
|
|
ISR(TIM1_CAPT_vect)
|
|
{
|
|
ms += 10;
|
|
}
|
|
|
|
// NeoPixel Funcs
|
|
static inline void send_bit_led0(uint8_t bitVal);
|
|
static inline void send_bit_led1(uint8_t bitVal);
|
|
static inline void send_bit_led2(uint8_t bitVal);
|
|
static inline void send_bit_led3(uint8_t bitVal);
|
|
static inline void send_byte(uint8_t byte, uint8_t led);
|
|
static inline void send_pixel(uint8_t r, uint8_t g, uint8_t b, uint8_t led);
|
|
void show_leds();
|
|
|
|
// Hardware Init
|
|
void init();
|
|
|
|
// Function to switch states
|
|
void state_switch(uint8_t is_onoff);
|
|
|
|
#ifdef ENABLE_OLED
|
|
// I2C Display Funcs
|
|
void init_display();
|
|
void send_command(uint8_t cmd);
|
|
void set_display_coords(uint8_t x_start, uint8_t x_end, uint8_t y_start, uint8_t y_end);
|
|
void show_time(uint64_t ms);
|
|
void draw_dots(uint8_t pos);
|
|
void draw_digit(uint8_t pos, uint8_t digit);
|
|
#endif
|
|
|
|
// Call function to show a frame and prepare idx for next frame
|
|
void sun_and_moon(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led);
|
|
void clock_no_bg(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led);
|
|
void loading(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led);
|
|
void off(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led);
|
|
|
|
void (*func_list[4])(uint8_t, uint8_t*, uint8_t, uint8_t) =
|
|
{
|
|
sun_and_moon, clock_no_bg, loading, off
|
|
};
|
|
|
|
void (*send_ptr[4])(uint8_t) =
|
|
{
|
|
send_bit_led0, send_bit_led1, send_bit_led2, send_bit_led3
|
|
};
|
|
|
|
enum states
|
|
{
|
|
STATE_SUN_MOON = 0,
|
|
STATE_CLOCK_NO1,
|
|
STATE_CLOCK_NO2,
|
|
STATE_LOADING,
|
|
STATE_PC
|
|
};
|
|
|
|
uint8_t led0_idx = 0;
|
|
uint8_t led1_idx = 0;
|
|
uint8_t led2_idx = 0;
|
|
uint8_t led3_idx = 0;
|
|
uint8_t colour = 0;
|
|
uint8_t func_idx = 0;
|
|
uint8_t backup_func_idx = sizeof(func_list) / sizeof(func_list[0]) - 1;
|
|
uint8_t btn_old_state = 0;
|
|
uint8_t colour_state = STATE_SUN_MOON;
|
|
uint8_t current_state;
|
|
uint64_t btn_down = -1;
|
|
|
|
int main()
|
|
{
|
|
uint8_t show;
|
|
|
|
init();
|
|
// Main loop
|
|
while(1)
|
|
{
|
|
show = 0;
|
|
|
|
if (ms >= led_ms_update[0])
|
|
{
|
|
led_ms_update[0] += LED0_MS;
|
|
func_list[func_idx](LED0_COUNT, &led0_idx, colour, 0);
|
|
show = 1;
|
|
}
|
|
|
|
if (ms >= led_ms_update[1])
|
|
{
|
|
led_ms_update[1] += LED1_MS;
|
|
func_list[func_idx](LED1_COUNT, &led1_idx, colour, 1);
|
|
show = 1;
|
|
}
|
|
|
|
if (ms >= led_ms_update[2])
|
|
{
|
|
led_ms_update[2] += LED2_MS;
|
|
func_list[func_idx](LED2_COUNT, &led2_idx, colour, 2);
|
|
show = 1;
|
|
}
|
|
|
|
if (ms >= led_ms_update[3])
|
|
{
|
|
led_ms_update[3] += LED3_MS;
|
|
func_list[func_idx](LED3_COUNT, &led3_idx, colour, 3);
|
|
show = 1;
|
|
}
|
|
|
|
if (show)
|
|
{
|
|
show_leds();
|
|
}
|
|
|
|
#ifdef ENABLE_OLED
|
|
if (ms - 1000 >= old_time_ms)
|
|
{
|
|
show_time(ms);
|
|
old_time_ms = ms;
|
|
}
|
|
#endif
|
|
|
|
// Button Press
|
|
current_state = PINB & 0x04;
|
|
if (btn_old_state && !current_state)
|
|
{
|
|
btn_down = ms;
|
|
}
|
|
|
|
// Button Unpress
|
|
if (!btn_old_state && current_state)
|
|
{
|
|
if (ms - BTN_DEBOUNCE_MS >= btn_down)
|
|
{
|
|
btn_down = -1;
|
|
state_switch(0);
|
|
}
|
|
}
|
|
btn_old_state = current_state;
|
|
|
|
// Long Press Time Has Passed
|
|
if (ms - BTN_LONG_PRESS_MS >= btn_down)
|
|
{
|
|
btn_down = -1;
|
|
state_switch(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void send_bit_led0(uint8_t value)
|
|
{
|
|
if (value)
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED0_PORT)),
|
|
[bit] "I" (LED0_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T1H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T1L) - 2)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED0_PORT)),
|
|
[bit] "I" (LED0_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
|
|
);
|
|
}
|
|
}
|
|
|
|
inline void send_bit_led1(uint8_t value)
|
|
{
|
|
if (value)
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED1_PORT)),
|
|
[bit] "I" (LED1_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T1H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T1L) - 2)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED1_PORT)),
|
|
[bit] "I" (LED1_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
|
|
);
|
|
}
|
|
}
|
|
|
|
inline void send_bit_led2(uint8_t value)
|
|
{
|
|
if (value)
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED2_PORT)),
|
|
[bit] "I" (LED2_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T1H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T1L) - 2)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED2_PORT)),
|
|
[bit] "I" (LED2_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
|
|
);
|
|
}
|
|
}
|
|
|
|
inline void send_bit_led3(uint8_t value)
|
|
{
|
|
if (value)
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED3_PORT)),
|
|
[bit] "I" (LED3_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T1H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T1L) - 2)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
asm volatile
|
|
(
|
|
"sbi %[port], %[bit] \n\t"
|
|
".rept %[onCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
"cbi %[port], %[bit] \n\t"
|
|
".rept %[offCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[port] "I" (_SFR_IO_ADDR(LED3_PORT)),
|
|
[bit] "I" (LED3_BIT),
|
|
[onCycles] "I" (NS_TO_CYCLES(T0H) - 2),
|
|
[offCycles] "I" (NS_TO_CYCLES(T0L) - 2)
|
|
);
|
|
}
|
|
}
|
|
|
|
inline void send_byte(uint8_t byte, uint8_t led)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
send_ptr[led](byte & 0xF0);
|
|
byte <<= 1;
|
|
}
|
|
}
|
|
|
|
inline void send_pixel(uint8_t r, uint8_t g, uint8_t b, uint8_t led)
|
|
{
|
|
cli();
|
|
send_byte(g, led);
|
|
send_byte(r, led);
|
|
send_byte(b, led);
|
|
sei();
|
|
}
|
|
|
|
void show_leds()
|
|
{
|
|
asm volatile
|
|
(
|
|
".rept %[resCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
".rept %[resCycles] \n\t"
|
|
"nop \n\t"
|
|
".endr \n\t"
|
|
::
|
|
[resCycles] "I" (NS_TO_CYCLES(RES_HALF) - 2)
|
|
);
|
|
}
|
|
|
|
void init()
|
|
{
|
|
DDRA = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 7);
|
|
PORTB = (1 << 2);
|
|
|
|
#ifdef ENABLE_OLED
|
|
init_display();
|
|
#endif
|
|
|
|
// TIM1 init - CTC - prescaler 8 - 10ms interrupt
|
|
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
|
|
ICR1 = (F_CPU / 8 / 100) - 1;
|
|
TIMSK1 = (1 << ICIE1);
|
|
sei();
|
|
}
|
|
|
|
void state_switch(uint8_t is_onoff)
|
|
{
|
|
uint8_t tmp_func_idx;
|
|
|
|
if (is_onoff == 0)
|
|
{
|
|
// If we're off don't change anything
|
|
if (func_idx == sizeof(func_list) / sizeof(func_list[0]) - 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (colour_state)
|
|
{
|
|
case STATE_SUN_MOON:
|
|
func_idx = 1;
|
|
colour_state = STATE_CLOCK_NO1;
|
|
colour = 0;
|
|
break;
|
|
|
|
case STATE_CLOCK_NO1:
|
|
colour_state = STATE_CLOCK_NO2;
|
|
colour = 1;
|
|
break;
|
|
|
|
case STATE_CLOCK_NO2:
|
|
func_idx = 2;
|
|
colour_state = STATE_LOADING;
|
|
colour = 0;
|
|
break;
|
|
|
|
case STATE_LOADING:
|
|
func_idx = 0;
|
|
PORTA ^= 0x20;
|
|
colour_state = STATE_PC;
|
|
break;
|
|
|
|
case STATE_PC:
|
|
PORTA ^= 0x20;
|
|
colour_state = STATE_SUN_MOON;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tmp_func_idx = backup_func_idx;
|
|
backup_func_idx = func_idx;
|
|
func_idx = tmp_func_idx;
|
|
}
|
|
led0_idx = 0;
|
|
led1_idx = 0;
|
|
led2_idx = 0;
|
|
led3_idx = 0;
|
|
}
|
|
|
|
void sun_and_moon(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led)
|
|
{
|
|
uint8_t i;
|
|
uint8_t colour1[3] = {0xFF, 0x80, 0x00};
|
|
uint8_t colour2[3] = {0x00, 0x80, 0xFF};
|
|
uint8_t min;
|
|
uint8_t max;
|
|
|
|
if (*idx <= count / 2)
|
|
{
|
|
min = *idx;
|
|
max = *idx + count / 2;
|
|
|
|
for (i = 0; i < min; ++i)
|
|
{
|
|
send_pixel(colour1[0], colour1[1], colour1[2], led);
|
|
}
|
|
for (i = min; i < max; ++i)
|
|
{
|
|
send_pixel(colour2[0], colour2[1], colour2[2], led);
|
|
}
|
|
for (i = max; i < count; ++i)
|
|
{
|
|
send_pixel(colour1[0], colour1[1], colour1[2], led);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
min = *idx - count / 2;
|
|
max = *idx;
|
|
|
|
for (i = 0; i < min; ++i)
|
|
{
|
|
send_pixel(colour2[0], colour2[1], colour2[2], led);
|
|
}
|
|
for (i = min; i < max; ++i)
|
|
{
|
|
send_pixel(colour1[0], colour1[1], colour1[2], led);
|
|
}
|
|
for (i = max; i < count; ++i)
|
|
{
|
|
send_pixel(colour2[0], colour2[1], colour2[2], led);
|
|
}
|
|
}
|
|
(*idx)++;
|
|
(*idx) %= count;
|
|
}
|
|
|
|
void clock_no_bg(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led)
|
|
{
|
|
uint8_t i;
|
|
uint8_t colour1[3] = {0xFF, 0x80, 0x00};
|
|
uint8_t colour2[3] = {0x00, 0x80, 0xFF};
|
|
uint8_t black[3] = {0x00, 0x00, 0x00};
|
|
uint8_t* main_colour;
|
|
|
|
if (0 == colour)
|
|
{
|
|
main_colour = colour1;
|
|
}
|
|
else
|
|
{
|
|
main_colour = colour2;
|
|
}
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i == *idx)
|
|
{
|
|
send_pixel(main_colour[0], main_colour[1], main_colour[2], led);
|
|
}
|
|
else
|
|
{
|
|
send_pixel(black[0], black[1], black[2], led);
|
|
}
|
|
}
|
|
|
|
(*idx)++;
|
|
(*idx) %= count;
|
|
}
|
|
|
|
void loading(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led)
|
|
{
|
|
uint8_t i;
|
|
uint8_t colour1[3] = {0xFF, 0x80, 0x00};
|
|
uint8_t colour2[3] = {0x00, 0x80, 0xFF};
|
|
|
|
if (*idx < count)
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i <= *idx)
|
|
{
|
|
send_pixel(colour1[0], colour1[1], colour1[2], led);
|
|
}
|
|
else
|
|
{
|
|
send_pixel(colour2[0], colour2[1], colour2[2], led);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i <= *idx - count)
|
|
{
|
|
send_pixel(colour2[0], colour2[1], colour2[2], led);
|
|
}
|
|
else
|
|
{
|
|
send_pixel(colour1[0], colour1[1], colour1[2], led);
|
|
}
|
|
}
|
|
}
|
|
|
|
(*idx)++;
|
|
(*idx) %= count * 2;
|
|
}
|
|
|
|
void off(uint8_t count, uint8_t* idx, uint8_t colour, uint8_t led)
|
|
{
|
|
uint8_t black[3] = {0x00, 0x00, 0x00};
|
|
|
|
for (uint8_t i = 0; i < count; ++i)
|
|
{
|
|
send_pixel(black[0], black[1], black[2], led);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_OLED
|
|
void init_display()
|
|
{
|
|
uint16_t i = 0;
|
|
uint8_t cmdInit[] =
|
|
{
|
|
0xAE, 0xD5, 0x80, 0xA8,
|
|
0x1F, 0xD3, 0x00, 0x40,
|
|
0x8D, 0x14, 0x20, 0x00,
|
|
0xA1, 0xC8, 0xDA, 0x02,
|
|
0x81, 0x8F, 0xD9, 0xF1,
|
|
0xDB, 0x40, 0xA4, 0xA6,
|
|
0x2E, 0xAF
|
|
};
|
|
|
|
i2c_init();
|
|
for (i = 0; i < sizeof(cmdInit); ++i)
|
|
{
|
|
send_command(cmdInit[i]);
|
|
}
|
|
|
|
set_display_coords(0x00, 0x7F, 0x00, 0x03);
|
|
|
|
for(i = 0; i < 128*4; ++i)
|
|
{
|
|
i2c_write(0x00);
|
|
}
|
|
i2c_stop();
|
|
}
|
|
|
|
void send_command(uint8_t cmd)
|
|
{
|
|
i2c_start(display_address);
|
|
i2c_write(0x00);
|
|
i2c_write(cmd);
|
|
i2c_stop();
|
|
}
|
|
|
|
void set_display_coords(uint8_t x_start, uint8_t x_end, uint8_t y_start, uint8_t y_end)
|
|
{
|
|
send_command(0x21);
|
|
send_command(x_start);
|
|
send_command(x_end);
|
|
|
|
send_command(0x22);
|
|
send_command(y_start);
|
|
send_command(y_end);
|
|
|
|
i2c_start(display_address);
|
|
i2c_write(0x40);
|
|
}
|
|
|
|
void show_time(uint64_t ms)
|
|
{
|
|
uint8_t new_time[7] = {0, 0, 0, 0, 0, 0, 0};
|
|
uint8_t i;
|
|
|
|
ms /= 1000;
|
|
new_time[6] = ms % 10;
|
|
ms /= 10;
|
|
new_time[5] = ms % 6;
|
|
ms /= 6;
|
|
new_time[4] = ms % 10;
|
|
ms /= 10;
|
|
new_time[3] = ms % 6;
|
|
ms /= 6;
|
|
new_time[2] = ms % 10;
|
|
ms /= 10;
|
|
new_time[1] = ms % 10;
|
|
ms /= 10;
|
|
new_time[0] = ms % 10;
|
|
|
|
for (i = 0; i < 7; ++i)
|
|
{
|
|
if (old_time[i] != new_time[i])
|
|
{
|
|
if (((2 == i) || (4 == i)) && (0 == old_time[i]))
|
|
{
|
|
draw_dots(i);
|
|
}
|
|
|
|
draw_digit(i, new_time[i]);
|
|
}
|
|
old_time[i] = new_time[i];
|
|
}
|
|
}
|
|
|
|
void draw_dots(uint8_t pos)
|
|
{
|
|
// Between hours and minutes
|
|
if (2 == pos)
|
|
{
|
|
set_display_coords(50, 53, 1, 2);
|
|
}
|
|
|
|
// Between minutes and seconds
|
|
if (4 == pos)
|
|
{
|
|
set_display_coords(90, 93, 1, 2);
|
|
}
|
|
|
|
i2c_write(0x0F);
|
|
i2c_write(0x0F);
|
|
i2c_write(0x0F);
|
|
i2c_write(0x0F);
|
|
i2c_write(0xF0);
|
|
i2c_write(0xF0);
|
|
i2c_write(0xF0);
|
|
i2c_write(0xF0);
|
|
i2c_stop();
|
|
}
|
|
|
|
void draw_digit(uint8_t pos, uint8_t digit)
|
|
{
|
|
uint8_t i, j;
|
|
uint8_t x_start;
|
|
uint8_t x_end;
|
|
uint8_t row[12];
|
|
|
|
x_start = pos * 16;
|
|
|
|
if (pos > 2)
|
|
{
|
|
x_start += 8;
|
|
}
|
|
|
|
if (pos > 4)
|
|
{
|
|
x_start += 8;
|
|
}
|
|
|
|
x_end = x_start + 15;
|
|
set_display_coords(x_start + 2, x_end - 2, 0, 3);
|
|
|
|
row[0] = 0xF0;
|
|
row[1] = 0x00;
|
|
row[2] = 0x00;
|
|
row[3] = 0x03;
|
|
row[4] = 0x00;
|
|
row[5] = 0x00;
|
|
row[6] = 0xC0;
|
|
row[7] = 0xC0;
|
|
row[8] = 0xC0;
|
|
row[9] = 0x0F;
|
|
row[10] = 0x03;
|
|
row[11] = 0x0F;
|
|
|
|
if (digit > 1)
|
|
{
|
|
row[1] = 0xF0;
|
|
}
|
|
|
|
if (digit > 2)
|
|
{
|
|
row[2] = 0xF0;
|
|
}
|
|
|
|
for (i = 3; i < 8; ++i)
|
|
{
|
|
if (digit > i)
|
|
{
|
|
row[i] = 0xFF;
|
|
}
|
|
}
|
|
|
|
if (0 == digit)
|
|
{
|
|
row[2] = 0xF0;
|
|
row[3] = 0xFF;
|
|
row[5] = 0xFF;
|
|
row[6] = 0xFF;
|
|
row[8] = 0xFF;
|
|
}
|
|
|
|
for (i = 0; i < 12 * 4; ++i)
|
|
{
|
|
i2c_write(row[i / 4]);
|
|
}
|
|
|
|
i2c_stop();
|
|
}
|
|
|
|
#endif
|