hjælp til servo kontrol med timer (Læst 128909x)

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #30 Dato: August 13, 2011, 19:18:23 »
Har efterhånden banket mig igennem og forstået timer tutorials med avr. Godt nok på en mega men princippet må være det samme

Helt rigtigt. Det er samme princip over hele AVR serien.
-De er alle i familie med hinanden. Forskellen på tiny og mega er i store træk at tiny har normalt ikke UART/USART (serielt interface), og tiny har ikke gange-instruktion; dette løses i software.
(Ingen af AVR microcontrollerne har divisions-instruktion; dette løses i software, så undgå så vidt muligt at dividere i dit program; det er langsomt og fylder).
-Men undgå for alt i verden at bruge floating point. Brug kun integers (int8_t, int16_t og int32_t) - du burde ikke behøve noget større end 32 bit.
Undgå også C++, da det er så stort, at Hello World næsten ikke kan være i en tiny... ;

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #31 Dato: August 14, 2011, 00:56:36 »
hvordan h.... tegner man et print hvor banerne ikke krydser hinnanden hmm :o

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #32 Dato: August 14, 2011, 01:40:48 »
hvordan h.... tegner man et print hvor banerne ikke krydser hinnanden hmm :o

(fnis)... Jeg er faktisk igang med at tegne mit første hjemme-ætsede print. Det er dobbeltsidet.
Men du kan lave et enkeltsidet print, hvor du router banerne ind og ud mellem hinanden, under komponenter, osv.

Lad os antage at det er et enkeltsidet print til "gennem hul montering". Dette er nemt, idét man kan krydse baner med "0-ohm modstande", også kaldet "Lus" og "Straps". Disse er faktisk bare lednings-stumper eller fortinnet kobber. (Man kan få dimser der ligner modstande, hvor der er 2 sorte ringe på; de kaldes 0-ohm modstande).

Hvis du tegner enkeltsidet print, er det "nemt". Hvis du tegner dobbeltsidet print, så pas på, at dine baner på oversiden *ikke* kommer til at skulle loddes inde under stik, elektrolyt-kondensatorer, krystaller eller brokoblinger (find selv på flere). For har du en bane der fx. starter på fx. et D-Sub stik, og denne bane ligger på oversiden, hvordan vil du så lodde den ? Stikket sidder ind over hele lodde-øen, og du har ingen gennemplettering, som laver forbindelsen for dig... ;)

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #33 Dato: August 14, 2011, 02:16:40 »
hvis jeg dropper den visuelle gengivelse her i prototypefasen kan jeg så ikke druge et af de overskydende ben til at trigger næste pumpes system således at jeg kan programerer en forsinkelse på eks 16 minutter ind mellem apslutningen på første og starten på næste?

Har jo til at starte med det visuelle på eks dip-switch og ved en scala på potmeterne.

Skal til at have lagt mig fast på prototypens funktionalitet ellers får jeg aldrig skrevet en linje kode. så opridser lige hvad og hvordan. ligeså meget for min egen skyld.

Prototype
2 pumper.
1 - 5 gentagelser i døgnet
1-5 gentagelser pr. gang
disse styres af dip-switches
antal ml pr gentagelse - styres af potmeter
pumpe 2 må først starte 16 minutter efter pumpe 1 er afsluttet (håber det kan gøres med en enkelt forbindelse fra a til b eks en ledning med et enkelt stik)
Ingen led eller andet på prototypen det kan altid komme når den grundlæggende funktionalitet er på plads

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #34 Dato: August 14, 2011, 04:05:58 »
hvis jeg dropper den visuelle gengivelse her i prototypefasen kan jeg så ikke druge et af de overskydende ben til at trigger næste pumpes system således at jeg kan programerer en forsinkelse på eks 16 minutter ind mellem apslutningen på første og starten på næste?

Jo, det kan jeg ikke se nogen hindring i.

Citér
Har jo til at starte med det visuelle på eks dip-switch og ved en scala på potmeterne.

Jeg sender et parn (uden beregning) dip-switches m/4 kontakter (bemærk: billedet viser en med 8 kontakter) med, og en stang skod-sokler (8-benede) -Disse er den billigste type sokkel man kan få.
Selv anbefaler jeg tulipan-sokler; der ryger IC'erne ikke ud af sig selv. De er dyrere, men duer.

Citér
Skal til at have lagt mig fast på prototypens funktionalitet ellers får jeg aldrig skrevet en linje kode. så opridser lige hvad og hvordan. ligeså meget for min egen skyld.

Prototype
2 pumper.
1 - 5 gentagelser i døgnet
1-5 gentagelser pr. gang

Husk: Med en 3-kontakt dip-switch kan du lave 8 kombinationer, hvis du laver dem binært.

Citér
disse styres af dip-switches
antal ml pr gentagelse - styres af potmeter
pumpe 2 må først starte 16 minutter efter pumpe 1 er afsluttet (håber det kan gøres med en enkelt forbindelse fra a til b eks en ledning med et enkelt stik)
Ingen led eller andet på prototypen det kan altid komme når den grundlæggende funktionalitet er på plads

Det lyder næsten som om du skal have et breadboard; hvis du laver meget om på din prototype, kan det være en god idé at have breadboard (jeg har et, der er nogenlunde godt, med 840 huller til 40 kr), da du så nemt kan skifte komponenter/rette fejl, mm.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #35 Dato: August 14, 2011, 08:01:11 »
ja det kunne være du har ret med et breadboard her i starten. det giver da plads til at eksperimenterer.
glæder mig til at komme igang  :P
det vil jeg meget gerne købe af dig. Min drøm som barn var at blive svagstrømsingenør kom dog ikke så langt men interessen er der stadig og er sikker på at det her projekt giver mig blod på tanden til at lege noget mere med det.
« Senest Redigeret: August 14, 2011, 15:54:30 af jascore »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #36 Dato: August 15, 2011, 01:13:43 »
Her har jeg et opdateret diagram (farverne er bare for min egen skyld ha ha)


Må indrømme at jeg er rimelig rusten i kodning er næsten blank men kæmper mig der ud af. sender lige et eksempel op hvis du gider kommenterer om det er helt ude i skoven. (en meget simpel while, for og if procedure.

du skrev tidligere at jeg skulle dele det op i 4 men skal hele koden ikke ligge i en fil når der skal programeres ?
beklager hvis jeg er lidt tung på det område :-S
Kode:
todo:
Setup servo hardware
set up potentiometer1 (pot1)  reading  zero placement. Convert to value betwene 0.8 to 1 ms high in a 20 ms cycle
set up potentiometer2(pot2)  ml reading. Convert to value betwene 1 to 2.1 ms high in a 20 ms cycle
set up dipswitches for time (diptime) 4 possibilities converted to minute 1440- 720 - 360 - 120
setup dipswitches for repeats (diprep) 4 possibilities converted to value 1 -2 - 4 - 10
set up timer 0 for clock emulation  (minutes)
set up timer1 for servo movement (pwm 20 ms) (16 bit timer da opløsningen ellers bliver alt for lille)

Variables:
Int servo_min =  (calculation that converts input from pot1 to lenght of high pulse in a 20 ms cycle 0.8 to 1.1)
Int servo_max = (calculation that converts input from pot2 to lenght of high pulse in a 20 ms cycle 1 to 2.1)
Int dosering=(conversion of diptime to int 1440-720-360-120)
Char  repeats = (conversion of diprep to int 1-2-4-10)

Pseudo:


int main()
{
Int servo_min;
Int servo_max;
Int dosering;
        Char repeats;
        Int servo_move=0; /* for movement controll and update
        Int a=0;         /* for repeat counter use
}

while timer0<=1440;  /* one day count in minutes to minimize sync error
    if (dosering = 120) /*Checks if dosing mode set by dip (repeats pr. Day)
    {
If (timer0=120) /*start first dosing in a 12 times a day setup
        {
          For (a = repeats; a<=repeats) /*set counter for number of repeats set by dip
           {
            /* start dosing by moving servo from its zeropiont to the value set by pot1*/
            for(servo_move = servo_min ;  servo_move < servo_max ; servo_move +=0.1)
              {
                send servo pulse;
               /*Checks if servo ras reached value set by pot1 starts to reverse servo to zero*/
                  if (servo_move==servo_max)
          {
                  /*starts to reverse servo to zero*/
                     For (servo_move=servo_max; servo_move>servo_min; servo_move-=0.1)
                     {
                      send servo pulse;
                     }
           A++ /* ads one to a and loops until a = repeats
           }
                }
              }
         }
    }
If (timer0=240) and so on for the value 360, 480…1440 also the same if’s when dosering =  360, 720, 1440


Læser næsten alt hvad jeg kan finde men så er det i c og så er det pseudo og så er det i noget helt tredie som er helt sort så ved ikke hvor jeg skal begynde, men tygger videre på de tekster jeg kan finde :-D
« Senest Redigeret: August 15, 2011, 02:22:16 af jascore »

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #37 Dato: August 15, 2011, 07:10:12 »
Her har jeg et opdateret diagram...

Ser ikke så tosset ud. :)
Jeg vil dog anbefale følgende regler:

GND vender altid nedad, dvs. stregen er vandret, og ledningen går 'opad' fra stregen. Det skulle så ligne et 'T' der vender på hovedet. -Hvis GND ligner et retvendt 'T', vil man tro at den går op til VCC.

VCC vender altid opad, dvs. ligner et retvendt 'T'.
Signaler kan ligne et 'T' der ligger på siden. Bruges denne måde, skal signal-navnet altid skrives (på T'ets "top-side", dvs. er T'et drejet 90 grader med uret, vil signalet skulle stå på højre side).

Citér
Må indrømme at jeg er rimelig rusten i kodning er næsten blank men kæmper mig der ud af. sender lige et eksempel op hvis du gider kommenterer om det er helt ude i skoven. (en meget simpel while, for og if procedure.

Det skal nok komme tilbage..

[/quote]du skrev tidligere at jeg skulle dele det op i 4 men skal hele koden ikke ligge i en fil når der skal programeres ?[/quote]

Der er følgende trin når man laver kode til en microcontroller (de går vældig hurtigt, så man mærker det sådan set ikke:

1: compiling. Dette foretages normalt af gcc eller g++. Kan også foretages af compilere til andre sprog.
2: linking. Linkeren 'klistrer' binære filer sammen. Hvis du for eks. kalder rutinen 'test()' fra fil 1, så finder linkeren adressen på 'test' og sætter den ind, hvor referencen til 'test' var.
3: flashing (brænding) af chippen. Dette er noget, som avrdude tager sig af. Den kan klare stort set alle AVR chips.

Alt dette styres normalt af en file, der hedder 'Makefile'
-Men vær forsigtig, når du retter i denne fil, for der er forskel på betydningen af mellemrum og betydningen af tabuleringer (!)

I en Makefile, kan man definere en liste af filer, som linkeren skal lede efter interessante symboler i.
Ofte kalder man sin primære kildekode for 'main.c' (men kan også kalde den navnet på det færdige produkt). Kaldes den primære kildetekst 'main.c', vil den primære binære fil hedde 'main.o'.
Et sted i din Makefile står der således 'main.o', og dér kan du fx. skrive 'adc.o', 'timer.o', 'servo.o', osv.
Rettelser:
'Int' ændret til 'int16_t'.
'Char' ændret til 'int8_t'.

'Kommentar ...' ændret til '/* Kommentar ... */'

'while <udtryk>' ændret til 'while(<udtryk>)'

Derudover har jeg fjernet semikolon fra den første while, da programmet vil blive ved med at køre rundt dér, og aldrig komme ud derfra.
'while(timer0 <= 1440);' er det samme som 'while(timer0 <= 1440){}'

Jeg har følgende kodestil (bemærk rækkefølgen jeg nævner det i):
Ingen mellemrum mellem funktionsnavne og start-paranteser.
Ingen mellemrum mellem start-parantes og første parameter.
Ingen mellemrum mellem parameter og komma.
Mellemrum mellem komma og næste parameter.
Ingen mellemrum mellem sidste parameter og slut-parantes.
Disse regler gælder alt, både funktions-definitioner, funktions-kald, 'if', 'while', 'for', 'switch' osv...

Eks:
Kode:
if ( a==10&&b<=100 ) {
    if( c>1000){
    }
}

ændrer jeg til...

Kode:
if(a == 10 && b <= 100)
{
    if(c > 1000)
    {
    }
}
-Bemærk jeg sætter også krølleparantes på en tom linie, så de står i samme kolonne.
Denne kodestil bruges af rigtig mange; jeg lærte den da jeg arbedede sammen med et team på Opera Software i Norge.


'If' ændret til 'if'.

Hvis du bruger '=' inde i en if-sætning...

Kode:
if(a = 4)
{
    /* denne kode vil altid udføres. */
    /* a vil altid have værdien 4. */
}

I stedet, hvis du bruger '==' inde i en if-sætning...

Kode:
if(a == 4)
{
    /* denne kode vil udføres når a har værdien 4. */
}

-Så jeg har ændret 'if( ... = ...)' til 'if( ... == ...)'

'For (' er ændret til 'for('

'send servo pulse;' er ændret til 'send_servo_pulse();', dvs. jeg har lavet det til et funktions-kald.

'A++' er ændret til 'a++;', da der kendes forskel på store og små bogstaver, og semikolon skal afslutte denne linie.

'For (a = repeats; a<=repeats)' er ændret til 'for(a = repeats; a<=repeats;)' (har indsat et semikolon, da der skal være 3 statements).

Diverse 'ensartethed' er også indført...

Kode:
/* Variables: */
int16_t servo_min =  (calculation that converts input from pot1 to lenght of high pulse in a 20 ms cycle 0.8 to 1.1)
int16_t servo_max = (calculation that converts input from pot2 to lenght of high pulse in a 20 ms cycle 1 to 2.1)
int16_t dosering=(conversion of diptime to int 1440-720-360-120)
int8_t  repeats = (conversion of diprep to int 1-2-4-10)


/* Pseudo: */


int main()
{
    int16_t servo_min;
    int16_t servo_max;
    int16_t dosering;
    int8_t  repeats;
    int16_t servo_move=0;                                       /* For movement control and update */
    int16_t a=0;                                                /* for repeat counter use

    while(1)                                                    /* Stay in this while-loop (never exit). */
    {
        while(timer0 <= 1440)                                   /* One day count in minutes to minimize sync error */
        {
            if(dosering == 120)                                 /* Checks if dosing mode set by dip (repeats pr. Day) */
            {
                if(timer0 == 120)                               /* Start first dosing in a 12 times a day setup */
                {
                    for(a = repeats; a<=repeats;)               /* Set counter for number of repeats set by dip */
                    {
                        /* Start dosing by moving servo from its zeropiont to the value set by pot1 */
                        for(servo_move = servo_min;  servo_move < servo_max; servo_move += 0.1)
                        {
                            send_servo_pulse();
                            /* Checks if servo ras reached value set by pot1 starts to reverse servo to zero */
                            if(servo_move == servo_max)
                            {
                                /* Starts to reverse servo to zero */
                                for(servo_move = servo_max; servo_move > servo_min; servo_move -= 0.1)
                                {
                                    send_servo_pulse();
                                }
                                a++;                            /* Adds one to a and loops until a = repeats
                            }
                        }
                    }
                }
            }
            if(timer0 == 240)  /* and so on for the value 360, 480…1440 also the same if’s when dosering =  360, 720, 1440 */
            {
            }
        }
    }
}

OK, nu, da jeg har rettet kodens udseende til... Du vil nok synes at koden vil opføre sig underligt.

Da microcontrolleren kører vældig hurtigt, vil du opdage at linien 'if(timer0 == 120)' køres mange gange og derved vil koden inde i denne if-sætning også køres mange gange, for timer0 tælles jo i minutter, og der er derfor masser af tid, til at gentage denne process.

Der er flere måder at løse det problem på. Mange vælger at lave en 'state-machine', men det har jeg altid syntes var noget rod at se på.
Du kan i stedet... vente på at timer0 skifter fra 120 til 121...
Kode:
if(timer0 == 120)
{
    /* Execute action, which happens when 120 minutes has passed */
    for(a = repeats; a <= repeats;)
    {
        /* ...etc...*/
    }
    /* Wait until timer0 is no longer 120... */
    while(timer0 == 120)
    {
    }
}

Kig også på 'for(a = repeats; a <= repeats;) sætningen, for den vil faktisk aldrig udføre denne kode, idét 'for' stopper så snart a er større end, eller har samme værdi som repeats.

Forslag:
Kode:
for(a = 0; a < repeats; a++)
{
    /* ...kode... */
    /* fjern den kodelinie der hedder 'a++;' */
}

Derudover vil du også se noget andet, der vil drille...

1: Du har 2 stk. 'for(servo_move = ...)' Det er i orden, men den ene ligger inde i den anden.
2: Du venter på at 'servo_move' får værdien 'servo_max', og så snart den har nået 'servo_max', vil koden i 'for'-løkken ikke længere udføres. Derfor vil din 'if(servo_move == servo_max)' nok aldrig blive udført.

Forslag:
Lav en...
Kode:
for(servo_move = servo_min; servo_move < servo_max; servo_move += 0.1)
{
    send_servo_pulse();
}

...og efter den (dvs. udenfor), lav en...

Kode:
for(servo_move = servo_max; servo_move > servo_min; servo_move -= 0.1)
{
    send_servo_pulse();
}

...OK... Så er der en sidste ting...

servo_move er en int16_t, hvilket vil sige den er heltal.
Jeg anbefaler at du holder det i heltal, og derfor ændrer koden til ikke at bruge 0.1 (det bliver rundet ned til 0.0 alligevel; selv 0.999999 bliver rundet ned til 0.0).

Så koden kunne fx. se således ud:

Kode:
for(servo_move = servo_min; servo_move < servo_max; servo_move++)
{
    send_servo_pulse();
}

Hint: Du vil sikkert gerne kunne kende forskel på fremad og baglæns, mht. 'send_servo_pulse()'.

Citér
Læser næsten alt hvad jeg kan finde men så er det i c og så er det pseudo og så er det i noget helt tredie som er helt sort så ved ikke hvor jeg skal begynde, men tygger videre på de tekster jeg kan finde :-D

C kan du bruge til næsten alt. -Så jeg anbefaler C.
Uden C, kan du heller ikke C++. =)

Der er et andet alternativ, assembler, som der sjovt nok er mange begyndere, vælger at bruge, når de laver kode til microcontrollere.
Assembler har altid været noget, folk har undgået, fordi det 'lyder farligt og mystisk'.
-Men start bare med C, for det er lidt lettere at overføre til andre microcontrollere, også dem, som ikke er fra Atmel.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #38 Dato: August 15, 2011, 11:46:51 »
Mange tak  :-[
Skal nok finde ud af det.

Vil arbejde videre med koden idag og håbe på at lyset pludselig viser sig he he

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. 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)

Det spare mig for en del kode gentagelser.

ser det her rigtigt ud for repeats ? sveder og krydser mine fingre GG
Koden kræver fcpu 1 mhz så det er også en todo
Kode:
/*
 * repeat.c
 *
 * Created: 16-08-2011 01:45:43
 *  Author: jascore
 */
#include <avr/io.h>

int restart(void)
{
    while(1)
    {
int8_t repeats;                                 /*number read from dip pos. 1 - 2 - 4 - 10*/
int8_t a;                                       /*For counting number of repeats*/
uint16_t ElapsedSeconds;
/*todo conversion of dip pos. to int8_t repeats*/
void dosing()                                   /*No value returned*/
{
            for(a = 0; a < repeats; a++)                /*count number of repeats*/
            {
                send_servo_pulse();                     /*Calls function to move servo*/
                TCCR1B |= ((1 << CS10) | (1 << CS11) | (1 << CS10));  /* Set up timer at prescaler8 (for timerdelay before next repeat*/
                for (;;)
                {
                    /* Check timer value in if statement, true when count matches 6 second*/
                    TCNT1 = 0;                          /* Reset timer value*/
                    if (TCNT1 >= 93744)                 /*Counts up to 6 sec.*/
                    {
                    }
                }
            }
            if(a==repeats)
            {
                /*Timer for delay befor next pump starts*/
                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*/
                    ElapsedSeconds = 0;   
                    if (TCNT1 >= 15624)
                    {
                        TCNT1 = 0; /* Reset timer value*/
                        ElapsedSeconds++;
                        if (ElapsedSeconds >= 960) /* Check if 16 minute has elapsed*/
                        {   
                            ElapsedSeconds = 0; /*Reset counter variable*/
                            DDRA=0b00000001
                            PORTA=0b00000001; /*Set I/0 PA0 (pin13) high sendt trigger to next pump to begin*/
                        }
                    }
                }
            }
        }   
    }
}

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
her følger timer funktionen

Kode:
/*
 * 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;
   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
/*Dosing every 2nd hour*/
if(dosing == 1 && Elapsedminutes == 0)
{
repeate();
while(Elapsedminutes == 0)
{
}
}

if(dosing == 1 && Elapsedminutes == 120)
{
repeate();
while(Elapsedminutes == 120)
{
}
}
if(dosing == 1 && Elapsedminutes == 240)
{
repeate();
while(Elapsedminutes == 240)
{
}
}
if(dosing == 1 && Elapsedminutes == 360)
{
repeate();
while(Elapsedminutes == 360)
{
}
}
if(dosing == 1 && Elapsedminutes == 480)
{
repeate();
while(Elapsedminutes == 480)
{
}
}
if(dosing == 1 && Elapsedminutes == 600)
{
repeate();
while(Elapsedminutes == 600)
{
}
}
if(dosing == 1 && Elapsedminutes == 720)
{
repeate();
while(Elapsedminutes == 720)
{
}
}
if(dosing == 1 && Elapsedminutes == 840)
{
repeate();
while(Elapsedminutes == 840)
{
}
}
if(dosing == 1 && Elapsedminutes == 960)
{
repeate();
while(Elapsedminutes == 960)
{
}
}
if(dosing == 1 && Elapsedminutes == 1080)
{
repeate();
while(Elapsedminutes == 1080)
{
}
}
if(dosing == 1 && Elapsedminutes == 1200)
{
repeate();
while(Elapsedminutes == 1200)
{
}
}
if(dosing == 1 && Elapsedminutes == 1320)
{
repeate();
while(Elapsedminutes == 1320)
{
}
}
/* Dosing every 6th hour*/
if(dosing == 2 && Elapsedminutes == 0)
{
repeate();
while(Elapsedminutes == 0)
{
}
}
if(dosing == 2 && Elapsedminutes == 360)
{
repeate();
while(Elapsedminutes == 360)
{
}
}
if(dosing == 2 && Elapsedminutes == 720)
{
repeate();
while(Elapsedminutes == 720)
{
}
}
if(dosing == 2 && Elapsedminutes == 1080)
{
repeate();
while(Elapsedminutes == 1080)
{
}
}
/*Dosing every 12th hour*/
if(dosing == 3 && Elapsedminutes == 0)
{
repeate();
while(Elapsedminutes == 0)
{
}
}
if(dosing == 3 && Elapsedminutes == 720)
{
repeate();
while(Elapsedminutes == 720)
{
}
}
/*Dosing every 24th hour*/
if(dosing == 4 && Elapsedminutes == 0)
{
repeate();
while(Elapsedminutes == 0)
{
}
}
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
« Senest Redigeret: August 16, 2011, 03:29:19 af jascore »

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #39 Dato: August 16, 2011, 18:03:52 »
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.

Citér
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. =)

Citér
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.
Kode:
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.

Citér
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. ;)


Citér
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...
Kode:
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...
Kode:
PORTA = (1 << PA0);
-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).


Citér
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*.

Citér
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.

Kode:
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;

Kode:
/*
 * 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;
                }
            }
        }
    }
}

Citér
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.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #40 Dato: August 16, 2011, 18:38:27 »
På den igen :-P
Og arbejde videre med koden ELSKER at lære nyt stof. men måske er det en lidt stejl indlærings kurve der er her he he
Prøvede at køre det i avr studio men vil hente winavr istedet, som du anbefaler. det fylder jo også kun en brøkdel
mailer snart en kold fadbamse til dig :-P

Nu er de ankommet til Peru! ha ha Danmark Peru ja det staves jo også næsten ens



 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #41 Dato: August 16, 2011, 20:23:33 »
På den igen :-P
Og arbejde videre med koden ELSKER at lære nyt stof. men måske er det en lidt stejl indlærings kurve der er her he he

Min ærlige mening er at du klarer dig mange gange bedre end de fleste.
Jeg har prøvet at lære folk op før, og jeg tror at du nok er den nemmeste at have med at gøre.
Jeg kan mærke du brænder for at lave dette projekt. og jeg kan allerede nu sige at det vil lykkes.

Citér
Prøvede at køre det i avr studio men vil hente winavr istedet, som du anbefaler. det fylder jo også kun en brøkdel
mailer snart en kold fadbamse til dig :-P

Æh, desværre drikker jeg ikke øl. :)

WinAVR kan muligvis ikke lave simuleringer (program-kørsler), dér kan det nok være at AVR Studio vil være længere fremme.
Men WinAVR vil have nogle fordele over AVR Studio (og vice versa).
En af de fordele WinAVR har, er at den bruger en robust standard-compiler, nemlig gcc. Denne gcc er open source, og er udviklet gennem rigtig mange år, og følger nærmest alle forskrifter. Du kan næsten ikke komme galt afsted, hvis du skriver koden, så den compiler med denne compiler.

Citér
Nu er de ankommet til Peru! ha ha Danmark Peru ja det staves jo også næsten ens

Nåja, enhver kan tage fejl, men 2 gange i streg ?
Jeg forstår ikke liige hvordan det lader sig gøre; der ér vel navn og adresse på.
(Desuden ved DHL også at Danmark er 'destinationen' for pakken).

Menmen, jeg tror der skulle være en ny i løbet et par dage, måske 3.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #42 Dato: August 17, 2011, 03:30:34 »
Jeg faldt over at bruge CTC i timeren men er i tvivl om det vil konflikte med den 16 bit timer jeg skal bruge til at styre servoen.

Men prøvede alligevel :-D

Grunden til at jeg prøver at holde mig uden om det tcnt eksempel du kom med helt i starten er at jeg ikke syntes at kunne finde hoved og hale i det   :o

her er mit eksempel på CTC  :-X
Kode:
#include <avr/io.h>

int8_t sec=0;
int8_t minutes=0;
int8_t dose;    /*=2, 6, 12 eller 24 ( ser by pot1)*/
int8_t hours=dose; /*ER I TVIVL OM DEN HER. Det er for at dosere første gang med det samme*/

int main (void)
{
TCCR1B |= (1 << WGM12); /* Configure timer 1 for CTC mode*/
OCR1A   = 15624;   /* Set CTC compare value to 1Hz at 1MHz AVR clock, no prescale*/
TCCR1B |= ((1 << CS10)); /* Start timer at Fcpu/64*/
for (;;)
{
if (TIFR1 & (1 << OCF1A))   /*Check CTC flag*/
{
TIFR1 = (1 << OCF1A); /* clear the CTC flag*/
sec++;       /*second counter*/
if (sec>=60)
{
sec=0;
minutes++;   /*minute counter*/
}
if (minutes>=60)
{
minutes=0;
hours++;     /*hour counter*/
}
if (hours==dose)   /*checks if hour = dosing and then doses*/
{
/*repeats();*/ /*call function repeat*/
hours=0;     /*resets hours*/
}
  }
}
}

Noget kun kortere end den tidligere timer funktion
« Senest Redigeret: August 17, 2011, 03:39:51 af jascore »

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #43 Dato: August 17, 2011, 08:30:17 »
Jeg faldt over at bruge CTC i timeren men er i tvivl om det vil konflikte med den 16 bit timer jeg skal bruge til at styre servoen.

Hvis du er skrap, kan du bruge samme interrupt til begge ting, men det kan være en balancegang.
Jeg anbefaler at du bruger 8-bit timeren til at "tælle sekunder" med, da den alt rigeligt kan klare den opgave.

Ellers ser det ud til at din timing er rigtig i dit eksempel.

Bemærk at du kunne skrive...
Kode:
OCR1A = (F_CPU / 64) - 1;
Og hvis du så sætter F_CPU til 1000000, skulle det gerne passe. Prøv at regne efter.
Ovennævnte kodestump vil compileren regne om til ét konstant tal, idét vi kun har konstanter. Dvs. compileren kan reducere udregningen for os, så der bliver ikke regnet run-time.

Citér
Grunden til at jeg prøver at holde mig uden om det tcnt eksempel du kom med helt i starten er at jeg ikke syntes at kunne finde hoved og hale i det   :o
-Du er der alligevel næsten.

Det eneste du mangler at klistre på, er interruptet. :)

Jeg har lavet en ny omgang eksempel-kode. Det er nok lidt mere simpelt end det første jeg lavede; og koden skulle kunne håndtere fuld dosering på tid. ADC koden er ikke inkluderet.

Bemærk: Koden er slet ikke afprøvet, så der er sikkert masser af fejl. ;)

Prøv at starte med at kigge på timer interrupt funktionen (den hedder 'SIG_OVERFLOW0'). Du skulle kunne forstå det meste af denne. Den køres hver gang TCNT0 ændrer værdi fra 255 til 0; dette sker én gang i sekundet.

Interrupt funktionen kalder en rutine ('timer0Elapsed'), som ligger i Dosing.c; dette sker når minut-nedtællingen (minuteCountdown) ændres fra 1 til 0.

Kode:
/*
 * File: Timer0.h
 *
 * (8-bit timer with simple event handling)
 *
 */

#ifndef __Timer0_h__
#define __Timer0_h__

void setMinuteCountdown(uint16_t aMinuteCountdown);         /* this routine controls how often the interrupt will occur */
void timer0Elapsed();                                       /* this is a routine that you implement */
void initTimer0();

#endif /* __Timer0_h__ */


Kode:
/*
 * File: Timer0.c
 *
 * (8-bit timer with simple event handling)
 *
 */

#include <avr/io.h>
#include <avr/interrupt.h>

#include "Timer0.h"

static volatile uint8_t seconds = 0;                        /* variables that are changed by an interrupt, *MUST, MUST* be volatile! */
static volatile uint16_t minuteCountdown = 0;               /* variables that are changed by an interrupt, *MUST, MUST* be volatile! */
static uint16_t minuteCountdownRestart = 0;

void setMinuteCountdown(uint16_t aMinuteCountdown)
{
    cli();                                                  /* make sure interrupt is not occurring while writing the 16-bit value */
    minuteCountdown = aMinuteCountdown;                     /* (that could cause an incorrect reading by the interrupt) */
    minuteCountdownRestart = aMinuteCountdown;              /* set our restart-value as well */
    sei();
}

SIGNAL (SIG_OVERFLOW0)                                      /* This interrupt occurs when TCNT0 wraps to 0 */
{
    /* ATtiny24/44/84 Preliminary, page 83; section 11.9.3 */
    TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125));         /* interrupt occurs once per second. */

    seconds++;                                              /* increment our number of seconds elapsed */

    if(seconds >= 60)                                       /* when we've reached 60 seconds */
    {
        seconds = 0;                                        /* wrap to zero */
        if(minuteCountdown)                                 /* is our minuteCountdown nonzero ? */
        {
            if(0 == --minuteCountdown)                      /* if minuteCountdown reaches 0 when it counts down (eg going from 1 to 0) */
            {
                minuteCountdown = minuteCountdownRestart;   /* restart countdown */
                timer0Elapsed();                            /* it's time for applying another dose */
            }
        }
    }
}

void initTimer0()
{
    cli();                                                  /* disable interrupts if not already done */

    seconds = 0;
    minuteCountdown = 0;
    minuteCountdownRestart = 0;

    /* ATtiny24/44/84 Preliminary, page 83; section 11.9.6 */
    TIMSK0 &= (1 << TOIE0);                                 /* clear 'Timer Overflow Interrupt Enable 0' bit in 'Timer Interrupt MaSK 0' */

    /* set up timer to run in normal mode: (WGM02:WGM01:WGM00 = 000 */
    /* make timer use PRESCALER8: (CS02:CS01:CS00 = 000): */

    /* ATtiny24/44/84 Preliminary, page 79; section 11.9.1 */
    TCCR0A = (0 | (0 << COM0A1) | (0 << COM0A0) | (0 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (0 << WGM00));

    /* ATtiny24/44/84 Preliminary, page 82; section 11.9.2 */
    TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00));

    /* Clear any pending interrupts, so we don't get an accidental interrupt immediately after enabling interrupts... */
    /* ATtiny24/44/84 Preliminary, page 84; section 11.9.7 */
    TIFR0 |= (1 << TOV0);                                   /* clear 'Timer OVerflow 0' bit in 'Timer Interrupt Flag Register 0' */

    /* enable Timer OVerflow 0 interrupt: */
    /* ATtiny24/44/84 Preliminary, page 83; section 11.9.6 */
    TIMSK0 |= (1 << TOIE0);                                 /* set 'Timer Overflow Interrupt Enable 0' bit in 'Timer Interrupt MaSK 0' */
}


Kode:
/*
 * File: ADC.h
 *
 * (Controls when the dosing occurs, but also holds the code to do the actual dosing)
 *
 */

#ifndef __ADC_h__
#define __ADC_h__

uint16_t getADC3Value();                                    /* this routine returns the low 10 bits of the ADC3's value, no matter if you use 8-bit or 10-bit ADC */
void initADC(uint8_t aBits);

#endif /* __ADC_h__ */


Kode:
/*
 * File: Dosing.h
 *
 * (Controls when the dosing occurs, but also holds the code to do the actual dosing)
 *
 */

#ifndef __Dosing_h__
#define __Dosing_h__

void startDosing();                                         /* this routine should be called when the 'start' button is pressed */
void setDosing(int8_t aDosing);                             /* usually you wouldn't call this routine (call startDosing instead) */
void initDosing();

#endif /* __Dosing_h__ */


Kode:
/*
 * File: Dosing.c
 *
 * (Controls when the dosing occurs, but also holds the code to do the actual dosing)
 *
 */

#include <avr/io.h>

#include "Dosing.h"

#include "Timer0.h"
#include "ADC.h"

#define ADC3_CALIBRATION    0                               /* I'll let you know later, how to find this calibration value */

void setDosing(int8_t aDosing)
{
    switch(aDosing)
    {
      case 1:
        setMinuteCountdown(2 * 60);                         /* every 2nd hour */
        break;
      case 2:
        setMinuteCountdown(6 * 60);                         /* every 6th hour */
        break;
      case 3:
        setMinuteCountdown(12 * 60);                        /* every 12th hour */
        break;
      case 4:
        setMinuteCountdown(24 * 60);                        /* every 24th hour */
        break;
    }
}

void startDosing()                                          /* this routine should be called when the 'start' button is pressed */
{
    int16_t adcValue;
    int8_t  dosing;

    adcValue = getADC3Value();                              /* read value of ADC channel 3 */
    adcValue = adcValue + ADC3_CALIBRATION;                 /* add calibration value */
    dosing = ((adcValue * 4) >> 10) + 1;                    /* calculate the dosing (we'll get a value from 1 to 4) */

    setDosing(dosing);                                      /* when this routine is called, the dosing countdown starts */
}

void timer0Elapsed()
{
    repeate();                                              /* well, the code from inside repeate could go directly here, if desired */
}

void initDosing()
{
    startDosing();                                          /* in case of power failure, automatically restart with the current value */
}


Kode:
/*
 * File: main.c
 */

#include <avr/io.h>
#include <avr/interrupt.h>

#include "main.h"
#include "ADC.h"
#include "Timer0.h"
#include "Dosing.h"

int main()
{
    initADC(8);                                             /* initialize ADC, we'll use the 8-bit precision for now */
    initTimer0();
    initDosing();
    sei();                                                  /* globally enable interrupts */

    while(1)
    {
        /* we don't really need to do anything here. Everything is handled by the interrupts */
    }
    return(0);                                              /* (never reached) */
}


-Måske er det lidt mere forståeligt, når det er kortere... Bemærk: Det jeg gør, er at jeg ikke tæller minutterne 'opad', men i stedet sætter et startpunkt og tæller nedad derfra. Når minutterne så når 0, så startes doseringen, og minut-tælleren sættes tilbage til dens start-værdi.
« Senest Redigeret: August 17, 2011, 08:37:33 af pacman »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #44 Dato: August 18, 2011, 03:32:06 »
Jo ok tror jeg har forstået koden nu.

Inde i sig_overflow0, som trigger på en countdown) kalder jeg så rutinen repeats hvor gentagelser bliver defineret og brugt i ADC.c
aMinuteCountdown bliver defineret i dosing's set_dosing fouktionen og brugt i sig_overflow0,  og det hele med en 8 bit timer/counter så tror sq jeg har forstået det nu - næsten

Lavede selv main.h udfra hvordan jeg kunne se at du havde lavet de andre header filer

Kode:
#ifndef __MAIN_H__
#define __MAIN_H__

void initTimer0();
void initDosing();

#endif /* MAIN_H_ */
Men her ville jeg jo også gerne have haft void initADC( 8 ); med men det kan jeg jo ikke, da den allerede er som void initADC(uint8_t aBits) i ADC.h
Gør jeg det alligevel bliver de conflicting. Gør jeg det ikke bliver initADC( 8 ) undefined (ved godt der er mellemrum i ( 8 ) men det er for at undgå ham her (8)
det driller mig lidt at gennemskue.
Er lidt træt nu så må hellere holde en pause.
« Senest Redigeret: August 18, 2011, 03:47:02 af jascore »