Другой вариант часов. Индикатор с общим катодом. Сегменты -PORTB.Разряды цифр PD2-PD5 через резисторы 220 Ом. Кнопка коррекции PD0. Внешний кварц на 8МГц.
char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};
char Buffer[] = { 1, 2, 5, 9, 0 };
int Size[] = { 2, 10, 6, 10, 60 };
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
volatile int Counter;
void DisplayNextDigital() {
char segs;
Digit = (Digit+1) % 4;//считаем от 0 до 4
char Char = Buffer[Digit];
if (Digit == 0 && Char == 0) Char = 10; // delete zero
if (Digit == 1)segs= CharMap[Char]|Point;
else segs = CharMap[Char];
DDRB = DDRB & 0x00; // B7-B0 all inputs
PORTB = PORTB | segs; // 1 = high
DDRB = DDRB | segs; // 1 = output
}
void SetTime() {
int Speed = 2000;
if ((PIND & 1)==0) Speed = 4; // Check set time button
if (Counter == 0) { // Runs at 1Hz
Counter = Speed;
Point = Point ^ 0x80; // Flash point
int Carry = 1;
for (int p=4; p>=0; p--) {
char temp = Buffer[p] + Carry;
Buffer[p] = temp % Size[p];
Carry = temp / Size[p];
if (Buffer[0]==2 && Buffer[1]==4) { // 24 hour
Buffer[0] = 0;
Buffer[1] = 1;
}
}
}
Counter--;
}
ISR (TIMER1_COMPA_vect) {
pinMode(Columns[Digit], INPUT); // Turn off display
DisplayNextDigital();
SetTime();
}
ISR (TIMER1_COMPB_vect) {
pinMode(Columns[Digit], OUTPUT); // Turn on display
digitalWrite(Columns[Digit], LOW);
}
void setup() {
pinMode(0, INPUT);
TCCR1A = 0<<WGM10;
TCCR1B = 1<<WGM12 | 2<<CS10; // Divide by 8
OCR1A = 499; // Compare match at 2000Hz
OCR1B = 0; // Brightness; reduce for brighter min=480 max=0
TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
}
// All done under interrupt!
void loop() {
}
+DS3231. Внутренний кварц на 8Мгц. Кнопки коррекции PDO - часы,PD1 - минуты
#define SDA PA0
#define SCL PA1
// plus_h PDO
// plus_m PD1
char CharMap[11] = {
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x00, //
};
char Buffer[] = { 1, 2, 5, 9, 0 };
unsigned long Alarm,debonce;
char Columns[4] = { 4, 5, 6, 7};
int Digit;
int Point;
unsigned char hour,min;
void DisplayNextDigital() {
char segs;
Digit = (Digit+1) % 4;//считаем от 0 до 4
char Char = Buffer[Digit];
if (Digit == 0 && Char == 0) Char = 10; // delete zero
if (Digit == 1)segs= CharMap[Char]|Point;
else segs = CharMap[Char];
DDRB = DDRB & 0x00; // B7-B0 all inputs
PORTB = PORTB | segs; // 1 = high
DDRB = DDRB | segs; // 1 = output
}
// Timer interrupts - multiplex display
ISR (TIMER1_COMPA_vect) {
pinMode(Columns[Digit], INPUT); // Turn off display
DisplayNextDigital();
}
ISR (TIMER1_COMPB_vect) {
pinMode(Columns[Digit], OUTPUT); // Turn on display
digitalWrite(Columns[Digit], LOW);
}
void setup() {
pinMode(0, INPUT);
pinMode(1, INPUT);
TCCR1A = 0<<WGM10;
TCCR1B = 1<<WGM12 | 2<<CS10; // Divide by 8
OCR1A = 499; // Compare match at 2000Hz
OCR1B = 0; // Brightness; reduce for brighter min=480 max=0
TIMSK = TIMSK | 1<<OCIE1A | 1<<OCIE1B; // Compare match interrupt enable
}
void loop() {
read_time();
Buffer[0] = hour / 10;
Buffer[1] = hour % 10;
Buffer[2] = min / 10;
Buffer[3] = min % 10;
if (digitalRead(0) == 0&&millis()-debonce>300)
{hour++;
if (hour > 23) hour = 0;
ds_write(0x02,(hour/10<<4)+hour%10);
debonce= millis();
}
if (digitalRead(1) == 0&&millis()-debonce>300)
{min++;
if (min > 59) min = 0;
ds_write(0x01,(min/10<<4)+min%10);
debonce= millis();
}
if(millis()-Alarm>1000){
Point= Point^0x80; Alarm=millis();
}
}
bool i2c_read_bit() {
bool i2c_bit = 1;
DDRA &= ~(1 << SDA);
delayMicroseconds(10);
DDRA &= ~(1 << SCL);
if((PINA >> SDA) & 1) i2c_bit=0;
delayMicroseconds(10);
DDRA |= (1 << SCL);
return i2c_bit;
}
byte i2c_write_byte(byte data){
for (byte i=0; i<8; i++){i2c_write_bit((data&0x80)==0);data<<=1;}
return i2c_read_bit();
}
byte i2c_read_byte(byte a){
byte i, data=0;
for(i=0; i<8; i++){if (!i2c_read_bit()) data++;if(i!=7) data<<=1;}
i2c_write_bit(a);return data;
}
void i2c_write_bit(byte b){
delayMicroseconds(5);
if(b){DDRA |= (1 << SDA);}else{DDRA &= ~(1 << SDA);}
delayMicroseconds(5);
DDRA &= ~(1 << SCL);
delayMicroseconds(10);
DDRA |= (1 << SCL);
}
void i2c_start(){
delayMicroseconds(10);
DDRA &= ~(1 << SDA); DDRA &= ~(1 << SCL);
delayMicroseconds(10);
DDRA |= (1 << SDA); PORTA &= ~(1 << SDA);
delayMicroseconds(10);
DDRA |= (1 << SCL); PORTA &= ~(1 << SCL);
delayMicroseconds(10);
}
void i2c_stop() {
DDRA |= (1 << SDA);
delayMicroseconds(10);
DDRA &= ~(1 << SCL);
delayMicroseconds(10);
DDRA &= ~(1 << SDA);
}
byte ds_read(byte reg){
byte data = 0;
i2c_start();
i2c_write_byte(0b11010000);
i2c_write_byte(reg);
i2c_start();
i2c_write_byte(0b11010001);
data = i2c_read_byte(0);
i2c_stop();
return data;
}
void ds_write(byte reg, byte data){
i2c_start();
i2c_write_byte(0b11010000);
i2c_write_byte(reg);
i2c_write_byte(data);
i2c_stop();
}
void set_time(byte hours ,byte minute, byte second){
ds_write(0x00,(second/10<<4)+second%10);
ds_write(0x01,(minute/10<<4)+minute%10);
ds_write(0x02,(hours/10<<4)+hours%10);
}
void read_time(){
min = (ds_read(1) & 0x0F) + (((ds_read(1) & 0x70) >> 4) * 10);
hour = (ds_read(2) & 0x0F) + (((ds_read(2) & 0x70) >> 4) * 10);
}
GPS часы без учета часового пояса.
// David Johnson-Davies - www.technoblogy.com - 9th July 2018
// ATtiny2313 @ 8 MHz (external crystal; BOD disabled)
// Seven-segment definitions
const int charArrayLen = 12;
uint8_t charArray[] = {
// ABCDEFG Segments
0b1111110, // 0
0b0110000, // 1
0b1101101, // 2
0b1111001, // 3
0b0110011, // 4
0b1011011, // 5
0b1011111, // 6
0b1110000, // 7
0b1111111, // 8
0b1111011, // 9
0b0000001, // 10 '-'
0b0000000 // 11 Space
};
const int Dash = 10;
const int Space = 11;
uint8_t Buffer[] = { Dash, Dash, Dash, Dash};
uint8_t dp = -1; // Decimal point position 0 to 3
uint8_t digit = 0;
uint8_t Digits[] = {4, 7, 5, 6};
// Segments must all go to port B; this specifies how they're wired up:
// g f e d c b a dp
uint8_t Segments[] = {2, 4, 5, 3, 1, 6, 7, 0};
//G-PB0,F-PB1..A-PB6,DP-PB6 without void ReorderBits()
void ReorderBits() { //переупорядить биты.
uint8_t segs, newsegs;
for (int i=0; i<charArrayLen; i++) {
segs = charArray[i];
newsegs = 0;
for (int i=0; i<8; i++) {
newsegs = newsegs | ((segs & 1)<<Segments[i]);
segs = segs >> 1;
}
charArray[i]=newsegs;
}
}
void DisplayNextDigit() {
pinMode(Digits[digit], INPUT);
digit = (digit+1) % 4;
uint8_t segs = charArray[Buffer[digit]];
// Display decimal point?
if (digit == dp) segs = segs | (1<<Segments[7]);
DDRB = 0; // All inputs
PORTB = segs; // 1 = high
DDRB = segs; // 1 = output
pinMode(Digits[digit], OUTPUT);
digitalWrite(Digits[digit], LOW);
}
// Display a four/five digit decimal number
void Display (unsigned int number) {
boolean dig = false;
int j;
if (number>9999) { j=10000; dp=2; }
else { j=1000; dp=1; }
for (int d=0; d<4 ; d++) {
int i = (number/j) % 10;
if (!i && !dig && j>100) Buffer[d]=Space;
else { Buffer[d]=i; dig = true; }
j=j/10;
}
}
// ParseGPS
// Example: $GPRMC,194509.000,A,4042.6142,N,07400.4168,W,2.03,221.11,160412,,,A*77
const char fmt[] PROGMEM =
"$GPRMC,dddtdd.ddm,A,????.????,?,?????.????,?,djdk,???.??,??????,,,?*??";
int state = 0;
unsigned int temp;
// GPS variables
volatile unsigned int Time;
void ParseGPS (char c) {
if (c == '$') { state = 0; temp = 0; }
uint8_t mode = pgm_read_byte_near(fmt + state++);
// If received character matches format string, or format is '?' - return
if ((mode == c) || (mode == '?')) return;
// d=decimal digit
uint8_t d = c - '0';
if (mode == 'd') temp = temp*10 + d;
// t=Time - hhmm
else if (mode == 't') { Time = temp*10 + d; temp = 0; }
else state = 0;
}
// Timer interrupt - multiplexes display
ISR (TIMER1_COMPA_vect) {
DisplayNextDigit();
}
// USART interrupt - receives data from GPS module
ISR (USART_RX_vect) {
uint8_t c = UDR;
ParseGPS(c);
}
void setup() {
ReorderBits();
// Set up Timer1 to multiplex the display
TCCR1A = 0<<WGM10;
TCCR1B = 1<<WGM12 | 2<<CS10; // Divide by 8
OCR1A = 4999; // Compare match at 200Hz
TIMSK |= 1<<OCIE1A; // Compare match interrupt enable
// Set up USART
UCSRB = 1<<RXEN | 1<<RXCIE; // Enable Rx and interrupt
UCSRC = 3<<UCSZ0; // 8-bit UART mode
UBRRL = 51; // 9600 baud
}
void loop() {
unsigned int temp;
cli(); temp = Time; sei();
Display(temp);
}