VFD modular clock firmware
Dependencies: DipCortex-EEprom RTC flw mbed
VFDDisplay.cpp
- Committer:
- Backstrom
- Date:
- 2015-02-20
- Revision:
- 9:4bb5c30a475f
- Parent:
- 0:f6e68b4ce169
File content as of revision 9:4bb5c30a475f:
/* * VFD Modular Clock - mbed * (C) 2011-14 Akafugu Corporation * * 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 2 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. * */ #include "VFDDisplay.h" #include <stdarg.h> #define sbi(a, b) (a) |= (1 << (b)) #define cbi(a, b) (a) &= ~(1 << (b)) uint8_t calculate_segments_7(uint8_t character); VFDDisplay::VFDDisplay(PinName data, PinName clock, PinName latch, PinName blank, uint8_t digits) : m_mode(Long) , m_blink_mode(Full) , m_data(data) , m_clock(clock) , m_latch(latch) , m_blank(blank) , m_digits(digits) , m_multiplex_counter(0) , m_position(0) , m_scroll_offset(0) , m_message_length(0) , m_blink(false) , m_display_on(true) , m_brightness(10) { //m_blank.period_ms(1); //m_blank = 0.0; m_blank = 0; } void VFDDisplay::cls() { memset(m_buffer, ' ', MESSAGE_LIMIT); memset(m_char_buffer, ' ', MESSAGE_LIMIT); memset(m_dot_buffer, ' ', MESSAGE_LIMIT); m_position = 0; m_scroll_offset = 0; m_message_length = 0; } void VFDDisplay::setPosition(uint8_t pos) { m_position = pos; if (m_position >= MESSAGE_LIMIT) m_position = MESSAGE_LIMIT-1; } // Write 8 bits to HV5812 driver void VFDDisplay::writeHV5812(uint8_t data) { // shift out MSB first for (uint8_t i = 0; i < 8; i++) { if (!!(data & (1 << (7 - i)))) m_data = 1; else m_data = 0; m_clock = 1; m_clock = 0; } } const uint32_t BLINK_OFF_TIMER = 200; const uint32_t BLINK_ON_TIMER = 350; volatile uint32_t blink_countdown = BLINK_ON_TIMER; extern DigitalOut led; void VFDDisplay::multiplexTick() { char d; if (m_reverse_display) d = m_char_buffer[m_digits - m_multiplex_counter - 1 + m_scroll_offset]; else d = m_char_buffer[m_multiplex_counter + m_scroll_offset]; // fixme: does not work properly when scrolling if (m_dot_buffer[m_multiplex_counter + m_scroll_offset - 1] == '.') setDot(m_multiplex_counter, true); else setDot(m_multiplex_counter, false); if (m_blink) { blink_countdown--; if (blink_countdown == 0) { m_display_on = !m_display_on; if (m_display_on) blink_countdown = BLINK_ON_TIMER; else blink_countdown = BLINK_OFF_TIMER; } } handleBlink(d); m_multiplex_counter++; if (m_multiplex_counter > m_multiplex_limit) m_multiplex_counter = 0; } int VFDDisplay::printf(const char* format, ...) { va_list ap; va_start(ap, format); int ret = vsnprintf(m_buffer, MESSAGE_LIMIT, format, ap); va_end(ap); // post-processing for seamless dot support // splits buffer into two: one that contains characters // and one that contains dots uint8_t pos = 0; char* temp = m_buffer; while (*temp) { if (*temp == '.') { if (pos > 0) m_dot_buffer[pos-1] = '.'; temp++; } else { m_dot_buffer[pos] = ' '; m_char_buffer[pos++] = *temp; temp++; } } /* for (uint8_t i = 0; i < strlen(m_buffer); i++) { char c = m_buffer[i]; if (c == '.') { m_dot_buffer[pos-1] = '.'; //m_char_buffer[pos++] = c; i++; } else { m_dot_buffer[pos] = ' '; m_char_buffer[pos++] = c; } } */ m_dot_buffer[pos] = 0; m_char_buffer[pos] = 0; m_position = ret; m_message_length = strlen(m_char_buffer); return ret; } int VFDDisplay::_putc(int c) { // fixme: support dot buffer m_char_buffer[m_position] = c; m_buffer[m_position++] = c; m_message_length++; return 1; } int VFDDisplay::_getc() { return -1; } void VFDDisplay::scroll(int8_t spaces /*= 1*/) { m_scroll_offset += spaces; //if (m_scroll_offset > MESSAGE_LIMIT - m_digits) // m_scroll_offset = 0; } void VFDDisplay::resetScroll() { m_scroll_offset = 0; } bool VFDDisplay::scrollFinished() { if (m_scroll_offset > strlen(m_char_buffer)) return true; return false; } void VFDDisplay::setDot(uint8_t pos, bool on) { if (on) { sbi(m_dots, pos); } else { cbi(m_dots, pos); } } void VFDDisplay::toggleTimeMode() { if (m_mode == Short) m_mode = Extra; else if (m_mode == Extra) m_mode = Long; else m_mode = Short; } void VFDDisplay::setBrightness(uint8_t brite) { if (brite > 10) brite = 10; m_brightness = brite; } uint8_t VFDDisplay::incBrightness() { float f = m_blank; if (f >= 0.9) f = 0.0; f+= 0.1; m_blank = f; return f*10; }