#include "Arduino.h" #include "timer-api.h" #define DEBUG #define DEBUG_SERIAL_PARSER #define DDR_BYTE 0 #define PORT_BYTE 1 #define BLINK_STATE 0 #define DESIRED_PWM_VALUE 1 #define BLINK 1 #define ROWS 5 #define COLUMNS 4 #define LED_COUNT ROWS * COLUMNS #define CONTROL_DDRX DDRC #define CONTROL_PORTX PORTC #define A 16 #define B 8 #define C 4 #define D 2 #define E 1 #define DEBUG_LINE 32 /* LED Matrix; only useful without multiplexing * * uint8_t ledMatrix[LED_COUNT][2] = { //DDR_BYTE //PORT_BYTE // abcde // abcde //RowColumn Index { 0b00000011 , 0b00000010 }, //ED 00 { 0b00001001 , 0b00000100 }, //EC 01 { 0b00001001 , 0b00001000 }, //EB 02 { 0b00010001 , 0b00010000 }, //EA 03 // abcde // abcde { 0b00000011 , 0b00000001 }, //DE 04 { 0b00000110 , 0b00000100 }, //DC 05 { 0b00001010 , 0b00001000 }, //DB 06 { 0b00010010 , 0b00010000 }, //DA 07 // abcde // abcde { 0b00000101 , 0b00000001 }, //CE 08 { 0b00000110 , 0b00000010 }, //CD 09 { 0b00001100 , 0b00001000 }, //CB 10 { 0b00010100 , 0b00010000 }, //CA 11 // abcde // abcde { 0b00001001 , 0b00000001 }, //BE 12 { 0b00001010 , 0b00000010 }, //BD 13 { 0b00001100 , 0b00000100 }, //BC 14 { 0b00011000 , 0b00010000 }, //BA 15 // abcde // abcde { 0b00010001 , 0b00000001 }, //AE 16 { 0b00010010 , 0b00000010 }, //AD 17 { 0b00010100 , 0b00000100 }, //AC 18 { 0b00011000 , 0b00001000 }, //AB 19 }; */ const uint8_t displayMatrix[ROWS][COLUMNS + 1] ={ //Enable Row, Columns { E, D, C, B, A}, { D, E, C, B, A}, { C, E, D, B, A}, { B, E, D, C, A}, { A, E, D, C, B}, }; //BLINK_STATE DESIRED_PWM_VALUE volatile uint8_t outputBuffer[ROWS][COLUMNS][1 + 1]; const uint16_t pwmtable_8D[32] = { 0, 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 10, 11, 13, 16, 19, 23, 27, 32, 38, 45, 54, 64, 76, 91, 108, 128, 152, 181, 215, 255 }; uint8_t PercentTo255(uint8_t percent){ double result = percent * 255.0 / 100.0; result = round(result); return (uint8_t)result; } //found on: forgotten link String Split(String data, char separator, int index) { int found = 0; int strIndex[] = { 0, -1 }; int maxIndex = data.length() - 1; for (int i = 0; i <= maxIndex && found <= index; i++) { if (data.charAt(i) == separator || i == maxIndex) { found++; strIndex[0] = strIndex[1] + 1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; } unsigned int RowCharColumnCharToIndex(char value){ unsigned int result = (value - ('A' - '0')) - '0'; return result; } void setup() { Serial.begin(9600); for(int8_t row = 0; row < ROWS; row++){ for(int8_t column = 0; column < COLUMNS; column++){ outputBuffer[row][column][DESIRED_PWM_VALUE] = 128; } } // 66666 Hz 15.0us, 8, 29 // 62500 Hz 16.0us 8, 31 timer_init_ISR(TIMER_DEFAULT, TIMER_PRESCALER_1_8, 29); } void loop() { //Serial Parser #ifdef DEBUG static String command; while(Serial.available()) { char in = (char)Serial.read(); if(in == '\n') { command.toUpperCase(); String led_string = Split(command, ' ', 0); String state_string = Split(command, ' ', 1); String percent_string = Split(command, ' ', 2); unsigned int row = 0; unsigned int column = 0; #ifdef DEBUG_SERIAL_PARSER Serial.print("Received Command: ");Serial.println(command); #endif if(led_string[0] >= 'A' && led_string[0] <= 'E'){ row = RowCharColumnCharToIndex(led_string[0]); }else{ #ifdef DEBUG_SERIAL_PARSER Serial.println("Command Rejected! Because LED unknown!"); #endif command == ""; break; } if(led_string[1] >= 'A' && led_string[1] <= 'D'){ column = RowCharColumnCharToIndex(led_string[1]); }else{ #ifdef DEBUG_SERIAL_PARSER Serial.println("Command Rejected! Because LED unknown!"); #endif command = ""; break; } if(percent_string == " "){ #ifdef DEBUG_SERIAL_PARSER Serial.println("Command Rejected! Because PWM Percent Value is empty!"); #endif command = ""; break; }else if(percent_string.toInt() < 0 || percent_string.toInt() > 100){ #ifdef DEBUG_SERIAL_PARSER Serial.println("Command Rejected! Because PWM Percent Value not between 0 and 100!"); #endif command = ""; break; } #ifdef DEBUG_SERIAL_PARSER Serial.print("Processed Command: ");Serial.print(led_string[0]);Serial.println(led_string[1]); Serial.print("Row: ");Serial.print(row + 1);Serial.print(" ");Serial.print("Column:");Serial.println(column + 1); #endif if(state_string == "OFF"){ outputBuffer[row][column][BLINK_STATE] = 0; outputBuffer[row][column][DESIRED_PWM_VALUE] = 0; }else if(state_string == "ON"){ outputBuffer[row][column][BLINK_STATE] = 0; if(percent_string == ""){ outputBuffer[row][column][DESIRED_PWM_VALUE] = 255; } else{ outputBuffer[row][column][DESIRED_PWM_VALUE] = PercentTo255((uint8_t)percent_string.toInt()); } }else if(state_string == "BLINK"){ outputBuffer[row][column][BLINK_STATE] = BLINK; if(percent_string == ""){ outputBuffer[row][column][DESIRED_PWM_VALUE] = 255; } else{ outputBuffer[row][column][DESIRED_PWM_VALUE] = PercentTo255((uint8_t)percent_string.toInt()); } }else{ #ifdef DEBUG_SERIAL_PARSER Serial.println("Command rejected! Because State unknown."); #endif command = ""; break; } #ifdef DEBUG_SERIAL_PARSER Serial.print("State: ");Serial.print(state_string);Serial.print(" ");Serial.println(outputBuffer[row][column][DESIRED_PWM_VALUE]); #endif Serial.println("ACKNOWLEDGE"); command = ""; }else{ command = command + in; } } #endif } void timer_handle_interrupts(int timer){ static uint8_t currentDiplay = 0; static uint8_t pwm_tick = 0; static uint16_t blink_tick = 0; static bool blink = false; if(timer == TIMER_DEFAULT){ uint8_t column0_state = outputBuffer[currentDiplay][0][BLINK_STATE]; uint8_t column0_desired_pwm_value = outputBuffer[currentDiplay][0][DESIRED_PWM_VALUE]; uint8_t column1_state = outputBuffer[currentDiplay][1][BLINK_STATE]; uint8_t column1_desired_pwm_value = outputBuffer[currentDiplay][1][DESIRED_PWM_VALUE]; uint8_t column2_state = outputBuffer[currentDiplay][2][BLINK_STATE]; uint8_t column2_desired_pwm_value = outputBuffer[currentDiplay][2][DESIRED_PWM_VALUE]; uint8_t column3_state = outputBuffer[currentDiplay][3][BLINK_STATE]; uint8_t column3_desired_pwm_value = outputBuffer[currentDiplay][3][DESIRED_PWM_VALUE]; bool column_on = pwm_tick == 0; uint8_t controlLine = displayMatrix[currentDiplay][0]; uint8_t column0 = displayMatrix[currentDiplay][1]; uint8_t column1 = displayMatrix[currentDiplay][2]; uint8_t column2 = displayMatrix[currentDiplay][3]; uint8_t column3 = displayMatrix[currentDiplay][4]; uint8_t ddrByte = CONTROL_DDRX; uint8_t portByte = CONTROL_PORTX; //Column0 if(column0_desired_pwm_value == pwm_tick){ ddrByte &= ~column0; portByte &= ~column0; }else if(column_on){ ddrByte |= column0 | controlLine; portByte |= column0; portByte &= ~controlLine; } if(blink && column0_state == BLINK){ ddrByte &= ~column0; portByte &= ~column0; } //Column1 if(column1_desired_pwm_value == pwm_tick){ ddrByte &= ~column1; portByte &= ~column1; }else if(column_on){ ddrByte |= column1 | controlLine; portByte |= column1; portByte &= ~controlLine; } if(blink && column1_state == BLINK){ ddrByte &= ~column1; portByte &= ~column1; } //Column2 if(column2_desired_pwm_value == pwm_tick){ ddrByte &= ~column2; portByte &= ~column2; }else if(column_on){ ddrByte |= column2 | controlLine; portByte |= column2; portByte &= ~controlLine; } if(blink && column2_state == BLINK){ ddrByte &= ~column2; portByte &= ~column2; } //Column3 if(column3_desired_pwm_value == pwm_tick){ ddrByte &= ~column3; portByte &= ~column3; }else if(column_on){ ddrByte |= column3 | controlLine; portByte |= column3; portByte &= ~controlLine; } if(blink && column3_state == BLINK){ ddrByte &= ~column3; portByte &= ~column3; } //PWM Counter ca. 260Hz if(pwm_tick == 255){ pwm_tick = 0; //Display Counter ca. 52Hz currentDiplay++; if(currentDiplay == ROWS){ currentDiplay = 0; #ifdef DEBUG CONTROL_DDRX ^= DEBUG_LINE; CONTROL_PORTX ^= DEBUG_LINE; #endif } //Blink Counter ca. 1Hz blink_tick++; if(blink_tick == 259){ blink_tick = 0; blink ^= true; } }else{ pwm_tick++; } CONTROL_DDRX = ddrByte; CONTROL_PORTX = portByte; } }