Часики
Имеется у меня 9-разрядный 7-сегментный светодиодный индикатор с общим катодом. У него 17 ног (9 разрядов + 7 сегментов цифра + 1 сегмент точка). Экспериментировал с динамической индикацией, в итоге написал программу часов.
Сам девайс в работе выглядит так:
Выводы индикатора подключены к цифровым выводам адруины. Выводы сегментов напрямую, разрядов - через резистор к75. Можно сопротивление уменьшить раза в 2, чтобы ярче светило. Но для экспериментов сойдет.
Программный код:
/** * 2013-02-12 */ //my nine-digit display #define DIGITS 9 //mapping indicator pins -> arduino pins int digits[DIGITS] = {38,36,34,32,30,28,26,24,22}; // A // F B // G // E C // D DP int segments[8] = {33,25,37,29,31,23,27,35}; //A,B,C,D,E,F,G,DP //digits (segments on/off) byte d[10] = { B00111111, //0 B00000110, //1 B01011011, //2 B01001111, //3 B01100110, //4 B01101101, //5 B01111101, //6 B00000111, //7 B01111111, //8 B01101111, //9 }; byte minus = B01000000; byte space = 0; //less to write void on(int pin) { digitalWrite(pin, HIGH); } void off(int pin) { digitalWrite(pin, LOW); } void out(int pin) { pinMode(pin, OUTPUT); } void offSegments(){ for(int i=0; i<8; i++) { off(segments[i]); } } void onSegments(){ for(int i=0; i<8; i++) { on(segments[i]); } } //---------------------------------------------- void setup() { Serial.begin(9600); int i=0; //init pins for(i=0; i < DIGITS; i++) { out(digits[i]); off(digits[i]);//led's cathod set low } for(i=0; i<8; i++) { out(segments[i]); } //test light all. segments anod set high onSegments(); delay(500); //hide for(i=0; i < DIGITS; i++) { on(digits[i]); } offSegments(); } //---------------------------------------------- byte framebuffer[9] = {0,0,0,0,0,0,0,0,0}; //call every second void clock() { int sL=0, sH=1, mL=3, mH=4, hL=6, hH=7;//low/high digits of seconds, minutes, hours if(++framebuffer[sL] < 10) { return; } framebuffer[sL] = 0; if(++framebuffer[sH] < 6) { return; } framebuffer[sH] = 0; if(++framebuffer[mL] < 10) { return; } framebuffer[mL] = 0; if(++framebuffer[mH] < 6) { return; } framebuffer[mH] = 0; if(++framebuffer[hL] < 10 && framebuffer[hH] < 2) { return; } if(framebuffer[hL] < 4 && framebuffer[hH] == 2) { return; } framebuffer[hL] = 0; if(++framebuffer[hH] < 3) { return; } framebuffer[hH] = 0; } //---------------------------------------------- int counter = 0; void loop() { for(int i=0; i < DIGITS-1; i++) { int countOn=0; byte currentChar = d[framebuffer[i]]; //delimiter if(i==2 || i==5) { currentChar = minus; } for(int j=0; j<8; j++){ if(bitRead(currentChar, j)){ on(segments[j]); countOn++; } else { off(segments[j]); } } off(digits[i]); //fire delayMicroseconds(countOn*400); on(digits[i]);//hide } if(millis()/1000 > counter) { clock(); counter++; } } //------------------------------------------------------------- //serial port events handler void serialEvent(){ for(int i=8; Serial.available(); i--) { framebuffer[i] = Serial.read() - 0x30; } }
Особенности. Из-за зависимости яркости цифры от количества зажженых сегментов (цифра 1 светит заметно ярче цифры 8), применяю такой прием: delayMicroseconds(countOn*400); Т.е. длительность включенного состояния зависит от количества светящихся сегментов. В результате, сейчас все светится одинаково.
Установка текущего времени производится через COM порт отправкой строки, на подобии: '0чч0мм'. Пока что не было желания тут оптимизировать для удобства или добавлять для этого кнопки на плату и соответсвующий код. Так же не исследовалась ситуация, когда переполнится 'unsigned long' в результате функции millis(). Хотя сбой, скорее всего, произойдет раньше, т.к. переменная counter у меня int со знаком.
.