PIC-programmeringsuppgift (PROA)



Relevanta dokument
Microprocessor / Microcontroller. Industrial Electrical Engineering and Automation

Microprocessor / Microcontroller

Boiler with heatpump / Värmepumpsberedare

Dessa komponenter plus några motstånd, klockkrets, kondensatorer och annat smått och gott har åstadkommit ett fungerande POV-hjul.

Digitala Projekt(EITF40) - Larm

BRUKSANVISNING. Oscilla 910

Effektpedal för elgitarr

Support Manual HoistLocatel Electronic Locks

Beijer Electronics AB 2000, MA00336A,

Laborera med SmartCard

Växtviskaren EITF11 Digitala projekt VT15, I12

Bruksanvisning. Multimeter KEWTECH KT115

Beskrivning av porthantering i mikroprocessorn SAM3U som används på vårt labkort SAM3U- EK.

Styrteknik: Binära tal, talsystem och koder D3:1

INGENJÖRSHÖGSKOLAN INGENJÖRSHÖGSKOLAN

Table of Contents. Credits

Realtidsprogrammering. En introduktion Implementering (med exempel från PIC)

2.45GHz CF Card Reader User Manual. Version /09/15

Rev No. Magnetic gripper 3

Datakommunikation med IR-ljus.

Föreläsningsanteckningar till Konstruktionsmetoder

Styrteknik 4.5/7.5 hp distans: Tidskretsar, räknare

William Sandqvist



Digitala Projekt(EITF40) - Larm

Systemkonstruktion SERIEKOMMUNIKATION

Product configurations Produire configuration Produkt konfigurationen Producto configuraciones Produkt konfigurationerna


DIGITALA PROJEKT Väderstation

#include <pic.h> #include <sys.h> char LEFT,RIGHT,MOTORHASTIGHET;

ATtiny 85. Krympa projekt från Arduino Uno

Tenta i Digitalteknik

TMT-918 Fjärrkontroll med timer. Säkerhet. Tekniska data

Pulsmätare med varningsindikatorer

2.1 Installation of driver using Internet Installation of driver from disk... 3

Decoration Light Dekorationsbelysning/Dekorasjonsbelysning

Laborationens mål är att få displayen att visa timmar, minuter och sekunder samt att kunna ställa klockan.

Bruksanvisning DAB One

Exempeluppgift i Logikstyrning. 1 Inledning. 2 Insignaler och utsignaler

Manual för EQE PLC enhet

Bruksanvisning Multimeter Elma 805 / Elma 807

Lösenordsportalen Hosted by UNIT4 For instructions in English, see further down in this document

Webbregistrering pa kurs och termin

Provmoment: Ladokkod: Tentamen ges för: Tentamen TE111B El3. Namn: Personnummer: Tentamensdatum: Tid: 14:00-18:00.

DOWN/RESET(Knapp C) UP/START(Knapp D)

Monteringsanvisning / Installation instruction Felsökningsschema Styxx Troubleshooting Styxx STEG 1

Digitala Projekt (EITF11)

L/C-meter 2007 Byggbeskrivning v

Att använda pekare i. C-kod

BRUKSANVISNING FÖRPACKNINGENS INNEHÅLL: MONTERINGSMÅTT: METER för solcellssystem med dubbla batterier

Laboration i digitalteknik Datablad

electiaprotect GSM SEQURITY SYSTEM Vesta EZ Home Application SMART SECURITY SYSTEMS! SVENSKA ios Android

, fukt- och temperaturdetektor Modbus RTU, trafikljus

Laboration i digitalteknik Datablad

FIX LED-LYSRÖRSARMATUR MED AKRYLKÅPA IP44

Föreläsning 6: Introduktion av listor

Elektromagnetiska flödesmätare. Modell AMC2100

Föreläsning 8. Designmönster

Hur man kompilerar och kör IT++-program med MinGW. 1 Sammanfattning. 2 Om dokumentet. 3 Om min konfiguration

1. Knappar: Startar vågen samt nollställning. Tara. Stänger av vågen. Inställning utav konfiguration ON/ ZERO TARE OFF SET 1-9

TSIU50 Mikrodatorprojekt. LAB1 AVR-introduktion och logikanalysator

Föreläsning 4: Poster

Digitala Projekt (EITF11) Hemlarm

Styrteknik: Tidskretsar, räknare

Telia Anita 20i Nummerpresentatören med telesvarsindikation

Laboration D184. ELEKTRONIK Digitalteknik. Sekvensnät beskrivna med VHDL och realiserade med PLD

Övning 6. Parallellport, timer

PROJEKT LJUD. KOPIERINGSUNDERLAG Martin Blom Skavnes, Staffan Melin och Natur & Kultur Programmera i teknik ISBN

TENTAMENSUPPGIFTER I ELEKTROTEKNIK

HÖSTEN i BILD och TEXT

Examination i. PROGRAMMERINGSTEKNIK F1/TM1 TIN212 (Dugga) Dag: Onsdag Datum: Tid: (OBS 3 tim) Rum: V

IRAB Mottagare sida 2-5 Tele Radio AB Mottagare sida 6

Schenker Privpak AB Telefon VAT Nr. SE Schenker ABs ansvarsbestämmelser, identiska med Box 905 Faxnr Säte: Borås

Remote control Fjärrströmbrytare / Fjernstrømbryter

Elektroteknik MF1016 föreläsning 9 MF1017 föreläsning 7 Mikrodatorteknik

LEGO Robot programmering och felsökning Hur svårt ska det vara att följa den svarta linjen?

Föreläsning 4 IS1300 Inbyggda system

Bruksanvisning till LEDMasterBasic1

NXT LEGO-robot laboration Programmering och felsökning av en LEGOrobot

EITF11 - Digitala projekt. Hastighetsmätare. Hugo Backmyr Mattias Karlsson

Systemkonstruktion LABORATION REALTIDSPROGRAMMERING

PRESS FÄLLKONSTRUKTION FOLDING INSTRUCTIONS

SNABBGUIDE. Telia Anita 20 Bruksanvisning. Bläddra bland lagrade telefonnummer. Radera ett nummer. Radera alla nummer

Får endast utföras av behörig personal. May only be carried out by authorized electrician

Jan Babor och Oscar Ågren Handledare: Bertil Lindvall 5/16/2011

Anvisning för Guide for

Klock Radio KCR-9. Svensk Bruksanvisning

Larmcentral. Digitala Projekt. Cecilia Olsson & Erika Björck Handledare: Bertil Lindvall LUNDS TEKNISKA HÖGSKOLA

22/02/16. Arduino Introduktion till Arduino. Arduino. Microcontroller - Embedded systems. Historia Organisation - Ekosystem

Tele Radio 860. Manual IM A3

Lösningförslag till Exempel på tentamensfrågor Digitalteknik I.

1. Unpack content of zip-file to temporary folder and double click Setup

Outline. For. I istället för att följa det normala ordningen, man ändra den. I i Java får man inte göra hopp hur som helst

INSTALLATION INSTRUCTIONS

Thunder s Truck projektrapport

DATORTEKNIK. Tangentbord, knappsatser och deras avkodning

VHDL testbänk. Mall-programmets funktion. Låset öppnas när tangenten 1 trycks ned och sedan släpps. William Sandqvist

Utkast. Programmering. Signals. Olika typer av program. Sommarkurs Avbrott i mjukvara.

Transkript:

PIC-programmeringsuppgift (PROA) Ugnsklocka digital klocka med en timer-funktion Tillämpad Digitalteknik med PIC-processor IL131V (HT12) Karl-Axel Zander 920208-5594 28-01-2013 underskrift

Uppgift & beskrivning Ursprunglig uppgift (28-10-2012) En timer, "ugnsklocka", på en 4-digit 7-segmentdisplay (min:sek) som man ställer in en tid med hjälp av en/flera knapp(ar), ev vridomkopplare, den ska räkna ner. Timern startas med en knapp och när tiden når 00:00 görs ett lämpligt ljud ifrån en hörlur under ett par sekunder. Efteråt kan användaren ställa in och starta en ny nedräkning. Utökad uppgift (05-12-2012) jag utökar min uppgift med att lägga in en klockfunktion som kan visa vad klockan är när timern inte används. Håller det enkelt genom att den får ställas in på nytt när kretsen startas efter power-off och utan extern kristall (för bättre noggrannhet). Denna produkt beskriven ovan ska byggas och redovisas prototypaktigt med hjälp av en pic-processor och de nödvändiga elektroniska komponenter som krävs för att uppgiftsidén ska vara demonstrerbar. Hårdvara Jag har använt mig av PIC-processorn 16F628A med 4MHz intern oscillator, 3,5KB program minne och 16st input/output pinnar (1 input only, 1 input half output). Fig 1. Pinnkarta för PIC16F628A (och liknande modeller)

Jag har valt att koppla in så mycket som tre knappar för att styra produkten för att användaren lättsamt ska kunna förstå och använda den. För att göra ett hörbart alarmljud sitter en hörlur kopplad till en port som kan spela upp ljud genom att med olika hastigheter skifta porten mellan 1 och 0. Displayen är en enkel 4-siffrig 7-segment display med 16 pinnar. För att koppla samman dessa komponenter och dessutom smidigt kunna införa spänningskälla och ledningar in för att kunna programmera och hantera PIC-processorn så är allt detta monterat på ett kopplingsdäck av lagom storlek. I figur 2 ses ett förenklat blockdiagram över hur komponenterna är kopplade från processorn. Fig 2. Blockdiagram I figur 3 ses produkten färdigmonterad på kopplingsdäcket.

Fig 3 Kopplingsdäcket Komponentlista - PIC-processor 16F628A - Motstånd 240Ω (segmentenkopplingarna till displayen) - Mostånd 1,5KΩ (till transistorerna) - Motstånd 10KΩ, (i förslutningen av matningsspänningen och pull-up motstånd till knapparna) - PNP-transistorer BC557B, Ic max (A) 0,2A (stödförsörning till displayen, kopplingarna digit1-digit4) - Diod 100V 150mA - Kondensator 2,7µF - Trycknappar - 4-digit 7-segment display (modell ATA3492BW) - Keramisk hörlur utan plugg - Sladdar, kopplingstråd, ISCP-kabel till Microchip PICkit 2 programmerare En kodensator är kopplad mellan + och i mattningsspänningen, se längst ner till vänster i figur 3. Denna fungerar som ett utjämnande filter för eventuella spänningsfall från matningskällan. Pullup motstånd är kopplade i varje tryckknapp krets för att signalen ska hålla sig till hög (5V) och inte fladdrar till vilket läge som helst av sig själv när knappen inte trycks. Hur funkar 7-segment displayen? Bara en siffra kan användas åt gången då alla de 4 displayerna delar ut-pinnar, segmentpinnar. Se kopplingsscehmat i figur 4. Detta är en fördel då vi skär ner på antalet ledningar, samtidigt som vi kan få alla lampor att till synes att lysa samtidigt, genom att med sk multiplexing mycket snabbt tända en siffra, släcka den,

ställa om segmentpinnarna, tända nästa siffra, osv och konstant så loopa runt alla siffror. Gör man detta väldigt snabbt (1000 gånger i sekunden) så ser en människa inte att det blinkar utan som att alla lampor faktiskt är tända samtidigt. Fig 4. Displayens kopplingsschema Det uppmätta spänningsfallet över displayen är 3V, om räknar med att vi har 5V från spänningkällan så har vi 2V kvar. Varje led i varje siffra (8st) får således strömmen 2/240 = 8mA då dessa är kopplade genom individuella 240Ω motstånd, vilket är tillräckligt för att lysa upp en LED synbart. PNP-transistorer används till displayen för att pic-processorn bara kan sourca 25mA från portarna (även agera jord, sinka 25mA). Då 8 LEDS drar ~64mA så klarar inte porten alla dessa lampor. Nu slår porten på och av spänningen som kommer direkt från matningskällan genom en transistor (kopplade genom 1,5KΩ motstånd), som i sin tur är kopplad till displayen. Mjukvara I figur 5 ses ett sturkturdiagram (JSP-diagram) över programflödet med sparsamt med detaljoperationer för att göra det överskådligt. En del förstå till logiken och hur programmet fungerar faller tyvärr bort i denna förenklade variant, och kan behöva kompletterande förklaring. Programmet börjar i main metoden med att ställa in portar och timers, och initiering av programvariabler sker. Dessa steg är väl kommenterade och förklarade i programkoden. Komparatorer och dyl stängs av så att alla portar kan utnyttjas för out eller input då denna hårdvarukonstruktion kräver det. Två timers ställs in för att göra interrupt med olika frekvens, vilket är centralt för programmet, användas för klockans & timerns tidräkning och för att kunna göra en fördröjningsfunktioner i programmet utan låsning. Programmet går sedan in i en oändlig loop, programmet körs till användaren rycker sladden. Programmet har 4 tillstånd, states eller som kallat modes. Dessa är:

1: set clock 2: display clock 3: set timer 4: timer running Button1, button2 och button3 gör olika saker beroende på vilket tillstånd man befinner sig. Loopen består av ett antal partier kod omringande av en villkorsats var, se strukturdiagrammet. Uppfylls villkoret körs kodpartiet, annars hoppas det över och kollas först igen vid nästa vända. Tex så kollas Timer2 och Timer0s interrupt flagga således en gång per loop, dvs dessa bevakas inte under konstant låst polling utan lite annan kod får köra imellan. Eftersom dessa timrar triggar ofta så undviks helt att använda låsta programdelayer (programmet fastnar på ett ställe för att vänta ut en bestämd tid). Delays är i stället gjorda med countervariabler som ökas på i samband med timerinterrupten, värdena på dessa kan kollas på övriga ställen i programmen och räknas om till hur lång riktig tid som har förflutit sedan senaste nollställningen. Ett problem jag blev osäker på är noggrannheten för tidräkningen. Timer2 är inställd för att ge interrupt ungefär 1/244 sekund enligt denna beräkning: Count = fclk / (4*Prescaler*(PR2-TMR2)*Postscaler*fout = 4MHz / (4*1*(256-0)*16*1Hz) = 244,14 Efter att timern har triggat ungefär 244 gånger så bör det således gått en sekund. Detta är tydligen inte noggrant nog då klockan drog sig märkbart. Då jag var osäker hur jag skulle lösa och testa detta så lämnade jag detta som en parantes i projektet. Jag testade dock att ändra detta värde till 246 efter manuellt testande vilket verkade bli klart bättre, jag är dock osäker på matematiken och eventuella andra faktorer som behövs ta hänsyn till. Sedan är jag även osäker på hur programmets struktur påverkar noggrannheten på hur snabbt dessa interrupts upptäcks. Optimalt vore om timerns flagga bevakades med låst polling, medan nu körs en massa annan kod och flaggan kollas bara ibland. Men jag antar att det fungerar dugglig i nuläget som en prototyp för demonstration, på 10 minuter manuellt testande kan jag inte se att klockan drar sig märkbart efter den manuella korrigeringen.

Fig 5. Förenklat strukturdiagram (JSP) för programkoden

Programkod Kompilator: C-kompilatorn Cc5x 3.4A (C-dialekt för PIC) av Bengt Knudsen /* owenclock.c B Knudsen Cc5x C-compiler - not ANSI-C An ordinary digital clock on a with a countdown alarm timer function - Processor "pic16f628a" - 4-digit 7-segment display - 3 buttons: "mode", "increase", "set/start/stop" - Ceramic earphone for alarm \/ Button1 -- RA2 16F628A RA1 -- Digit1 Digit4 -- RA3 RA0 -- Digit2 Digit3 -- RA4-od RA7/OSC1 -- Earphone Button2 -- RA5/MCLR RA6/OSC2 -- Segment A GND -- Vss Vdd -- +5V Button3 -- RB0/INT (RB7)/PGD -- Segment G Segment E -- RB1/Rx (RB6)/PGC -- Segment C Segment B -- RB2/Tx RB5 -- Colon Segment D -- RB3/CCP (RB4)/PGM -- Segment F 7-segment digit: A F B G E C */ D #include "16F628A.h" #pragma config = 0x3F10 //Low Volt Programming off (RB4), RA5 I/O internal MCLR (RA5 can only be used as input) void setsegments(char number); void main(void) //configure ports CMCON = 0b111; //turn off comparators (port RA3 RA4) TRISA = 0b00100100; //port RA2 RA5 input, port RA0 RA1 RA3 RA4 RA6 RA7 output TRISB = 0b00000001; //port RB0 input, port RB1-RB7 output //Timer0, inbuilt 8-bit interrupt timer TMR0 = 0; //TMR0 initiation T0CS = 0; //use internal CLK T0SE = 0; //react on Low2High edge PSA = 0; //use presacler PS0 = 0; PS1 = 0; //presacler PS2 PS1 PS0 bits set to "000" = 1:2 PS2 = 0;

//Timer2, another inbuilt 8-bit interrupt timer T2CON = 0b01111100; //Timer2 initalization: postscaler = 1111 (1:16), timer2 set to ON, prescaler = 00 (1:1) TMR2 = 0; //start value = 0 PR2 = 0xFF; //stop value = 255 RB1 = 1; RB2 = 1; RB3 = 1; RB4 = 1; RB5 = 1; RB6 = 1; RB7 = 1; RA6 = 1; RA0 = 1; RA1 = 1; RA3 = 1; RA4 = 1; //turn off display char timer0counter = 0; //count number of times timer0 has interrupted char timer2counterclock = 0; //count number of times timer2 has interrupted char timer2countertimer = 0; //count number of times timer2 has interrupted //button 1 ("mode") state variables (single signal on press) char button1counter = 0; //time counter used for debounce char button1pressed = 0; //boolean, sets to true when the press is detected on port char button1pressedalready = 0; //boolean, sets to true when waiting on deboucning on pressdown (study button handling code to see how this and following state variables are used) char button1waitforrelease = 0; //boolean, sets to true when debouncing is done char button1releasedalready = 0; //boolean, sets to true when waiting on debouncing on release //button 2 ("increase") state variables (continous signals (with delay between them) on hold down) char button2counter = 0; char button2pressed = 0; char button2pressedalready = 0; char button2delay = 35; //amount of delay between each signal (decreasing slowly when button hold down long for faster stepping) //button 3 ("set/start/stop") state variables (same as button 1) char button3counter = 0; char button3pressed = 0; char button3pressedalready = 0; char button3waitforrelease = 0; char button3releasedalready = 0; //earphone state variables char soundcounter = 0; //time counter used for duration of a sound char notecounter = 0; //time counter used for make diffrent long vibrations (notes) char timerstartsound = 0; //boolean, true if sound "Timer start sound" is playing char timerendsound = 0; //boolean, true if sound "Timer end sound" is playing char soundfirsttime = 1; //boolean, keep track of current state in loop //state variables for blinking digits char displayblinkcounter = 0; char displayblinkactivated = 0; char displayblinkactivatedalready = 0; //the timer "time", signed data type to handle negative values (handy when counting down) signed char timerdigit1 = 0; signed char timerdigit2 = 0; signed char timerdigit3 = 0; signed char timerdigit4 = 0; //least significant digit char timerstarted = 0; //boolean, true if timer is running //the clock "time" char clockdigit1 = 0; char clockdigit2 = 0; char clockdigit3 = 0; char clockdigit4 = 0; //least significant digit char clockstarted = 0; //boolean, true if clock is running

char clockminutecounter = 0; //counter used to count interrupts (to 60 seconds) char setclockchoosendigit = 1; //state variable 1-4, selected digit when setting clock char mode = 1; //program states 1-4, see list below /* modes: 1: set clock 2: display clock 3: set timer 4: timer running */ while(1) //program loop, "semi polling" used for program updates, buttons, sounds etc i.e non blocking if (TMR2IF) //check if timer2 has interrupted (every 1/244 sec) TMR2IF = 0; //reset flag //update diffrent counters used everywhere timer2counterclock++; timer2countertimer++; button1counter++; button2counter++; button3counter++; soundcounter++; displayblinkcounter++; //blink display function, toogle a boolean every 1/2 sec if (displayblinkactivatedalready == 0) displayblinkactivatedalready = 1; displayblinkcounter = 0; if (displayblinkcounter >= 122) displayblinkactivatedalready = 0; displayblinkactivated =!displayblinkactivated; // if (timer2counterclock >= 246) //every 1 sec (to fix: Count should be ~244 to simualte 1 second but it triggers slighty too fast, why? Manually adjusted value used for now) if (clockstarted) //is clock running? clockminutecounter++; if (clockminutecounter == 60) //one minute passed yet? clockminutecounter = 0; //update clock "time" clockdigit4++; if (clockdigit4 > 9) clockdigit4 = 0; clockdigit3++; if (clockdigit3 > 5) clockdigit3 = 0; clockdigit2++; if (clockdigit1 == 2 && clockdigit2 > 3) clockdigit2 = 0; clockdigit1 = 0; if (clockdigit2 > 9)

clockdigit2 = 0; clockdigit1++; timer2counterclock = 0; if (timer2countertimer >= 246) //every 1 sec (to fix: Count should be ~244 to simualte 1 second but it triggers slighty too fast, why? Manually adjusted value used for now) if (timerstarted) //is timer running? //update timer "time" timerdigit4--; if (timerdigit4 < 0) timerdigit4 = 9; timerdigit3--; if (timerdigit3 < 0) timerdigit3 = 5; timerdigit2--; if (timerdigit2 < 0) timerdigit2 = 9; timerdigit1--; if (timerdigit1 == 0 && timerdigit2 == 0 && timerdigit3 == 0 && timerdigit4 == 0) //00:00? then make alarm and stop timerendsound = 1; timerstarted = 0; if (mode == 1) //if in "set clock" mode, set clock as of the selection it was (when timer triggerd) and start clock clockstarted = 1; //start clock timer2counterclock = 0; mode = 3; timer2countertimer = 0; if (T0IF) //check if timer0 has interrupted (every 1/2000 sec) T0IF = 0; //rested flag //update counters used everywhere notecounter++; timer0counter++; if (timer0counter >= 2) //every 1/1000 sec timer0counter = 0;

//update display, multiplex digits (light them one at the time) with ~1/1000 sec delay to avoid flicker (must due to shared segment pins on each digit on display) if (mode == 1) //"set clock": blink non selected digits, light colon and selected digit RB5 = 0; //colon if (!displayblinkactivated) if (RA1 == 0) //digit 1 setsegments(clockdigit2); RA1 = 1; RA0 = 0; if (RA0 == 0) //digit 2 setsegments(clockdigit3); RA0 = 1; RA4 = 0; if (RA4 == 0) //digit 3 setsegments(clockdigit4); RA4 = 1; RA3 = 0; if (RA3 == 0) //digit 4 setsegments(clockdigit1); RA3 = 1; RA1 = 0; setsegments(clockdigit1); RA1 = 0; //selected digit should be lit without blinking RA1 = 1; RA0 = 1; RA4 = 1; RA3 = 1; if (setclockchoosendigit == 1) setsegments(clockdigit1); RA1 = 0; if (setclockchoosendigit == 2) setsegments(clockdigit2); RA0 = 0; if (setclockchoosendigit == 3) setsegments(clockdigit3); RA4 = 0; if (setclockchoosendigit == 4) setsegments(clockdigit4); RA3 = 0; if (mode == 2) //"display clock": blink colon, light digits

if (!displayblinkactivated) RB5 = 0; //colon RB5 = 1; if (RA1 == 0) //digit 1 setsegments(clockdigit2); RA1 = 1; RA0 = 0; if (RA0 == 0) //digit 2 setsegments(clockdigit3); RA0 = 1; RA4 = 0; if (RA4 == 0) //digit 3 setsegments(clockdigit4); RA4 = 1; RA3 = 0; if (RA3 == 0) //digit 4 setsegments(clockdigit1); RA3 = 1; RA1 = 0; setsegments(clockdigit1); RA1 = 0; if (mode == 3 mode == 4) //"set timer" and "timer running": light digits and colon, no blinking RB5 = 0; //colon if (RA1 == 0) //digit 1 setsegments(timerdigit2); RA1 = 1; RA0 = 0; if (RA0 == 0) //digit 2 setsegments(timerdigit3); RA0 = 1; RA4 = 0; if (RA4 == 0) //digit 3 setsegments(timerdigit4); RA4 = 1; RA3 = 0; if (RA3 == 0) //digit 4 setsegments(timerdigit1); RA3 = 1; RA1 = 0; setsegments(timerdigit1); RA1 = 0;

//"semi polling" of buttons //button 1 "mode" (single signal on press) if (RA2 == 0) button1pressed = 1; if (button1pressed) if (button1pressedalready == 0) //first time we get here while button1pressed = ture? if (mode == 1) //"set clock": select next digit setclockchoosendigit++; if (setclockchoosendigit > 4) setclockchoosendigit = 1; if (mode == 2) //"display clock": switch to timer if (timerstarted) mode = 4; mode = 3; if (mode == 3 mode == 4) //"set timer" and "timer running": switch to clock mode = 2; button1pressedalready = 1; button1counter = 0; if (button1counter >= 5) //delay ~20ms to debounce button after press button1waitforrelease = 1; if (button1waitforrelease == 1 && RA2 == 1 && button1releasedalready == 0) //released button yet? button1releasedalready = 1; button1counter = 0; if (button1releasedalready == 1 && button1counter >= 5) //delay ~20ms to debounce button after release //button is released and debounced, reset all state variables for next press button1pressedalready = 0; button1pressed = 0; button1waitforrelease = 0; button1releasedalready = 0; //button 2 "increase" (continous signals (with delay between them) on hold down) if (RA5 == 0) button2pressed = 1; button2delay = 35; //delay ~150ms delay between each signal on holddown, reseted to this value if button is released if (button2pressed) if (button2pressedalready == 0) if (mode == 1) //"set clock": increase selected digit by 1

if (setclockchoosendigit == 1) clockdigit1++; if (clockdigit1 == 2 && clockdigit2 > 3) clockdigit1 = 0; if (clockdigit1 > 2) clockdigit1 = 0; if (setclockchoosendigit == 2) clockdigit2++; if (clockdigit1 == 2 && clockdigit2 > 3) clockdigit2 = 0; if (clockdigit2 > 9) clockdigit2 = 0; if (setclockchoosendigit == 3) clockdigit3++; if (clockdigit3 > 5) clockdigit3 = 0; if (setclockchoosendigit == 4) clockdigit4++; if (clockdigit4 > 9) clockdigit4 = 0; //mode 2 "display clock": do nothing time 90:00 if (mode == 3) //"set timer": increase time with 1 second at the timerdigit4++; if (timerdigit4 > 9) timerdigit4 = 0; timerdigit3++; if (timerdigit3 > 5) timerdigit3 = 0; timerdigit2++; if (timerdigit2 > 9) timerdigit2 = 0; timerdigit1++; if (timerdigit1 > 9) //to fix: max number (99:59) goes to timerdigit1 = 9; //mode 4 "timer running": do nothing button2pressedalready = 1; button2counter = 0; if (button2counter >= button2delay) //delay button2pressedalready = 0; button2pressed = 0;

if (RA5 == 0) //button2delay equals amount of delay between each signal (decreasing slowly when button hold down long for faster stepping) button2delay--; if (button2delay < 1) button2delay = 1; //button 3 "set/start/stop" (single signal on press) if (RB0 == 0) button3pressed = 1; if (button3pressed) if (button3pressedalready == 0) //first time we get here when button3pressed = ture? if (mode == 1) //"set clock": set selected time and enter mode 2 clockstarted = 1; //start clock timer2counterclock = 0; mode = 2; //exit "set clock" mode and enter "display clock" mode if (mode == 2) //"display clock": stop clock and enter mode 1 clockstarted = 0; mode = 1; if (mode == 3) //"set timer": start timer and enter mode 4 if (timerdigit1 == 0 && timerdigit2 == 0 && timerdigit3 == 0 && timerdigit4 == 0) //if no time is set (00:00), just play sound and do nothing timerendsound = 1; timerstartsound = 1; timerstarted = 1; timer2countertimer = 0; mode = 4; if (mode == 4) //"timer running": stop timer, reset it and enter mode 3 timerstarted = 0; timerdigit1 = 0; timerdigit2 = 0; timerdigit3 = 0; timerdigit4 = 0; mode = 3; button3pressedalready = 1; button3counter = 0; if (button3counter >= 5) //delay ~20ms to debounce button after press button3waitforrelease = 1; if (button3waitforrelease == 1 && RB0 == 1 && button3releasedalready == 0) //released button yet? button3releasedalready = 1; button3counter = 0; if (button3releasedalready == 1 && button3counter >= 5) //delay ~20ms to debounce button after release //button is released and debounced, reset all state variables for next press

button3pressedalready = 0; button3pressed = 0; button3waitforrelease = 0; button3releasedalready = 0; //"Timer start sound" if (timerstartsound) if (soundfirsttime) soundfirsttime = 0; soundcounter = 0; //start counting time if (soundcounter <= 122) //play half a second if (notecounter >= 2) //bright tune, lower value give faster vibrations (changes on port RA7) notecounter = 0; RA7 =!RA7; soundfirsttime = 1; timerstartsound = 0; //"Timer end sound" if (timerendsound) if (soundfirsttime) soundfirsttime = 0; soundcounter = 0; //start counting time if (soundcounter <= 244) //play 1 second if (notecounter >= 4) //dark tune, higher value give slower vibrations (changes on port RA7) notecounter = 0; RA7 =!RA7; soundfirsttime = 1; timerendsound = 0; void setsegments(char number) //enable segments to form argument number switch (number) //0 = on, 1 = off <segment order: A B C D E F G> case 0: RA6 = 0; RB2 = 0; RB6 = 0; RB3 = 0; RB1 = 0; RB4 = 0; RB7 = 1; break; case 1: RA6 = 1; RB2 = 0; RB6 = 0; RB3 = 1; RB1 = 1; RB4 = 1; RB7 = 1; break; case 2: RA6 = 0; RB2 = 0; RB6 = 1; RB3 = 0; RB1 = 0; RB4 = 1; RB7 = 0; break; case 3: RA6 = 0; RB2 = 0; RB6 = 0; RB3 = 0; RB1 = 1; RB4 = 1; RB7 = 0; break; case 4: RA6 = 1; RB2 = 0; RB6 = 0; RB3 = 1; RB1 = 1; RB4 = 0; RB7 = 0; break; case 5: RA6 = 0; RB2 = 1; RB6 = 0; RB3 = 0; RB1 = 1; RB4 = 0; RB7 = 0; break;

case 6: RA6 = 0; RB2 = 1; RB6 = 0; RB3 = 0; RB1 = 0; RB4 = 0; RB7 = 0; break; case 7: RA6 = 0; RB2 = 0; RB6 = 0; RB3 = 1; RB1 = 1; RB4 = 1; RB7 = 1; break; case 8: RA6 = 0; RB2 = 0; RB6 = 0; RB3 = 0; RB1 = 0; RB4 = 0; RB7 = 0; break; case 9: RA6 = 0; RB2 = 0; RB6 = 0; RB3 = 1; RB1 = 1; RB4 = 0; RB7 = 0; break; default: RA6 = 1; RB2 = 1; RB6 = 1; RB3 = 1; RB1 = 1; RB4 = 1; RB7 = 1; break; //turn off all segments if number!= 0..9