Nathan warns that this method does not use current limiting resistors, so be careful you don't blow your display! The code makes use of Pulse Width Modulation (PWM) to limit the current to the segments, and Persistence of Vision allows you to see the segments illuminated without being aware of the pulsing. PWM is possible using certain Arduino pins, and in this case, Arduino Pins 6, 9, 10 and 11 are utilised. These would normally be used with analogWrite() to get PWM, but Nathan uses digitalWrite() with a delay:
149: delayMicroseconds(DISPLAY_BRIGHTNESS);
I think this is called Bit-banging, using a software technique rather than the available hardware capability, and this can be done on any of the Arduino's data pins - it doesn't have to be on the PWM pins 3, 5, 6, 9, 10 and 11 (which have the symbol ~ in front of them on the Arduino board).
The details of the display are as follows:
This model is a white light display, while mine is green. These can be bought for less than £2 from most suppliers. There are 8 pins (number 1 is the first one on the left that you can see above, and as with most chips, the numbers are sequential in an anti-clockwise direction).
There are actually 35 LEDs in all, including 4x7 digits, a colon, an upper point - apostrophe for use as an am/pm indicator if used in a clock) and a lower point for each digit. These are annotated here:
The 35 LEDs are connected to the 16 pins as follows:
The common anodes of the digits DIG1, DIG2, DIG3 and DIG4 (minus the decimal points - DP) are connected to the PWM inputs of the Arduino. The points L1 & L2,(colon) L3 (apostrophe) and decimal points DP1, DP2, DP3 and DP4 can be, but in this case, are not, connected. So the display's pins 4 & 12 (colon common anodes and common cathodes respectively), 7 (decimal point common cathodes), 9 & 10 (apostrophe cathode and anode, respectively) are not used in this project. Be careful here if you're tempted to connect them up, as the PWM requirements are unknown (to me).
Because these other features are not being used, Nathan's code has only programmed the digits with the characters 0 to 9, without decimal points, apostrophe and colon. Note that there are some redundant lines of code which have been commented out. The code, which also describes the wiring, is here:
1:
2: /*
3: 6-13-2011
4: Spark Fun Electronics 2011
5: Nathan Seidle
6:
7: This version modified by www.hobbytronics.co.uk as a countdown timer
8: Ideal as a simple egg timer or other timer. Easily add a buzzer
9:
10: This code is public domain but you buy me a beer if you use this
11: and we meet someday (Beerware license).
12:
13: 4 digit 7 segment display:
14: http://www.sparkfun.com/products/9483
15: Datasheet:
16: http://www.sparkfun.com/datasheets/Components/LED/7-Segment/YSD-439AR6B-35.pdf
17:
18: This is an example of how to drive a 7 segment LED display from an ATmega
19: without the use of current limiting resistors.
20: This technique is very common but requires some knowledge of electronics
21: - you do run the risk of dumping too much current through the segments
22: and burning out parts of the display. If you use the stock code you should
23: be ok, but be careful editing the brightness values.
24:
25: This code should work with all colors (red, blue, yellow, green) but the
26: brightness will vary from one color to the next because the forward voltage
27: drop of each color is different. This code was written and calibrated for the
28: red color.
29:
30: This code will work with most Arduino's but you may want to re-route some of
31: the pins.
32:
33: 7 segments
34: 4 digits
35: 1 colon
36: =
37: 12 pins required for full control
38:
39: */
40:
41: int digit1 = 11; //PWM Display pin 1
42: int digit2 = 10; //PWM Display pin 2
43: int digit3 = 9; //PWM Display pin 6
44: int digit4 = 6; //PWM Display pin 8
45:
46: //Pin mapping from Arduino to the ATmega DIP28 if you need it
47: //http://www.arduino.cc/en/Hacking/PinMapping
48: int segA = A1; //Display pin 14
49: int segB = 3; //Display pin 16
50: int segC = 4; //Display pin 13
51: int segD = 5; //Display pin 3
52: int segE = A0; //Display pin 5
53: int segF = 7; //Display pin 11
54: int segG = 8; //Display pin 15
55:
56: int start_num=9999; // Number to countdown from
57: unsigned long time;
58:
59: void setup() {
60: pinMode(segA, OUTPUT);
61: pinMode(segB, OUTPUT);
62: pinMode(segC, OUTPUT);
63: pinMode(segD, OUTPUT);
64: pinMode(segE, OUTPUT);
65: pinMode(segF, OUTPUT);
66: pinMode(segG, OUTPUT);
67:
68: pinMode(digit1, OUTPUT);
69: pinMode(digit2, OUTPUT);
70: pinMode(digit3, OUTPUT);
71: pinMode(digit4, OUTPUT);
72:
73: pinMode(13, OUTPUT);
74: }
75:
76: void loop() {
77:
78: //long startTime = millis();
79: if((millis()/1000) < start_num){
80: displayNumber(start_num -(millis()/1000));
81: }
82: else {
83: // reached zero, flash the display
84: time=millis();
85: while(millis() < time+200) {
86: displayNumber(0); // display 0 for 0.2 second
87: }
88: time=millis();
89: while(millis() < time+200) {
90: lightNumber(10); // Turn display off for 0.2 second
91: }
92: }
93: //while( (millis() - startTime) < 2000) {
94: //displayNumber(1217);
95: //}
96: //delay(1000);
97: }
98:
99: //Given a number, we display 10:22
100: //After running through the 4 numbers, the display is left turned off
101:
102: //Display brightness
103: //Each digit is on for a certain amount of microseconds
104: //Then it is off until we have reached a total of 20ms for the function call
105: //Let's assume each digit is on for 1000us
106: //If each digit is on for 1ms, there are 4 digits, so the display
107: //is off for 16ms.
108: //That's a ratio of 1ms to 16ms or 6.25% on time (PWM).
109: //Let's define a variable called brightness that varies from:
110: //5000 blindingly bright (15.7mA current draw per digit)
111: //2000 shockingly bright (11.4mA current draw per digit)
112: //1000 pretty bright (5.9mA)
113: //500 normal (3mA)
114: //200 dim but readable (1.4mA)
115: //50 dim but readable (0.56mA)
116: //5 dim but readable (0.31mA)
117: //1 dim but readable in dark (0.28mA)
118:
119: void displayNumber(int toDisplay) {
120: #define DISPLAY_BRIGHTNESS 500
121:
122: #define DIGIT_ON HIGH
123: #define DIGIT_OFF LOW
124:
125: long beginTime = millis();
126:
127: for(int digit = 4 ; digit > 0 ; digit--) {
128:
129: //Turn on a digit for a short amount of time
130: switch(digit) {
131: case 1:
132: digitalWrite(digit1, DIGIT_ON);
133: break;
134: case 2:
135: digitalWrite(digit2, DIGIT_ON);
136: break;
137: case 3:
138: digitalWrite(digit3, DIGIT_ON);
139: break;
140: case 4:
141: digitalWrite(digit4, DIGIT_ON);
142: break;
143: }
144:
145: //Turn on the right segments for this digit
146: lightNumber(toDisplay % 10);
147: toDisplay /= 10;
148:
149: delayMicroseconds(DISPLAY_BRIGHTNESS);
150: //Display digit for fraction of a second (1us to 5000us, 500 is pretty good)
151:
152: //Turn off all segments
153: lightNumber(10);
154:
155: //Turn off all digits
156: digitalWrite(digit1, DIGIT_OFF);
157: digitalWrite(digit2, DIGIT_OFF);
158: digitalWrite(digit3, DIGIT_OFF);
159: digitalWrite(digit4, DIGIT_OFF);
160: }
161:
162: while( (millis() - beginTime) < 10) ;
163: //Wait for 20ms to pass before we paint the display again
164: }
165:
166: //Given a number, turns on those segments
167: //If number == 10, then turn off number
168: void lightNumber(int numberToDisplay) {
169:
170: #define SEGMENT_ON LOW
171: #define SEGMENT_OFF HIGH
172:
173: switch (numberToDisplay){
174:
175: case 0:
176: digitalWrite(segA, SEGMENT_ON);
177: digitalWrite(segB, SEGMENT_ON);
178: digitalWrite(segC, SEGMENT_ON);
179: digitalWrite(segD, SEGMENT_ON);
180: digitalWrite(segE, SEGMENT_ON);
181: digitalWrite(segF, SEGMENT_ON);
182: digitalWrite(segG, SEGMENT_OFF);
183: break;
184:
185: case 1:
186: digitalWrite(segA, SEGMENT_OFF);
187: digitalWrite(segB, SEGMENT_ON);
188: digitalWrite(segC, SEGMENT_ON);
189: digitalWrite(segD, SEGMENT_OFF);
190: digitalWrite(segE, SEGMENT_OFF);
191: digitalWrite(segF, SEGMENT_OFF);
192: digitalWrite(segG, SEGMENT_OFF);
193: break;
194:
195: case 2:
196: digitalWrite(segA, SEGMENT_ON);
197: digitalWrite(segB, SEGMENT_ON);
198: digitalWrite(segC, SEGMENT_OFF);
199: digitalWrite(segD, SEGMENT_ON);
200: digitalWrite(segE, SEGMENT_ON);
201: digitalWrite(segF, SEGMENT_OFF);
202: digitalWrite(segG, SEGMENT_ON);
203: break;
204:
205: case 3:
206: digitalWrite(segA, SEGMENT_ON);
207: digitalWrite(segB, SEGMENT_ON);
208: digitalWrite(segC, SEGMENT_ON);
209: digitalWrite(segD, SEGMENT_ON);
210: digitalWrite(segE, SEGMENT_OFF);
211: digitalWrite(segF, SEGMENT_OFF);
212: digitalWrite(segG, SEGMENT_ON);
213: break;
214:
215: case 4:
216: digitalWrite(segA, SEGMENT_OFF);
217: digitalWrite(segB, SEGMENT_ON);
218: digitalWrite(segC, SEGMENT_ON);
219: digitalWrite(segD, SEGMENT_OFF);
220: digitalWrite(segE, SEGMENT_OFF);
221: digitalWrite(segF, SEGMENT_ON);
222: digitalWrite(segG, SEGMENT_ON);
223: break;
224:
225: case 5:
226: digitalWrite(segA, SEGMENT_ON);
227: digitalWrite(segB, SEGMENT_OFF);
228: digitalWrite(segC, SEGMENT_ON);
229: digitalWrite(segD, SEGMENT_ON);
230: digitalWrite(segE, SEGMENT_OFF);
231: digitalWrite(segF, SEGMENT_ON);
232: digitalWrite(segG, SEGMENT_ON);
233: break;
234:
235: case 6:
236: digitalWrite(segA, SEGMENT_ON);
237: digitalWrite(segB, SEGMENT_OFF);
238: digitalWrite(segC, SEGMENT_ON);
239: digitalWrite(segD, SEGMENT_ON);
240: digitalWrite(segE, SEGMENT_ON);
241: digitalWrite(segF, SEGMENT_ON);
242: digitalWrite(segG, SEGMENT_ON);
243: break;
244:
245: case 7:
246: digitalWrite(segA, SEGMENT_ON);
247: digitalWrite(segB, SEGMENT_ON);
248: digitalWrite(segC, SEGMENT_ON);
249: digitalWrite(segD, SEGMENT_OFF);
250: digitalWrite(segE, SEGMENT_OFF);
251: digitalWrite(segF, SEGMENT_OFF);
252: digitalWrite(segG, SEGMENT_OFF);
253: break;
254:
255: case 8:
256: digitalWrite(segA, SEGMENT_ON);
257: digitalWrite(segB, SEGMENT_ON);
258: digitalWrite(segC, SEGMENT_ON);
259: digitalWrite(segD, SEGMENT_ON);
260: digitalWrite(segE, SEGMENT_ON);
261: digitalWrite(segF, SEGMENT_ON);
262: digitalWrite(segG, SEGMENT_ON);
263: break;
264:
265: case 9:
266: digitalWrite(segA, SEGMENT_ON);
267: digitalWrite(segB, SEGMENT_ON);
268: digitalWrite(segC, SEGMENT_ON);
269: digitalWrite(segD, SEGMENT_ON);
270: digitalWrite(segE, SEGMENT_OFF);
271: digitalWrite(segF, SEGMENT_ON);
272: digitalWrite(segG, SEGMENT_ON);
273: break;
274:
275: case 10:
276: digitalWrite(segA, SEGMENT_OFF);
277: digitalWrite(segB, SEGMENT_OFF);
278: digitalWrite(segC, SEGMENT_OFF);
279: digitalWrite(segD, SEGMENT_OFF);
280: digitalWrite(segE, SEGMENT_OFF);
281: digitalWrite(segF, SEGMENT_OFF);
282: digitalWrite(segG, SEGMENT_OFF);
283: break;
284: }
285: }
And here's the result of my version which counts down from 9999 seconds and then flashes the display:
Thanks Nathan - clever stuff - there's a pint of Guinness for you when we meet at my local pub! (This is now known locally as a GuinnessWare License).
No comments:
Post a Comment