Zugegeben eine Binäruhr ist schon etwas schräg, aber zum Üben ist sie optimal. Die Zeit muss nicht für die Anzeige aufbereitet werden, sondern kann direkt ausgegeben werden. Trotzdem bietet so eine Uhr noch genügend Herausforderungen. Für einen guten Sekundentakt wird ein 2,097152 MHz Quarz verwendet. Es wird eine Einstellmöglichkeit für die Uhrzeit benötigt und es darf natürlich auch eine Stromausfallsicherung nicht fehlen. Zusätzlich ist es möglich die Uhr mit dem DCF77 Signal synchron laufen zu lassen.
Doch der Anfang ist die Schaltung.

Die Schaltung ist an sich sehr einfach. Die Transistoren links (NPN) schalten die Kathoden der Leuchtdiodenreihen, die Transistoren unten (PNP) die Anoden der LED-Reihen. Die LED-Vorwiderstände sind zwischen den PNP Transistoren und dem Plus-Anschluss der LEDs, da in diesen Reihen immer nur eine LED zur Zeit an sein wird. Die drei Taster werden auch nach einander abgefragt, sie bekommen ihr positive Versorgung von den drei Ausgängen die die NPN Transistoren steuern und leiten es dann auf den Eingang weiter. Durch geschicktes Schalten der Ausgänge kommt man so mit wenig Pins am IC aus und kann trotzdem die 17 Leuchtdioden und die drei Schalter ansteuern bzw. abfragen.
Für den Fall, dass mal die Stromversorgung ausfallen sollte wird der Goldcap (C3) verwendet, um die Versorgung zu übernehmen. Dazu wird der Transistor Q4 so verwendet, dass er sobald im Kondensator C4 die Spannung unter etwa 2 Volt fällt er den Eingang des PIC auf Vdd wechseln lässt. Der PIC kann dann die LEDs ausschalten. Der Goldcap hat dann genug Energie um den PIC alleine noch etwa 1,5 Stunden zu versorgen.
Der Festspannungsregler ist ein Low-Drop Linearregler, der gleichzeitig einen Verpolungsschutz bietet (bin mir aber nicht 100% sicher). Er ermöglicht es die Uhr mit 3 bis 9 Volt zu versorgen, da er bei kleiner Spannung nur 0,5 Volt Spannungsabfall hat die Spannung in der Schaltung aber nicht größer als 5 Volt werden lässt. Die Diode D23 sorgt beim Stromausfall dafür, dass die Spannugssüberwachung spannungslos wird, und der Goldcap nur den PIC versorgt.
Das DCF77-Empfangsmodul von Conrad ist extern in einem kleinen Gehäuse untergebracht, weil es sonst von der Schaltung zu stark gestört wird. Dazu sind die drei Anschlüsse unten im Schaltplan. Auf der Empfängerplatine selbst ist noch ein Pullup-Widerstand sowie eine Entstörung untergebracht. Verwendet wurde eine 3,5mm Kopfhörerbuchse, damit man den Empfänger auch während des Betriebs an oder abstecken kann wird in die Plusleitung noch vor der Buchse ein 100Ω Widerstand eingebaut und die Signalleitung noch mit einem 22kΩ Pullup-Widerstand ausgestattet. Dies sorgt dafür, dass es keinen Kurzschluss während des Steckvorgangs gibt, der Pullupwiderstand sorgt für einen definierten Pegel auch ohne den Empfänger. Es muss das nicht invertierte Signal (100ms oder 200ms high; 900ms oder 800ms low) eingespeist werden.
Die Lastkondensatoren für den Quarz sowie die Entstörkondensatoren wurden nicht in den Schaltplan eingezeichnet. Es wäre empfehlenswert noch einen ICSP-Anschluss vorzusehen. Zusätzlich wurde der Widerstand, der den MCLR auf Vdd zieht nicht mit eingezeichnet.
Nach dem Aufbau und einem Funktionstest der LEDs und Transistoren beginnt das Programmieren.


Fotos der Uhr. Auf dem oberen Bild ist unten der ICSP-Anschluss zu sehen, welcher aus Platzgründen unter der IC-Fassung angelötet wurde. Auf dem unteren Bild sieht man, dass alle Leuchtdioden leicht leuchten, so ist die Zeit im Dunkeln besser abzulesen. Auf dem unteren Foto ist es gerade 19:43:18 .
Auch wenn das Programm bis jetzt fehlerfrei Läuft, bin ich an einer kontinuierlichen Verbesserung interessiert. Wenn du noch Teile erkennst, die man einfacher oder schneller machen kann bin ich sehr
Es stehen zwei Betriebsarten zur Verfügung. Die Uhr kann ohne DCF-Unterstützung nur durch den Quarz getaktet betrieben werden, oder aber mit DCF-Unterstützung. Wenn die DCF Synchronisierung eingeschaltet ist versucht die Uhr so oft wie möglich die Zeit zu empfangen. Fällt in diesem Modus der Empfang länger als 24 Stunden aus, dann wird dies durch ein leichtes Flackern in der Anzeige signalisiert. Es wurde alles in einzelne Schleifen und Unterprogramme ausgelagert, die nur bei bedarf ausgeführt werden. Die einzelnen Module sind:
Alles weitere zum Programm sollte man den Kommentaren im Programm entnehmen können.
1. ; Binäruhr mit 6 Bit bei Sekunden und Minuten, 5 Bit bei Stunden 2. ; LED-Array gemultiplext zwischen RA0 - RA2 und RB0 - RB5 3. 4. ; RA0 out high-aktiv Sekunden Zeile 5. ; RA1 out high-aktiv Minuten Zeile 6. ; RA2 out high-aktiv Stunden Zeile 7. 8. ; RA4 in - DCF-Signal vom Empfänger (100ms oder 200ms high; 900ms oder 800ms low) 9. 10. ; RA3 in high-aktiv Taster Abfrage (gemultiplext mit RA0 - RA2) 11. ; RB6 in low-aktiv Spannungskontrolle 12. 13. ; RB0 out low-aktiv 2^0 Bit 14. ; RB1 out low-aktiv 2^1 Bit 15. ; RB2 out low-aktiv 2^2 Bit 16. ; RB3 out low-aktiv 2^3 Bit 17. ; RB4 out low-aktiv 2^4 Bit 18. ; RB5 out low-aktiv 2^5 Bit 19. ; ************************************************************** 20. #include <P16f84A.INC> 21. __CONFIG _PWRTE_ON & _WDT_OFF & _XT_OSC 22. ; ************************************************************** 23. ; Variablennamen vergeben 24. aloops Equ 0x22 ; Zähler für Warteschleife 25. bloops Equ 0x23 ; Zähler für Warteschleife 26. Bits1 Equ 0x24 ; Speicherstelle für einzelne Bits 27. Bits2 Equ 0x25 ; Speicherstelle für einzelne Bits 28. 29. T1_Wert Equ 0x26 ; Betätigungszeit Taster1 Messen 30. T2_Wert Equ 0x27 ; Betätigungszeit Taster2 Messen 31. T3_Wert Equ 0x28 ; Betätigungszeit Taster3 Messen 32. 33. DCF_Zeit_L Equ 0x29 ; Zeit die das DCF_Signal Low ist 34. DCF_Zeit_H Equ 0x2a ; Zeit die das DCF_Signal High ist 35. DCF_BitN Equ 0x2b ; Zählt mit, welches Bit vom DCF nun kommt 36. DCF_BitWS Equ 0x2c ; Gibt die Wertigkeit an, die das DCF-Bit hat, wenn es ein Bit für die Stunden ist 37. DCF_BitWM Equ 0x2d ; Gibt die Wertigkeit an, die das DCF-Bit hat, wenn es ein Bit für die Minuten ist 38. DCF_WertM Equ 0x2e ; Zähler zur Mittelung des DCF-Signals 39. DCF_ok Equ 0x2f ; Stundenwechsel seit dem letzten erfolgreichen DCF-Empfang 40. 41. Teiler Equ 0x30 ; Teiler für weiteres Herunterteilen des Timers 42. 43. Sekunden Equ 0x31 ; Speicher für die aktuellen Sekunden 44. Minuten Equ 0x32 ; Speicher für die aktuellen Minuten 45. Stunden Equ 0x33 ; Speicher für die aktuellen Stunden 46. 47. Min_dcf_zw Equ 0x34 ; Zwischenspeicher für die empfangenen DCF Minuten 48. Std_dcf_zw Equ 0x35 ; Zwischenspeicher für die empfangenen DCF Stunden 49. 50. Sek_dcf Equ 0x36 ; Speicher für die empfangenen DCF Sekunden 51. Min_dcf Equ 0x37 ; Speicher für die empfangenen DCF Minuten 52. Std_dcf Equ 0x38 ; Speicher für die empfangenen DCF Stunden 53. 54. ; Konstanten definieren 55. #define T1_Set Bits1,0 56. #define T2_Set Bits1,1 57. #define T3_Set Bits1,2 58. #define T1_Fast Bits1,3 59. #define T2_Fast Bits1,4 60. #define DCF_Bit_L Bits1,5 61. #define DCF_Bit_H Bits1,6 62. #define DCF_Good Bits2,0 63. #define DCF_PortM Bits2,1 64. #define DCF_Bit_OK Bits2,2 65. #define DCF_ON Bits2,3 66. 67. #define Power_Good PORTB,6 68. #define DCF_Port PORTA,4 69. 70. #define Sec_Zeile PORTA,0 71. #define Min_Zeile PORTA,1 72. #define Std_Zeile PORTA,2 73. #define T_Input PORTA,3 74. 75. ; ************************************************************** 76. ; Initialisieren 77. 78. ; Ausgänge und 256 Hz-Timer einstellen 79. bsf STATUS,RP0 ; auf Bank 1 umschalten 80. movlw B'10000010' 81. movwf OPTION_REG ; internen Takt zählen, Vorteiler zum Timer0, 8:1 82. movlw B'11111000' 83. movwf TRISA ; PortA RA0-RA2 output, RA3,RA4 input 84. movlw B'11000000' 85. movwf TRISB ; PortB RB0-RB5 output, RB6 input 86. bcf STATUS,RP0 ; auf Bank 0 zurückschalten 87. clrf TMR0 ; (((2097152Hz : 4 ): 8 ): 256 = 256 Hz) 88. 89. ; Variablen setzen 90. clrf T1_Wert 91. clrf T2_Wert 92. clrf T3_Wert 93. clrf Sekunden 94. clrf Minuten 95. clrf Stunden 96. clrf Bits1 97. clrf Bits2 98. clrf Teiler 99. clrf DCF_WertM 100. bsf DCF_WertM,3 101. clrf Min_dcf_zw 102. clrf Std_dcf_zw 103. clrf Min_dcf 104. clrf Std_dcf 105. clrf Sek_dcf 106. clrf DCF_Zeit_L 107. clrf DCF_Zeit_H 108. clrf DCF_BitN 109. clrf DCF_BitWS 110. clrf DCF_BitWM 111. clrf DCF_ok 112. bsf DCF_ON 113. ; ************************************************************** 114. All_on 115. ; Aufblitzen 116. bsf Sec_Zeile 117. bsf Min_Zeile 118. bsf Std_Zeile ; Alle Zeilen an 119. clrf PORTB ; Alle LEDs an 120. movlw D'250' ; 25 ms Pause 121. call wait 122. bcf Sec_Zeile 123. bcf Min_Zeile 124. bcf Std_Zeile ; Alle Zeilen aus 125. 126. Anzeige 127. ; Sekunden Anzeigen, Taster 1 abfragen 128. comf Sekunden,0 ; Sekunden laden und negieren 129. btfss DCF_Bit_OK ; Wenn DCF_Bit_OK 0, dann LEDs aus lassen 130. movlw B'11111111' 131. movwf PORTB ; Sekunden in PORTB schreiben 132. bsf Sec_Zeile ; Sekunden an 133. movlw D'3' ; 0.3 ms Pause 134. call wait 135. clrz 136. btfsc T_Input 137. incf T1_Wert,1 ; Wenn Taster 1 gedrückt, dann erhöhen 138. btfsc STATUS,Z ; Wenn Taster 1 lange genug gedrückt(Überlauf; 256 Durchläufe; 1,14s), dann zum einstellmod 139. goto einstellmod 140. btfss T_Input 141. clrf T1_Wert ; Wenn Taster 1 nicht gedrückt, dann Zähler löschen 142. bcf Sec_Zeile ; Sekunden aus 143. movlw D'12' ; 1.2 ms Pause 144. call wait 145. 146. ; Minuten Anzeigen, Taster 1 Zeit prüfen 147. comf Minuten,0 ; Minuten laden und negieren 148. btfss DCF_Bit_OK ; Wenn DCF_Bit_OK 0, dann LEDs aus lassen 149. movlw B'11111111' 150. movwf PORTB ; Minuten in PORTB schreiben 151. bsf Min_Zeile ; Minuten an 152. movlw D'3' ; 0.3 ms Pause 153. call wait 154. bcf Min_Zeile ; Minuten aus 155. movlw D'12' ; 1.2 ms Pause 156. call wait 157. 158. ; Stunden Anzeigen 159. comf Stunden,0 ; Stunden laden und negieren 160. btfss DCF_Bit_OK ; Wenn DCF_Bit_OK 0, dann LEDs aus lassen 161. movlw B'11111111' 162. movwf PORTB ; Stunden in PORTB schreiben 163. bsf Std_Zeile ; Stunden an 164. movlw D'3' ; 0.3 ms Pause 165. call wait 166. bcf Std_Zeile ; Stunden aus 167. clrf PORTB ; Alle Transistoren rechtzeitig an , sonst im nachfolgenden der Wert der Stunden erkennbar 168. movlw D'12' ; 1.2 ms Pause 169. call wait 170. 171. ; Alle Leuchtdioden leicht glimmen lassen, Schleife schließen 172. bsf Sec_Zeile 173. bsf Min_Zeile 174. bsf Std_Zeile ; Alle Zeilen an 175. nop 176. nop 177. nop 178. nop 179. bcf Sec_Zeile 180. bcf Min_Zeile 181. bcf Std_Zeile ; Alle Zeilen aus 182. goto Anzeige ; Wiederholen 183. ; ********************************************************** 184. ; Schleife wird 256 mal pro Sekunde ausgeführt 185. zaehler 186. ; Diese Schleife nur ausführen, wenn noch mindestens 0.5 ms gewartet werden soll 187. movlw D'251' 188. addwf aloops,0 189. btfss STATUS,C 190. return ; Wenn aloops größer als 5, dann nicht zurück 191. 192. bcf INTCON,T0IF ; Interruptbit wieder löschen um das nächste Interrupt zu bemerken 193. 194. ; Tiefpass mit nachgeschaltetem Schmitt-Trigger 195. btfsc DCF_Port 196. incf DCF_WertM,1 ; Wenn DCF-Port 1, dann Mittelwert hochzählen 197. btfss DCF_Port 198. decf DCF_WertM,1 ; Wenn DCF-Port 0, dann Mittelwert runterzählen 199. 200. btfsc DCF_WertM,7 ; Wenn DCF_WertM,7 = 1, dann Wert größer 128, negativer Überlauf 201. bcf DCF_PortM ; DCF_PortM auf 0 202. btfsc DCF_WertM,7 203. incf DCF_WertM,1 ; Wert wieder in den gewünschten Bereich zurückbringen 204. 205. btfsc DCF_WertM,3 ; Wenn DCF_WertM,3 = 1, dann Wert auf 8 gestiegen, Grenze 206. bsf DCF_PortM ; DCF_PortM auf 1 207. btfsc DCF_WertM,3 208. decf DCF_WertM,1 ; Wert wieder in den gewünschten Bereich zurückbringen 209. 210. call anzeige_flacker; Erzeugt Flackern falls letzter erfolgreicher DCF-Empfang zulange zurückliegt 211. 212. btfss DCF_ON 213. bcf DCF_PortM ; Wenn DCF_ON nicht 1, dann DCF_PortM immer wieder auf 0 => kein DCF-Empfang 214. btfss DCF_ON 215. bsf DCF_Bit_OK ; Wenn DCF_ON nicht 1, dann DCF_Bit_OK immer 1, weil im Quarzmodus der Empfang nie zu lang her sein kann 216. 217. call dcf_zeit_fax ; DCF-Signale Auswerten, wenn eine gültige Zeit in Speicher, dann ist Sek_dcf größer 0 218. 219. incf Teiler,1 ; Teiler um 1 erhöhen 220. btfss STATUS,Z 221. return ; Wenn Teiler noch nicht überläuft, dann zurück 222. 223. call zaehler_normal ; Sonst die Zähler bedienen 224. call zaehler_dcf 225. 226. movlw D'3' 227. subwf aloops,1 ; Die Zeit, die die Schleifen etwa brauchten (ca 0.3ms) von der Wartevariable abziehen 228. 229. return 230. ; ********************************************************** 231. ; Stellt die Anzeige für 8/256 aus, um zu signalisieren, dass letzter gültiger Empfang zu lange her 232. anzeige_flacker 233. bsf DCF_Bit_OK 234. 235. movf DCF_ok,1 236. btfss STATUS,Z 237. return ; Wenn DCF_ok gleich 0, dann flackern und nicht zurück 238. 239. movlw D'20' 240. addwf Teiler,0 241. btfsc STATUS,C 242. bcf DCF_Bit_OK ; Wenn Teiler größer als 247 (235 + 20 = Überlauf), dann Anzeige aus 243. 244. return 245. ; ********************************************************** 246. ; Normaler Zähler, der mit dem Teiler(Quarz und DCF abhängig) die Zeit zählt 247. zaehler_normal 248. incf Sekunden,1 ; Sekunden um 1 erhöhen 249. 250. movlw D'60' 251. xorwf Sekunden,0 252. btfss STATUS,Z 253. return ; Wenn Sekunden noch nicht 60, dann zurück 254. 255. incf Minuten,1 ; Minuten um 1 erhöhen 256. clrf Sekunden ; Sekunden löschen 257. 258. movlw D'60' 259. xorwf Minuten,0 260. btfss STATUS,Z 261. return ; Wenn Minuten noch nicht 60, dann zurück 262. 263. incf Stunden,1 ; Stunden um 1 erhöhen 264. clrf Minuten ; Minuten löschen 265. 266. movlw D'24' 267. xorwf Stunden,0 268. btfsc STATUS,Z 269. clrf Stunden ; Wenn Vergleich 0 ergibt, war Stunden vorher 24 270. 271. movf DCF_ok,1 272. btfss STATUS,Z 273. decf DCF_ok,1 ; Wenn DCF_ok geleich 0, dann nicht mehr runterzählen, Empfang zu lange her 274. 275. return 276. ; ********************************************************** 277. ; Schreibt bei gültigem Empfang zur vollen Minute die neue Zeit in die normalen Variablen 278. zaehler_dcf 279. movf Sek_dcf,1 ; Wenn Sek_dcf gleich 0, dann zurück, weil kein gültiger Empfang vorliegt 280. btfsc STATUS,Z 281. return 282. 283. incf Sek_dcf,1 ; Sek_dcf um 1 erhöhen 284. 285. movlw D'60' 286. xorwf Sek_dcf,0 287. btfss STATUS,Z 288. return ; Wenn Sek_dcf noch nicht 60, dann zurück 289. 290. movfw Min_dcf ; Min_dcf nach Minuten schreiben 291. movwf Minuten 292. movfw Std_dcf ; Std_dcf nach Stunden schreiben 293. movwf Stunden 294. clrf Sek_dcf ; Sek_dcf löschen 295. clrf Sekunden ; Sekunden löschen 296. 297. movlw D'24' ; Erfolgreicher Empfang, Countdown wieder auf 24 Stunden setzen 298. movwf DCF_ok 299. 300. return 301. ; ********************************************************** 302. dcf_zeit_fax 303. ; Liest die Daten aus dem DCF Brief, Aufruf 256 mal die Sekunde 304. 305. ; Wartet auf mindestens 1 Sekunde Pause im DCF um den Anfang zu erkennen 306. btfsc DCF_PortM ; Wenn 1, dann DCF_Zeit_H erhöhen 307. incf DCF_Zeit_H,1 308. 309. btfsc DCF_PortM ; Wenn 1, dann DCF_Zeit_L löschen 310. clrf DCF_Zeit_L 311. 312. clrz 313. btfss DCF_PortM ; Wenn DCF-Port 0, dann DCF_Zeit_L erhöhen 314. incf DCF_Zeit_L,1 315. btfsc STATUS,Z ; Wenn DCF_Zeit_L überläuft, dann 1 Sekunde Pause im Signal => neues Fax 316. clrf DCF_BitN 317. 318. ; Länge der Signale messen um zu entscheiden, ob es korrekt als 1 oder 0 erkannt wurde 319. btfsc DCF_PortM ; Wenn DCF-Port 1, dann zurück 320. return 321. 322. movf DCF_Zeit_H,1 ; Wenn DCF_Zeit_H gleich 0, dann zurück 323. btfsc STATUS,Z 324. return 325. 326. bcf DCF_Bit_L ; Wenn high dann eine 0 327. bcf DCF_Bit_H ; Wenn high dann eine 1 328. 329. movlw D'238' 330. addwf DCF_Zeit_H,0 331. btfsc STATUS,C 332. bsf DCF_Bit_L ; Wenn DCF_Zeit_H größer als 18 (238 + 18 = Überlauf), dann war Signal länger als 0,07 Sekunden => lang genug für eine 0 333. 334. movlw D'222' 335. addwf DCF_Zeit_H,0 336. btfsc STATUS,C 337. bcf DCF_Bit_L ; Wenn DCF_Zeit_H größer als 34, dann war Signal länger als 0,13 Sekunden => zu lang für eine 0 338. 339. movlw D'212' 340. addwf DCF_Zeit_H,0 341. btfsc STATUS,C 342. bsf DCF_Bit_H ; Wenn DCF_Zeit_H größer als 44, dann war Signal länger als 0,17 Sekunden => lang genug für eine 1 343. 344. movlw D'197' 345. addwf DCF_Zeit_H,0 346. btfsc STATUS,C 347. bcf DCF_Bit_H ; Wenn DCF_Zeit_H größer als 59, dann war Signal länger als 0,23 Sekunden => zu lang für eine 1 348. 349. bcf DCF_Good ; Mindestens DCF_Bit_H = 1 oder DCF_Bit_L = 1, dann wird DCF_Good gesetzt 350. btfsc DCF_Bit_H 351. bsf DCF_Good 352. btfsc DCF_Bit_L 353. bsf DCF_Good 354. 355. btfss DCF_Good ; Wenn ein Error, dann DCF_BitN auf 0 um neu zu beginnen, verzichte auf return 356. clrf DCF_BitN 357. 358. ; Die Bits nach Wertigkeit zuordnen 359. movlw D'20' ; Min_dcf_zw leeren 360. xorwf DCF_BitN,0 361. btfsc STATUS,Z 362. clrf Min_dcf_zw 363. 364. movlw D'21' ; Beginnen mit B'00000001' 365. xorwf DCF_BitN,0 366. btfsc STATUS,Z 367. bsf DCF_BitWM,0 368. 369. movfw DCF_BitWM ; Bitwertigkeit Minuten in W, falls Bit 1 sonst 0 in W (Wertigkeit * 0 = 0) 370. btfsc DCF_Bit_L 371. clrw 372. addwf Min_dcf_zw,1 373. 374. movlw B'00001000' 375. xorwf DCF_BitWM,0 376. btfss STATUS,Z ; Wenn B'00001000' dann kein leftschift... 377. rlf DCF_BitWM,1 378. btfsc STATUS,Z ; ...in dem Fall dann das 1. Bit setzen => B'00001010' 379. bsf DCF_BitWM,1 380. 381. movlw D'27' ; Letztes Bit drin Ende Minuten, deshalb clr 382. xorwf DCF_BitN,0 383. btfsc STATUS,Z 384. clrf DCF_BitWM 385. 386. movlw D'28' ; Std_dcf_zw leeren 387. xorwf DCF_BitN,0 388. btfsc STATUS,Z 389. clrf Std_dcf_zw 390. 391. movlw D'29' ; Beginnen mit B'00000001' 392. xorwf DCF_BitN,0 393. btfsc STATUS,Z 394. bsf DCF_BitWS,0 395. 396. movfw DCF_BitWS ; Bitwertigkeit Stunden in W, falls Bit 1 sonst 0 in W (Wertigkeit * 0 = 0) 397. btfsc DCF_Bit_L 398. clrw 399. addwf Std_dcf_zw,1 400. 401. movlw B'00001000' 402. xorwf DCF_BitWS,0 403. btfss STATUS,Z ; Wenn B'00001000' dann kein leftschift... 404. rlf DCF_BitWS,1 405. btfsc STATUS,Z ; ...in dem Fall dann das 1. Bit setzen => B'00001010' 406. bsf DCF_BitWS,1 407. 408. movlw D'34' ; Letztes Bit drin Ende Stunde, deshalb clr 409. xorwf DCF_BitN,0 410. btfsc STATUS,Z 411. clrf DCF_BitWS 412. 413. movlw D'34' ; Zeit empfangen, jetzt prüfen 414. xorwf DCF_BitN,0 415. btfsc STATUS,Z 416. call dcf_zeit_test ; DCF-Zeit auf Schlüssigkeit prüfen 417. 418. movf DCF_BitN,1 ; Wenn DCF_BitN ungeleich 0, dann Teiler_dcf syncronisieren 419. btfss STATUS,Z 420. call teiler_dcf_sync 421. 422. clrf DCF_Zeit_H ; DCF_Zeit_H ausgewertet, wieder löschen (erst hier, damit in teiler_dcf_sync vorhanden) 423. 424. incf DCF_BitN,1 425. return 426. ; ********************************************************** 427. teiler_dcf_sync 428. movfw DCF_Zeit_H ; Teiler_dcf syncronisieren 429. subwf Teiler,0 430. 431. btfss STATUS,C 432. incf Teiler,1 ; Wenn Teiler_dcf kleiner als DCF_Zeit_H => + 1, incf, weil Carry unbeeinflusst 433. 434. btfsc STATUS,C 435. decf Teiler,1 ; Wenn Teiler_dcf größer als DCF_Zeit_H => - 1, decf, weil Carry unbeeinflusst 436. 437. return 438. 439. dcf_zeit_test 440. movlw D'34' ; Sek_dcf auf die 34 Sekunde setzen 441. movwf Sek_dcf 442. 443. movfw Min_dcf_zw 444. subwf Min_dcf,1 ; Min_dcf_zw ist das Ältere und sollte 1 kleiner oder 59 größer als aktuelles sein 445. 446. bcf DCF_Good 447. 448. movlw D'255' ; Bei 255 (-1) wird DCF_Good gesetzt 449. xorwf Min_dcf,0 450. btfsc STATUS,Z 451. bsf DCF_Good 452. 453. movlw D'59' ; Bei 59 wird DCF_Good gesetzt 454. xorwf Min_dcf,0 455. btfsc STATUS,Z 456. bsf DCF_Good 457. 458. btfss DCF_Good ; Wenn DCF_Good 0 war (keine Bedingung wahr), dann wird Sek_dcf gelöscht 459. clrf Sek_dcf 460. 461. movfw Std_dcf_zw 462. subwf Std_dcf,1 ; Std_dcf_zw ist das Ältere und sollte maximal 2 kleiner, 1 kleiner oder gleich wie aktuelles sein 463. 464. bcf DCF_Good 465. 466. movlw D'254' ; Bei 254 (-2) wird DCF_Good gesetzt 467. xorwf Min_dcf,0 468. btfsc STATUS,Z 469. bsf DCF_Good 470. 471. movlw D'255' ; Bei 255 (-1) wird DCF_Good gesetzt 472. xorwf Min_dcf,0 473. btfsc STATUS,Z 474. bsf DCF_Good 475. 476. movlw D'0' ; Bei 0 wird DCF_Good gesetzt 477. xorwf Min_dcf,0 478. btfsc STATUS,Z 479. bsf DCF_Good 480. 481. btfss DCF_Good ; Wenn DCF_Good 0 war (keine Bedingung wahr), dann wird Sek_dcf gelöscht 482. clrf Sek_dcf 483. 484. movfw Min_dcf_zw ; Min_dcf und Std_dcf mit Aktuellem füllen 485. movwf Min_dcf 486. 487. movfw Std_dcf_zw 488. movwf Std_dcf 489. 490. return 491. ; ********************************************************** 492. einstellmod 493. movlw B'11111111' 494. movwf PORTB ; Alle Transistoren aus 495. bsf Sec_Zeile ; Nur Sekundenzeile an 496. movlw D'100' ; 10 ms Pause 497. call wait 498. btfsc T_Input 499. goto einstellmod ; Warten bis Taster losgelassen 500. bcf Sec_Zeile ; Jetzt Sekundenzeile aus 501. clrf T1_Wert 502. clrf T2_Wert 503. clrf T3_Wert 504. 505. dcf_test 506. movlw B'11100000' 507. movwf PORTB 508. 509. bsf Sec_Zeile 510. bsf Min_Zeile 511. bsf Std_Zeile 512. 513. btfss DCF_Port 514. bsf PORTB,2 515. 516. btfss DCF_ON 517. bsf PORTB,1 518. btfss DCF_ON 519. bsf PORTB,3 520. 521. call pol_taster 522. btfsc T1_Set ; Taster 1 nächster Modus 523. goto edit_sek_on 524. 525. btfsc T2_Set ; Taster 2 DCF off 526. bcf DCF_ON 527. 528. btfsc T3_Set ; Taster 3 DCF on 529. bsf DCF_ON 530. 531. goto dcf_test 532. 533. edit_sek_on 534. bsf Sec_Zeile 535. bcf Min_Zeile 536. bcf Std_Zeile ; Nur Sekunden an 537. clrf PORTB 538. movlw D'250' ; 25 ms Pause 539. call wait 540. bcf Sec_Zeile ; Sekunden aus 541. 542. edit_sec 543. call pol_taster 544. 545. comf Sekunden,0 ; Sekunden laden und negieren 546. movwf PORTB ; Sekunden in PORTB schreiben 547. bsf Sec_Zeile ; Sekunden an 548. 549. btfsc T1_Set ; Taster 1 nächster Modus 550. goto edit_min_on 551. 552. btfsc T2_Set 553. clrf Sekunden 554. btfsc T2_Set 555. clrf Teiler 556. 557. btfsc T3_Set 558. clrf Sekunden 559. btfsc T3_Set 560. clrf Teiler 561. 562. goto edit_sec 563. 564. edit_min_on 565. bcf Sec_Zeile 566. bsf Min_Zeile 567. bcf Std_Zeile ; Nur Minuten an 568. clrf PORTB 569. movlw D'250' ; 25 ms Pause 570. call wait 571. bcf Min_Zeile ; Minuten aus 572. 573. edit_min 574. call pol_taster 575. 576. comf Minuten,0 ; Minuten laden und negieren 577. movwf PORTB ; Minuten in PORTB schreiben 578. bsf Min_Zeile ; Minuten an 579. 580. btfsc T1_Set ; Taster 1 nächster Modus 581. goto edit_std_on 582. 583. btfsc T2_Set 584. incf Minuten,1 585. movlw B'00111100' 586. xorwf Minuten,0 587. btfsc STATUS,Z 588. clrf Minuten 589. 590. btfsc T3_Set 591. decf Minuten,1 592. movlw B'11111111' 593. xorwf Minuten,0 594. btfsc STATUS,Z 595. movlw B'00111011' 596. btfsc STATUS,Z 597. movwf Minuten ; Wenn -1 (255), dann Minuten auf 59 stellen 598. 599. goto edit_min 600. 601. edit_std_on 602. bcf Sec_Zeile 603. bcf Min_Zeile 604. bsf Std_Zeile ; Nur Stunden an 605. clrf PORTB 606. movlw D'250' ; 25 ms Pause 607. call wait 608. bcf Std_Zeile ; Stunden aus 609. 610. edit_std 611. call pol_taster 612. 613. comf Stunden,0 ; Stunden laden und negieren 614. movwf PORTB ; Stunden in PORTB schreiben 615. bsf Std_Zeile ; Stunden an 616. 617. btfsc T1_Set ; Taster 1 nächster Modus 618. goto All_on 619. 620. btfsc T2_Set 621. incf Stunden,1 622. movlw B'00011000' 623. xorwf Stunden,0 624. btfsc STATUS,Z 625. clrf Stunden 626. 627. btfsc T3_Set 628. decf Stunden,1 629. movlw B'11111111' 630. xorwf Stunden,0 631. btfsc STATUS,Z 632. movlw B'00010111' 633. btfsc STATUS,Z 634. movwf Stunden ; Wenn -1 (255), dann Stunden auf 23 stellen 635. 636. goto edit_std 637. 638. pol_taster 639. movlw D'20' ; 2 ms Pause 640. call wait 641. 642. bcf Sec_Zeile 643. bcf Min_Zeile 644. bcf Std_Zeile ; Alle Zeilen aus 645. 646. movlw B'11111111' ; Alle LEDs aus 647. movwf PORTB 648. 649. bcf T1_Set ; Alle Taster zurücksetzen 650. bcf T2_Set 651. bcf T3_Set 652. 653. ; Drücken von Taster 1 Überwachen 654. bsf Sec_Zeile ; Taster 1 an 655. movlw D'3' ; 0,3 ms Pause 656. call wait 657. btfsc T_Input 658. incf T1_Wert,1 ; Wenn Taster 1 gedrückt, dann erhöhen 659. movfw T1_Wert 660. btfss T_Input 661. clrf T1_Wert ; Wenn nicht gedrückt, dann löschen 662. xorwf T1_Wert,0 663. btfss STATUS,Z 664. bsf T1_Set ; Wenn löschen den Wert verringert hat, dann auch Taster 1 Bit setzen 665. btfsc T1_Set 666. clrf T1_Wert ; Wenn Tasterbit gesetzt, dann Zähler löschen 667. bcf Sec_Zeile ; Taster 1 aus 668. 669. ; Drücken von Taster 2 Überwachen 670. bsf Min_Zeile ; Taster 2 an 671. movlw D'3' ; 0,3 ms Pause 672. call wait 673. btfsc T_Input 674. incf T2_Wert,1 ; Wenn Taster 2 gedrückt, dann erhöhen 675. 676. movfw T2_Wert 677. btfss T_Input 678. clrf T2_Wert ; Wenn nicht gedrückt, dann löschen 679. xorwf T2_Wert,0 680. btfss STATUS,Z 681. bsf T2_Set ; Wenn löschen den Wert verringert hat, dann auch Taster 2 Bit setzen 682. 683. btfsc T2_Wert,5 684. bsf T1_Fast ; Taster 2 Schnellbit setzen 685. 686. btfsc T2_Wert,5 687. bsf T2_Set ; Taster 2 Bit setzen 688. 689. movlw B'0000111' 690. btfsc T1_Fast 691. addwf T2_Wert,1 ; Wenn Schnellbit gesetzt, dann schneller zählen. 692. 693. btfss T_Input 694. bcf T1_Fast ; Wenn nicht gedrückt, dann Schnellbit löschen 695. 696. btfsc T2_Set 697. clrf T2_Wert ; Wenn Tasterbit gesetzt, dann Zähler löschen 698. bcf Min_Zeile ; Taster 2 aus 699. 700. ; Drücken von Taster 3 Überwachen 701. bsf Std_Zeile ; Taster 3 an 702. movlw D'3' ; 0,3 ms Pause 703. call wait 704. btfsc T_Input 705. incf T3_Wert,1 ; Wenn Taster 3 gedrückt, dann erhöhen 706. 707. movfw T3_Wert 708. btfss T_Input 709. clrf T3_Wert ; Wenn nicht gedrückt, dann löschen 710. xorwf T3_Wert,0 711. btfss STATUS,Z 712. bsf T3_Set ; Wenn löschen den Wert verringert hat, dann auch Taster 3 Bit setzen 713. 714. btfsc T3_Wert,5 715. bsf T2_Fast ; Taster 3 Schnellbit setzen 716. 717. btfsc T3_Wert,5 718. bsf T3_Set ; Taster 3 Bit setzen 719. 720. movlw B'0001111' 721. btfsc T2_Fast 722. addwf T3_Wert,1 ; Wenn Schnellbit gesetzt, dann schneller zählen. 723. 724. btfss T_Input 725. bcf T2_Fast ; Wenn nicht gedrückt, dann Schnellbit löschen 726. 727. btfsc T3_Set 728. clrf T3_Wert ; Wenn Tasterbit gesetzt, dann Zähler löschen 729. bcf Std_Zeile ; Taster 3 aus 730. 731. movlw D'100' ; 10 ms Pause 732. call wait 733. 734. return 735. ; ********************************************************** 736. ; Ohne Anzeige 737. power_save 738. movlw B'11111111' 739. movwf PORTB 740. movlw B'00000000' 741. movwf PORTA ; Alle Transistoren aus 742. 743. movlw D'5' ; Zeitkonstante damit Zähler ausgeführt werden kann 744. movwf aloops 745. btfsc INTCON,T0IF ; Wenn Interuptbit gesetzt ist... 746. call zaehler 747. 748. btfsc Power_Good 749. goto power_save 750. return 751. ; ********************************************************** 752. ; Warteschleife 753. wait 754. movwf aloops ; Zeitkonstante für gewünschte Wartezeit in 0.1 ms 755. await 756. movlw D'5' ; Zeitkonstante für etwa 0.1ms 757. movwf bloops 758. btfsc INTCON,T0IF ; Wenn Interuptbit gesetzt ist... 759. call zaehler 760. btfsc Power_Good 761. call power_save ; Wenn der Power_Good Pin high wird dann Anzeige aus 762. bwait 763. nop 764. nop 765. nop 766. nop 767. nop 768. decfsz bloops, F ; 1 ms vorbei? 769. goto bwait ; nein, noch nicht 770. decfsz aloops, F ; Wunschzeit vorbei? 771. goto await ; nein, noch nicht 772. return ; das Warten hat ein Ende 773. 774. end
Erstellt im März 09