1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
/* ATTiny2313 skeleton */
// asheem you better clean up the comments if you publish this at all.
// jes sayin.
#define F_CPU 8000000 // assuming fuses set already.
// if not use avrdude arguments to set 8MHz internal, no ckdiv.
// -U lfuse:w:0xe4:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
#define INIT_DELAY 300 // initial delay when between numbers when holding button
#define COUNTDOWN_START_BUTTON_DELAY 2000 // how long the countdown button must be held
#include <avr/io.h>
#include <util/delay.h>
void setsevseg(int sevsegnum)
{
int sevsegconfig[11] =
{
// LED configuration data, with a byte for each numeric character.
// This configuration was tuned after wiring up the 7SEG.
// It's a common-anode-configuration display so a HIGH bit is off.
// Note that the MSB is not used. It would be the decimal point if
// PORTD had enough pins, but it doesn't. >:o
0b10001000, //0
0b10111101, //1
0b10010010, //2
0b10010100, //3
0b10100101, //4
0b11000100, //5
0b11000000, //6
0b10011101, //7
0b10000000, //8
0b10000101, //9
0b11111111 //blanked
};
PORTD = sevsegconfig[sevsegnum];
}
// flash a number VAL on the 7SEG REPS times, DUR milsec each time
void flash_num_sevseg(int val, int reps, int dur)
{
for(1;reps;reps--)
{
setsevseg(val);
_delay_ms(dur);
setsevseg(10);
_delay_ms(dur);
setsevseg(val);
}
}
void countdown_timer(int time)
{
for(1;time;time-=1)
{
if (time <1) break;
flash_num_sevseg(time,2,275);
}
PORTB=0xFF; // trips PORTB on
flash_num_sevseg(0,5,100);
PORTB=0x00; // and off again
}
int main(void)
{
int sevsegnum = 1;
int got_release = 1;
int number_held = 0;
int release_break_counter = 0;
/* Port A is the input buttons.
* B is the output-on-countdown-complete. Just an LED right now.
* D is the output to the seven segment display.
*/
DDRA = 0x00;
PORTA = 0xFF;
DDRB = 0xFF;
PORTB = 0x00;
DDRD = 0xFF;
setsevseg(0); // start number
while (1)
{
if(bit_is_clear(PINA,1))
{
// feeds the current number into the countdown timer
// i don't know why but the buttonpress autoincrements
// the time when pressed, so it's got a workaround -1.
countdown_timer(sevsegnum-1);
sevsegnum=0; // clean up, return to 0.
setsevseg(0);
goto goto_on_button_release;
}
else if(bit_is_clear(PINA,0)) // on button press
{
if(sevsegnum==10) sevsegnum=0; // overflow back to 0 (single digit lol.)
setsevseg(sevsegnum); // set the sevseg display
sevsegnum++;
// keep track of whether a buttonrelease has been caught
// which is necessary when tuning the increment speed.
got_release = 0;
if(number_held == 0)
{
// I am using delay increments of 20ms. that's where the 20 comes from.
// the first term of the for calculates how many 20ms delays are needed
// to get INIT_DELAY.
for(release_break_counter=(INIT_DELAY/20);
release_break_counter;
release_break_counter--)
{
// break when a button release is caught so the user
// doesn't have to wait to increment again.
if(!bit_is_clear(PINA,0)) goto goto_on_button_release;
_delay_ms(20);
}
}
else
{
// increment speed goes up with duration of keypress
_delay_ms(INIT_DELAY / ((number_held/2)+1) );
}
if (number_held < 500) number_held++; // prevent overflow, limit speed.
}
else{
// clean up after button release.
goto_on_button_release:
got_release = 1;
number_held = 0;
}
}
}
|