#include #include #include #include #include #include #include static bool report_change = false; static void init() { /* PB2 BUTTON0 PB3 BUTTON1 PB4 BUTTON2 PB5 BUTTON3 PB6 BUTTON4 PC0 BUTTON5 PC1 BUTTON6 PC2 CANTX PC3 CANRX PC4 BUTTON7 PC5 VFDRS PC6 VFDRW PC7 VFDE PD0 VFDDB0 PD1 VFDDB1 PD2 VFDDB2 PD3 VFDDB3 PD4 VFDDB4 PD5 VFDDB5 PD6 VFDDB6 PD7 VFDDB7 */ // PB2, PB3, PB4, PB5, PB6, PC0, PC1, PC4: input, no pullup (button0..7) // PC5, PC6, PC7: output (VFD RS, RW, E), RS=0, RW=H, E=H // PD: output (VFD DB) - can be switched to input w/ pullup PORTB = 0x00; DDRB = 0x00; PORTC = _BV(PC6) | _BV(PC7); DDRC = _BV(PC5) | _BV(PC6) | _BV(PC7); PORTD = 0x00; DDRD = 0xff; // Initialize CAN interface can_init(BITRATE_125_KBPS); // Regular receive/transmit mode can_set_mode(NORMAL_MODE); // Filter for messages addressed to us (RTR on) can_filter_t us = { .id = CAN_HOSTID_DISPLAY, .mask = CAN_HOSTID_MASK, .flags = { .rtr = 1, .extended = 0, }, }; can_set_filter(0, &us); // Filter for public messages (RTR off) can_filter_t pub = { .id = CAN_HOSTID_BROADCAST, .mask = CAN_HOSTID_MASK, .flags = { .rtr = 0, .extended = 0, }, }; can_set_filter(1, &pub); // Enable interrupts to start reception sei(); } static uint8_t get_buttons() { uint8_t pinb = PINB; uint8_t pinc = PINC; uint8_t buttons = 0; if (pinb & _BV(PB2)) buttons |= _BV(0); if (pinb & _BV(PB3)) buttons |= _BV(1); if (pinb & _BV(PB4)) buttons |= _BV(2); if (pinb & _BV(PB5)) buttons |= _BV(3); if (pinb & _BV(PB6)) buttons |= _BV(4); if (pinc & _BV(PC0)) buttons |= _BV(5); if (pinc & _BV(PC1)) buttons |= _BV(6); if (pinc & _BV(PC4)) buttons |= _BV(7); return buttons; } static void send_status() { uint8_t status = get_buttons(); if (can_check_free_buffer()) { can_t msg = { .id = CAN_MSG_DISPLAY_STATUS, .flags = { .rtr = 0, }, .length = 1, .data = { (uint8_t) status, }, }; can_send_message(&msg); } } static uint8_t read_ir() { // switch PD to input DDRD = 0x00; // E=0 (enable/clock) RS=0 (IR) RW=1 (read) PORTC = (PORTC & ~(_BV(PC5) | _BV(PC7))) | _BV(PC6); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); _delay_us(0.16); uint8_t data = PIND; _delay_us(0.23 - 0.16); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); DDRD = 0xff; return data; } static uint8_t read_dr() { // switch PD to input DDRD = 0x00; // E=0 (enable/clock) RS=1 (IR) RW=1 (read) PORTC = (PORTC & ~_BV(PC7)) | (_BV(PC5) | _BV(PC6)); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); _delay_us(0.16); uint8_t data = PIND; _delay_us(0.23 - 0.16); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); DDRD = 0xff; return data; } static void write_ir(uint8_t data) { // E=0 (enable/clock) RS=0 (IR) RW=0 (write) PORTC &= ~(_BV(PC5) | _BV(PC6) | _BV(PC7)); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); // data PORTD = data; _delay_us(0.23); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); PORTD = 0x00; } static void write_dr(uint8_t data) { // E=0 (enable/clock) RS=1 (IR) RW=0 (write) PORTC = (PORTC & ~(_BV(PC6) | _BV(PC7))) | _BV(PC5); _delay_us(0.23); // E=1 (enable/clock) PORTC |= _BV(PC7); // data PORTD = data; _delay_us(0.23); // E=0 (enable/clock) PORTC &= ~_BV(PC7); _delay_us(0.01); // reset to idle PORTC = _BV(PC6) | _BV(PC7); PORTD = 0x00; } static void wait_ready() { while (read_ir() & _BV(7)); } static void write_display(uint8_t command, const uint8_t *data, uint8_t length) { wait_ready(); write_ir(command); for (uint8_t i = 0; i < length; i++) { write_dr(data[i]); } } static void loop() { // Check for new messages if (can_check_message()) { can_t msg = { 0 }; uint8_t status = can_get_message(&msg); if (status != 0) { switch (msg.id) { case CAN_MSG_DISPLAY_STATUS: send_status(); break; case CAN_MSG_DISPLAY_CMD: if (msg.length >= 1) { write_display(msg.data[0], &msg.data[1], msg.length - 1); } break; case CAN_MSG_AUTO_STATUS: if (msg.length == 1) { report_change = msg.data[0] ? true : false; } break; } } } } int main() { init(); while (1) { loop(); } }