本体は内部RCで1 MHzで動作し、時計用タイマは外部クロック端子につながっている時計用水晶振動子の32.768 kHzで動作させています。24時間制です。
時計合わせ用にボタン2つ(←と↑)がついています。←を押すと順に1分の位、10分の位、1時間の位、10時間の位が点滅して、その位の数字が調整できます。↑を押すと、点滅している桁の数字が1つ増えます。10秒なにもボタンを押さないと元にもどります。
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TIMEOUT 10//config timeout
#define S_IDOL 0 //idol state
#define S_ONEMIN 1
#define S_TENMIN 2
#define S_ONEHOUR 3
#define S_TENHOUR 4
volatile uint8_t sec = 0;//0-60
volatile uint16_t min = 0;//0-60*(24 + 1)
volatile uint8_t confsec = 0;//0-10+alpha
volatile uint8_t state = S_IDOL;//state
volatile uint8_t red_last = 1;
volatile uint8_t white_last = 1;
int8_t display(uint16_t num);
ISR(TIMER2_OVF_vect){ //int. per 1 sec
//count and set time
sec++;
if (sec >= 60){
min++;
sec = 0;
if (min >= 60*24){
min = 0;
}
}
display((min / 60)*100 + min % 60);
//config timeout
confsec++;
if(confsec > TIMEOUT){
state = S_IDOL;
confsec = 0;
}
}
ISR(TIMER2_COMPA_vect){ //int. per 1 sec + 1/2
//turn off -> unavailable 74141
if(state == S_ONEMIN){
//PB0,PD7
PORTB |= (1 << PORTB0);
PORTD |= (1 << PORTD7); //| (1 << PORTD6) | (1 << PORTD5));
}else if(state == S_TENMIN){
//PB1,2
PORTB |= ((1 << PORTB1) | (1 << PORTB2));
}else if(state == S_ONEHOUR){
//PD0,1
PORTD |= ((1 << PORTD0) | (1 << PORTD1));
}else if(state == S_TENHOUR){
//PC0,1
PORTC |= ((1 << PORTC0) | (1 << PORTC1));
}
}
ISR(PCINT1_vect){
_delay_ms(10);
uint8_t red_now = PINC & (1 << PINC4);
uint8_t white_now = PINC & (1 << PINC5);
if ((white_last != 0) & (white_now == 0)){//white pull down
//shift state
state++;
if(state > S_TENHOUR){
state = S_IDOL;
}
confsec = 0;
}
white_last = white_now;
if ((red_last != 0) & (red_now == 0)){//red pull down
confsec = 0;
if(state == S_ONEMIN){
min++;
if(min % 10 == 0){
min -= 10;
}
}else if(state == S_TENMIN){
min += 10;
if(min % 60 < 10){
min -= 60;
}
}else if(state == S_ONEHOUR){
min += 60;
if((min / 60) / 10 < 2){
if((min / 60) % 10 == 0){
min -= 60*10;
}
}else{
if((min / 60) % 10 == 4){
min -= 60*4;
}
}
}else if(state == S_TENHOUR){
min += 60*10;
if((min / 60) % 10 >= 4){
if((min / 60) / 10 == 2){
min -= 60*20;
}
}else{
if((min / 60) / 10 == 3){
min -= 60*30;
}
}
}
display((min / 60)*100 + min % 60);
}
red_last = red_now;
}
int8_t display(uint16_t num){
uint8_t one = num % 10;
uint8_t ten = (num / 10) % 10;
uint8_t hund = (num / 100) % 10;
uint8_t thou = (num / 1000) % 10;
//4one DCBA -> PB0,PD7,6,5
//3ten DCBA -> PB1,2,3,4
//2hundDCBA -> PD0,1,2,3
//1thouDCBA -> PC0,1,2,3
PORTB = (((ten & 0b0001)?1:0) << 4)
| (((ten & 0b0010)?1:0) << 3)
| (((ten & 0b0100)?1:0) << 2)
| (((ten & 0b1000)?1:0) << 1)
| (((one & 0b1000)?1:0) << 0);
PORTC = (((thou & 0b0001)?1:0) << 3)
| (((thou & 0b0010)?1:0) << 2)
| (((thou & 0b0100)?1:0) << 1)
| (((thou & 0b1000)?1:0) << 0)
| (1 << PORTC4)
| (1 << PORTC5);
PORTD = (((hund & 0b0001)?1:0) << 3)
| (((hund & 0b0010)?1:0) << 2)
| (((hund & 0b0100)?1:0) << 1)
| (((hund & 0b1000)?1:0) << 0)
| (((one & 0b0001)?1:0) << 5)
| (((one & 0b0010)?1:0) << 6)
| (((one & 0b0100)?1:0) << 7);
return 0;
}
int8_t init(void){
//pc4(PCINT12) red, pc5(PCINT13) white
DDRB = 0xFF;
DDRC = 0b11001111;
DDRD = 0xFF;
PORTB = 0x00;
PORTC = 0b00110000;
PORTD = 0x00;
ASSR = 0b00100000; // use crystal.
TCCR2B = 0b00000101; // 128 prescaler, timer on; 1 sec
//TCCR2B = 0b00000100; // 64 prescaler, timer on; 1/2 sec
//TCCR2B = 0b00000011; // 32 prescaler, timer on; 1/4 sec
TIMSK2 |= (1 << TOIE2) | (1 << OCIE2A); // overflow and A interrupts on
OCR2A = 0x80;
//interrupt.
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PCINT12) | (1 << PCINT13);//PCMSK1 = 0x30
GTCCR = 0b00000010; //timer reset
sei(); // allow interrupts
return 0;
}
int main(void){
init();
while(1){
}
return 0;
}