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

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #225 Dato: November 20, 2011, 01:26:41 »
Hmm nej. jeg forstår det ikke.
hvis jeg har prescaler 8 i TCCR0B kan jeg godt toggle leds ved tryk på start knap, og følge det helt hen til start dosing. men den vil ikke toggle pr. sek i timeren.
sætter TCCR0B prescaleren til 64 som den skal kan jeg tænde og slukke dem med en setLED(1) eller 0 i main lige efter init led, men reagerer ikke på noget med toggle eller on eller off  hvis jeg smider det ind i startknap funktionen ??
Til gengæld kan jeg se at den springer direkte over i startdosing i dosing.c uden at jeg trykker på knappen for der kan jeg kode leds til at tænde eller slukke men stadig reagerer de ikke på startknappen

Efterfølgende har jeg fået 1 led til at toggle ved tryk på start, med prescaler 64, men den lyser stadig konstant hvis jeg smider toggle ind efter sSeconds++

tror også jeg fandt en anden fejl.
når der trykkes på start kaldes startdosing rutinen, men den har jo ingen adc1 værdier at forholde sig til så ved ikke om  flg skal ind i startknap rutinen lige inden startdosing bliver kaldt
gSettings = calculateSettingsDip(getADC1Value());
« Senest Redigeret: November 20, 2011, 03:10:36 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 #226 Dato: November 20, 2011, 08:25:26 »
Man skulle næsten tro at min avr er brændt af eller noget. når jeg sætter prescaler til det som du sagde, så lyser alle leds hvad enten jeg sætter dem til off eller ej ?!?!  :-[

Heh, den er ikke brændt af; der skal en del til. :)

Denne prescaler værdi burde være korrekt.
I Makefile er fuses sat til H:0xdf og L:0x62.
Dette betyder at microcontrolleren kører 1 MHz.
F_CPU skal derfor være 1000000, det er den også.

Hvis vi dividerer F_CPU med 64, får vi 15625.
Dividerer vi 15625 med 125, får vi 125. Begge disse værdier (125 og 125) passer i en byte.
Da vi har sat WGM0x til 0:0:0, er vores Timer0's MAX værdi 255.
-Så den ene trækker vi fra 256 og lægger i TCNT0 (for Timer0's MAX er 255, og der er så 256 tælle-værdier). altså 256 - ((1000000 / 64) / 125) = 131.

Derfor ser linien der sætter TCNT0's værdi sådan ud:
Kode:
TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125));

TCNT0 starter med andre ord på 131 og tæller op til 255, hvorefter Timer0's overflow interrupt udføres så snart TCNT0 vippes om fra 255 til 0.

I overflow-interruptet gen-indstilles værdien på TCNT0, til næste gang. (Dette er det aller første der skal være i interruptet, for ellers vil værdien kunne 'glide', og derved ville tidsmåleren kunne tabe tid.

Derudover har jeg været årsag til endnu en fejl (fordi jeg ikke har været ordentlig vågen), i initTimer0 står nemlig:
Kode:
	TIMSK0 &= (1 << TOIE0);

Dette skulle have været...
Kode:
	TIMSK0 &= ~(1 << TOIE0);

... tilde (~) vender nemlig alle bits i en værdi til det modsatte.

Hvis der stadig ikke er nogen ændring, så prøv lige midlertidigt, at stille værdien tilbage til CS0x = 0:1:0, og se om der ændres noget.
Hvis alle LEDs derefter lyser, er det ikke pga. timeren det er galt.

Min initTimer0 ser nu således ud:
Kode:
void initTimer0()
{
cli(); /* disable interrupts if not already done */
sSeconds = 0;
sMinuteCountdown = 0;
sMinuteCountdownRestart = 0;
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 PRESCALER64: (CS02:CS01:CS01 = 011): */
TCCR0A = (0 | (0 << COM0A1) | (0 << COM0A0) | (0 << COM0B1) | (0 << COM0B0) | (0 << WGM01) | (0 << WGM00));
TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS02) | (1 << CS01) | (1 << CS00));
/* Clear any pending interrupts, so we don't get an accidental interrupt immediately after enabling interrupts... */
TIFR0 |= (1 << TOV0); /* clear 'Timer OVerflow 0' bit in 'Timer Interrupt Flag Register 0' */
/* enable Timer OVerflow 0 interrupt: */
TIMSK0 |= (1 << TOIE0); /* set 'Timer Overflow Interrupt Enable 0' bit in 'Timer Interrupt MaSK 0' */
}

 

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 #227 Dato: November 20, 2011, 09:28:32 »
Hmm nej. jeg forstår det ikke.
Her kan jeg være helt med. ;D

...Men du skal ikke lade dig forvirre af disse ting. :)
Citér

hvis jeg har prescaler 8 i TCCR0B kan jeg godt toggle leds ved tryk på start knap, og følge det helt hen til start dosing. men den vil ikke toggle pr. sek i timeren.

OK. Vi skal prøve at lave en test. =)

Prøv at lave main's while loop om til...
Kode:
while(1)
{
    setLED1((SREG >> 7) & 1);
}

Dette skulle gøre at LED1 fortæller (hele tiden) om vores interrupts kører eller ej.

Citér
sætter TCCR0B prescaleren til 64 som den skal kan jeg tænde og slukke dem med en setLED(1) eller 0 i main lige efter init led, men reagerer ikke på noget med toggle eller on eller off  hvis jeg smider det ind i startknap funktionen ??

HOV! Jeg kom til at klokke i det; en ting jeg næsten altid glemmer med hensyn til toggle.

Toggle-linien må ikke hedde...

Kode:
PINA |= (1 << PA4);

men skal hedde

Kode:
PINA = (1 << PA4);

-Det kan godt påvirke i den retning, at det slukker alle de andre portben på PORT A, og dermed alle andre LEDs. :)

-Jeg har sendt dig en ny leds.c og leds.h. =)

Citér


Til gengæld kan jeg se at den springer direkte over i startdosing i dosing.c uden at jeg trykker på knappen for der kan jeg kode leds til at tænde eller slukke men stadig reagerer de ikke på startknappen

...Mumle, mumle... Måske indsætte toggle-LED i timer0Elapsed() ?

Citér
Efterfølgende har jeg fået 1 led til at toggle ved tryk på start, med prescaler 64, men den lyser stadig konstant hvis jeg smider toggle ind efter sSeconds++

Sikkert beslægtet med toggle-LED fejlen jeg omtalte ovenover.

Citér
tror også jeg fandt en anden fejl.
når der trykkes på start kaldes startdosing rutinen, men den har jo ingen adc1 værdier at forholde sig til så ved ikke om  flg skal ind i startknap rutinen lige inden startdosing bliver kaldt
gSettings = calculateSettingsDip(getADC1Value());

Korrekt. Et bedre sted at sætte den er dog i startDosing(), fordi startDosing bliver kaldt 2 steder fra, nemlig i initDosing() og fra start-knappen.

Nu ser min startDosing således ud:
Kode:
void startDosing()											/* this routine starts when the 'start' button is pressed */
{ /* setMinuteCountdown initiated corrosponding to dip setting*/
static const uint16_t timeTable[] PROGMEM = { 2 * 60, 24 * 60, 12 * 60, 6 * 60 };

gSettings = calculateSettingsDip(getADC1Value()); /* read dip switches and update gSettings */
setMinuteCountdown(pgm_read_word(&timeTable[(gSettings >> 2) & 0x03]));
timer0Elapsed();
}

 

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 #228 Dato: November 20, 2011, 15:52:08 »
Tænk at man kan få en weeee fornemmelse af at se en led toggle he he, men glæder mig faktisk gg

Ja, jeg har selv prøvet den med en LED. ;)
-Det var endda efter AVR, for jeg gik videre til ARM, men ... Det tog jeg ved ikke hvor meget bøvl, først skulle jeg have compilet en hel toolchain, så skulle denne toolchain sættes op (dvs. compiler + brænder/debugger programmet OpenOCD), så skulle JTAG'en konfigureres i OpenOCD, for den setting der var med duede ikke. Nå, men langt om længe fik jeg lavet et program, compilet det, brændt det over i ARM-chippen og den ville ikke noget, der skulle speciel hardware-opsætning til (5 gange så meget opsætning som AVR), og den var stadig umulig. Men efter nogle måneder lykkedes det mig at få en lysdiode til at blinke på netop den måde jeg ville blinke den (dvs. uden toggle; alle eksempler der var givet, var nemlig med toggle; jeg ville skrive den direkte værdi til porten).

...Jeg stoppede med Atmel ARM, da jeg yderligere efter flere måneder (og spørgen om hjælp på AT91 forum'et) ikke kunne få timeren til at køre; jeg fik dog lavet mit proof-of-concept. :)

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #229 Dato: November 20, 2011, 22:24:15 »
Så er jeg igang igen.
Har lavet alle ændringer som du skrev og brugt de nye led.c og h, og har ikke nogle toggleled() eller setLed(#) nogle andre steder i koden.
og det her er en kedelig mail der bare beskriver hvordan jeg går frem, ligeså meget for min egen skyld, så jeg prøver at være systematisk i min fejlsøgning  :o
Når jeg starter systemet op lyser alle dioder pa4-7.

så prøver jeg at skrive
Kode:
setLED1(0);
setLED2(0);
setLED3(0);
setLED4(0);
lige efter initled() i main så slukker alle led (det gør de ikke hvis jeg først skriver dem efter eks sei)
apropos SEI. skal den stå 2 steder. kan det ikke skabe problemer at enable interrupts 2 steder?

så men efter de alle er slukket, smider jeg setLED1((SREG >> 7) & 1); ind i main's while løkke og alt er stadig slukket så væk med den igen.
prøver at smide en toggleLED1(); ind i startknap funktionen efter prell sikring, og intet sker. stadig slukket.

prøver en setLED1(1) samme sted stadik slukket

fjerner alle setLED#(0) og smider toggle led ind i startknap funktionen igen og ser hvad der sker. Alt lyser og intet toggler. prøver også lige setLED1(0). ingen reaktion

Prøver at skrive PINA = (1 << PA4); alt lyser fortsat når der trykkes på start.
Smider alle setLED#(0) ind igen og prøver med samme toggle alle leds er nu bare slukket  :-[
gør jeg noget forkert her?

Fandt ud af noget interessant. Jeg kan bruge setLED#(0) før initdosing i main.c men samme komando virker ikke efter initdosing
så det må vel betyde at den hænger i init af dosing et eller andet sted

Så søgte videre ved at følge programmet.
den går til initdosing hvorfra den går til startdosing og setLED#(0) komandoen virker indtil gSettings = calculateSettingsDip(getADC1Value()); efter denne kommando virker det ikke mere så søger videre derfra
Gennem hele uint8_t calculateSettingsDip(uint16_t gDipSwitches) virker det også men så tænker jeg
i startdosing sætter den gSettings = calculateSettingsDip(getADC1Value()); men  calculateSettingsDip funktionen hedder calculateSettingsDip(uint16_t gDipSwitches) det stemmer jo ikke overens, så prøver at ændre i startdosing så det er gSettings = calculateSettingsDip(uint16_t gDipSwitches istedet for gSettings = calculateSettingsDip(getADC1Value());
og det kunne jeg ikke.
så må jeg jo kigge videre i getADC1Value() og se hvad der sker der

den slukker led gennem hele uint16_t getADCValue(uint8_t aADC) men i void waitUntilADCStable() slukker den ikke noget
i funktionen uint16_t getADC1Value() slukker den for led men ikke i de 2 efterfølgende
uint16_t getADC2Value() og uint16_t getADC3Value()
og nu vil jeg stoppe for i dag og hoppe i seng  8)
« Senest Redigeret: November 21, 2011, 01:12:27 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 #230 Dato: November 21, 2011, 08:17:05 »
lige efter initled() i main så slukker alle led (det gør de ikke hvis jeg først skriver dem efter eks sei)

Aha. Jeg tror jeg er klar over hvad der sker nu. :)

Jeg har på fornemmelsen at programmet går ned.
-Du skal nemlig kunne tænde/slukke LEDs uanset hvor du er i koden.
Virker det ikke efter sei(), så betyder det at programmet ikke kommer videre.

Dvs. der er sikkert et eller andet interrupt, som er gået i ged. Mere om hvordan vi får det på plads senere.

Citér
apropos SEI. skal den stå 2 steder. kan det ikke skabe problemer at enable interrupts 2 steder?

cli() slår interrupts fra.
sei() slår interrupts til.
Du kan gøre dette så ofte du vil.
Mere detaljeret: sei() sætter bit 7 i SREG, mens cli() sletter bit 7 i SREG.
SREG's bit 7 hedder I, og står for "global Interrupt enable'.

Citér
så men efter de alle er slukket, smider jeg setLED1((SREG >> 7) & 1); ind i main's while løkke og alt er stadig slukket så væk med den igen.

Sikkert fordi programkørslen aldrig kommer ind i main's while-loop. ;)

Citér
Fandt ud af noget interessant. Jeg kan bruge setLED#(0) før initdosing i main.c men samme komando virker ikke efter initdosing

Aha.. Fejlen er fundet.

Citér
så det må vel betyde at den hænger i init af dosing et eller andet sted

Fuldstændig korrekt.

Citér
men så tænker jeg
i startdosing sætter den gSettings = calculateSettingsDip(getADC1Value()); men calculateSettingsDip funktionen hedder calculateSettingsDip(uint16_t gDipSwitches) det stemmer jo ikke overens, så prøver at ændre i startdosing så det er gSettings = calculateSettingsDip(uint16_t gDipSwitches istedet for gSettings = calculateSettingsDip(getADC1Value());
og det kunne jeg ikke.

Nej, for gDipSwitches er en parameter som er lokal og kun kan ses af calculateSettingsDip, og derfor bør denne parameter ikke hedde gDipSwitches, men aDipSwitches. :)

Kode:
uint8_t calculateSettingsDip(uint16_t aDipSwitches)
-Så alle steder i koden, bør gDipSwitches blive erstattet med aDipSwitches.
(Dette er i Dosing.h og Dosing.c)

Citér

den slukker led gennem hele uint16_t getADCValue(uint8_t aADC) men i void waitUntilADCStable() slukker den ikke noget

Fejlen(e) er:

1: Koden venter på at ADC'en er stabil, men ADC'en er ikke sat igang endnu, så den venter forgæves og bliver ved med at vente.

2: Hvis nu vi kom forbi waitUntilADCStable(), så ville vi komme ind i timer0Elapsed, som venter 10 sekunder. Her vil den blive ved og ved at vente, fordi timer0 ikke er startet endnu.

Løsningen er ganske simpel:

Du bør ikke kalde startDosing() fra din initDosing().
Dette er fordi init____ rutinerne er ment som at skulle lave opsætning (opsætning der lige tager få clock-cycles) og ikke andet; de må ikke vente på noget.

Så prøv at flytte startDosing() fra initDosing over i Main.c, lige efter sei();


Citér
og nu vil jeg stoppe for i dag og hoppe i seng  8)

Fornuftigt. :)
Denne beskrivelse har været rigtig god. Jeg regner med at du i dag kan få lysdioderne til både at lyse og blinke, plus nogle andre småting. ;)

Du burde efter ændringen kunne få følgende i main's while-loop til at virke...

Kode:
while(1)
{
    toggleLED1();
    waitSeconds(1);
}

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #231 Dato: November 21, 2011, 14:42:13 »
Citér
Så prøv at flytte startDosing() fra initDosing over i Main.c, lige efter sei();

Det virkede desværre ikke den hænger stadig i waitUntilADCStable().
når jeg bruger setLED1(0); i den første getADC1Value slukker den godt nok, men ikke i de efterfølgende 2 getADC#Value
uint16_t getADC1Value()
{
   return(getADCValue(1));
}

uint16_t getADC2Value()
{
   return(getADCValue(2));
}

uint16_t getADC3Value()
{
   return(getADCValue(3));
}
« Senest Redigeret: November 21, 2011, 14:48:31 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 #232 Dato: November 21, 2011, 15:34:41 »
Citér
Så prøv at flytte startDosing() fra initDosing over i Main.c, lige efter sei();

Det virkede desværre ikke den hænger stadig i waitUntilADCStable().

OK, men lad den blive dér, for det vil ikke komme til at fungere, hvis den sidder i initDosing. ;)

Prøv at åbne ADC.c og ændre det sidste af den til følgende:
Kode:
	adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo;				/* save the value we've read above */

if(adcChannel++ >= ADC_LAST) /* next channel. If channel reached last channel... */
{
adcChannel = ADC_FIRST; /* ...start over */
adcWriteIndex = adcWriteIndex >= (ADC_SIZE - 1) ? 0 : (adcWriteIndex + 1); /* increment write position and wrap if necessary */
adcReadIndex = adcReadIndex >= (ADC_SIZE - 1) ? 0 : (adcReadIndex + 1); /* increment read position and wrap if necessary */
if(adcCounter < ADC_STABLE) /* if we haven't reached the number of conversions required for the ADC to stabilize... */
{
adcCounter++; /* increment counter */
}
}
ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07); /* set which channel to read next time */
ADCSRA |= (1 << ADSC); /* start another conversion */
}

Jeg har lavet følgende ændringer:
  • flyttet ADCSRA |= (1 << ADSC); ned i bunden.
  • sat paranteser omkring adcWriteIndex + 1 og adcReadIndex + 1

ADCSRA-linien bør nok stå efter ADMUX linien, fordi ADMUX fortæller hvilken kanal vi vil læse fra næste gang, og ADCSRA-linien starter næste konvertering.
Derudover sætter jeg parantes omkring adcWriteIndex + 1 og adcReadIndex + 1, fordi 'select', dvs. udtrykket " <udtryk> ? <udtryk> : <udtryk> " har det med at være prioriteret anderledes end man forventer, så det er bedst altid at bruge paranteser, når man bruger dem.

Det burde hjælpe at få ADCSRA linien flyttet. Jeg har ingen anelse om hvorfor jeg ikke har sat den efter ADMUX linien... <glob> :)

Prøv at sætte noget lysdiode-test ind i ADC-interruptet.

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #233 Dato: November 21, 2011, 15:50:46 »
Med en toggleLED inde lige efter adcCounter++; toggler den ikke led med mindre at det går så hurtigt at jeg ikke kan se det
Med en setLED1(0) slukker den godt nok der inde


« Senest Redigeret: November 21, 2011, 16:02:45 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 #234 Dato: November 21, 2011, 16:05:44 »
i flg
if(ADCSRB & (1 << ADLAR))                                          /* check hardware alignment-configuration and act accordingly */
      {
         adLo = 0;
         adHi = inb(ADCH);                                             /* (read highbyte only) */
      }
      else
      {
         adHi = 0;
         adLo = inb(ADCH);                                             /* (read highbyte only) */
      }
reagerer den ikke med en setLED i if, kun i else
og i den overordnet funktion if(adcBits <= 8)
reagerer den ikke i else

men under alle omstændigheder er det efter med gSettings = calculateSettingsDip(getADC1Value()); kaldet i startdosing funktionen at systemet stopper
« Senest Redigeret: November 21, 2011, 16:30:35 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 #235 Dato: November 21, 2011, 17:23:44 »
Med en toggleLED inde lige efter adcCounter++; toggler den ikke led med mindre at det går så hurtigt at jeg ikke kan se det
Med en setLED1(0) slukker den godt nok der inde

prøv i toppen af interruptet at sætte en...

Kode:
setLED1(1);

og i bunden...

Kode:
setLED1(0);

...Hvis så du kan se lysdioden sender (sikkert svagt) lys ud, vil det betyde at ADC-interruptet kører hele tiden.

Hvis derimod lysdioden er helt slukket (og du måler 0V med multimetret), så betyder det at ADC-interruptet kun kører én gang.

Citér
i flg
if(ADCSRB & (1 << ADLAR))                                          /* check hardware alignment-configuration and act accordingly */
      {
         adLo = 0;
         adHi = inb(ADCH);                                             /* (read highbyte only) */
      }
      else
      {
         adHi = 0;
         adLo = inb(ADCH);                                             /* (read highbyte only) */
      }
reagerer den ikke med en setLED i if, kun i else
og i den overordnet funktion if(adcBits <= 8)
reagerer den ikke i else
Dette er korrekt opførsel. Den skal kun komme ind i én af disse 3.
Dette er fordi vi indstiller ADC-rutinen til at håndtere 8-bits i main().
Havde vi valgt at bruge 10-bits, ville det være den nederste den kom ind i.

Citér
men under alle omstændigheder er det efter med gSettings = calculateSettingsDip(getADC1Value()); kaldet i startdosing funktionen at systemet stopper

Ja, det er fordi waitUntilADCStable() venter på at adcCounter er talt op til værdien af ADC_STABLE (som er 8 i dette tilfælde).
adcCounter bliver talt op af ADC-interruptet i linien...
Kode:
			adcCounter++;

-Og den tæller kun op, hver gang vi har været alle ADC-kanaler igennem, og kun så længe den er under værdien af ADC_STABLE.

Men køres ADC-interruptet kun én gang, vil adcCounter kun nå op på værdien 1.
-Så vi må finde ud af om interruptet bliver ved med at køre, eller om det er faldet i søvn...

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #236 Dato: November 21, 2011, 17:34:26 »
den lyser hele tiden når jeg prøver det du har skrevet.
kan ikke se forskel på om den er svag eller skarp. men
hvis jeg sætter led til at være slukket i toppen og undlader at tænde den i bunden, forbliver den slukket. hvis jeg slukker den i starten af interrupt tænder den i bunden forbilver den tændt
if (adcCounter ==#)
{
setLED1(0);
}
hvor # er 1-8 og den slukker som den skal og stopper ved 9 med at slukke


sorry. jo den bliver svag, så interrupt må køre
trykker jeg så på startknappen, slukker den helt

« Senest Redigeret: November 21, 2011, 17:42: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 #237 Dato: November 21, 2011, 17:49:45 »
den lyser hele tiden når jeg prøver det du har skrevet. har også prøvet at lave
kan ikke se forskel på om den er svag eller skarp. men
hvis jeg sætter led til at være slukket i toppen og undlader at tænde den i bunden, forbliver den slukket. hvis jeg slukker den i starten af interrupt tænder den i bunden forbilver den tændt

Dette er en rigtig god nyhed.
Altså vil det sige at interruptet kører. :)

Citér
if (adcCounter ==#)
{
setLED1(0);
}
hvor # er 1-8 og den slukker som den skal og stopper ved 9 med at slukke

Også en ganske god nyhed, for den skal jo tælle op så længe adcCounter er mindre end 8.

Og så er der fundet en fejl til... Mere herom senere. ;)

Citér

sorry. jo den bliver svag, så interrupt må køre
trykker jeg så på startknappen, slukker den helt

Fint.

Prøv at nærlæs denne kode...
Kode:
    if(adcCounter < ADC_STABLE)
    {
        adcCounter++;
    }

Derefter prøv at nærlæs denne kode...
Kode:
    while(adcCounter < ADC_STABLE)
    {
    }

Ser rigtig godt ud, ikke, men der er faktisk en fejl. Lad os lige gøre det mere klart for os hvad der sker:
Så koden således ud...
Kode:
    if(adcCounter < 8)
    {
        adcCounter++;
    }

Hvad ville den maksimale værdi af adcCounter så være ?

... og ...

Kode:
    while(adcCounter < 8)
    {
    }

Hvad sker her ? :)

(Hvor mange kvajekager er jeg oppe på nu?) ;D

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #238 Dato: November 21, 2011, 17:54:43 »
Citér
Hvad ville den maksimale værdi af adcCounter så være ?
vil den ikke være 7 med mindre den hedder <=

Citér
while(adcCounter < 8)
    {
    }

der sker vel ingen ting. er den under 7 udføres det intet. er den over 7 springes while over og der sker intet alligevel
eller fryser den i løkken

 

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 #239 Dato: November 21, 2011, 18:41:07 »
Æh, det var en and! :o

Der er intet galt dér alligevel.
Fordi...
Hvis adcCounter er mindre end 8, bliver der lagt én til, dvs. er den 7, bliver der lagt én til, og den bliver 8.

While... Så længe værdien er under 8, bliver den i while-løkken, og låser, men kun så længe værdien er mindre end 8. Den bliver nøjagtig 8, og derfor kommer den ud af while-løkken. (I teorien ihverfald).

HAH. Det er noget helt andet, der er galt. :)

Et interrupt bliver ikke afbrudt af et andet interrupt.

Så hvis vi er inde i et interrupt, fx. start-knap interruptet, så kan dette ikke afbrydes, fordi når man kommer ind i et interrupt, bliver interrupts slået fra globalt, dvs. bit 7 i SREG bliver sat til 0.
(Dette er fordi man vil undgå at et interrupt afbryder sig selv, hvis det er for lang tid om at udføre sin kode). Når interruptet så er færdigt, bliver interrupts så slået til igen.

Her er et forslag til løsning af problemet. (Nogle programmører vil have ganske gode argumenter mod at gøre det, men.. jeg gør det alligevel).

Hvad vi gør, er at vi slår interrupts til, før vi begynder at vente.
Men lige inden dette, så gemmer vi det gamle status-register (SREG), og når vi er færdige med at vente, sætter vi SREG til den gamle værdi, hvilket vil betyde at hvis interrupts var slået fra, bliver de slået fra igen, ellers bliver de ved med at være slået til.

Kode:
void waitSeconds(uint8_t aSeconds)
{
uint8_t oldSREG;

aSeconds = (aSeconds + sSeconds); /* add current second value to aSeconds */
if(aSeconds >= 60) /* we can't wait more than 59 seconds, so if the result is larger than 59... */
{
aSeconds -= 60; /* ...then subtract 60 */
}
oldSREG = SREG; /* save global interrupt flag */
sei(); /* enable interrupts */
while(aSeconds != sSeconds) /* wait until sSeconds has the same value as aSeconds */
{
}
SREG = oldSREG; /* restore global interrupt flag */
}

Kode:
void waitUntilADCStable()
{
uint8_t oldSREG;

oldSREG = SREG; /* save global interrupt flag */
sei(); /* enable interrupts */
while(adcCounter < ADC_STABLE) /* keep waiting, until ADC is reliable */
{
}
SREG = oldSREG; /* restore global interrupt flag */
}

(4 nye linier i hver rutine)
« Senest Redigeret: November 21, 2011, 18:43:35 af pacman »