Vil arbejde videre med koden idag og håbe på at lyset pludselig viser sig he he
Du skal næsten have en compiler, så du kan trykke på "compile" knappen, og se hvor der er fejl; compileren vil afsløre mange ting (men selvfølgelig ikke alt).
Jeg anbefaler
WinAVR med GCC og
avrdude (jeg ved ikke om gcc skal downloades separat, eller om den er med i WinAVR; det er muligt at avrdude også er med i WinAVR.
Jeg venter stadig på microcontrollerne. Jeg blev lidt utålmodig, og ringede så til RS.
Det ser ud til at DHL har klokket lidt i det, for de sendte dem til Tyskland. Tyskerne fandt så ud af at de var sendt forkert, og rettede fejlen. Nu er de ankommet til Peru!
RS sender mig en ny pakke med det samme; det synes jeg er mægtig flinkt af dem.
Har besluttet at bryde koden op i følgende dele:
main (initialisering)
timer_0 (hoved timer kontrol med funktionskald til repeats via if statements)
timer_1 (kaldes fra servo_move, 16 bit PWM)
repeats (antal repeats pr dosering og kalder funktion servo_move. Her kan jeg ikke bruge heltal da bevægelsen ligger i intervallet 0.8 til 2.1 hvor decimalerne bestemmer grader på servoen.
Jojo, så går du bare fra 8 til 21 i stedet.
Det er den måde man undgår floating point.
Skal du bruge 'finere opløsning', så går du fra 80 til 210. Det kan endda stadig ligge i en byte. =)
Der skal til gengæld kun bruges 2 decimaler. Men kan jeg ikke f.eks få pot1 til at give en værdi fra 0-180 og så sætte f.eks 1=0.85, så slipper 44'ern for at skulle ud i et floating point regnestykke og så bare bruge 0.82ms high i 20 ms PWM cycle) servo_move (styre servo movement)
ADC'en afleverer en værdi til dig, der ligger på 0...255 (hvis du bruger 8-bit), eller 0...1023 (hvis du bruger 10-bit).
Der er forskellige måder du kan omdanne disse værdier til hvad du skal bruge.
Har du masser af program-plads, kan du bruge en tabel. Da du ikke har så meget program-plads, kan det være en bedre idé at regne det om, men lav kun udregningen én gang, hvis du kan komme til det; dvs. når potmetret har en ny værdi, laver du udregningen, og husker hvad den nye værdi er.
eks.
potmeterValue = getADC2Value(); /* aflæs ADC værdien for ADC-kanal 2 (eller hvilken kanal du nu har valgt) */
if(potmeterValue != oldPotmeterValue)
{
oldPotmeterValue = potmeterValue;
degrees = (potmeterValue * 180) >> 8; /* hvis 8-bit */
/* eller... */
degrees = (potmeterValue * 180) >> 10; /* hvis 10-bit */
}
Ovenstående udregning foretages så kun når der er ændring på potmetret. Vælg enten 8-bit linien, eller 10-bit linien, alt efter hvilken ADC opløsning du kører.
potmeterValue bør være en uint16_t, da getADC2Value() vil returnere en 16-bit værdi, uanset om du bruger 8-bit eller 10-bit ADC.
Således vil det være lettere for dig at ændre mellem 8-bit og 10-bit, uden at koden skal ændres.
Det spare mig for en del kode gentagelser.
Det er altid godt at gøre kode kort. Ofte bliver koden også hurtigere, nemmere at overskue, og der kan jo ikke være lige så mange fejl i en kort stump kode, som en kæmpe stor omgang kode.

ser det her rigtigt ud for repeats ?
MMmjj-nej.

Du har en funktion, der hedder 'restart'.
Inde i denne funktion, har du en funktion der hedder 'dosering'.
Ded får du kun bøvl ud af; i teorien burde det kunne lade sig gøre, men i praksis, vil compileren nok blive noget snerpet.
Derudover... Inde i while(1){ ... }, har du variable-deklarationer ('int8_t repeats', mm.).
Disse bør du lægge lige i toppen af din funktion; dvs. før 'while(1)'-linien i dette tilfælde.
Men din 'for(a = 0; a < repeats; a++)' er helt rigtig, hvis det var dét spørgsmålet gik ud på.

Derudover bruger du også binære tal; det er ikke sikkert at compileren vil godtage dette (men prøv da)..
0b11001001 er bedre at skrive som hexadecimal 0xc9.
I de fleste tilfælde er der variabel-navne for AVR's benforbindelser.
-så 0b00000001 vil nok i dette tilfælde være mere praktisk som...
DDRA = (1 << PA0); /* Pin PA0 is output, rest is input */
PORTA |= (1 << PA0); /* set PA0 high */
PORTA &= ~(1 << PA0); /* set PA0 low */
PINA |= (1 << PA0); /* toggle PA0 value, so it gets the oposite value of what it currently is */
Ovenstående sætter først PA0 til output, derefter er der 3 eksempler på hvordan man...
1: Tænder et ben uden at ændre de andre bens værdi.
2: Slukker et ben, uden at ændre de andre bens værdi.
3: Toggler værdien så den får modsat værdi, uden at ændre de andre bens værdi.
Du kan stadig sætte hele porten's værdi med...
-Da vil PA0 være tændt, mens PA1 til PA7 bliver slukket (hvis de er input, vil deres pull-up modstand blive slået fra).
De 6 sekunder pause jeg har inden næste repeat, vil jeg kunne erstatte dem med en returnvalue fra servo_move som giver besked om at servoen er tilbage i nul og klar til endnu en gentagelse? Det vil gøre systemet lidt sikre tror jeg at man ikke risikere at en gentagelse tager længere tid end forventet og der så startes en my inden første er færdig.
Håber ikke jeg er heltt afsporet
Nej, du kommer selvfølgelig tættere og tættere på; selvom der kommer fejl hist og her. Fejl vil du ikke kunne undgå.
Selv engang jeg skrev et program, der kun fyldte 9 linier, og jeg havde gennemlæst det, og var *sikker* på der ingen fejl var... Ja, så brokkede compileren sig. *nedtur*.
her følger timer funktionen
Ser ikke helt tosset ud.
Jeg har rodet lidt i koden, lavet nogle ændringer (forslag til hvordan du kan gøre det lidt kortere).
(Lige en lille bemærkning: 'for(;

' er det samme som 'while(1)', så du ikke bliver i tvivl om du skal bruge den ene eller den anden).
For en god ordens skyld, bruger jeg altid /* Kommentarer */ i C-kode, mens // Kommentarer ryger i C++ kode.
-Det er ikke alle C-compilere der kan lide '//'.
Jeg vil gerne rette på disse ting, inden du får nogle vaner der ikke er til at rette op på...

Det er også en god idé at alle variabel-navne starter med lille forbogstav.
Typer, såsom strukturer er en god idé at have med stort forbogstav, fx.
typedef struct Rectangle Rectangle;
struct Rectangle
{
int16_t x;
int16_t y;
int16_t width;
int16_t height;
};
Ovenstående er en struktur, der indeholder 4 16-bit værdier. Man kan bruge den på følgende måde, hvis man har typedef linien med:
Rectangle myCanvas;
myCanvas.x = 10;
myCanvas.y = 20;
myCanvas.width = 75;
myCanvas.height = 53;
/*
* timer_0.c
*
* Created: 16-08-2011 01:45:43
* Author: jascore
*/
#include <avr/io.h>
#include "repeate.h"
/* todo Convert dip pos. to int8_t = 1 or 2 or 3 or 4 */
int8_t dosing;
int main (void)
{
unsigned char ElapsedSeconds = 0; /* Make a new counter variable and initialise to zero */
unsigned char Elapsedminutes = 0;
unsigned char frozenMinutes;
DDRB |= (1 << 0); /* Set LED as output */
TCCR1B |= ((1 << CS10) | (1 << CS11) | (1 << CS11)); /* Set up timer at prescaler64 */
for(;;)
{
/* Check timer value in if statement, true when count matches 1 second */
if(TCNT1 >= 15624)
{
TCNT1 = 0; /* Reset timer value */
ElapsedSeconds++;
if(ElapsedSeconds >= 60) /* Check if one minute has elapsed */
{
Elapsedminutes++;
ElapsedSeconds = 0; /* Reset counter variable */
frozenMinutes = Elapsedminutes;
if(dosing == 1) /* Dosing every 2nd hour */
{
switch(frozenMinutes)
{
case 0:
case 120:
case 240:
case 360:
case 480:
case 600:
case 720:
case 840:
case 960:
case 1080:
case 1200:
case 1320:
repeate();
break;
}
}
else if(dosing == 2) /* Dosing every 6th hour */
{
switch(frozenMinutes)
{
case 0:
case 360:
case 720:
case 1080:
repeate();
break;
}
}
else if(dosing == 3) /* Dosing every 12th hour */
{
switch(frozenMinutes)
{
case 0:
case 720:
case 0:
case 0:
repeate();
break;
}
}
else if(dosing == 4 && Elapsedminutes == 0) /* Dosing every 24th hour */
{
repeate();
}
while(Elapsedminutes == frozenMinutes) /* Wait until Elapsedminutes changes from the value we had above */
{
}
if(Elapsedminutes>=1440)
{
Elapsedminutes=0;
}
}
}
}
}
Jeg er meget i tvivl om jeg får sat prescaler rigtigt og har endnu ikke fundet ud af hvordan jeg sikre mig den løre 1 mhz
Det var vist en af de længere posts
På et eller andet tidspunkt, vil du kunne se en fejl ved koden som den er nu. Det er blevet lidt lettere at se fejlen, nu da koden er kortet ned (den gør nøjagtig det samme som tidligere).
Der er faktisk mere end én fejl.
Første fejl er:
Tallene over 255 (dvs. 360, 480, ... 1200, 1320) kan ikke være i en unsigned char.
Dér er du nødt til at gå op i en short.
Jeg anbefaler at bruge uint8_t i stedet for unsigned char og uint16_t i stedet for unsigned short; disse typer bruges normalt med AVR.
Men hvad værre er, er at programmet vil fryse fast.
Dette er fordi Elapsedminutes ikke ændrer sig mens du er i while-loopet.
Jeg anbefaler at du i stedet for at kigge på TCNT hele tiden, laver et interrupt (som nævnt for nogen tid siden); dette interrupt kan så tælle både minutter og sekunder for dig.
-Du kan evt. lave en nedtælling, og når tælleren når nul, kan timer-interruptet kalde en handlings-rutine, som udfører arbejdet.
Derfor vil det være muligt for dig at korte det yderligere ned.

Bare tag én ting ad gangen.
Det er en god idé at lave en prøve-kode først, som kun indeholder 'timer' kode, og intet andet.
Prøve-koden skal så bare blinke en lysdiode med 1 sekund tændt, 1 sekund slukket inde i timer-funktionen.

Når du har den til at gøre dette, så vil du se, at du nemt kan styre tiden rimelig nøjagtigt.
Brug meget gerne variablen F_CPU til at udregne hvor ofte timeren skal køre, derved kan du justere clock-frekvensen ét sted, og resten af din kode vil bruge denne værdi.
Indstillingen af F_CPU ligger så i din Makefile, så den variabel/definition vil være tilgængelig i alle dine filer.

PS: Jeg synes allerede på nuværende tidspunkt, at din kode-stil er god; bedre end mange på nettet. Det lønner sig senere, for hvis din kode så rodet ud, ville der kunne skjule sig mange fejl, og de ville tilmed være svære at finde. Pæn kode er lettere at finde/rette fejl i, og ofte bliver koden mere fejlfri, når den er pæn. Ensartethed er her et godt og vigtigt nøgleord.