Часики
Имеется у меня 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 со знаком.
.