/* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /** @file main.c @author King Kévin @date 2016 @brief show the time on a LED strip The LED strip consists of 60 WS2812b LEDs. The time is read from a DS1307 RTC module. */ /* standard libraries */ #include // standard integer types #include // standard I/O facilities #include // standard utilities #include // standard streams #include // error number utilities /* STM32 (including CM3) libraries */ #include // real-time control clock library #include // general purpose input output library #include // vector table definition #include // Cortex M3 utilities #include // interrupt utilities #include // external interrupt utilities /* own libraries */ #include "global.h" // board definitions #include "usart.h" // USART utilities #include "usb_cdcacm.h" // USB CDC ACM utilities #include "led_ws2812b.h" // WS2812b LEDs utilities #include "rtc_ds1307.h" // Real Time Clock DS1307 utilities /** @defgroup main_flags flag set in interrupts to be processed in main task @{ */ volatile bool button_flag = false; /**< flag set if board user button has been pressed */ /** @} */ /** the number of ticks in one second * @note the other values are derived from this value @ref main_ticks */ #define TICKS_PER_SECOND 255 /** @defgroup main_ticks ticks per time units * @note I have to use type variables because defines would be stored in signed integers, leading to an overflow it later calculations * @{ */ /** number of ticks in one second */ const uint32_t ticks_second = TICKS_PER_SECOND; /** number of ticks in one minute */ const uint32_t ticks_minute = 60*TICKS_PER_SECOND; /** number of ticks in one hour */ const uint32_t ticks_hour = 60*60*TICKS_PER_SECOND; /** number of ticks in one midday (12 hours) */ const uint32_t ticks_midday = 12*60*60*TICKS_PER_SECOND; /** @} */ /** RGB values for the WS2812b clock LEDs */ uint8_t clock_leds[WS2812B_LEDS*3] = {0}; int _write(int file, char *ptr, int len) { int i; if (file == STDOUT_FILENO || file == STDERR_FILENO) { for (i = 0; i < len; i++) { if (ptr[i] == '\n') { // add carrier return before line feed. this is recommended for most UART terminals usart_putchar_nonblocking('\r'); // a second line feed doesn't break the display cdcacm_putchar('\r'); // a second line feed doesn't break the display } usart_putchar_nonblocking(ptr[i]); // send byte over USART cdcacm_putchar(ptr[i]); // send byte over USB } return i; } errno = EIO; return -1; } void led_on(void) { #ifdef SYSTEM_BOARD gpio_clear(LED_PORT, LED_PIN); #elif MAPLE_MINI gpio_set(LED_PORT, LED_PIN); #endif } void led_off(void) { #ifdef SYSTEM_BOARD gpio_set(LED_PORT, LED_PIN); #elif MAPLE_MINI gpio_clear(LED_PORT, LED_PIN); #endif } void led_toggle(void) { gpio_toggle(LED_PORT, LED_PIN); } /** @brief switch off all clock LEDs * @note LEDs need to be set separately */ static void clock_clear(void) { // set all colors of all LEDs to 0 for (uint16_t i=0; i=WS2812B_LEDS*255 || led_minute>=WS2812B_LEDS*255) { // a calculation error occurred return; } // show hours and minutes on LEDs if (led_hour>led_minute) { // show hours in blue (and clear other LEDs) for (uint16_t led=0; led=0xff) { // full hours clock_leds[led*3+2] = 0xff; } else { // running hours clock_leds[led*3+2] = led_hour; } led_hour -= clock_leds[led*3+2]; } // show minutes in green (override hours) for (uint16_t led=0; led0; led++) { clock_leds[led*3+0] = 0; if (led_minute>=0xff) { // full minutes clock_leds[led*3+1] = 0xff; } else { // running minutes clock_leds[led*3+1] = led_minute; } led_minute -= clock_leds[led*3+1]; clock_leds[led*3+2] = 0; } } else { // show minutes in green (and clear other LEDs) for (uint16_t led=0; led=0xff) { // full minutes clock_leds[led*3+1] = 0xff; } else { // running minutes clock_leds[led*3+1] = led_minute; } led_minute -= clock_leds[led*3+1]; clock_leds[led*3+2] = 0; } // show hours in blue (override minutes) for (uint16_t led=0; led0; led++) { clock_leds[led*3+0] = 0; clock_leds[led*3+1] = 0; if (led_hour>=0xff) { // full hours clock_leds[led*3+2] = 0xff; } else { // running hours clock_leds[led*3+2] = led_hour; } led_hour -= clock_leds[led*3+2]; } } // don't show seconds on full minute (better for first time setting, barely visible else) if (time%ticks_minute==0) { return; } uint16_t led_second = (WS2812B_LEDS*(time%ticks_minute))/ticks_minute; // get LED for seconds uint8_t brightness_second = (255*(time%ticks_second))/ticks_second; // get brightness for seconds // set second LED clock_leds[led_second*3+0] = brightness_second; clock_leds[led_second*3+1] = 0; clock_leds[led_second*3+2] = 0; // set previous LED clock_leds[((led_second-1)%WS2812B_LEDS)*3+0] = 0xff-brightness_second; clock_leds[((led_second-1)%WS2812B_LEDS)*3+1] = 0; clock_leds[((led_second-1)%WS2812B_LEDS)*3+2] = 0; } /** @brief set the LEDs * @details set the LED colors on WS2812b LEDs * @note WS2812b LED color values need to be transmitted separately */ static void leds_set(void) { for (uint16_t i=0; i