Dansk Elektronik Forum

Generel Elektronik => Generel Elektronik => Emne startet af: jascore efter August 03, 2011, 16:56:27

Titel: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 03, 2011, 16:56:27
Hej der.
Jeg er ved at lave et projekt, der kræver at en servo går fra 0 grader til 180 grader til 0 grader og kun én gang hver X time.
Jeg overvejer at bruge en 4060b til 0-24 timers timer (behøver ikke være mere præcis end +- 5 minutter) og en 555 til at kontrollere servoens bevægelse.
Når PIN 3 på 4060b trigger pin 2 på 555 skal servoen køre 1 cyklus 0 ->180 -> 0.

Jeg har et diagram for en 4060b timer og et for 555, men jeg kan ikke at servoen til kun at køre en cyklus.
Jeg overvejer at bruge en pic binary counter til at gøre arbejdet, men jeg har ingen erfaring med programmering af sådan en, og heller ikke et diagram

Håber i kan hjælpe mig
på forhånd tak
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 04, 2011, 23:03:20
Jeg overvejer at bruge en pic binary counter til at gøre arbejdet, men jeg har ingen erfaring med programmering af sådan en, og heller ikke et diagram.

Desværre ved jeg intet om servo, så der kan jeg ikke hjælpe ret meget.
Men jeg vil (personligt) anbefale en Atmel AVR til styring. Jeg synes de er meget lettere at arbejde med end PIC (du får sådan set også mere for pengene).
Du behøver ikke en timer kreds, hvis du bruger en microcontroller. AVR kan købes hos de fleste elektronik-forhandlere i Danmark (også El-Supply, selvom han ikke skilter så meget med det; ring evt. og spørg).
De fleste vælger at købe en Arduino, men hvis du ønsker det, behøver du faktisk kun selve AVR chippen, en 4k7 og en 100nF kondensator.
Hvis du ønsker høj eller præcis hastighed på microcontrolleren, kan du også koble et clock-krystal og 2 stk. 18pF kondensatorer på.

Selv den mindste AVR (har 3 ben) kan klare at styre en servo motor.
Jeg vil dog nok anbefale minimum en ATtiny85. Du kan få ATtiny (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294590393+4294571396+4294587109&Ns=I18NPrc1_dk&Nso=0) fra omkring 10-12 kr. pr. stk.

Har du PC, kan du programmere den via parallel-porten og et hjemmelavet kabel. Har du en computer uden parallel-port, skal du nok have fat i fx. en AVRISPmkII (fx. gennem El-Supply (http://el-supply.dk/)).

Jeg har hørt at servo kan drille, men mange har lavet servo-styring med AVR, så bare vær tålmodig. :)

Vælger du AVR, kan du få adskillige værktøjer gratis. Har du PC, kan du bruge Atmel's egen udviklerpakke; har du Mac/Linux, kan du downloade avrdude + GCC. Med disse værktøjer kan du programmere chippen både i C og i assembler, hvis du synes.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 04, 2011, 23:21:44
Hej der.
Jeg er ved at lave et projekt, der kræver at en servo går fra 0 grader til 180 grader til 0 grader og kun én gang hver X time.

Her er lidt mere information (http://www.electroons.com/electroons/servo_control.html) også omkring hvordan man kobler servoen til microcontrolleren.

Hvis nu din microcontroller kører på 8MHz (fx. den interne clock source), så vil du kunne sætte en timer op til at tælle, fx. hver gang der er gået 800000 clock-cycles, så tæller den 1/10 sekund ad gangen.
Når du så har talt 36000 af disse interrupts, er der gået en time.

Hvis du vil køre fra batteri, vil du nok også synes det er en god idé at bruge "sleep" kommandoen, hvilket får microcontrolleren til at køre 'langsomt' og derved spare strøm. Du vil så kunne 'vække' den, når den skal lave servo-sjov, og så sætte den til at sove igen bagefter.

Det kan forresten være en god idé at koble servo-motoren til et af microcontrolleren's PWM-ben eller timer-ben (OCxA/OCxB). Lad os antage at du har besluttet dig for at bruge en ATtiny85.
Først skal du vide noget om microcontrolleren. Gå derfor ind på dk.rs-online.com og skriv "attiny85" i søgefeltet. Der kommer så omkring 3 resultater. Der vil være én med ben på, som kan monteres i breadboard og hulprint. I den's række er der et PDF-ikon. Klik på denne. Der kommer nu en boks frem med tekniske referencer. Klik på "8-bit Microcontroller with 2/4/8K Bytes In-System Programmable Flash Data Sheet".
Gem dette datablad på din harddisk, så du senere kan hente det frem nemt.
Åbner du PDF'en, vil du kunne bladre til side 2, hvor du ser benforbindelserne på chippen.
Her ser du bla. 2 ben der har 'OC1B' i navnet. Forskellen er at den ene har en streg over OC1B, hvilket betyder at den er inverteret i forhold til OC1B.
Men samtidig ligger disse ben på XTAL1 og XTAL2. Hvis du nu vil bruge eksternt clock-krystal, vil det være en god idé at holde de 2 ben frie.
I stedet vil du nok foretrække at bruge PB0 til servo-styringen Den har OC0A. Der er også PB1, som har OC0B.
Hold RESET-benet fri. Dette skal du koble til en pull-up modstand på mellem 4k7 og 10k; fx. en 4k7 modstand fra RESET-ben til +5V. Ved VCC benet sætter du en 100nF kondensator som du plejer ved alle IC'er, for at undgå støj-påvirkninger.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 05, 2011, 23:33:13
Tusind tak for dit svar pacman.
Det jeg skal lave er et doserings system til saltvandsakvarie. Meningen er at en servo skal trække en sprøjte ud til X antal milimeter og derefter sprøjte det i akvariet. alt det mekanik tekniske er lavet mangler bare at lave styrringen.
Der er nogle få krav bla at det skal være nemt og hurtigt for enhver at ændre mængden så min løsning er i prototypen at lave følgende.
1 4001 ,pr væske der skal leveres, der fungerer som multivibrator med en variabel modstand til at ændre frekvensen til servoen og derved bestemme hvilken position den skal køre frem til (x antal ml)
og så en 4001 kreds til at trykke alle sprøjter i bund og leverer væsken, også med variabel modstand til at justerer hvor bunden er alt efter sprøjte størrelse.
hver sprøjte skal styres af en alt digital on/off timer så man kan stille hvornår og hvor mange gange i døgnet væsken skal tilføres.

mit problem lige nu er som følger.
Har en alm digital timer der kan programeres til 1 minut. Det skal leverer strøm til en anden timer som kan tænde et rælæ vente vente 20 sek. og slukke vente et par sek og så tænde et andet relæ i 20 sek. for derefter at slukke.

De to relæer leverer strøm til henholdsvis den ene og den anden 4001

Det er sammenlagt 42 sek men der kommer strøm fra den alm timer i 1 minut så det er vigtigt at efter at relæ nr 2 er slukket at det ikke køre i loop.
Jeg er elektrikker og kunne nok klare det med alm relæ teknik men det skal jo helst fylde så lidt som muligt, derfor har jeg bevæget mig usikkert ind på svagstrøms området og takker de højere magter for internettet :-P.

Jeg tænker jeg kan gøre det med noget flip flop A B men mit problem er at det kun skal ske 1 gang indtil styrestrømmen slukkes og den skal reset og sår styrestrømmen tænder igen skal den køre A B en gang osv osv


(http://desmond.imageshack.us/Himg846/scaled.php?server=846&filename=servostyr.jpg&res=medium)

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 06, 2011, 00:48:39
...mangler bare at lave styrringen...
...nemt og hurtigt for enhver...
...et potmeter til at ændre frekvensen til servoen...
...4001 kreds...
...potmeter til at justerer hvor bunden er alt efter sprøjte størrelse...
...hver sprøjte styres af en digital on/off timer...
...tænde et rælæ vente vente...
...tænde et andet relæ...
det skal jo helst fylde så lidt som muligt...

Alt ovenstående kan programmeres ind i en microcontroller.
Hvis det skal fylde så lidt som muligt, vil jeg absolut anbefale en microcontroller. :)
En sådan microcontroller kan fåes ned i 4mm x 4mm (lige netop dén størrelse er ikke sjov at lodde i hånden)

Men for de mere almindelige mennesker er en ATtiny44A-20PU (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=searchProducts&lastSearch=&autoc=false&storedtfgList=&searchTerm=attiny44a&x=0&y=0) nok liige sagen.
Her er lidt af hvad du kan med den:
Den inkluderer alt hvad CD4001 kan plus mere, både at den kan tænde og slukke for ben, plus de logiske funktioner.
Den har 12 i/o ben. i/o betyder at man enten kan aflæse fx. en kontakt eller med programmet tænde/slukke benet.
Ud af de 12 i/o ben, kan 8 af dem bruges til analog aflæsning (dvs. 0 til 2,56Vdc; opdelt i enten 256 eller 1024 værdier)
Den har 2 uafhængige timere. Dvs. 1 timer kan sagtens gøre flere ting på én gang, så du behøver kun at bruge en enkelt timer.

Skal du tænde/slukke et relæ (fx. 250V/10A), kan du nøjes med at sætte en 1K modstand fra microcontrolleren til basis på en BC547 transistor. Emitter sætter du til GND, mens collector sættes til relæet og relæet til +5V. Du sætter så en 1N4148 fra +5V til collector, for at beskytte transistoren mod transienter (kendt opstilling).

På dette (stjålne) billede (http://www.dwengo.org/sites/default/files/domotics_circuit_0.png), kan du se et "Control circuit". Det ben der står "uC+bluetooth" på, svarer til microcontroller-benet. Som modstand anbefaler jeg en 1K; det har jeg altid selv brugt uden bøvl. Transistoren kan være fx. en BC546...BC548, alt efter hvad du har i skuffen. Relæet kan du evt. spørge Danni Hansen om. ;)
Dioden er en 1N4148.
Spændingen kan være fra 5V til 12V, alt efter hvad relæet kræver, op til hvad transistoren kan klare. (Så vidt jeg husker i hovedet: BC546 klarer 65V, BC547 klarer 45V).
-Men det err nok bedst at holde den på 12V eller under.

OK, hvad har vi nu?

1: Microcontroller (http://docs-europe.electrocomponents.com/webdocs/0d68/0900766b80d68843.pdf) styring med timer funktion, hvor du kan vælge at køre i få mikrosekunder op til så mange år som du har lyst til.
2: Tilkobling af 2 potmetre (skulle det blive nødvendigt, kan der kobles flere på)
3: Tænd/Sluk af relæer
4: Styring af Servo-motor. (Brug fx. PA6, PA7, PB2 eller PA5 til servo-motoren)

Følgende komponenter er så nødvendige:
Selve styringen:
ATtiny44A (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6962538)
100nF kondensator (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6530080)
4k7 modstand (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=7077726) til at forbinde fra RESET til +5V.
En Transformer (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Ns=I18NPrc1_dk&Ne=4294958306&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294963478+4294957775+4294676590&Nso=0&binCount=462) - Fx. 2x6V til et 5V kredsløb.

Strømforsyning:
7805 spændings-regulator (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=7044010)
47uF/25V kondensator (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=7111084) (2 stk, en før, og en efter din 7805)
Evt. Diodebro (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6875939)

Per potmeter:
én modstand med samme værdi som potmetret; fx. 1K (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6916888) eller 5k (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6916901) vil nok være et godt valg.

Per relæ:
BC546 (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=5449292)
1K modstand (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=7077666) mellem microcontroller og Basis på transistor
1N4148 (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6708858) til at sætte over relæet fra +5V/+12V til Collector på transistor.
(og så selve relæet; regn med cirka 10-30 kr. ex. moms, alt efter hvilken type du vælger)

Potmeter sætter du så i serie med en modstand, fx:
Fra +5V sættes en 1K modstand til det ene yderben på et 1K potmeter. Det andet yderben sættes på 0V. Midterbenet (udtræk) sættes direkte ind på et af microcontrolleren's ADC ben. Her kan du så måle 5V/2 = 0V til 2.5V. Simpelt og nemt, ikke ?
-Du skal bare vælge en modstand med samme værdi som potmetret, fx. en 5K modstand til et 5K potmeter, osv; for så divideres spændingen med 2.

Skal du have kontakter eller tryk-knapper på, sætter du en 4k7 modstand fra det valgte i/o ben op til +5V. Fra samme i/o-ben sætter du så din trykknap/kontakt til 0V, så når knappen er trykket ned, går der 0V direkte ind på benet; når knappen er sluppet, går der +5V igennem modstanden ind på i/o benet, nemt, ikke?
(Du kan også lave det omvendt, hvis du synes det er lettere at finde rundt i.)

Derudover... Programmerings-muligheder til din Microcontroller. Du kan fx. sætte den i sokkel på printet, og så programmere den før du propper den i; eller du kan lave et programmerings-stik i dit print, og programmere hver microcontroller mens den sidder i printet med strøm på.
Som programmerings-stik kan man bruge en alm. 2.54mm spacing "Header" (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=0155715) -disse kan "klippes/skæres" i mindre bidder. Du har brug for en 2x3, så ud af 2x40 kan der blive 13, når du har øvet dig i at skære dem i et par minutter; først lidt ned i den ene side, derefter i den anden side, ellers sprækker/knækker de forkert. ;)

Resten er ligetil. På ovenstående stjålne billede er vist en strømforsyning; denne er god nok til både 12V og 5V. Skal du bruge 5V, skal du udskifte 7812 med 7805.
Bemærk: Microcontrolleren kan køre på 1.8V til 5V, så giv den ikke mere end 5V, da den ellers brænder af.
(N)y (B)emærkning: Du burde ikke behøve relæer til dit projekt. Så vidt jeg har forstået, kan servo-motoren sættes direkte til microcontrolleren.
Relæ-komponenterne er bare inkluderet, siden du er elektrikker og nok en dag vil få lyst til at have kaffen klar når du står op om morgenen, eller lign. ;)
-Og så selvfølgelig til de forbipasserende, der netop har brug for at tænde/slukke relæer.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 06, 2011, 01:02:24
tusind tak
ok prøver at lave et diagram og smider op jeg er jo temmelig grøn i det svagstrømsske univers men kan godt se logikken så prøver lige.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 06, 2011, 03:44:44
kan godt se at det bliver lidt mere besværligt end jeg troede.
Kan finde eksempler på servocontroller ved brug af ATTiny2313 og jeg kan nogenlunde c++ programering så jeg finder nok ud af det.
men kan jeg overføre principperne fra ATTiny2313 til 44'ern når de alle er 8 bit ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 06, 2011, 04:54:57
kan godt se at det bliver lidt mere besværligt end jeg troede.

Nu har du ihvertfald en mulighed for lidt hjælp herfra, så det skulle gerne lette det en del. ;)

Kan finde eksempler på servocontroller ved brug af ATTiny2313 og jeg kan nogenlunde c++ programering så jeg finder nok ud af det.

Hvis du kan C++, kan du også C. Der bruges ikke C++ i AVR, idét C++ er alt for kæmpestort til de små microcontrollere.

men kan jeg overføre principperne fra ATTiny2313 til 44'ern når de alle er 8 bit ?

Lige præcis. AVR er instruktions-sæt-typen. Dvs. de kan alle forstå samme assembler instruktioner.
Der er dog få variationer mellem nogle af chip-typerne, men de fleste ATtiny bruger samme instruktioner.
Nogle af IC'erne kan endda dele samme binære filer, men det er ikke altid tilfældet, for addresser på fx. I/O-porte kan være anderledes.

Skriver du koden i C, så vil du ikke behøve bekymre dig ret meget. Det hele checkes stort set når der compiles. Du skal bare sørge for at din CPU-frekvens i din Makefile er korrekt, og at din DEVICE er korrekt (fx. attiny44)

Nu må jeg selvfølgelig ikke glemme at Timere, ADC og PWM også sættes forskelligt op på mange microcontrollere.
Fx. har ATtiny2313 ingen ADC. Den har en comparator, hvilket er en mere skrabet 'fattigmands ADC'.

Jeg vil anbefale dig at lave 3-4 forskellige source-filer...
1: main.c + main.h
2: ADC.c + ADC.h
3: Timer.c + Timer.h
4: Servo.c + Servo.h

main.c kunne se nogenlunde sådan ud:

Kode:
#include <avr/io.h>

#include "main.h"
#include "ADC.h"
#include "Timer.h"
#include "Servo.h"

void init()
{
  cli(); /* disable all interrupts */
  initADC();
  initTimer();
  initServo();
  sei();  /* enable interrupts */
}

int main()
{
  DDRA = 0xff;  /* all outputs */
  DDRB = 0xff;  /* all outputs */
  PORTA = 0xff; /* all high */
  PORTB = 0xff; /* all high */
  init();
  while(1) /* loop forever; everything is handled by interrupts */
  {
  }
  return(0);
}
...Så kunne de andre filer indeholde specifikke opgaver i deres område.

I ATtiny44's fulde datablad (http://www.atmel.com/dyn/resources/prod_documents/doc8183.pdf) kan du se hvordan Timer, ADC og PWM sættes op.
Tag én ting ad gangen, ellers bliver det for overvældende; dette er også grunden til jeg foreslår at dele filerne op i 4 bidder.

Aflæsning af ADC bør gøres via en funktion; dette vil jeg komme tilbage til senere.

En timer-interrupt funktion kunne se således ud (trigger på Timer-overflow):
Kode:
/* Timer.h */

/* Accessor functions; you may find these useful... */
uint8_t getHz10000();
void setEvent1CountDown(uint16_t aCountDown);
void setEvent2CountDown(uint16_t aCountDown);

/* external functions; you must implement these... */
void handleEvent1();
void handleEvent2();

Kode:

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

static volatile uint16_t hz10000 = 0; /* *must* be volatile! */
static volatile uint8_t hz100 = 0;
static volatile uint8_t hz1 = 0;
static volatile uint8_t minutes = 0;
static volatile uint8_t hours = 0;
static volatile uint16_t event1CountDown = 0;
static volatile uint16_t event2CountDown = 0;

uint16_t getHz10000() /* accessor-function */
{
  uint16_t result;

  result = hz10000; /* read value */
  if(0x00 == (result & 0xff)) /* value just wrapped, make sure we read it properly */
  {
    result = hz10000; /* read value again; this is the fastest way to do it safely */
  }
  return(result);
}

void setEvent1CountDown(uint16_t aCountDown)
{
  event1CountDown = aCountDown;
}

void setEvent2CountDown(uint16_t aCountDown)
{
  event2CountDown = aCountDown;
}

SIGNAL (SIG_OVERFLOW0)
{
  static uint8_t hz100counter = 0;
  static uint8_t hz1counter = 0;
  static uint8_t minuteCounter = 0;

  /* ATtiny24/44/84 Preliminary, page 83; section 11.9.3 */
  TCNT0 = 256 - ((uint8_t) ((F_CPU / 8) / 10000)); /* intterupt occurs 10000 times per second */

  /* we get here 10000 times per second. */
  hz10000++;   /* increment counter */

  /* let's have a 100 Hz counter, a 1 Hz counter and a 1-minute counter... */

  if(0 == hz100counter--)
  {
    /* we get here 100 times per second. */
    hz100counter = 100 - 1;  /* restart countdown */
    hz100++;  /* increment counter */
    if(0 == hz1counter--)
    {
      hz1counter = 100 - 1;  /* restart countdown */
      hz1++;  /* increment counter */
      if(0 == minuteCounter--)
      {
        /* we get here once every minute */
        minuteCounter = 60 - 1; /* restart countdown */
        minutes++;  /* increment counter */
        if(minutes >= 60)
        {
          minutes = 0;
          hours++;
        }
        if(event1CountDown && 0 == event1CountDown) /* if nonzero, count down until it's zero */
        {
          handleEvent1();
        }
        if(event2CountDown && 0 == event2CountDown) /* if nonzero, count down until it's zero */
        {
          handleEvent2();
        }
      }
    }
  }
}

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

  /* clear our counter variables: */
  hz10000 = 0;
  hz100 = 0;
  hz1 = 0;
  minutes = 0;
  hours = 0;

  /* ATtiny24/44/84 Preliminary, page 83; section 11.9.6 */
  cbi(TIMSK0, 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 */
  sbi(TIFR0, 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 */
  sbi(TIMSK0, TOIE0); /* set 'Timer Overflow Interrupt Enable 0' bit in 'Timer Interrupt MaSK 0' */
}

-Ja, jeg har lavet kommentarerne på engelsk, for jeg kan ikke holde ud at der står danske kommentarer i engelsk kode. ;)

Timer-funktionen kalder her 2 funktioner, når event1CountDown og event2CountDown tæller ned til 0.
Hvis tællerne allerede er 0, foretages intet; men når fx. event1CountDown går fra værdi 1 til 0, vil handleEvent1() funktionen blive kaldt.
Denne funktion kan du så lave noget kode i, som bliver udført efter fx. 30 minutter når event1CountDown er sat til 30.
Der tillades så her helt op til 65535 minutter, hvilket er 45 dage. =)
Er dette 'for lang tid' eller 'for upræcist'; fx. hvis du vil have sekunder i stedet for minutter, kan du bare flytte de 2 funktions-kald med tilhørende 'if' op, så de står lige under 'hz1++';

Koden er ikke testet på en ATtiny44, der er muligvis nogle fejl, men grund-princippet virker; jeg bruger det ofte på andre ATtiny'er. Jeg har sådan set et par ATtiny44 på vej hertil, så jeg kommer nok snart til at afprøve det, da jeg skal bruge tilsvarende kode på en 44'er selv.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 06, 2011, 16:22:32
Puha føler mig godt nok usikker men vil det her virke baseret på en 44 ?
det skal helst være sådan at systemet kan konfigureres fra 1 til X antal doseringsenheder derfor er udgangspunktet 1 kreds pr enhed men der kan vel sluttes et par mere på hvis det skulle være nødvendigt
Og hov der skal ikke stå pa1 pen pa10

(http://img811.imageshack.us/img811/1160/attiny44.jpg)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 06, 2011, 19:30:12
Puha føler mig godt nok usikker men vil det her virke baseret på en 44 ?

Liige næsten.
Husk at sætte C3 så tæt på IC'ens VCC ben (dvs. ben 1) som muligt; jaja, altså om det er 5 mm væk eller 10mm, det går nok i dette tilfælde; men det er en god vane at sætte den lige op ad.

Jeg har følgende forslag til ændringer...
Nu bruger du et 50K potmeter, så bør du også sætte en 50K modstand mellem potmetret's plus-ben og VCC; dette giver dig lidt bedre kontrol i software, plus at du får 0.0V-2.5V ind på benet. For hvis du får over 2.56V ind på dit ADC ben, vil den bare sige "max", så du kan ikke kende forskel på 3V og 5V. Kommer der mere end 5V ind, kan du risikere at ADC-benet (eller micro'en) brænder af.

Jeg vil derudover anbefale at du sætter impuls til servo på et af følgende ben:
PB2 (ben 5), PA5 (ben 8), PA6 (ben 7) eller PA7 (ben 6).
Dette er fordi du så kan sætte en PWM kanal op til at give den præcise frekvens til din servo motor.
Vælger du at bruge PA5 eller PA6, kan du opnå en meget fin frekvens-kontrol (16-bits præcision), mens PB2 og PA7 'kun' har 8-bit præcision.
Jeg valgte i tidligere kode-eksempel, at bruge 8-bit timeren (Timer0), som har PWM kanal på PB2 og PA7, fordi så har du lidt friere hænder til at bruge den mere præcise timer til PWM.

Der kan opstå lidt bøvl ved at styre med at tænde/slukke for en strømforsyning.
Mange strømforsyninger har indbyggede kondensatorer. En microcontroller som AVR, bruger ikke ret meget strøm, og derfor vil den ikke lige tømme kondensatoren (som jo virker som batteri) med det samme. Der kan måske gå flere uger, før den er tømt, alt efter kondensatorens størrelse.

Dette er dog en opgave, der kan løses, fx. med en opto-coupler på primærsiden af en transformator, eller ved at sætte nogle komponenter ind, som sluger masser af strøm.

Hvis du alligevel vil bruge tænd/sluk som en one-shot trigger, vil du nok også skulle bruge en Reset-kreds (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=searchProducts&searchTerm=667-4219) med tilhørende modstande/kondensatorer. Dette behøver du dog nok ikke tænke på til prototypen.

Til de første tests kan du selvfølgelig gå lidt udenom at programmere PWM med timer, men når du har fået det grundlæggende til at fungere, så vil du nok foretrække at det kører med en PWM-timer, da det er mere stabilt.

Ben 4 bør du sætte en 4k7 modstand på. Den anden ende af modstanden bør sættes til +5V.

Det er en god idé med C1 og C2. Det stabiliserer din aflæsning af potmetret og du undgår derved det værste prel (prel=kort forklaret: 'støj', når man rører potmetret; dette findes også på tryk-knapper/kontakter). Det kan lade sig gøre at filtrere prel ud i softwaren, ved at lave fx. 16 målinger og så tage gennemsnittet. Dette kan gøres over fx. 100 millisekunder, så det vil stadig føles som om enheden reagerer straks man drejer på potmetret. Det kan også løses på en mere korrekt måde: At man sammenligner de sidste fx. 4 målinger (over 20 millisekunder), og ser om de er nogenlunde ens (+/- 3%); er de det, kan man godt stole på aflæsningen. Dette kan vi komme ind på senere, når der bliver behov for det.

Yderligere hints:
For at programmere IC'en, bruges følgende ben:
1: VCC
4: RESET
7: MOSI
8: MISO
9: SCK (her kaldet USCK)
14: GND

Det kan være godt at downloade og gemme denne PDF (http://www.atmel.com/dyn/resources/prod_documents/AVRISPmkII_UG.pdf); for på side 26 kan du se hvordan man forbinder atmel's AVRISPmkII USB programmerings-enhed til microcontrolleren. Dette er det 6-polede stik jeg tidligere omtalte. Mange andre programmerings-enheder bruger samme type stik. Nogle bruger dog et 10-polet stik; det er en lidt ældre type programmerings-enhed, for kun 6 ben er nødvendige.

Når du skal til at sætte det i produktion, så husk at alle komponenter skal overholde RoHS direktivet (dette er lovkrav); dette kan jeg godt hjælpe med, når du er klar.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 06, 2011, 21:38:43
Oki. her er så en redigeret udgave
ved ikke om d1 og d2 er nødvendige når benene på 44'ern bruges af 2 komponenter men min logik siger mig at de vil forhindre at der bliver sendt "baglens" signaler

Grunden til at jeg prøver at fastholde de digitale on off ure er at jeg ellers vil være nød til at sætte et display på systemet hvor timer funktioner kan styres, med tilhørende knapper og garanteret også en hel del mere kode. Nogle akvarier skal have nogle doser flere gange i døgnet og andre vil kunne bruge doseringssystemet til at fodre f.eks plankton op til 6 gange i døgnet. Jeg kunne jo selvfølgelig lave et user interface på pc og så kunne almendelige mennesker bruge det når de ville sætte timer op. men jeg kan heller ikke gå ud fra at de har en pc i nærheden af deres akvarie. desuden skal omkostningerne holdes nede for det er netop for at give os fattigrøve mulighed for at have et doseringsanlæg som ellers nemt koster 1000 pr kanal. en digital timer kan erhverves for omkring 50 kr og det kan jeg garanteret ikke gøre det for hvis jeg selv skal smide et display på, men ved det ikke, har ikke tjekket priser ud endnu.

(http://img638.imageshack.us/img638/1160/attiny44.jpg)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 06, 2011, 22:38:04
Oki. her er så en redigeret udgave
ved ikke om d1 og d2 er nødvendige når benene på 44'ern bruges af 2 komponenter men min logik siger mig at de vil forhindre at der bliver sendt "baglens" signaler

Du er der næsten. :)

D1 og D2 er ikke gode at have i dette tilfælde.
En diode 'spiser' 0.7V (+/- 0.1V alt efter hvad temperatur der er), hvilket vil sige at dine målinger først begynder, når potmetret er skruet godt op.
Du skal have 2 stk 50K modstande i alt; en for hvert potmeter.
R3 skal flyttes om på venstre side af den lodrette forbindelse, dvs. mellem R2's top-ben og +5V.
Den ekstra modstand kan vi kalde R5; denne skal så sidde fra hvor 4k7 sidder på +5V og ned til R1's top-ben.

Dvs. hvert potmeter skal have en 50k modstand i serie på +5V siden.

Programmerings-stikket's ben 5 (RESET) er sat til IC'ens ben 3; den skulle sættes til ben 4 (dvs. direkte på benet, hvor 4k7 modstanden også er sat på; den skal altså mødes med både benet og 4k7)


Bortset fra det, ser det rimelig fornuftigt ud. :)

Citér
Grunden til at jeg prøver at fastholde de digitale on off ure er at jeg ellers vil være nød til at sætte et display på systemet hvor timer funktioner kan styres, med tilhørende knapper og garanteret også en hel del mere kode. en digital timer kan erhverves for omkring 50 kr og det kan jeg garanteret ikke gøre det for hvis jeg selv skal smide et display på, men ved det ikke, har ikke tjekket priser ud endnu.

Næ, det kan du have ret i. -Ellers har du nok brug for flere ben-forbindelser (hvis det skulle være et display med både tal og bogstaver). Koreanerne, Kineserne (og folk fra Taiwan) kan dog også lave displays efter dine designs; der er noget med at man bare kan sende dem en PDF fil, så laver de et display der kan vise de tegn som PDF'en viser.
Se fx. Customized LCD module (http://www.winstar.com.tw/products_detail_ov.php?lang=en&ProID=129) hos Winstar.
Her er et par andre idéer: LXD i USA/Kina (http://www.lxdinc.com/custom_displays), OrientDisplay i USA (http://www.orientdisplay.com/custom-lcd-panels.html), Dongfu i Kina (http://www.dongfu.com/maindoc/custom%20lcd.htm), og mange andre (http://www.google.com/search?q=custom+LCD+modules&hl=en&client=safari&rls=en&prmd=ivns&ei=WJ89TpsoyMC0BozZxAw&start=10&sa=N&biw=1444&bih=912) (men pas på, for der kan være banditter. Ser hjemmesiden ikke 100% professionel ud; med billeder af deres egne displays, eller står der AliExpress/Alibaba et eller andet sted, så gå langt udenom - for de snyder og du får enten et plastic-kort eller en gammel hullet sko i stedet for hvad du bestilte hos dem) - og så befinder de sig normalt i Nigeria, ikke i Kina.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 06, 2011, 23:30:05
Mange tak for din tålmodighed. jeg har jo ikke lavet noget svagstrøm siden grundforløbet he he.

Har lavet de rettelser du skrev. vil lige spørge om det vil være nok at sætte en modstand og en 4 volt lysdiode ind i starten af diagrammet, vil det være nok til at aflade kondensator fra strømforsyningen?

Hvor er det lettest og billigst at bestille komponenter, og kan det betale sig at lave sit eget print frem for el hulprint. (bruger bare hulprint her i prototypen, men senere. ved jo heller ikke lige om der er lovkrav i forhold til det.

Endnu en gang tusind tak for hjælpen.
hvis det er ok vil jeg tillade mig at skrive til dig når det kommer til programeringen. begynder så småt at læse lidt om det og ser på dine eksempler.

 ;D

(http://img221.imageshack.us/img221/1160/attiny44.jpg)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 07, 2011, 00:49:33
Mange tak for din tålmodighed. jeg har jo ikke lavet noget svagstrøm siden grundforløbet he he.

Jeg synes nu du klarer dig ganske fint. :)

Citér
Har lavet de rettelser du skrev. vil lige spørge om det vil være nok at sætte en modstand og en 4 volt lysdiode ind i starten af diagrammet, vil det være nok til at aflade kondensator fra strømforsyningen?

De fleste lysdioder er på 3V/20mA. En 100 ohm modstand i serie med en sådan vil aflade de fleste strømforsyninger i løbet af nogle sekunder; men det kommer igen an på størrelsen af den kondensator der sidder på strømforsyningen.

Citér
Hvor er det lettest og billigst at bestille komponenter, og kan det betale sig at lave sit eget print frem for el hulprint. (bruger bare hulprint her i prototypen, men senere. ved jo heller ikke lige om der er lovkrav i forhold til det.

Til produktion, bruger jeg selv RS. Dette skyldes at deres priser er rimelig fornuftige, og at man kan se om de ting man bestiller er i overensstemmelse med RoHS direktivet. Derudover har RS en afdeling i Danmark.
De fleste komponenter skulle du have mulighed for at få iløbet af 3-4 dage; der kan dog være leveringstid på nogle komponenter. Men så længe du holder dig til standard-komponenter, så er der kort leveringstid.

Jeg vil anbefale at lave print i SMD. Det fylder ganske lidt, og komponenterne er ofte billigere.
Prisen afhænger også af størrelsen på printet; derfor er SMD oftest at foretrække.

Lad os antage at du vil lave ovenstående i SMD, så kan du bruge...
ATtiny44-20SSSU (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6962513) (bemærk: billedet er forkert, det er en Small Outline Integrated Circuit kreds med 14 ben; benafstanden er 1.27mm hvilket vil sige at den er mulig at lodde i hånden uden for meget besvær).
Af modstande bruger jeg selv 0603 størrelsen (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294591198+4294590494+4294606655&binCount=13215&Ns=I18NPrc1_dk&Nso=0#resultArrow).
Af keramiske kondensatorer bruger jeg også 0603 størrelsen (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294607515+4294607302+4294915359&binCount=2826&Ns=I18NPrc1_dk&Nso=0#resultArrow).
De fleste vil nok foretrække 1206 eller 0805, da de er lidt lettere at placere/holde på (med speciel SMD-pincet) mens der loddes.
Størrelser:
0603: 1.6mm x 0.8mm
0805: 2.0mm x 1.3mm
1206: 3.2mm x 1.6mm

Til lodning af SMD bør man bruge minimum en Weller WS81 (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=4310367) med variabel temperatur og termostat (absolut ikke en 'loddekolbe på ledning'!) og så en god loddetin med 96.5% tin og 3% fluss; MBO (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=0555282) er et fornuftigt valg.

Printet burde nemt kunne fylde 1cm x 2.5cm i dit tilfælde (potmetre er ikke medregnet, da de nok vil sidde i et chassis), hvis man bruger 0603 og en SOIC14 ATtiny; det kan også laves mindre, men om det skulle være nødvendigt, ved jeg ikke.

Normalt koster et print minimum 225 kr. excl. fragt og moms, men i tilfælde af at printet er 1.5cm x 2.5cm, tror jeg, at jeg kan få ovenstående SMD print for 20 kr/stk. ved køb af 16, eller 15 kr/stk. ved køb af 80 (priser er ex. moms).

Ved større produktioner, fx. 1000 print ad gangen, burde de kunne fåes billigere.

Prototypen kan du sagtens lave på et Vero board, eller breadboard.

Bestiller du komponenter gennem RS, skal du være opmærksom på at der er 85 kr. i fragt (ex. moms), hvis du køber for under 500 kr; overstiger vareværdien 500 kr. ex. moms, får du gratis fragt.
Hvis beløbet ikke kommer derop, kan du spørge El-Supply (http://el-supply.dk) om han kan skaffe de komponenter du har brug for; jeg tror det kan betale sig i dit tilfælde.

Bor du i København, eller kommer du dertil, kan du gå ind i RS-butikken og købe komponenterne dér. Jeg har ikke selv prøvet dette, og ved ikke om man skal bestille i forvejen, men har på fornemmelsen at man kan få varerne et kvarter efter man har bestilt, og så skal man jo ikke betale fragt.

-Ellers kan jeg godt tage dem med i købet, når jeg alligevel bestiller fra RS, så behøver du kun betale porto for brev. Sådan set kunne jeg også montere de få komponenter på et vero-board for 100 kr, hvis det har interesse. (Min normale timeløn er 150 til 250 kr alt efter opgavetype, men vi skal lige have dig igang.)
Prisen pr. leaded modstand/keramisk kondensator vil så være 50 øre, og for en 13 kr for en ATtiny44, 7 kr. for en sokkel til ATtiny44, 1 kr pr. lysdiode, 50 øre for det 2x3 polede stik og uhm ca. 10 kr. for 1/3 vero-board (jeg bruger dem der har 3 sammenhængende øer), 5 kr. per skrueterminal med 2 skruer, 8 kr for et DC-stik.
Dvs. for ovenstående (testet) og incl. 'en yellow amber' lysdiode: 53 kr + 100 i arbejdsløn = 153 kr ex. moms og porto på 8 kr. oveni - konvolut er gratis. ;)
Således vil det være muligt, hvis du har en 5VDC strømforsyning, at koble den på printet. Det kan være at det er mest praktisk at bruge en skrue-terminal, for ikke alle DC strømforsyninger har + i midten og GND på yder-ringen. -Dette bør du lige måle med et multimeter, inden du sætter den til.
-Men du er ikke tvunget til at bruge mig; for jeg vil ikke tage nørde-fornøjelsen fra dig - jeg er klar over at det også er sjovt at sætte komponenterne sammen selv, især hvis du vil ændre noget undervejs. :)

Citér
Hvis det er ok vil jeg tillade mig at skrive til dig når det kommer til programeringen. begynder så småt at læse lidt om det og ser på dine eksempler.

Helt klart; ingen problemer. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 08, 2011, 01:36:43
Jeg tror lige jeg beholder nørde glæden her i starten men tusind tak for tilbudet. kan godt være jeg benytter mig af det hvis fingrene sidder forkert.

prototyen tror jeg jeg holder i standard "store" komponenter og alm hul kort.

lige et sidste spørgsmål inden jeg i morgen begynder.
Vil det med nuværende 44 være muligt at smide et display på der viser antal ml.
det er jo bare værdien fra pot, med 1 decimal der skal vises ud fra en eller anden formel der omregner pot værdi så antal grader på servo stemmer med antal ml der trækkes ind i sprøjten. et sådan minidisplay kan vel ikke koste al verden
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 08, 2011, 02:04:58
Jeg tror lige jeg beholder nørde glæden her i starten men tusind tak for tilbudet. kan godt være jeg benytter mig af det hvis fingrene sidder forkert.

-Det regner jeg jo også med, når vi nu er i dette forum. ;)


Citér
prototyen tror jeg jeg holder i standard "store" komponenter og alm hul kort.

fornuftigt.. Det er nemmere at lave om på.

Citér
lige et sidste spørgsmål inden jeg i morgen begynder.
Vil det med nuværende 44 være muligt at smide et display på der viser antal ml.
det er jo bare værdien fra pot, med 1 decimal der skal vises ud fra en eller anden formel der omregner pot værdi så antal grader på servo stemmer med antal ml der trækkes ind i sprøjten. et sådan minidisplay kan vel ikke koste al verden

Uhm... Hvis du køber dem som 7-segment displays (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Nty=1&Ntx=mode%2bmatchallpartial&Ntk=I18NAll&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294548099&binCount=255&Ntt=7+segment&Ns=I18NPrc1_dk&Nso=0#resultArrow), skal der nok bruges en 3 stk, og prisen er cirka 6-7 kr. pr. stk. (Husk der er forskel på størrelserne og ben-placerinerne alt efter hvad du køber, og også om de har fælles anode eller fælles katode.)
Men for at drive sådan en fætter, skal du enten have flere ben på microcontrolleren, eller have sat en driver (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6607981) på pr. 7-segment (jeg kender desværre ikke drivere der ikke er SMD).

Som du ser vil det blive cirka 16-17 kr. ex. moms pr. display.
Det er muligt det er billigere at få speciel-fremstillet et LCD display i Kina, men jeg kender ikke priserne præcist...
-Du kan selvfølgelig også være heldig at finde et LCD display der lige passer til hvad du skal bruge.
Denne driver har kun brug for 2 benforbindelser på microcontrolleren. Skal du have 3 drivere på, kan du sætte alle 3 på samme 2 ben, bare du sikrer dig at A0, A1 og A2 er 'addresseret forskelligt'; mere herom, hvis du vælger denne løsning.

Jeg var lige ved at glemme det...

Fra R2 går der en forbindelse til Ben 9 på ATtiny'en.
Da du måler med ADC'en på denne, vil du garanteret få forkerte måleresultater, når du har programmerings-stikket sat i.
Hvis du vil gøre det lidt nemmere for dig selv, så flyt denne forbindelse til fx. ben 11, 12 eller 13.
-Så kan du bare lade ISP-stikket sidde i hele tiden.
ISP-benene (programmerings-benene) kan godt bruges som input, men da er det nok mest praktisk med digitale inputs (fx. IR modtagere, kontakter, trykknapper og lign.).
Det er nemmere at bruge dem som output ben (fx. til at styre relæer, transistorer eller lysdioder), så undgår du for megen bøvl.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 09, 2011, 18:16:38
Ok super :-P tak
laver lige ændringerne.

Jeg har sendt dig en privat besked men ved ikke om du har fået den da min sendte beskeder er tom, som om jeg intet har sendt ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 09, 2011, 18:25:11
Ok super :-P tak
laver lige ændringerne.

Jeg har sendt dig en privat besked men ved ikke om du har fået den da min sendte beskeder er tom, som om jeg intet har sendt ?

De er modtaget, svar er på vej tilbage. :)

-Foretrækker du at bruge breadboard (uden lodning) eller at lodde på prototype-printplade (Vero board) ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 10, 2011, 00:26:07
Ikke breadboard. vil hellere pare lode på et hulprint i baner
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 10, 2011, 20:28:31
Sidder og KÆMPER med koden og kom til at tænke på om jeg ikke kunne droppe den eksterne digitale timer. er det ikke muligt at sætte et potmeter på der giver 44 besked på om der skal gentages hver 6. - 16. - 18. eller 24. time kan man ikke få sådan en 4 possitions pot?
og så yderligere et pot der definerer om servoen skal køre 1 - 2 - 3 eller 4 gange ?
for så vil jeg smide en reset knap på så brugeren kan resette den til hvornår første dosis skal gives, og en bateribackup hvis strømmen skulle ryge

Du skal lige vide hvor taknemmelig jeg er for at du gider bruge lidt tid på at hjælpe mig igang  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 10, 2011, 21:24:11
Du skal lige vide hvor taknemmelig jeg er for at du gider bruge lidt tid på at hjælpe mig igang  ;D

Du er da lige så velkommen som alle andre. -Det er derfor vi har dette alle tiders forum... :)

Citér
... besked på om der skal gentages hver 6. - 16. - 18. eller 24. time kan man ikke få sådan en 4 possitions pot?
og så yderligere et pot der definerer om servoen skal køre 1 - 2 - 3 eller 4 gange ?

Mht. indstilling.. Tænk meget simplere.
Der er lidt forskellige muligheder.
2 muligheder droppede lige ind i mine tanker:

Den første løsning: Brug 2 stk. encodere. De ligner potmetre, men i virkeligheden er det nogle digitale drejeknapper.
Der er 3 ben (ligesom der er på et potmeter), men de 2 udgangs-ben er enten "tændt" eller "slukkede". Det eneste de giver dig af signaler er en rækkefølge af 2 ben.

Her er nogle eksempler på rækkefølge:
00 01 11 10 00 01 11 10  (kører den ene vej)
00 10 11 01 00 10 11 01  (kører den anden vej)

Der er på de fleste encodere 12 signaler pr. fulde rotation, men man kan få nogle, som har flere.

OK. Så skal du have noget, så man kan se indstillingen.

Hvad med 4 lysdioder, og så et grafisk tryk ud for hver lysdiode; der kunne så stå:
6   16   18   24
og servoen... 4 lysdioder...
1   2   3   4

Den anden løsning (alternativ til encoderen) er en simplere og muligvis endnu bedre løsning:
"Tryk-knapper". 2 til interval, 2 til antal gange servoen kører.

Tryk-knapper og lysdioder skal nok bruge et par ekstra ben.
Faktisk, med et lille ADC-trick, kan man lave alle 4 tryk-knapper på ét i/o ben, men det kræver en modstand pr. tryk-knap)

Til 8 LEDs kan man godt nøjes med 6 i/o ben:
På de 2 første i/o ben (vi kalder dem for V1 og V2) sættes en alm. diode (fx. 1N4148) plus en passende modstand, og disse sættes fx. til anoden på 4 LEDs hver (række 1 kalder vi LED1...LED4, række 2 kalder vi LED5...LED8).
Af de andre i/o-ben, sættes i/o-ben A til katode på LED1 og LED5, i/o-ben B til katode på LED2 g LED6, i/o ben C til katode på LED3 og LED7, og sidst i/o-ben C til katode på LED4 og LED8.
Du vælger så med V1 og V2 at du vil arbejde på "øverste række", interval...
Dernæst vælger du hvilken kolonne af lysdioder du vil have til at lyse, tænder den, venter i X antal millisekunder, og slukker den igen.
Du vælger så med V1 og V2 at arbejde på "nederste række" (antal gange servoen skal køre), og igen vælger du kolonne, tænder, venter, slukker.

Dette gøres i dit timer-interrupt, fx. mellem 200 og 1000 gange i sekundet; helst ikke under, da man så vil kunne lægge mærke til flimmeret (det er det, som sker med kinesiske bil-baglygter; de flimrer da de kører omkring 50Hz) - flimmer virker 'billigt'.

-Det vil nu fint se ud som om de 2 lysdioder lyser hele tiden.

Alt efter hvordan du vender din 1N4148, kan du 'slukke' begge rækker ved enten at sætte både V1 og V2 høj, eller at sætte dem begge lav. Husk: Hvis du sender spændingen den forkerte vej, kan de med tiden futte af; men du finder hurtigt ud af hvilken måde der er rigtig.

Når du skal have én række til at lyse, skal V1 bare være modsat værdi af V2.

Det kan være at du på et tidspunkt synes at du vil have flere ben at lege med.
Er dette tilfældet, har en ATtiny261/461/861 16 i/o ben, hvoraf 10 af dem rimelig nemt kan bruges som ADC-ben (jeg anbefaler at undgå at bruge RESET benet, da du så kun vil kunne programmere chippen én gang, så skal du have en speciel enhed som kan slette chippen's indstillinger, for at kunne gen-programmere den; det har jeg altid selv undgået).

-Men stadig kan det lade sig gøre med en ATtiny44; og det er måske godt at holde det på denne pris-venlige chip, så længe det er muligt.
Du kan bruge nogle af MISO, MOSI og SCK benene til fx. V1 og V2.

-Men der er sådan set stadig ben nok til at du kan have en lysdiode på hvert ben; så skal du bare også have en modstand for hver lysdiode. På den ovennævnte måde behøver du kun 2 modstande og 2 dioder mod 8 modstande. (Hver SMD komponent koster ca. 1 kr. i montage ved maskin-placering, så selvom komponenten måske koster 0.04 øre ved antal på 20000, så skal montage-prisen jo oveni, og du mærker næsten ikke modstandens mængde-rabat).

Hver tryk-knap kunne så sidde ude i hver side af lysdiode-rækken (for at give en 'indlysende brugerflade')
-Du kunne også sætte 8 knapper på, men hver knap 'koster jo også knapper', når vi snakker produktion, for ud over kost-prisen, er der pris på montage, indkøb, osv. ;)

Endnu et alternativ til lysdioder, som du selv er inde på, et 4-positioners potmeter kunne bruges (en attenuator; disse har ofte 10 positioner, men det er ofte muligt at definere et 'stop'), og så kan de kobles til én ADC indgang hver. Det koster kun 2 chip-ben, og er måske den letteste løsning.

Du kunne også vælge at have en dreje-omskifter på; evt. koble denne over modstande, så de kan læses med ADC'en; dreje-omskifter løsningen vil jo også give dig mulighed for direkte at bruge i/o benene digitalt.

(Hovsa, det blev en lidt lang omgang)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 11, 2011, 01:40:02
Prøver at holde tungen lige i munden  :o
umidelbart kan jeg godt lide løsningen med 4 knapper og 2 led rækker. hvilken løsning der er billigst og fylder mindst ved jeg ikke.
mit mål er at holde det under 250 pr enhed og en servo ligger på ca 100 for en nogenlunde kvalitet men kan fåes helt ned til 70 kr hvis det skulle være nødvendigt


Hvis jeg ikke skal bruge reset er der så en anden mulighed for at brugeren kan sætte timeren igang ved første dosering?

Lad os sige at brugeren lige er kommet hjem med enheden og vil lave den første dosering kl 18 og de efterfølgende dage kl 18. han kan selvfølgelig vente med at sætte stikket i til kl 18 mendet ville være lettere hvis der var sådan en START fra nu knap.



Så det jeg har er
en plus og minus knap for interval mellem dosering
en plus og minus knap for antal doseringer pr interval
og en start med første dosering NU knap
2 potmetre 1 til styring af impulser fra 0,8-2.0 ms 20 ms mellem impulser til udtrækning af sprøjten, og 1 til at justerer 0 punket (hvor sprøjten er trykket i bund) 0.8 - 1.1 ms med 20 ms interval

Det kan kun blive et hit :-P
 
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 11, 2011, 02:09:31
Prøver at holde tungen lige i munden  :o
umidelbart kan jeg godt lide løsningen med 4 knapper og 2 led rækker. hvilken løsning der er billigst og fylder mindst ved jeg ikke.

Jeg tror næsten tryk-knap udgaven vil være billigst, for du kunne faktisk være fræk og bore nogle Ø5mm huller og sætte en af disse (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=browseSubRange&productNum=7182405&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294947322&Ns=I18NPrc1_dk&Nso=0#resultArrow) igennem hullet, derefter få Skjern Serigrafi (http://www.skjern-serigrafi.dk/) til at lave en 'japaner-film' (meget god kvalitet; jeg tror det er 20 kr. pr. stk i 2 farver, ca. 10x10 cm ved køb af 100); så kan denne klistres ind over og virke som 'forplade' (endda hen over knapper og lysdioder, for man kan også bestemme hvor der ikke skal være klister og hvor den skal være gennemsigtig).

Knapperne fåes med forskellige længder 'skaft'. Det gælder om at finde den rigtige/passende længde og også holde en fast afstand til fronten af kabinettet, gerne med skruer og afstands-stag, eller nogle støbte holdere, som presser på printet fra begge sider, og gerne bagsiden i nærheden af hver knap.

Citér
mit mål er at holde det under 250 pr enhed og en servo ligger på ca 100 for en nogenlunde kvalitet men kan fåes helt ned til 70 kr hvis det skulle være nødvendigt

Du skal have fat i Kina dér. Det kan være at en af mine brødre kan skaffe kontakt.

Citér
Hvis jeg ikke skal bruge reset er der så en anden mulighed for at brugeren kan sætte timeren igang ved første dosering?

Hmm. En ledning der stikker ud til en samlemuffe? -Jeg kan ikke lige komme på noget seriøst. ;)

Jeg tror at knapperne er så billige (kan fåes ned til under 1 kr/stk), så det kan være det nok er dén løsning.

Citér
Lad os sige at brugeren lige er kommet hjem med enheden og vil lave den første dosering kl 18 og de efterfølgende dage kl 18. han kan selvfølgelig vente med at sætte stikket i til kl 18 mendet ville være lettere hvis der var sådan en START fra nu knap.

Start-knap er 'trendy', tror jeg. :)


Så det jeg har er
en plus og minus knap for interval mellem dosering
en plus og minus knap for antal doseringer pr interval
og en start med første dosering NU knap
2 potmetre 1 til styring af impulser fra 0,8-2.0 ms 20 ms mellem impulser til udtrækning af sprøjten, og 1 til at justerer 0 punket (hvor sprøjten er trykket i bund) 0.8 - 1.1 ms med 20 ms interval

Det kan kun blive et hit :-P
[/quote]

Det lyder ikke så tosset.

(Jeg fik display-koden til at virke... Man skal også give display'et en 'tænd' kommando.. hmm.)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 11, 2011, 20:25:29
gg ja det er fantastisk med sådan noget kode.
Jeg tod en multimediedesigner udd for nogle år tilbage det var der jeg lærte c++ og actionscript. Man kan godt blive lidt hysterisk når man sidder og fejlsøger efter et komma eller kolon. man stirer sig hurtigt blind
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 11, 2011, 22:05:05
gg ja det er fantastisk med sådan noget kode.
Jeg tod en multimediedesigner udd for nogle år tilbage det var der jeg lærte c++ og actionscript. Man kan godt blive lidt hysterisk når man sidder og fejlsøger efter et komma eller kolon. man stirer sig hurtigt blind

Ja, enig. En god idé til at undgå for megen vildledelse: Afslut alle dine .h filer med et semikolon.
-Også, inlines i header-filer, såsom...
inline CMyObject next(){ return(m_next); };
...(Ja, det eksempel er så et c++ eksempel, og er ikke relevant for AVR.

-Afslut linien med semikolon, selvom det ikke er nødvendigt.
For hvis der mangler semikolon i en header fil, så får du at vide at der er fejl i din c/c++ fil. ;)

Ovenstående lærte jeg, da jeg arbejdede hos Opera Software (web-browseren) for nogle år siden (det er alle tiders arbejdsplads, forresten).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 12, 2011, 23:08:08
God aften. sidder og prøver at smide dioder og trykknapper på.
Bruger 3 adc pben til potmeter og og servo. dvs at jeg kun har 5 adc pben tilbage og måske kan jeg bruge reset til i/o port forstår ikke helt hvad de mener med at den kan bruges som svag, men der står den kan bruges hvis man programerer disable program (‘0’) RSTDISBL fuse
Men kan jeg bruge disse adc selv om at jeg programerer på disse ben ? skaber det ikke samme problem som da jeg havde R2 koblet på PA4?
hvad nu hvis jeg bruger dip switches de er vel digitale eller det samme som encoder. så kan jeg vel i princippet have en dipswitch med 8 kontakter på en ADC og så programerer mig ud af at de første 4 bestemmer interval i timer og de sidste 4 anlat gentagelser eller er det for omstændigt? (husk på at jeg stadig mangler finde ud af at programerer. kan selvfølgelig også fordele dem på 2 ben. men gør jeg det på 1 har jeg 4 ADC tilbage til at lave en eller visuel fremstilling af hvad der er valgt.

Det gør ikke så meget at "bruger programeringen" ikke er så let tilgængelig af 2 grunde. Når man har valgt hvad man vil doserer skal der egentligt ikke laves om på dette med mindre man får et større akvarie eller skifter væske der skal doseres. en anden grund er at man ikke af vanvare kommer til at ramme en knap (eller ungerne leger med den) og derved slår sit akvarie ihjel, så derfor ville det ikke gøre noget om disse muligheder kræver lidt "arbejde" at ændre.

Jeg har endvidre tænkt over at hvis 4 ADC ben ikke er nok til visuel fremstilling af valg så kan R2 fjernes ved at programerer "nulpunket" for servoen. R2 vil aligevel være et skjult potmeter som egentligt kun skal bruges ved kalibreringen af anlæget, og det foretager jeg inden det sælges.

så det vil sige at jeg har 6 ADC ben tilgængeligt plus i/o funktionen på reset

Hvis dip tager 1 ben eller 2 er der så nok tilbage til at køre 2 7-segment en for gentagelser i døgnet og 1 for gentagelser pr dosering ???

Det var vist også en lang en he he, håber du kan finde hoved og hale i det

Hov syntes lige at jeg læste mig til at 7segment display kræver 7 ben eller en controller.

Og lige en ting til. er 44'erns interne clock præcis nok eller bør der smides en krystal på.
med præcis nok mener jeg er det minutter eller sekunder eller msek +- i døgnet ?


 

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 13, 2011, 03:14:39
Bruger 3 adc pben til potmeter og og servo. dvs at jeg kun har 5 adc pben tilbage og måske kan jeg bruge reset til i/o port forstår ikke helt hvad de mener med at den kan bruges som svag, men der står den kan bruges hvis man programerer disable program (‘0’) RSTDISBL fuse.
Men kan jeg bruge disse adc selv om at jeg programerer på disse ben ? skaber det ikke samme problem som da jeg havde R2 koblet på PA4?

Værre ... Du bør undgå helt at bruge RESET-benet. Her er lidt generel information (http://www.atmel.com/dyn/resources/prod_documents/doc2521.pdf) på AVR microcontrollere.

Grunden er: Hvis du én gang har programmeret RSTDISBL, så kan du ikke 'afprogrammere' den.
-Da skal du have en ny chip, eller et slette-apparat (http://www.microcontrollerprog.com/fuseprog.html) (som jeg ikke har selv; det er 'apparat' nummer 2 på siden - jeg køber nok én på et tidspunkt).

Citér
Og lige en ting til. er 44'erns interne clock præcis nok eller bør der smides en krystal på.
med præcis nok mener jeg er det minutter eller sekunder eller msek +- i døgnet ?

Med et clock-krystal skal du regne med en unøjagtighed på 60PPM (Parts Per Million).
Det betyder, at du på 1000000 sekunder taber eller vinder 60 sekunder.
1000000 / 60 / 60 / 24 = 11.57 dage.
Clock-krystaller er det mest nøjagtige. Den indbyggede oscillator er et RC-led som skal kalibreres for hver chip. Dette skal gøres mens chippen er i temperaturen der bruges 'normalt'.

Der er et alternativ: At bruge en RTC-chip (Real Time Clock). Sådan en findes i fx. computere.

Du kan også bruge det system, som rigtig mange elektriske ure brugte for år tilbage:
Frekvensen på strømmen i stik-kontakten. Så vidt jeg ved, skulle denne være meget nøjagtig (mere nøjagtig end en RTC chip).

Citér
Bruger 3 adc pben til potmeter og og servo. dvs at jeg kun har 5 adc pben tilbage og måske kan jeg bruge reset til i/o port forstår ikke helt hvad de mener med at den kan bruges som svag, men der står den kan bruges hvis man programerer disable program (‘0’) RSTDISBL fuse.
Men kan jeg bruge disse adc selv om at jeg programerer på disse ben ? skaber det ikke samme problem som da jeg havde R2 koblet på PA4?

RESET benet bør ikke bruges.

Her er hvad der er tilovers:

2 digitale I/O ben: (digital=tænd/sluk) XTAL1 (PB0) og XTAL2 (PB1) kan eventuelt bruges som digitale I/O ben (fx. lysdioder). Hvis microcontrolleren skulle blive 'uprogrammerbar' (pga. forkerte 'fuse-bits'), kan du få en anden microcontroller til at tænde/slukke for to I/O-ben, og bruge disse som clock-krystal.

1 digital I/O-ben: PB2 (fornuftigt at bruge denne til Servo)

5 'sikre' ADC-ben, som ikke bliver forstyrret af ISP-stikket.

3 ADC ben, som vil blive forstyrret, hvis du har ISP-programmerings stikket sat i: ADC4 (PA4), ADC5 (PA5) og ADC6 (PA6).
-Disse 3 ben kan med fordel bruges til at styre lysdioder; IC'en kan fortsat programmeres.

I alt: 5 uforstyrrede ADC ben (som også kan bruges som i/o ben) + 6 digitale i/o ben.

Her er hvad du har brug for:

1 ADC ben til 4-5 tryk-knapper (eller i alt 4 dip-switch positioner); disse kan sættes i et R2R netværk, og sluttes samlet til det ene ADC ben. Der bør nok ikke sættes meget mere end 5 knapper på et ADC-ben (måske 6), for aflæsningen kan blive unøjagtig i de nederste bits. Det er en god idé at sætte ADC'en til 10-bits, aflæse flere gange og tage gennemsnittet. For 5 knapper eller under, burde 8-bit være nøjagtigt nok.

2 ADC-ben til Potmetre.

Citér
Hov syntes lige at jeg læste mig til at 7segment display kræver 7 ben eller en controller.

6 digitale I/O-ben til 8 LEDs. (2 til at vælge række med, 4 til at vælge kolonne med)

1 digitalt I/O-ben til servo motor.

I alt: 3 'sikre' ADC + 7 digitale

Dvs. vi trækker først de 3 ADC-ben fra; så har vi 2 uforstyrrede ADC-ben + 6 digitale i/o ben = 8 digitale i/o ben.
Vi bruger så 7 af disse digitale i/o-ben (6 til LEDs, 1 til knapper) og har nu 1 ubrugt ben til overs, som er et uforstyrret ADC ben.

Prøv at se mit diagram (http://avr.bruger.mine.nu/Circuit.png) på et spil jeg lavede.. Jeg bruger et R2R netværk på en ATmega164's PC0...PC7.
Knap 1 bør så være hvor PC0 er, knap 2 hvor PC2 er, osv... Efter sidste forbundne knap (knap 5), bør du sætte en 1K til dit ADC-ben, og fra ADC-benet en 2K til GND; så får du igen max. 2.5V, som giver 'fuldt udslag'; ellers vil der være en knap du ikke kan aflæse, men det skulle du nok hurtigt finde ud af hvis der var bøvl med. ;)
R2R netværket virker simpelthen sådan: For hvert led, halveres spændingen.
Du kan også lave et noget simplere modstands-netværk:
Brug fx. følgende:
  4.02K modstand,
  2K modstand,
  1K modstand,
  499 ohm modstand
  200 ohm modstand
  100 ohm modstand

-Hver knap sættes så fra +5V til en af ovenstående modstande og videre til ADC-benet.
Fra ADC-benet til GND sættes så fx. en 100K modstand, for at vi har 0V, hvis der ikke er en knap som trykkes ned. Dette er billigere i komponenter end R2R netværket nævnt ovenover.

Citér
hvad nu hvis jeg bruger dip switches de er vel digitale eller det samme som encoder. så kan jeg vel i princippet have en dipswitch med 8 kontakter på en ADC

4 kontakter på en dip-switch skulle være nok, da 2 bits giver 4 kombinationer, og du gerne vil have 2 sæt med 4 kombinationer. :)
Programmering af dette er også forholdsvis let.
-Det ville være samme princip, som hvis du bruger en dreje-omskifter.

Citér
Jeg har endvidre tænkt over at hvis 4 ADC ben ikke er nok til visuel fremstilling af valg så kan R2 fjernes ved at programerer "nulpunket" for servoen. R2 vil aligevel være et skjult potmeter som egentligt kun skal bruges ved kalibreringen af anlæget, og det foretager jeg inden det sælges.

OK. Der kan du så bruge et trimpot. Disse trimpots (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=searchProducts&searchTerm=625-1945) er rigtig gode, du kan nok også bruge nogle mere 'unøjagtige' trimpots, de kræver bare fingerfærdighed at justere.

Citér
Det var vist også en lang en he he, håber du kan finde hoved og hale i det

Det ser ud til at jeg klarede mig (nogenlunde) ud af vanskelighederne denne gang. ;)
-Muligvis vrøvler jeg lidt hist og her, det er fordi jeg har flyttet rundt på mine besvarelser, så der kan nok være sket uheld/ulæseligheder, men jeg mener jeg har fanget de fleste af dem.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 13, 2011, 16:15:45
Tror det ender med at jeg skal op på flere ben. så kan jeg også lave kontrolenheden så den styrre 4 pumper i stedet for en 44 pr pumpe så vil det nok være billigere med eks en atmega fremfor 4X44'er. desuden er jeg løbet ind i endnu en udfordring :-D man skal også kunne stille tiden mellem de individuelle pumper, da der er nogle tilsætningsstoffer der SKAL doseres med minimum 15 minutters mellemrum
endvidre har jeg så også bedre mulighed for at udvide med større display, for med tiden skal anlæget også tage sig af at tænde og slukke lyset, pumper og styre servoer der skal lave bølgevægelser. Men lige nu gælder det prototypen og programmet så er det helt fint med at begynde med 44'ern da det vigtigste lige nu er at få 1 pumpe til at køre korrekt, så går jeg ud fra at jeg kan tage de fleste erfaringer med over i en atmega.

Så prototypen undlader jeg også 7segment display. det kan altid komme på når det grundlæggende fungerer :-P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 13, 2011, 17:59:02
...Hvorfor ikke lave to udgaver; en 'semi-pro' udgave og en super-udgave med alle klokker og fløjter ?

'semi-pro udgaven kan så være så presset i pris, som det nu lader sig gøre.
Pro udgaven kan være den "udviddede model", som kan styre flere pumper.

Det gode ved ATtiny44 er at den koster ikke ret meget, og dog har lige ben nok til de fleste behov, hvis man lægger det hele smart. Der er 4K program-hukommelse, så der burde være rigeligt, også til hvis der skal løses indviklede opgaver.. Skulle du være så heldig kun at bruge 2K, så kan du gå ned på en ATtiny24 (de er helt kompatible), eller du kan gå op på en ATtiny84, hvis du har brug for 8K.
-Samme gælder ATtiny261/461/861 (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Nty=1&Ntx=mode%2bmatchallpartial&Ntk=I18NAll&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294590393&Ntt=attiny*61&Ns=I18NPrc1_dk&Nso=0#resultArrow). Disse har jeg også liggende (ATtiny 461). ATtiny461 koster så kun et par kroner mere end ATtiny44, hvis man køber en håndfuld ad gangen.
Jeg forestiller mig at dit færdige print vil være udelukkende med SMD komponenter, da printet vil blive mindre, og dermed noget billigere at producere. -Bemærk at det er for det meste printet, som koster knapperne.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 13, 2011, 19:09:15
God ide. har også tønkt på at lave dem i enkeltenheder så kan man dubygge med en enhed ad gangen og sætte dem sammen ala lego. (her jeg f.eks bruger 3d, så jeg kan se hvad og hvordan samt kender målene inden jeg hamre og banker gg)

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
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106 (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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... ;
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 14, 2011, 00:56:36
hvordan h.... tegner man et print hvor banerne ikke krydser hinnanden hmm :o
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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... ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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 (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6161038) (bemærk: billedet viser en med 8 kontakter) med, og en stang skod-sokler (8-benede) -Disse er den billigste type sokkel (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&R=6007849) man kan få.
Selv anbefaler jeg tulipan-sokler (http://dk.rs-online.com/web/search/searchBrowseAction.html?method=retrieveTfg&Ns=I18NPrc1_dk&Ne=4294920774&Nr=AND%28avl%3adk%2csearchDiscon_dk%3aN%29&N=4294955779+4294919697&Nso=0&multiselectParam=4294955779&selectSubRange=IC-fatninger%20-%20DIP,%20drejede%20ben%20#breadCrumb); 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 15, 2011, 01:13:43
Her har jeg et opdateret diagram (farverne er bare for min egen skyld ha ha)
(http://img709.imageshack.us/img709/4903/servoh.jpg)

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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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 (http://winavr.sourceforge.net/download.html) med GCC og avrdude (http://www.nongnu.org/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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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


Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 18, 2011, 08:03:44
Inde i sig_overflow0, som trigger på en countdown) kalder jeg så rutinen repeats hvor gentagelser bliver defineret og brugt i ADC.c

ADC.c skal sådan set kun aflæse ADC'en. Der vil være en rutine, der hedder getADC3Value(), som returnerer værdien af ADC'en til den kaldende rutine. Noget a'la...
Kode:
/*
 * File   : ADC.c
 *
 */

#include <avr/io.h>

#include "ADC.h"

static uint8_t adcIndex = 0;
static uint16_t adc3Value[2];
static uint16_t adc2Value[2];

uint16_t getADC3Value()
{
    return(adc3Value[adcIndex]);
}

void initADC(uint8_t aBits)
{
    /* not yet implemented */
}

-Ovenstående er stort set tomt, og det er fordi jeg ikke er gået i dybden med den endnu.
For at den skal aflevere et rimeligt stabilt tal til dig, bør den aflæse - lad os sige - 4 gange, og aflevere gennemsnittet af disse 4 værdier til dig. Jeg vil kigge lidt videre på dette.

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

-Ja, aMinuteCountdown er en parameter (et argument), som bliver givet, når setMinuteCountdown funktionen kaldes. a'et i aMinuteCountdown står for "argument", hvilket vil sige, at man så nemt kan se, at det er en variabel der kommer som argument.

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

initDosing er defineret i Dosing.h, initTimer0 er defineret i Timer0.h, så main.h burde se således ud:

Kode:
#ifndef __main_h__
#define __main_h__


#endif /* _main_h_ */

-Altså ganske tom indtil videre.

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

Grunden til at initADC er undefined, er at du ikke har en ADC.c. Prøv at lægge ovennævnte ADC.c ind (som test), så tror jeg fejlen skulle forsvinde.
Bemærk: Det er linkeren der brokker sig over at initADC mangler.

...Interrupts er smarte; de kan spare mange CPU-kræfter, det er derfor jeg gerne vil have dig til at lære dem. Nogle ting kan drille ved interrupts, men det vil du nok ikke opleve lige med det første, og på en microcontroller bliver den slags fejl ikke så katastrofale som på en computer.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 18, 2011, 15:31:24
Citér
Grunden til at initADC er undefined, er at du ikke har en ADC.c. Prøv at lægge ovennævnte ADC.c ind (som test), så tror jeg fejlen skulle forsvinde.
Bemærk: Det er linkeren der brokker sig over at initADC mangler.

Ganske rigtigt nu siger den bare at den er defined but not used og det er jo ganske rigtigt.

Læser lidt videre på koden for at få banked metoden helt fast og begynder at se lidt på PWM delen.  ;D

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 19, 2011, 01:07:22
Vil det her virke som repeats ?
(en del af koden i dosing.c

Kode:
void timer0Elapsed()
{
   
for(a = 0; a <= repeats; a++)
{
for(Is looking for a way to implement seconds from the timer rutine to make the for last for 10 seconds befor continue)
{
rotation = adc3Value; /*TOP, (20ms) load*/
ServoMove()
}
for(Is looking for a way to implement seconds from the timer rutine to make the for last for 10 seconds befor continue)
{
rotation = adc2Value; /*TOP, (20ms) unload*/
ServoMove()
}
}
}

void ServoMove()
{
TCCR1A = 0; /* disable all PWM on Timer1 whilst we set it up*/
ICR1 = 20000; /*frequency is every 20ms/*

/*sets  fast PWM (mode 14) and no prescaler*/
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); 

DDRB |= (1<<PA7); /*Sets OC0B as output*/
OCR1A = ICR1 * rotation /20; /*pulse to load or unload servo on pa7 depending on the variable rotation*/
}

Jeg er lidt i tvivl om der vil blive pumpet signal ud i 20 ms cycler så længe funktionen ServoMove() bliver kaldt i "for" løkken i timer0elapsed eller om det kun sker 1 gang for hvert ++ der vil være, for det skal helst være kontinuerligt
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 19, 2011, 10:32:15
Citér
Jeg er lidt i tvivl om der vil blive pumpet signal ud i 20 ms cycler så længe funktionen ServoMove() bliver kaldt i "for" løkken i timer0elapsed eller om det kun sker 1 gang for hvert ++ der vil være, for det skal helst være kontinuerligt

Mit gæt er at servoen vil køre, indtil du slukker den, dvs. jeg tror at ServoMove tænder servoen, som så vil blive ved med at køre, indtil du kalder den uskrevne funktion "ServoStop".

Men jeg ville foretrække at lave et servo-timer-interrupt, og lade dette trigge på sluk-pulsen; muligvis kan denne stump kode være til nytte...

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

#ifndef __Timer1_h__
#define __Timer1_h__

uint8_t isServoRunning();
void stopServo();
void startServo(uint16_t aServoCountdown, uint16_t aRotation);
void initTimer1();

#endif /* __Timer1_h__ */

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

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

#include "Timer1.h"

static volatile uint16_t    servoCountdown = 0;                 /* variables that are changed by an interrupt, *MUST, MUST* be volatile! */
const uint16_t              servoFrequency = F_CPU / 50;        /* frequency is every 20ms = 50 times per second (50Hz) */

uint8_t isServoRunning()
{
    return(servoCountdown != 0);
}

SIGNAL (SIG_OUTPUT_COMPARE1B)
{
    if(servoCountdown)
    {
        if(0 == --servoCountdown)
        {
            stopServo();                                        /* turn off servo-timer (including interrupt) */
        }
    }
}

void stopServo()
{
    TCCR1B = 0;                                                 /* CS12 : CS11 : CS10 = 0, no clock source (Timer/Counter stopped) */
    TCCR1A = 0;
    TCNT1 = 0;
    OCR1A = 0;
    OCR1B = 0;
    ICR1 = 0;
    TIMSK1 = 0;
    TIFR1 = 0xff;
}

void startServo(uint16_t aServoCountdown, uint16_t aRotation)
{
    servoCountdown = aServoCountdown;                           /* number of pulses to send to servo, before turning it off */

    TCCR1A = 0;                                                 /* disable all PWM on Timer1 whilst we set it up */
    TCCR1B = 0;                                                 /* (disable clock-source, so the timer is frozen) */
    TIMSK1 = 0;                                                 /* disable all Timer1 interrupts */

    ICR1 = servoFrequency;                                      /* frequency is every 20ms, 50 times per second (50Hz) */

    /* select fast PWM (mode 14) and no prescaler */
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);      /* enable output COMpare 1 A, output COMpare 1 B, set WGM to Fast PWM  */
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);         /* set WGM to fast PWM, choose clock source CS12:CS11:CS10 = 1, clk/1 (no prescaling) */

    OCR1A = servoFrequency * aRotation / 20;                    /* pulse to load or unload servo on PA7 depending on the argument aRotation */

    /* ATtiny24/44/84 Preliminary, page 111; section 12.11.8 */
    TIMSK1 |= (1 << OCIE1B);                                    /* enable Output Compare Interrupt 1 B */
}

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

    DDRB |= (1 << PA7);                                         /* set OC0B as output */

    stopServo();                                                /* initially, the servo is not running */
}

Du kan så (efter min bedste overbevisning) #include "Timer1.h" fra fx. Dosing.c, og kalde
Kode:
startServo(50, getADC3Value());
-Da vil servoen køre i 50 pulser (i alt 1 sekund), og så slukke.

Jeg har inkluderet en funktion, så du kan se om servoen er igang med at køre.
isServoRunning() vil returnere true (1), hvis servoen kører, ellers false (0).

Du kan evt. lægge følgende ind i Timer0.h (efter #define, før #endif)...

Kode:
void waitSeconds(uint8_t aSeconds);

...og følgende i Timer0.c (fx. lige over setMinuteCountdown)...

Kode:
void waitSeconds(uint8_t aSeconds)
{
aSeconds = (aSeconds + seconds);                    /* 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 */
}
while(aSeconds != seconds)                          /* wait until seconds has the same value as aSeconds */
{
}
}

I Dosing.c burde du så kunne #include "Timer0.h" og så få muligheden for at vente x antal sekunder (max. 59 sekunder!)

Følgende er lidt omskrivning af din tidligere kode...

Kode:
void timer0Elapsed()
{
    uint8_t a;
    uint16_t adc2Value;
    uint16_t adc3Value;

    adc2Value = getADC2Value();
    adc3Value = getADC3Value();

    for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        startServo(50, adc3Value);

        /* unload: */
        waitSeconds(10);
        startServo(50, adc2Value);
    }
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 20, 2011, 23:49:34
Hvad skulle jeg dog gøre uden din hjælp.
Er ved at forstå at interrupts er vejen frem.  :o

implementere det i eksisterende kode.
Takker og bukker.

ville sådan ønske at jeg kunne gøre et eller andet til gengæld  :-[
HVis du nogensinde starter et saltvandsakvarie op så må du sige til he he.

Har lige et spørgsmål. Hvorfor ikke bruge CTC? kræver det ikke mindre regnekraft. Ved godt at lige i dette tilfælde her skal jeg bruge 16 bit timeren til PWM men generelt er det så ikke bedst at komme så tæt på ren hardware counter/timers og så bruge flags? (det er vel også en form for interrupts) ???
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 21, 2011, 04:12:53
Er ved at forstå at interrupts er vejen frem.  :o

Ja, interrupts er ret gode, for de bruger et minimum af CPU-tid, og er ret præcise.

Citér
ville sådan ønske at jeg kunne gøre et eller andet til gengæld  :-[
HVis du nogensinde starter et saltvandsakvarie op så må du sige til he he.

Tja, det kan være, når jeg en gang skal flytte i hus; men dér hvor jeg bor i øjeblikket, er der slet ikke plads. ;)

Citér
Har lige et spørgsmål. Hvorfor ikke bruge CTC? kræver det ikke mindre regnekraft.

"polling" (dvs. hvor man hele tiden kigger på en værdi, som ændrer sig) har en del ulemper:

Citér
Ved godt at lige i dette tilfælde her skal jeg bruge 16 bit timeren til PWM men generelt er det så ikke bedst at komme så tæt på ren hardware counter/timers og så bruge flags? (det er vel også en form for interrupts) ???

Du er tæt på. Timeren sætter nogle flags, og interrupts bliver udført når disse flags sættes. Dvs. du kan faktisk (hvor det er muligt) trigge et interrupt, ved at sætte det flag som timeren sætter.

Men igen... hvis man laver et loop, hvor man bliver ved med at kigge på én ting, kan det være man går glip af en anden, plus at man bruger meget CPU-tid på at kigge på den ene ting.
eks:
Kode:
while(TCNT <= 19998)
{
    /* here we're only waiting, no code. */
}
/* do something here */

Ovenstående har et par fejl...
1: Vi spenderer op til 1 sekund med at vente på at TCNT kommer op på 19999.
2: Er vi uheldige, er TCNT lig med 19998 lige når den aflæses, hvilket vil sige at while-løkken udføres igen. Når while så hopper tilbage, bruges 2 clock-cycles, hvilket vil sige at TCNT skifter 2 gange, og den kommer op på 20000, hvilket vil sige at den nul-stilles, så den er 0, når while igen tester værdien. Derved bruger vi mere end 1 sekund, hvis vi er uheldige, dvs. vi skipper en aflæsning, hvis vi er uheldige.
-Endnu værre havde det været, hvis vi skulle lave noget imens vi ventede på at TCNT nåede op på 19999; der ville være flere muligheder for at TCNT 'kappede over' og røg på 0, før vi kunne aflæse den.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 23, 2011, 00:12:45
...ADC.h, ADC.c...

Nu har jeg kigget lidt på ATtiny44's ADC håndtering.
Den er næsten helt magen til de ADC'er jeg har brugt tidligere.
Der er dog en forskel; dens reference spænding er 1.1V eller VCC.
De andre's reference-spændinger er normalt 2.56V.

Men det, at ATtiny44's reference-spænding er VCC, gør tingene lettere for dig! :)
1: Du behøver ikke at have en modstand i serie med dit 10K potmeter!!
2: Din omregning bliver en lille smule simplere end ellers.

Her er først en header-fil, som kan bruges til begge de efterfølgende kode-stumper...
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__

void waitUntilADCStable();
uint16_t getADC2Value();                                    /* this routine returns the low 10 bits of the ADC2's value, no matter if you use 8-bit or 10-bit ADC */
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__ */

I din main() rutine, bør du kalde initADC(8); eller initADC(10); og lige efter din 'sei();' instruktion (før 'while(1)'), bør du kalde...

Kode:
waitUntilADCStable();

-Denne rutine venter på at ADC'en afgiver fornuftige resultater du kan stole nogenlunde på.


OK nu til selve koden.. Først en forholdsvis enkel stump kode. Dette er ikke koden du bør implementere, men denne kode er primært fordi du så lettere kan overskue hvad der sker.

Koden her aflæser et par ADC'ers værdi (ADC2 og ADC3), og gemmer dem til senere videregivelse.
Der gemmes kun en enkelt værdi. Det, som er specielt ved denne kode, er at den ud over at køre flere gange i sekundet (prescaler 128), skriver et andet sted end den læser.
Du undgår således at læsning kommer i kambolage med skrivningen.

Kode:
/*
 * File: ADC.c - simple
 */

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

#include "ADC.h"

#ifndef inb
#define inb(sfr) _SFR_BYTE(sfr)
#endif

#define ADC_STABLE  4                                                                   /* ADC should be stable after 4 complete read cycles. You may need to adjust this number */

#define ADC_FIRST   2                                                                   /* first ADC channel to read */
#define ADC_LAST    3                                                                   /* last ADC channel to read */


static volatile uint16_t    adcValue[ADC_LAST][2];                                      /* this buffer holds our conversion results. Write to one place, read from another. */
static volatile uint8_t     adcIndex = 0;                                               /* this is the index we write values to. */
static volatile uint8_t     adcCounter = 0;                                             /* just a counter, that counts how many times we've read all the ADC channels */
static volatile uint8_t     adcChannel = 0;                                             /* current channel we're reading the ADC value from */

void waitUntilADCStable()
{
    while(adcCounter < ADC_STABLE)                                                      /* keep waiting, until ADC is reliable */
    {
    }
}

uint16_t getADC2Value()
{
    return(adcValue[2][adcIndex]);
}

uint16_t getADC3Value()
{
return(adcValue[3][adcIndex]);
}

SIGNAL (SIG_ADC)
{
    uint8_t        adLo;
    uint8_t        adHi;

    adLo = inb(ADCL);                                                                   /* read lowbyte before highbyte! */
    adHi = inb(ADCH);                                                                   /* read lowbyte before highbyte! */

    adcValue[adcChannel][adcIndex ^ 1] = (adHi << 8) | adLo;                            /* save the value we've read above */
    ADCSRA |= (1 << ADSC);                                                              /* start another conversion */

    if(adcChannel++ >= ADC_LAST)                                                        /* next channel. If channel reached last channel... */
    {
        adcChannel = ADC_FIRST;                                                         /* start over */
        adcIndex ^= 1;                                                                  /* swap index, so we write to one place and read from another */
        adcCounter++;                                                                   /* increment counter */
    }
    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07);                          /* set which channel to read next time */
}

void initADC(uint8_t aBits)                                                             /* in this simple example, we ignore the precision bits; we always use 10-bit conversion */
{
    adcCounter = 0;                                                                     /* (initialization of adcCounter is not really needed) */
    adcIndex = 0;                                                                       /* read at index 0, write at index 1 */
    adcChannel = ADC_FIRST;                                                             /* initialize ADC channel number to read */

    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07);                          /* VCC is used as analog reference, first channel */
    ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);                                /* free running mode */
    ADCSRA |= (1 << ADSC);                                                              /* start conversion */
}

Og nu den mere komplicerede kode. Denne stump kode aflæser nogle af ADC'ens kanaler, og gemmer de aflæste resultater i en buffer. Når du så vil have værdierne ud, tages gennemsnittet af de sidste (4) alæsninger...

Kode:
/*
 * File: ADC.c - complex version
 */

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

#include "ADC.h"

#ifndef inb
#define inb(sfr)    _SFR_BYTE(sfr)
#endif

#define ADC_SIZE    5                                                                   /* number of reads to average the ADC channel (we write one, and average over last 4) */
#define ADC_STABLE  (ADC_SIZE + 3)

#define ADC_FIRST   2                                                                   /* first ADC channel to read */
#define ADC_LAST    3                                                                   /* last ADC channel to read */


static volatile uint16_t    adcValue[ADC_LAST - ADC_FIRST][ADC_SIZE];                   /* this buffer holds a lot of conversion results, enough for us to average the values */
static volatile uint8_t     adcReadIndex = 0;                                           /* this is the index we start reading values from (up to, but excluding writeIndex) */
static volatile uint8_t     adcWriteIndex = 0;                                          /* this is the index we write values to */
static volatile uint8_t     adcCounter = 0;                                             /* just a counter, that counts how many times we've read all the ADC channels */
static volatile uint8_t     adcChannel = 0;                                             /* current channel we're reading the ADC value from */
static uint8_t              adcBits = 8;

void waitUntilADCStable()
{
    while(adcCounter < ADC_STABLE)                                                      /* keep waiting, until ADC is reliable */
    {
    }
}

uint16_t getADCValue(uint8_t aADC)
{
    uint16_t    result;
    uint8_t     i;
    uint8_t     idx;

    idx = adcReadIndex;                                                                 /* read from this index; avoiding reading at the 'write position' */
    i = ADC_SIZE - 1;                                                                   /* number of values to read (eg. if ADC_SIZE is 10, we only read 9 values) */
    result = 0;                                                                         /* zero our result */
    while(i--)
    {
        result += adcValue[aADC - ADC_FIRST][idx];                                      /* add the one value we've just read from the index */
        idx = idx >= (ADC_SIZE - 1) ? 0 : idx + 1;                                      /* next index */
    }
    return(result / (ADC_SIZE - 1));                                                    /* return the averaged result */
}

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

uint16_t getADC3Value()
{
    return(getADCValue(3));
}


SIGNAL (SIG_ADC)
{
    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8)                                                                    /* using 8-bit precision */
    {
        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) */
        }
    }
    else                                                                                /* using 10-bit precision */
    {
        adLo = inb(ADCL);                                                               /* read lowbyte before highbyte! */
        adHi = inb(ADCH);                                                               /* read lowbyte before highbyte! */
    }
    adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo;               /* save the value we've read above */
    ADCSRA |= (1 << ADSC);                                                              /* start another conversion */

    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 */
}

void initADC(uint8_t aBits)
{
    adcCounter = 0;                                                                     /* this is so we can see when the ADC conversions are stable */
    adcWriteIndex = 0;                                                                  /* start writing at index 0 */
    adcReadIndex = adcWriteIndex + 1;                                                   /* read right after the write-index */
    adcChannel = ADC_FIRST;                                                             /* initialize ADC channel number to read */
    adcBits = aBits;

    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07);                          /* VCC used as analog reference, first channel */
    ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR);                 /* free running mode, result is right aligned */
    ADCSRA |= (1 << ADSC);                                                              /* start conversion */
}

Hvorvidt koden fungerer, kan jeg ikke sige med sikkerhed.
Men her lægger jeg mere vægt på at du forstår systemet, end at det faktisk virker.
Hvis det virker, så har vi det som bonus. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 23, 2011, 11:41:21
Det var en ordentlig omgang  :P
det vil jeg lige tygge igennem og forstå hvordan det fungere mens jeg venter spændt på pakken  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 24, 2011, 01:51:49
...mens jeg venter spændt på pakken  ;D

Det ser ud til at de har 'opdaget' pakken nu. Dens tracking nr. er registreret; den venter nok stadig på afhentningen fra indleverings-stedet.
I mellemtiden har jeg fået IDC-stik og kappen til det 25-polede stik, så i dag, onsdag, vil jeg så sende resten.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 24, 2011, 02:07:53
Det lyder super glæder mig helt vildt til at komme igang med lidt praktisk he he
Den sidste kode syntes jeg ikke lige lå til højrebenet he he men tror jeg er ved at fange den.

Hvor store er udsvingene på en ADC value?
Jeg skal faktisk kun bruge en udsvingsmargien på lige over 100o ud af servoens 180.
Opløsningen skal være på ca 2 us i PWM. det må give lidt større spillerum i aflæsningspræcisionen når værdier går fra -30o til 45o og ikke alle 180o fordelt over pot værdierne.

Jeg overvejer stadig at droppe det ene pot og så kalibrere nulpunktet software mæssigt vha. en fast værdi, det spare da en del regnekræft som så måske kan bruges på at lave et mere præcist gennemsnit for det andet pot.

Jeg håber at det bliver sådan at der ikke er et større udsving end 0,2 ml +- pr dosering da saltvand kan være rimeligt hysterisk over for under og overdosering. men selvfølgelig fordelt over et vist antal doser
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 24, 2011, 02:52:14
Det lyder super glæder mig helt vildt til at komme igang med lidt praktisk he he

Ja, det er rart, når man kan holde på resultatet, i stedet for kun, at forestille sig hvordan det eventuelt kunne være/se ud.

Citér
Den sidste kode syntes jeg ikke lige lå til højrebenet he he men tror jeg er ved at fange den.

Det er også årsagen til at jeg forsøgte at forklare princippet bag; for det er måske en uventet måde at gøre tingene på, men den skulle gerne give mening, når du har det hele på plads.

ADC'en har sit eget interrupt. I den tidligere nævnte kode (det 'simple' eksempel), ser du at jeg aflæser en værdi fra ADC'ens data registre, og lagrer den i RAM'en.
Lad os antage at vi har kaldt rutinen til at oplyse os om den sidst lagrede ADC værdi, nemlig getADC2Value().
På det tidspunkt har vores adcIndex fx. værdien 1.
Vi aflæser adcValue[2][adcIndex], hvilket vil sige adcValue[2][1].
Imens vi er gået igang med at aflæse værdien, bliver vores ADC-interrupt måske aktiveret.
ADC-interruptet kører helt færdigt, før der returneres til vores aflæsnings-rutine, så derfor ville det være kedeligt, hvis vores ADC-værdi blev overskrevet imens (især hvis den består af 2 bytes, og vi allerede havde aflæst den ene). I ADC-interruptet skriver vi ADC-værdien i RAM-adressen adcValue[2][adcIndex ^ 1], hvilket betyder at den bliver skrevet et andet sted end vi er igang med at aflæse. Lidt forklaring: adcIndex ^ 1 giver samme resultat som ((adcIndex + 1) & 1). Altså vil værdien blive skrevet til adcValue[2][0].

Når ADC-interruptet er færdigt, kommer vi (som nævnt tidligere) tilbage til hvor vi blev afbrudt, og programmet fortsætter kørslen fra hvor vi slap.


En ADC giver dig nemlig ikke det samme resultat hver gang du aflæser den.
Ofte svinger den +/- 3, fx. hvis vi har en 10-bit ADC værdi, og vi læser værdien 252 første gang, kan det være vi læser 249 anden gang, 250 tredje gang og måske 249 fjerde gang.

Lægger vi dem sammen... 252+249+250+249, får vi værdien 1000, denne dividerer vi så med 4, og har et 'stabilt' resultat på 250.

Citér
Hvor store er udsvingene på en ADC value?

Nogle gange 2 bits, nogle gange +/- 3..4 stykker (cirka). Det kommer helt an på hvilken ADC vi har fat i, og hvad vej månen skinner i forhold til østenvinden.

Citér
Jeg skal faktisk kun bruge en udsvingsmargien på lige over 100o ud af servoens 180.
Opløsningen skal være på ca 2 us i PWM. det må give lidt større spillerum i aflæsningspræcisionen når værdier går fra -30o til 45o og ikke alle 180o fordelt over pot værdierne.

Burde nok kunne lade sig gøre. Hvis vi bruger en 10-bit ADC, har vi værdierne fra 0 til 1023, hvilket vil sige en inddeling på 5/1023 = 4.887mV indeling.
Hvis vi måler i grader, så har vi... 180/1023 = 0.176o indeling.

Skal du kun bruge 105o, får du 105/1023 = 0.103o indeling, hvilket jeg vil påstå er vældig fint. ;)

Uhm, PWM opløsningen burde kunne nå helt op på 1/2 af clock-frekvensen, dvs. 500kHz, hvilket vil sige 2μS. Skal du bruge mere, kan du bare sætte den interne clock-frekvens til 8MHz; jeg mener ikke at der skulle være bivirkninger ved dette.

Citér
Jeg overvejer stadig at droppe det ene pot og så kalibrere nulpunktet software mæssigt vha. en fast værdi, det spare da en del regnekræft som så måske kan bruges på at lave et mere præcist gennemsnit for det andet pot.

Det må du vurdere mens du sidder med det. Det kan sagtens være du kan undvære det ene potmeter, og derved komme et godt stykke ned i den endelige pris.
Når vi snakker produktion, begynder én enkelt komponent til 0.05 øre at blive 'dyr'.
Oftest tænker man på... "jamen... i forhold til alt det andet, er det jo ingenting".
Det er også rigtigt.
Men der er flere ting der spiller ind...
1: Prisen for at sætte en komponent på (med maskine), er 1 kr, så hvis komponenten koster 0.05 øre, bliver prisen pludselig 1.0005 kr.
2: Jo mindre printet er, desto billigere bliver produktet. Printet er normalt meget dyrt i forhold til komponenterne.
3: Fjerner vi en komponent, kan det være vi får en lettere kredsløbsvej, eller et simplere print-udlæg.

Dertil skal det også siges, at i modsætning til nummer 3, kan det i visse tilfælde blive lettere at tegne kredsløbet med flere komponenter. Fx. 2 baner krydser hinanden. Den ene bane kan gå midt under en SMD-modstand.

Og jo, jeg ved at i starten har vi med leadede komponenter at gøre, og muligvis vil potmetrene forblive leadede. Men det er godt at have i tankerne under hele forløbet.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 24, 2011, 20:52:24
Ved ikke lige om det giver nogen mening det her  :o
Regner ikke med at det gør noget at baner krydser under komponenter her på hul printet. men sidder og prøver at tegne en hvor det undgåes men det er jo stort set umu... nej meget svært gg

(http://img835.imageshack.us/img835/6268/unled1nqn.jpg)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 24, 2011, 22:36:21
Regner ikke med at det gør noget at baner krydser under komponenter her på hul printet.

Det gør ingenting.

Citér
men sidder og prøver at tegne en hvor det undgåes men det er jo stort set umu... nej meget svært gg

R6 (499K) skulle være 499 ohm, vil jeg tro.
R7 (200K) skulle nok være 250 ohm (hvilket vil sige 2 stk 499 ohm i serie), ellers kan det være koden vil drille lidt (det skulle dog kunne kompenseres for alligevel).

Forresten, i pakken lagde jeg 10 stk 0 ohm (dvs. lus). De kan være ganske praktiske hvis du selv ætser enkeltsidede print.
De kan også være praktiske, hvis du laver 2 krydsninger på oversiden af dit hulprint, så lægger du først ledningen, og når den er loddet, sætter du 0 ohm modstanden hen over; ellers kan det være du kommer til at brænde hul i isoleringen under lodningen.

Hmm... Måske jeg skulle have givet dig nogle 2k med; men hvis du sætter 2 stk 1k i serie, får du en 2k.
hvis du ikke har 499 ohm, kan du sætte 2 stk 1k i parallel, så giver det 500 ohm.
(4 stk 1k i parallel giver 250 ohm)

Din SCK ser ud til at være glemt. Den skulle nok have været forbundet til ben 9. :)

Ellers ser det ganske tilforladeligt ud. Det burde ikke gå hiel gal. ;)

R10 kan forresten være 0K (erstattes af lus), fordi ATtiny44's ADC måler i forhold til VCC (dvs. 1023 = 5V, 511 = 2.5V)

Husk at du kan sætte modstandene på højkant (dvs. bukke det ene ben 180o rundt, så får du et mellemrum på 1U (et unit, dvs. 2.54mm).

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 25, 2011, 04:00:39
Oki har lavet lidt ændringer og ellers sat modstande i serier og paralelt.
Havde ikke til at lave en 100 ohm så satte en 4k7 på R8 plads, men ved ikke om den er for stor.

har fjernet det ene pot (det til at stille nulpunkt) og sat en trykknap på den ledige ADC (startknap)

(http://img32.imageshack.us/img32/747/diagramcb.jpg)

Kønt blev det ikke, må nok ud og invistere i noget værktøj der er lidt finere end alm elektrikker grej  og en ordentlig kolbe :-[

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 25, 2011, 14:37:51
Oki har lavet lidt ændringer og ellers sat modstande i serier og paralelt.
Havde ikke til at lave en 100 ohm så satte en 4k7 på R8 plads, men ved ikke om den er for stor.

100K var korrekt (ikke 100 ohm). 4K7 kan bruges, men det vil være lettere at lave aflæsningen, hvis den er 4K præcis - ellers brug 100K.
-Sidder 4K7 der allerede, så prøv at lade den sidde, og se hvordan det går med aflæsnings-koden.

Idéen er at man "halverer spændingen" for hver dip-switch der er "slået til".
På denne måde kan man lave alle typer kombinationer, og stadig finde ud af hvordan kontakterne er indstillet uden for megen bøvl.

Bruges 'halveringer', bliver det forholdsvis nemt:

Hvis R8 har værdien 4K, 8K, 16K, 32K eller 64K, vil jeg gætte på at værdierne nedenfor skulle være rimelig tætte på den angivne værdi...
Kontakt 1 (R7) har værdi 512
Kontakt 2 (R6) har værdi 256
Kontakt 3 (R5) har værdi 128
Kontakt 4 (R4) har værdi 64

Er kontakt 2 og 4 tændt mens 1 og 3 er slukket, skulle ADC'en give dig en værdi meget tæt på 320.

Aflæsningen bør så foregå på nogenlunde denne måde:

Kode:
switches = (getADC1Value() + 3) & ~7;  /* '3' er for tolerance +/- 3. ~7 ignorerer de 3 laveste bits. */

Citér
har fjernet det ene pot (det til at stille nulpunkt) og sat en trykknap på den ledige ADC (startknap)

Start-knappen har en fejl. Den vil enten blive aflæst som værende 'trykket ned hele tiden', eller også vil den stå og flik-flakke mellem tændt/slukket, fordi den ikke har en pull-up eller pull-down modstand.

Oftest sætter man en pull-up modstand til +5V og selve knappen 'kortslutter' så til GND når den trykkes ned.

Hvis du hellere vil have det omvendt, så i/o-værdien er 1, når knappen trykkes ned, så behold det som det er nu og sæt en pulldown modstand fra ben 10 til GND med værdien 4K7...10K.

Så længe du ikke sætter en 'stærk' modstand på, kan du sagtens sætte start-knappen på fx. MISO, MOSI eller SCK benet, så har du stadig et ledigt ben til ADC. (Stærk modstand = lav værdi, fx. 100 ohm, svag modstand = fx. 10K..100K) 10K vil nok være godt i dette tilfælde.


Citér
Kønt blev det ikke

-Det er ligegyldigt når det er en prototype. :)

Citér
, må nok ud og invistere i noget værktøj der er lidt finere end alm elektrikker grej  og en ordentlig kolbe :-[

Det vigtigste du har brug for, er et multimeter...
Jeg vil anbefale et, som kan måle så meget af følgende, som muligt, højeste prioritet nævnt først:
1: Modstand (ohm)
2: Gennemgang (gerne med bip)
3: Jævnspænding
4: Kapacitet (kondensator-værdi)
5: Vekselspænding
6: Frekvens (Hz)
7: hFE (transistor)
8: Spoler (Henry, faktisk microHenry)
9: Ampere (ja, de fleste multimetre har Ampere sammen med spænding)

For ca. 200 kr, bør du kunne finde noget der kan klare fra 1 til 6 + ampere.
Et Branford (http://www.harald-nyborg.dk/merinfo.asp?varenr=2286&n=10) fra Harald Nybørge er faktisk ikke helt tosset. Det har gennemgangstester med bip, ohmmeter, vekselspændings voltmeter, jævnspædnings voltmeter, hFE, jævnstrøms amperemeter og vekselstrøms amperemeter (ja, hvorfor de er separate forstår jeg ikke!)

Desværre har Nybørge's multimeter ikke frekvens-måling, hvilket er meget rart at have, når man arbejder med microcontrollere. Der er et rimelig godt multimeter (http://el-supply.dk/?Gid=324&VNr=7730.8) hos El-Supply. det kan også måle kapacitans, men det koster også over 3 gange så meget.

Derudover, vil jeg anbefale Weller's WS81 (http://dk.rs-online.com/web/p/products/4310367/) loddestation. Det er en professionel station, som er værd at investere i.
Har du ikke råd til denne, er det laveste du bør gå ned på, nok en Unavngiven (http://www.butik4281.dk/butik/index.php?main_page=product_info&products_id=293) loddestation, den kan findes forskellige steder i landet, også hos Biltema; men den laveste pris finder du uden tvivl hos Hallenslev Radio/TV.
De fleste sætter deres eget navn på loddestationen, men det er samme producent.
"For alt i verden:" undgå 'loddekolbe på ledning'; de er intet værd.

Hvis du skal lave professionelle lodninger (senere hen), vil jeg anbefale WDC Tørrens (http://dk.rs-online.com/web/p/products/517-8546/). Loddespidsernes levetid forlænges markant, plus lodningerne bliver mange gange flottere, end hvis du bruger 'svamp med vand'. Bruger du svamp med vand, bør du bruge vand, der har været kogt, hvis du ikke har demineraliseret vand.

Før jeg fik en modstands-bukkelære (http://el-supply.dk/?Gid=&VNr=8177KB), brugte jeg ikke den slags. Men nu jeg har den, bruger jeg den rimelig ofte.
(Søg hos PC-Elektronik efter "Bukkeklods", han har også en udemærket billig elektronik-skævbider, den hedder "TANG 570" og koster 20 kr.)
Skævbideren kan klippe 'fladt ned til printet', hvilket jeg selv har fundet nyttigt mange gange.

En Olfa-kniv er også blandt mit favorit-værktøj, jeg bruger den nærmest hver eneste dag; jeg bruger også denne, når jeg skal "knække hulprint", da skærer jeg lige et par gange på hver side af printet før jeg knækker det, for at få et nogenlunde pænt knæk.

Og så selvfølgelig et finmekanisk værktøjssæt (http://el-supply.dk/?Gid=505&VNr=8150). Har du et sæt med 6 skruetrækkere allerede, så burde det være tilstrækkeligt. Disse skruetrækkere er også gode til at "løfte IC'er ud af sokler" med.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 25, 2011, 21:08:49
og så opdager man at der ikke er en paralel port på pc  >:(
Kan man ikke bruge serial (com1) til det har set at der er nogle diagrammer på nettet til serial AVR programmers men ved ikke om de funger til tiny f.eks denne
http://electronics-diy.com/avr_programmer.php (http://electronics-diy.com/avr_programmer.php)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 25, 2011, 22:57:19
og så opdager man at der ikke er en paralel port på pc  >:(

Uheldigt - er det ikke en stationær PC du har ?.
-Hvis det er en stationær PC, så har jeg et 5V PCI-32 kort (Sandberg), med Parallel-port og 2 serielle porte, som du kan få.

Citér
Kan man ikke bruge serial (com1) til det har set at der er nogle diagrammer på nettet til serial AVR programmers men ved ikke om de funger til tiny f.eks denne
http://electronics-diy.com/avr_programmer.php (http://electronics-diy.com/avr_programmer.php)

Mjo, den ser ikke helt dum ud. BC549 kan snildt erstattes af BC547 i dette tilfælde. Du mangler nok 5V1 zener-dioderne.

Uhm.. Jeg har sådan set det meste på lager. D-sub 9 med hus, diverse modstande; men zener-dioderne er jeg nødt til at skaffe, med mindre du vil forsøge med 3.3V zener-dioder (de burde virke, da 3.3V er langt over værdien for 'høj' signal spænding).

Forresten: Tip med hensyn til lodning... Husk at tørre loddekolben før hver lodning; dvs. for hver gang du har tørret spidsen (helst i messing-svampen), bør du lodde maks. 2-3 lodninger, for derefter at tørre spidsen igen.
En blank loddespids lodder godt, mens en "sort loddespids" kan slet ikke lodde, da slaggeren virker isolerende for varmen. ;)

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 25, 2011, 23:29:21
har splittet et gammelt joystick ad. der var 3 zener dioder men kan ikke lige se deres værdi det er dælme svært at se hvad der står. Så var der også en bunke smd modstande og et par smd catalysatore men dem står der ikke noget på så kender ikke deres værdi men de har forskellig farve så det vil jeg søge lidt på.
Hold da fast det er småt. der var også et par transistore og en masse micro knapper.

Jo det er en stationær men da jeg byggede den i sin tid tænkte jeg at jeg ikke lige ville få brug for en parallel port.
og den serial jeg har sidder på bundkortet så det er faktisk bare at smide et stik på. men var ikke klar over om jeg kunne gøre det med serial

Nyder lige at lege lidt med det praktiske (konen skal passe på plasma tv'et der er sikkert en masse guf i  :P )
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 25, 2011, 23:46:27
har splittet et gammelt joystick ad. der var 3 zener dioder men kan ikke lige se deres værdi det er dælme svært at se hvad der står.

Min erfaring er at der sjældent står noget brugbart.
Men... Hvis du har en variabel strømforsyning, kan du sætte en modstand i serie med zener-dioden, og skrue langsomt op. Mål på hver side af zener-dioden. Når spændingen står 'stabilt', har du fundet værdien.
Fx. er spændingen kun 3.3V, så har du fundet ud af at zener-dioden er enten en 3.3V eller 3.6V zener diode.

Men der er mange værdier på zener-dioder, så det er sjældent man lige løber ind i det man skal bruge.
Et joystick... Hmm, værdien af zener-dioderne vil nok ligge på omkring 5V eller under. Jeg kunne forestille mig de bliver brugt til at sænke spændingen til 3.3V.

Citér
Så var der også en bunke smd modstande og et par smd catalysatore men dem står der ikke noget på så kender ikke deres værdi men de har forskellig farve så det vil jeg søge lidt på.

Kondensatorerne kan du sådan set kun måle. Der er ingen angivelse af værdi.

Modstandene har enten 3 eller 4 cifre. Hvis de er 4 cifre, er der en god chance for at de er 1%.
Modstands-kodningen er den samme type som med farveringene. Fx.
472 er et 4-tal, et 7-tal og to nuller, dvs. 4700 ohm = 4k7.

Citér
Hold da fast det er småt. der var også et par transistore og en masse micro knapper.

Skøn komponent-kilde. :)

Citér
Jo det er en stationær men da jeg byggede den i sin tid tænkte jeg at jeg ikke lige ville få brug for en parallel port.
og den serial jeg har sidder på bundkortet så det er faktisk bare at smide et stik på. men var ikke klar over om jeg kunne gøre det med serial

Heh. Hvis det er en PCI maskine (ja, jeg ved at sansynligheden nok er lille efterhånden), så har jeg stadig det omtalte Sandberg kort.

Citér
Nyder lige at lege lidt med det praktiske (konen skal passe på plasma tv'et der er sikkert en masse guf i  :P )

Et godt råd: Vent til hun ikke er hjemme. ;)

Alternativt kan du lave denne; du har allerede 74HC125:
(http://elm-chan.org/works/avrx/avrx_com.png)

Du burde sagtens kunne sætte en 100nF ind istedet for 10nF.
Det eneste du mangler er fire 150K modstande.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 25, 2011, 23:50:07
den ene hedder 1n4 750 a synts jeg at kunne læse og så er der 2 der hedder 1n4 748p med det er vist 22 og 27 Vz
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 25, 2011, 23:59:18
den ene hedder 1n4 750 a synts jeg at kunne læse og så er der 2 der hedder 1n4 748p med det er vist 22 og 27 Vz
Hmm, ja, hvis du skal have 1N serien, så skal den nok hedde noget a'la 1N4733.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 26, 2011, 00:12:58
det er nok bedst at jeg holder mig til parallel så hvis du er interesseret i at sælge dit sandberg vil jeg da gerne købe det har da en enkelt eller to ledige pci slots det var bare lige for at se en diode blinke eller sådan noget. men tålmodighed er jo en dyd er der nogen der siger, men jeg er åbenbart ikke så fand... dydig  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 26, 2011, 15:45:32
det er nok bedst at jeg holder mig til parallel så hvis du er interesseret i at sælge dit sandberg vil jeg da gerne købe det har da en enkelt eller to ledige pci slots det var bare lige for at se en diode blinke eller sådan noget.

Hvad siger du til 25 kr. for kortet ? (Husk at sikre dig at det nu *er* et PCI, og ikke PCIe eller PCI-X slot du har ledigt).

Den kan sendes med Post Danmark for 25 kr, så er der 50g 'fri' i pakken.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 26, 2011, 19:49:43
det lyder helt fint. og det er pci GG

tvivler på at jeg nogensinde kommer til at lodde en smd på. de er jo knap nok 2 mm dem jeg har det er mine fingre nok for fede til ha ha

hvordan kan det være at smd resistors har sådan nogle skæve værdier?


Citér
Den kan sendes med Post Danmark for 25 kr, så er der 50g 'fri' i pakken
Kan jeg så ikke købe 10g 499 ohm og 10g 2 K ? og måske 10g 100 ohm af dig :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 29, 2011, 19:25:05
har lige et spørgsmål til AVRSP-COM. Den pil der går fra C1 hvad betyder den ?
og den streg der er ved vcc er det også til jord sammen med ben 13 på 125'ern?

Sidder og leger lidt med det og vil samle trådene her senere idag så jeg ved hvor jeg står og hvad jeg mangler
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 30, 2011, 00:30:45
har lige et spørgsmål til AVRSP-COM. Den pil der går fra C1 hvad betyder den ?

GND.

Citér
og den streg der er ved vcc er det også til jord sammen med ben 13 på 125'ern?

Det er VCC.

På teknisk skole lærer man diagramtegning og diagramforståelse.
Desværre er der mange hobby-folk som lærer diagrammer ved at bruge Eagle eller et andet diagramtegnings-program.
Disse folk laver diagrammer som ikke burde have været frigivet, da de lærer læserne forkerte uvaner.

En pil nedad, eller en 'bund-streg', betyder GND hvis ingen spænding angives (eller negativ spænding).
En pil opad eller 'top-streg' betyder positiv spænding (hvis der ingen spænding angives: VCC)
En pil eller streg til siden betyder input eller output.

Se vedhæftede billede. Pil og streg har samme betydning.

Citér
Sidder og leger lidt med det og vil samle trådene her senere idag så jeg ved hvor jeg står og hvad jeg mangler

Din pakke med kortet skulle ankomme tirsdag formiddag. Jeg har for en sikkerheds skyld lige lagt nogle modstande plus en 10nF kondensator i. Der er også nogle 2K modstande, for at lette lidt på modstands-netværkene.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 30, 2011, 01:25:52
Oki tak. blev bare forvirret fordi kondensatoren går allerede til gnd og så viser den et forbindelses led til den der pil derfor blev jeg forviret, og ben 13 til gnd også.

Citér
På teknisk skole lærer man diagramtegning og diagramforståelse.
Det var godt nok ikke meget vi havde syntes jeg men der var da lidt.

Citér
in pakke med kortet skulle ankomme tirsdag formiddag
Lyder fantastisk. Fandt også en "lokal" forhandler (pc-elektronik.dk) han ligger 20 km herfra, men har desværre ikke nogen butik. har dog fået lov til at komme hvis der lige er noget akut man står og mangler.
Regningen er betalt og skulle gerne vise sig i dit regnskab inden for en dag eller to.

Endnu engang mange mange tak for din tålmodighed, håber ikke den er helt opbrugt endnu  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 30, 2011, 01:55:03
Citér
På teknisk skole lærer man diagramtegning og diagramforståelse.
Det var godt nok ikke meget vi havde syntes jeg men der var da lidt.

Jeg tog basis-året på Hillerød; dér havde vi en god og grundig lærer, som ikke bare fortalte hvad man skulle gøre, men også hvad man ikke skulle gøre.
Citér
Fandt også en "lokal" forhandler (pc-elektronik.dk) han ligger 20 km herfra, men har desværre ikke nogen butik. har dog fået lov til at komme hvis der lige er noget akut man står og mangler.

Jeg kender ham godt og anbefaler ham helt bestemt, men vidste ikke han beode så tæt på dig!
Hils ham, når du møder ham. Han har ganske mange ting, og hans priser er vældig lave, så brug ham endelig. :)

Citér
Endnu engang mange mange tak for din tålmodighed, håber ikke den er helt opbrugt endnu  ;D

Velbekomme; og nej, det er en glæde for mig, at have elever der er så lette at lære op. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter August 31, 2011, 01:39:55
Så kom pakken og igen takker jeg.

Har lavet programmeren har dog lige 1 spørgsmål.
http://avrprogrammers.com/bld-par2.php (http://avrprogrammers.com/bld-par2.php)

Citér
The target microcontroller must provide it's own power.
Skal jeg tilslutte 5 volt til programmeren på 5 volt og gnd og så også 5 volt til 44'ern?

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter August 31, 2011, 01:53:14
Citér
The target microcontroller must provide it's own power.
Skal jeg tilslutte 5 volt til programmeren på 5 volt og gnd og så også 5 volt til 44'ern?

1: Der skal strøm (5V) på kredsløbet.
2: Programmerings-enheden får sin strøm (5V) fra kredsløbet.
3: GND er fælles for computer, programmerings-enhed og kredsløb.

-Dvs. Hvis der ikke er strøm på kredsløbet, vil intet fungere. ;)

Det kan være en god idé, først at sætte strøm på kredsløbet, derefter måle med multimeter, om GND og +5V er iorden.
Derefter sætte programmerings-enheden til (uden computer), for at checke de sidste ting, og om der evt. er kortslutninger, eller andet bøvl.

Når du er rimelig sikker på at der ikke er nogen katastrofe, så kobl strømmen fra, og tilslut programmerings-enheden til computeren, kobl kredsløb og 5V på, og prøv med din programmerings-software at kommunikere med chippen (dvs. aflæs eller send en hex-fil til ATtiny44'eren).

Bruger du AVRDUDE, kunne kommando-linien se således ud:
Kode:
avrdude -c avrispmkii -P usb -p attiny44 -U flash:w:MyHexFile.hex:i

...Jeg håber det fungerer ved første forsøg. =)

Det kan være du får en fejl som denne:
Kode:
avrdude: stk500v2_command(): command failed
avrdude: stk500v2_command(): unknown status 0xc9
avrdude: stk500v2_program_enable(): cannot get connection status
avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.


avrdude done.  Thank you.

...Da betyder det at der er en eller anden forbindelse der mangler, eller er forkert.
(Hvis der ikke er strøm på kredsløbet, får du også denne fejl).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 01, 2011, 19:28:11
Har målt det hele igennem og umidlbart ser det fint ud.
Men findes der en måde at parallel programere med win 7 64 bit? syntes ikke jeg kan finde nogen hjælp til avrdude på det område (giveio funger ikke)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 01, 2011, 21:09:24
Har målt det hele igennem og umidlbart ser det fint ud.
Men findes der en måde at parallel programere med win 7 64 bit? syntes ikke jeg kan finde nogen hjælp til avrdude på det område (giveio funger ikke)

Dér må jeg blive dig svar skyldig, for jeg ved slet ikke ret meget om windows.
(Jeg regnede med at siden du har alm. PCI, ville du nok køre et standard 32-bit system).

-Men prøv at se her (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=88034) -Det kan være det hjælper.

Når du får fejlkoder, fx. fra avrdude (eller andre programmer), så prøv at skrive den lange fejl-tekst i Google's søgefelt i quotes, fx:
(eksempel) (http://www.google.com/search?q=%22can't+open+device+giveio+avrdude%22)

-Dette er normalt den bedste måde at få svar på, og rammer næsten altid plet (måske ikke på første resultat-linie, men gerne indenfor de første 2 sider).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 01, 2011, 22:35:37
har været inde og læse en del om det. giveio fungerer ikke på 64 bit så prøver at smide en dualboot med en 32bit win 7. funger det ikke ryger der en xp partition på så skal det nok fungere. Det har noget at gøre med at den adgang til io var problematisk i forhold til mallware så ms fjernede adgangen, men måske det virker på 32 bit jf det link du sendte. Nu prøver jeg det hvertfald !
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 01:04:36
det kan jeg da godt få grå hår af  :o. hvilken -c skal jeg bruge med den programmer jeg har lavet ? er det dapa ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 01:24:14
Nu prøver jeg det hvertfald!

Jeg håber det virker (jeg selv har brugt Windows 98 til programmering på mit arbejde, men det var med AVRISPmkII; den burde vel også virke under 64-bit Windows).

det kan jeg da godt få grå hår af  :o. hvilken -c skal jeg bruge med den programmer jeg har lavet ? er det dapa ?

Bare rolig, når du har fået det til at virke første gang, så ved du at det kan fungere.

Her er min linie:
Kode:
avrdude -c avrispmkii -P usb -p attiny44 -U flash:w:main.hex:i
-Men som du allerede er inde på, bør parametret til -c skiftes.

Hvis det er denne (http://avrprogrammers.com/bld-par2.php) du har lavet, så får du et hint oppe i fanebladet; der står: "STK200".

Søger jeg med Goole efter avrdude stk200 (http://www.google.com/search?q=avrdude+stk200), får jeg et resultat på 3. søgeresultat, som kan læses direkte på søge-resultat siden:
Kode:
(PDF) C:\>avrdude -p m644 -c stk200 -P lpt1 -v avrdude: Version 5.5 ...
home.arcor.de/chlercher/elektronik/fuse.pdfFile Format: PDF/Adobe Acrobat - Quick View
3 Jan 2008 – System wide configuration file is "C:\Programme\winAVR\bin\avrdude.conf". Using Port. : lpt1. Using Programmer. : stk200. AVR Part ...

Derfor: Prøv denne linie:

Kode:
avrdude -c stk200 -P lpt1 -p attiny44 -U flash:w:main.hex:i
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 01:53:08
det er den programmer jeg har lavet x1 er den set fra stiksiden eller loddesiden ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 02:04:07
det er den programmer jeg har lavet x1 er den set fra stiksiden eller loddesiden ?

Stikket 'X1' (forkert navn; det burde hedde CON1, når der er tale om en konnektor, X1 ville være et krystal) er så vidt jeg selv kan se, set fra stikket's "forside" og ikke loddesiden.
Hvis du kigger på selve stikket, kan du se ben-numrene, der er meget små tal støbt ind i selve stikket.
Disse tal er normalt både på for- og bagside af stikket.
-Men det stik du har fået, står kun '1' på stikket's loddeside, mens tallene 1 til 25 står inde over/under benene, når du ser stikket fra forsiden.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 02:12:36
hold fast det havde jeg svært ved at se. men fandt en fejl gnd er smidt på ben 21 og ikke 18 :-[ så det vil jeg lige fikse og se om det hjælper (hat numreret ben som en avr hvor ben 15 ville være overfor 14)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 02:18:12
... gnd er smidt på ben 21 og ikke 18...

Det hjælper med garanti. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 03:19:58
desværre hjalp det ikke ingen kontakt prøver at være systematisk i morgen men syntes jeg kan måle det jeg skal de rigtige steder  :'(
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 03:47:34
desværre hjalp det ikke ingen kontakt prøver at være systematisk i morgen men syntes jeg kan måle det jeg skal de rigtige steder  :'(

OK. Husk at sende mig de fejl-koder som du får fra avrdude.
Men mest sansynligt er det dog at du får denne...
Kode:
initialization failed, rc=-1
         Double check connections and try again, or use -F to override this check.

Brug aldrig -F til at forsøge at løse problemet; det vil ikke løse noget, denne option er sådan set kun til beta-testere.

-Har du husket at ændre '-P usb' til '-P lpt1' ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 03:52:38
Yupper har husket at ændre dette og ja det er den fejlmeddelelse jeg får.

kan følgende have betydning ?
Citér
If it doesn't work straight away, look into lowering the value of R4. It may need to drive an input that has a pull-up resistor of around 1k to 2k, which would make it better to use a 120 to 180 ohm resistor

et sted blev følgende forslået til at teste ved at kortslutte mosi og miso
Citér
avrdude -c stk200 -P lpt1 -p attiny44 -vvvv
har dog ikke prøvet dette endnu

er også obs på at kablet mellem programmer og avr skal krydses så stik og ben passer sammen på begge
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 04:20:54
Yupper har husket at ændre dette og ja det er den fejlmeddelelse jeg får.

OK, så burde softwaren (avrdude) da virke. :)

Citér
kan følgende have betydning ?
Citér
If it doesn't work straight away, look into lowering the value of R4. It may need to drive an input that has a pull-up resistor of around 1k to 2k, which would make it better to use a 120 to 180 ohm resistor

Det mener jeg ikke. -Især ikke i dette tilfælde, da du har undgået at dele benene med ISP-interfacet til andre ting.

Citér
et sted blev følgende forslået til at teste ved at kortslutte mosi og miso
Citér
avrdude -c stk200 -P lpt1 -p attiny44 -vvvv
har dog ikke prøvet dette endnu

Dette kan være en fornuftig ting at prøve, men jeg har et andet forslag; prøv at udvidde din dims til denne version (http://avrprogrammers.com/bld-par3.php), du skal så bare sætte transistor (BC547=2N3904), et par ekstra modstande og en lysdiode på.

Bemærk: BC547 Transistorens ben er: 1=collector, 2=base, 3=emitter.
Dvs. emitter er benet med 'pilen' på.
Base er det ben, som 10K modstanden sættes på.
Collector er det ben, LED og 330 ohm sættes på.
...Husk også at det lange ben på lysdioden er plus (det er det ben, som du sætter på 330 ohm modstanden), det korte ben skal sættes til transistoren's collector ben.

Citér
er også obs på at kablet mellem programmer og avr skal krydses så stik og ben passer sammen på begge

Hvis du har et multimeter, sæt det til at måle ohm eller gennemgang (med bip, hvis det er muligt).
Tag parallel-port stikket ud af computeren, og fjern strømmen fra kredsløbet.
Sæt programmerings-enheden til dit kredsløb med fladkablet imellem.

Mål nu følgende med multimeteret:

Gennemgang fra ben 18 på parallel-port stikket til ben 14 på ATtiny44'en.
Gennemgang fra ben 1 på ATtiny44 til 'top-benet' af din 33K modstand (dvs. den side der er koblet til ben 2 på dit ISP-stik).

Gennemgang fra ben 3 på 74HC125 til ben 9 på ATtiny44
Gennemgang fra ben 6 på 74HC125 til ben 7 på ATtiny44
Gennemgang fra ben 8 på 74HC125 til ben 4 på ATtiny44
Gennemgang fra ben 12 på 74HC125 til ben 8 på ATtiny44
Og nu de 2 gode:
Gennemgang fra ben 7 på 74HC125 til ben 14 på ATtiny44
Gennemgang fra ben 14 på 74HC125 til ben 1 på ATtiny44

Hjalp det ? :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 04:41:27
hmm der er ingen gennemgang på de to "gode" man skulle næsten tro du vidste det på forhånd måske fordi jeg ikke har brugt dem til noget på 74HC125 gg
men alt det andet er som det skal være med bip og det hele hmm
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 04:48:20
hmm der er ingen gennemgang på de to "gode" man skulle næsten tro du vidste det på forhånd måske fordi jeg ikke har brugt dem til noget på 74HC125 gg
men alt det andet er som det skal være med bip og det hele hmm

Heh, forklaringen er enkel:

Du har fulgt diagrammet helt fuldstændig som du skulle.
Hvad ingen har fortalt dig, er at IC'er's GND og VCC ben ikke altid angives på diagrammer (man går simpelthen ud fra at de bliver forbundet korrekt).
Jeg gættede det, fordi jeg selv har lavet denne fejl nogle gange. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 11:29:31
ahhh ja det kan da måske godt gøre en forskel he he
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 19:18:32
Citér
Gennemgang fra ben 7 på 74HC125 til ben 14 på ATtiny44
Gennemgang fra ben 14 på 74HC125 til ben 1 på ATtiny44

7 -> 14 er ok fino
14 har gennemgang til ben 1 på tiny men også men 11

der er ingen ændring i avrdude så nu smider jeg en xp på en anden partition og ser om det hjælper
der er en del stk200 diagrammer der viser gnd på ben 20-25 samt kappe
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 02, 2011, 21:03:23
14 har gennemgang til ben 1 på tiny men også men 11

Dette vil jeg tro er pga. at potmetret er skruet helt ned. Hvis du skruer lidt på potmetret, vil gennemgangen forsvinde, korrekt?

Citér

der er ingen ændring i avrdude så nu smider jeg en xp på en anden partition og ser om det hjælper
der er en del stk200 diagrammer der viser gnd på ben 20-25 samt kappe

Jeg har lige kigget efter her (http://pinouts.ru/ParallelPorts/ParallelPC_pinout.shtml), og det burde ikke betyde noget, da ben 18...25 er koblet sammen internt på LPT porten.

Prøv forresten at skifte til...

Kode:
avrdude -c pony-stk200 -P lpt1 -p attiny44 -U flash:w:main.hex:i

-Hvis du har sat transistor, lysdiode og de 2 ekstra modstande på, burde lysdioden nu lyse/blinke, når du forsøger at køre programmet.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 21:23:37
Citér
Dette vil jeg tro er pga. at potmetret er skruet helt ned. Hvis du skruer lidt på potmetret, vil gennemgangen forsvinde, korrekt?
ja det var rigtigt. er lige ved at smide en diode osv på og så tester jeg igen inden der ryger xp på maskinen.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 02, 2011, 22:57:47
dioden lyser hele tiden,svagt, men bliver skarp når jeg sætter strøm på kredsløbet og blinker ikke. prøver med xp nu
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 01:20:25
dioden lyser hele tiden,svagt,

Det var egentlig mærkeligt. Det betyder nok at der hele tiden er lidt strøm på ben 8.

Citér
men bliver skarp når jeg sætter strøm på kredsløbet og blinker ikke.

OK, disse to ting lyder korrekt.

Citér
prøver med xp nu

Lad mig vide hvordan det går... ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 01:32:36
dioden lyser hele tiden,svagt, men bliver skarp når jeg sætter strøm på kredsløbet.

Hmm.. Vender transistoren rigtigt ?
Jeg har fundet et bedre datablad (http://www.fairchildsemi.com/ds/BC/BC547.pdf) (bemærk: det ser ud til at producenterne ikke kan finde ud af at blive enige om hvor ben 1, 2 og 3 sidder i forhold til hinanden. Fairchild mener ét, mens Philips mener noget andet).
Dette datablad (http://www.slabastruja.com/elementi/BC547.pdf) har navnene på benene i stedet. Bemærk: Dette gælder altså kun BC546/BC547/BC548. Andre transistorer har funktionerne placeret på andre ben.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 02:03:20
My bad. Nu har jeg sikkert brændt det hele af. havde godt nok vendt transistor rigtigt men havde ikke ændret på stikket, var vist for hurtig og bare sat ben 8 til som i diagrammet men ikke set at broen 2 ->12 og 3->11 er fjernet. prøver men ved jo ikke om det er futtet af :-S
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 02:15:07
My bad. Nu har jeg sikkert brændt det hele af.

Det kan lade sig gøre at brænde noget af på 5V, men det sker sjældent.
Jeg har da her i år brændt en lysdiode af, ved at sætte den til 5V ved et uheld, men det er også det eneste der er sket i lang, lang tid, så jeg tror ikke du behøver være bekymret. :)

Microcontrolleren kan dog ikke tåle omvendt spænding i mere end få sekunder.

Citér
havde godt nok vendt transistor rigtigt men havde ikke ændret på stikket, var vist for hurtig og bare sat ben 8 til som i diagrammet men ikke set at broen 2 ->12 og 3->11 er fjernet. prøver men ved jo ikke om det er futtet af :-S
-Det burde ikke have nogen fæl betydning. Hvis du kigger nøjere efter, forbinder det bare nogle ben på printer-porten med hinanden. På disse ben går der kun signaler.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 02:21:25
der var desværre ingen ændring. kan man måle sig til om microcontroler er brændt af ? tror det nu ikke.

kan jo prøve at bygge det op på breadboard igen og se om der er ændringer
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 03:09:58
der var desværre ingen ændring. kan man måle sig til om microcontroler er brændt af ? tror det nu ikke.

Det er stort set umuligt at måle om den er brændt af.
Men lad mig sige det på denne måde: Jeg har gennem 3 år kun oplevet én microcontroller der er brændt af, og dette var ved statisk elektricitet (en mand tog microcontrolleren ud af soklen og satte den i igen, og så var 3 porte brændt af).

Mja, 'der skal ingenting til' og 'der skal utrolig meget til'.

Men igen... Jeg har siddet mange gange uden ESD-armbånd og leget med dem for sjov, og jeg har ikke oplevet noget bøvl selv.

Her er et par tips til at undgå statisk elektricitet:
1: Brug altid skyllemiddel når du vasker tøj.
2: Hav aldrig syntetisk tøj på, mens du roder med elektronik. Bomuld og cowboy-bukser er fx. helt iorden.
3: Vask hænder inden du går igang, dér bliver du nemlig afladt når du rører ved vanhanen og fugten i hænderne vil være med til at holde dig afladt i lidt tid.
4: Hvis du har særlig følsomme komponenter, er det godt lige at røre ved radiatoren en enkelt gang, inden du monterer denne komponent.
5: Hvis du arbejder ofte med Mosfet, så bør du have et ESD armbånd, og forbinde det korrekt med 1Mohm til jord.

Citér
kan jo prøve at bygge det op på breadboard igen og se om der er ændringer

Prøvede du at lave den dersens omtalte 'loopback' ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 03:30:59
Citér
Prøvede du at lave den dersens omtalte 'loopback'
ja det er den samme fejl der bliver ved med at komme. den du skrev tidligere.
Det hele er målt igennem, om det var de rigtige modstande mellem ben og stik og om der var gennemgang de rigtige steder og syntes ikke der er noget at komme efter. kom godt nok til at sætte 125n'ern i omvendt på et tidspunkt og ved ikke om det kan have gjort udslaget. og har rørt ved radiator regelmæssigt. det ender nok med at heg må købe mig en "rigtig" programmertil usb, eller lave mig en. er godt nok ved at miste tålmodigheden med den her efter at have siddet med den i 2 dage og instaleret win 7 32 bit og xp 32 uden held. så jeg kan ikke se så mange muligheder tilbage lige nu he he har lidt en mistanke om at noget blokerer kommunikationen med lpt men igen jeg aner det ikke
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 04:13:00
Det hele er målt igennem, om det var de rigtige modstande mellem ben og stik og om der var gennemgang de rigtige steder og syntes ikke der er noget at komme efter. kom godt nok til at sætte 125n'ern i omvendt på et tidspunkt og ved ikke om det kan have gjort udslaget.

Det kan være, da den så vil have fået negativ spænding (hvis det altså var efter du koblede GND og VCC på). Hvis GND og VCC ikke har været koblet på, vil der ikke have sket noget ved at vende den forkert.

Citér
og har rørt ved radiator regelmæssigt. det ender nok med at heg må købe mig en "rigtig" programmertil usb, eller lave mig en.

Hvis du vil købe en USB-programmer, så vil jeg næsten anbefale AVRISPmkII, da det er Atmel's egen.
(Prøv at spørge El-Supply hvad den koster), du kan selvfølgelig også spørge PC-Elektronik om han kan skaffe den.

Grunden til at jeg anbefaler denne, er at den virker med mest mulig software (jeg tror faktisk at al AVR programmerings-software understøtter den).

Men fordelen med en parallel-port programmer, er at den er mange gange hurtigere, og den er også understøttet af både AVR Studio og avrdude.

Citér
er godt nok ved at miste tålmodigheden med den her efter at have siddet med den i 2 dage og instaleret win 7 32 bit og xp 32 uden held.

Jeg forstår. Men det er mærkeligt .

Citér
så jeg kan ikke se så mange muligheder tilbage lige nu he he har lidt en mistanke om at noget blokerer kommunikationen med lpt men igen jeg aner det ikke

Uhm, lige en anden ting du bør måle...
Hvad måler du, hvis du sætter dit multimeter på DC Volt, og måler med sort ledning fra Attiny's ben 14 og rød ledning på ben 1, lige før du skal programmere chippen ?

-Den bør være mellem +2V og +5V (stabilt), når du bruger stk200 eller pony-stk200.

Egentlig bør du nok også have en elektrolyt-kondensator på dit kredsløb fra GND til VCC, for det kan være at udfald i strømmen vil skabe bøvl. Husk at elektrolyt-kondensatorer skal vende rigtigt, ellers siger de bum og lugter (meget grim lugt). ;)

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 15:26:22
det ændrede ikke på noget at bygge det op igen på breadboard. stadig samme fejl og stadig en diode der lyser hele tiden. det gør den for ovrigt lige meget hvordan transistoren vender.
ved ikke om jeg skal prøve Direct AVR Parallel Access cable
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 16:07:30
det ændrede ikke på noget at bygge det op igen på breadboard. stadig samme fejl

Følgende bør gøres mens kredsløbet ikke er forbundet til noget; dvs. hverken strøm eller programmerings-interface:

Prøv at måle om der er kortslutning på ISP-stikket...

Fra ben 1 til 2, 3, 4, 5 eller 6
Fra ben 2 til 3, 4, 5 eller 6
Fra ben 3 til 4, 5 eller 6
Fra ben 4 til 5 eller 6
Fra ben 5 til 6

Hvis der er kortslutning mellem en af dem, så vil det absolut ikke kunne fungere. ;)

Har du sikret dig, at du måler (cirka) 4k7 mellem RST og VCC (på kredsløbet), inden du sætter programmerings-stikket på ?


Citér
og stadig en diode der lyser hele tiden. det gør den for ovrigt lige meget hvordan transistoren vender.

Hvis jeg havde lavet kredsløbet, ville jeg have sat en 1K modstand fra ben 8 til basis, og en 10K fra basis til GND.
Dette burde slukke lysdioden, når den 'ikke er i brug'.

Citér
ved ikke om jeg skal prøve Direct AVR Parallel Access cable

74HC125'eren sidder der, for at du ikke skal brænde din parallel-port af.
Men så længe der sidder modstande mellem AVR og parallel-porten, er der ikke så høj risiko for at porten ryger.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 16:51:56
jeg måler ikke nogen kortslutninger på isp, og jeg måler også 4k66 mellem rst og vcc på

Citér
Men så længe der sidder modstande mellem AVR og parallel-porten, er der ikke så høj risiko for at porten ryger.

så du mener godt jeg kan prøve det.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 03, 2011, 23:40:21
jeg måler ikke nogen kortslutninger på isp, og jeg måler også 4k66 mellem rst og vcc på

Så må kredsløbet være korrekt.

-Et eller andet sted kan man se hvilke porte der er koblet på computeren.
Prøv lige at sikre dig at 'LPT1' findes.
Da jeg ikke ved så meget om PC/Windows, så er det kun skud/gæt. Muligvis findes det et eller andet sted i et hardware kontrol panel.

Citér
Citér
Men så længe der sidder modstande mellem AVR og parallel-porten, er der ikke så høj risiko for at porten ryger.
så du mener godt jeg kan prøve det.

Ja, der skulle nok ikke ske noget ved det.
Jeg prøvede lige at kigge på Olimex's programmerings-enhed og et par andre.
De bruger 74HC244, men derudover er forskellen:
De har koblet ben 2 til ben 12
De har koblet ben 3 til ben 11
Ben 20,21,22,23 og 24 er alle koblet til GND (i en af dem er også ben 25 koblet til GND)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 03, 2011, 23:54:08
Jeg har lpt1 og har også prøvet at ændre den til 2 og 3 men uden held. prøver lige at kigge på Olimex og ser om det kan gøre en forskel  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 04, 2011, 00:04:41
prøver lige at kigge på Olimex og ser om det kan gøre en forskel  ;D

Her er et par hurtige links. Olimex's har ikke lige så mange forbindelser som de to andre.
Olimex (http://www.olimex.com/dev/images/avr-pg2b-sch.gif)
Lancos BetterSTK200 (http://www.lancos.com/e2p/betterSTK200.gif)
Lancos AVRISP-SIprog (http://www.lancos.com/e2p/avrisp-siprog.gif)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 04, 2011, 13:59:34
kan jeg godt bruge 74hc125n istedet for 244 hvis bare jeg er opmærksom på hvilke ben der svarer til hvad ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 04, 2011, 14:04:50
kan jeg godt bruge 74hc125n istedet for 244 hvis bare jeg er opmærksom på hvilke ben der svarer til hvad ?

Japp, den har samme funktion, men benplaceringerne er anderledes.
Dog lidt med forbehold, for 74HC244 har flere ind- og udgange (8 indgange, 8 udgange), hvor 74HC125 har 4 indgange og 4 udgange.
Bemærk at 74HC244 har 2 output-enable, mens 74HC125 har 4.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 04, 2011, 17:13:06
Jeg tror simpelthen jeg har et problem med at kommunikere med parallelporten så nu vil jeg se om jeg kan finde en serial programmer og prøve den. De kræver dog for det meste zener dioder så dem må jeg lige afvente  men prøver lige den du sendte et diagram over :D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 04, 2011, 22:20:53
Nixen bixen kan heller ikke komme i kontakt med den programmer så nu giver jeg op og bestiller en jeg ved virker  ;D
Så kan jeg få lavet koden færdig mens jeg venter på at den kommer
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 05, 2011, 01:09:31
Nixen bixen kan heller ikke komme i kontakt med den programmer så nu giver jeg op og bestiller en jeg ved virker  ;D

Underligt, at der er så mange knuder. Havde jeg tænkt på det, skulle jeg bare have lavet en lille opstilling, med et kredsløb der kunne programmeres.

Citér
Så kan jeg få lavet koden færdig mens jeg venter på at den kommer

Heh, ja, men der vil altid være nogle ændringer alligevel. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 08, 2011, 00:53:45
så er jeg tilbage på banen igen. havde lige brug for at lægge det på hylden en dags tid og rense hovedet  :o
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 08, 2011, 19:16:35
Så vidt jeg kan se mangler jeg at kalibrerer potmeter og at lave koden for aflæsning af dip, så det vil jeg give mig i kast med
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 08, 2011, 21:05:19
Så vidt jeg kan se mangler jeg at kalibrerer potmeter og at lave koden for aflæsning af dip, så det vil jeg give mig i kast med

Lyder fornuftigt. Sig bare til, hvis der er noget du får brug for hjælp til. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 10, 2011, 19:22:26
Lyder fornuftigt. Sig bare til, hvis der er noget du får brug for hjælp til. :)

Hvis du kan give mig en ledetråd til hvor jeg bør kigge ville det være dejligt.
Jeg har læst et par tutorials f.eks den her
http://metku.net/index.html?path=articles/microcontroller-part-2/index_eng4 (http://metku.net/index.html?path=articles/microcontroller-part-2/index_eng4)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 11, 2011, 20:31:44
Hvis du kan give mig en ledetråd til hvor jeg bør kigge ville det være dejligt.

Den tutorial du fandt, er faktisk rigtig god. Det kan godt være den ikke passer direkte til den microcontroller du bruger, men principperne er de samme.

Lige for tiden (hvor min arbejdscomputer trænger til hvile - strømforsyningen brændte af), har jeg begrænset adgang til mine ressourcer, så min mulighed for at være til hjælp er skåret kraftigt ned. :(

Dog vil jeg sige at stort set er det kun det praktiske du mangler.
Når du kan sende programmet til chippen, vil du kunne justere værdierne.
Bare tag én ting ad gangen, for ellers bliver det for forvirrende.

Det kan være en god idé at lave et 'debug-værktøj', fx. sæt en lysdiode på et af microcontrollerens ben.

Lad os antage at du har en variabel, du kalder 'count'.
Du aner ikke hvad værdien af 'count' er, men hvis du laver en lille rutine, som kan blinke med lysdioden, kan du finde ud af hvilken værdi 'count' har. Fx.

Kode:
void blinkLED(uint8_t aTimes)
{
    while(aTimes--)                     /* decrement aTimes until it reaches 0 */
    {
        LED_PORT |= (1 << LED_PIN);     /* turn LED on */
        /* wait half a second */
        _delay_ms(250);
        _delay_ms(250);
        LED_PORT &= ~(1 << LED_PIN);    /* turn LED off */
        /* wait half a second */
        _delay_ms(250);
        _delay_ms(250);
    }
    /* Finally wait one second, to create a clear delay: */
    for(aTimes = 0; aTimes < 4; aTimes++)
    {
        _wait_ms(250);
    }
}

Kan kaldes på denne måde...
Kode:
    blinkLED(count);

...Selvfølgelig gider du ikke sidde og tælle værdier der når for langt over 10. I sådanne tilfælde kunne du evt...
Kode:
    blinkLED(count / 10);
    blinkLED(count % 10);

Så vil du først få antal 'tiere', dernæst antal 'enere'.

Skal du helt op på tal over 100...
Kode:
    blinkLED(count / 100);
    blinkLED((count / 10) % 10);
    blinkLED(count % 10);

Alt kun teori, da jeg ikke lige kan afprøve det.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 11, 2011, 20:42:36
super. så venter jeg bare på programmer, og krydser fingre for mit kredsløb.

Ærgeligt med arbejdscomputer. men de skal selvfølgelig også have lidt ferie
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 11, 2011, 20:49:46
super. så venter jeg bare på programmer, og krydser fingre for mit kredsløb.

Har du fået at vide hvornår den kommer ?

Citér
Ærgeligt med arbejdscomputer. men de skal selvfølgelig også have lidt ferie

Mja.. Det er nok fordi jeg proppede for mange harddiske i. Men jeg har kørt med 5 harddiske i mere end 2 år uden at der har været noget bøvl. Her på det seneste kørte jeg kun med 4 harddiske i.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 20, 2011, 14:06:05
Tålmodighed har jeg godt nok svært ved, men har desværre ikke set skyggen af programmer endnu, men venter spændt.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 20, 2011, 14:41:57
Tålmodighed har jeg godt nok svært ved, men har desværre ikke set skyggen af programmer endnu, men venter spændt.

Jeg forstår det godt - jeg ved præcist hvordan det er. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: KennRosenkranz efter September 23, 2011, 19:02:11
Jeg lavede dette her meget hurtigt da jeg lige ville lege med en servo, for et stykke tid siden, og det kom til at virke fint:
servoen sat på GPIO2, og to taster til op og ned på GPIO4 og GPIO5
Jeg bruger PWM modulet i PIC12F629.

//SERVO.C  JAN2010
#include"C:\PICC\PIC12F629.C"
#use delay(clock=4000000)
#fuses NOWDT,NOMCLR,PUT,INTRC_IO

byte tik,d;

/*
Aktiv: 0 - 2.5ms

BRUN     GND
RØD      VCC
ORANGE   PWM

OPTION=6 32Hz:
Ok men lille opløsning


OPTION=5 62HHz:
Større opløsning,
*/

void main(void)
{
  CMCON=255;OPTION=5;TRIS=254;d=30;
  do
  {
    if(TMR0<=d) GPIO0=1; else GPIO0=0;
    if(T0IF)
    {
      T0IF=0;tik++;
      if(tik>30)
      {
        tik=0;
        if(!GPIO4 && d>1) d--;
        if(!GPIO5 && d<255) d++;
      }
    }
  } while(1);
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 23, 2011, 20:33:15
servoen sat på GPIO2, og to taster til op og ned på GPIO4 og GPIO5

Jeg tror desværre PIC og AVR er for forskellige til at det lige kan overføres.
Men tak for dit input alligevel. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter September 30, 2011, 16:31:08
Længe siden.
Nå nu kom den endelig så nu er det bare om at komme videre. har godt nok ligget stille et stykke tid
Hold fast der blev lige lavet nogle designændringer herinde :D

Sidder og læser koden igennem og syntes godt nok der er meget at holde styr på.

Jeg tænker på om det ikke ville være en god ide at programerer den i moduler, så eks først timerfunktionen og så pwm osv. smider jeg det hele op id avr på en gang er jeg bange for at jeg ikke aner hvor jeg skal begynde at lede hvis det ikke virker. Eller har du et godt forslag til fremgangsmåde?

Lige en anden ting. er der nogle fuses eller andet der skal sættes i 44 til at starte med ?

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter September 30, 2011, 18:35:40
Nå nu kom den endelig så nu er det bare om at komme videre.

Hvor godt; lækkert. :)

Citér
Jeg tænker på om det ikke ville være en god ide at programerer den i moduler ... smider jeg det hele op id avr på en gang er jeg bange for at jeg ikke aner hvor jeg skal begynde at lede hvis det ikke virker. Eller har du et godt forslag til fremgangsmåde.

Jo, lige mine ord.

Det første du bør gøre, er nok at lave et simpelt program, der tænder for et ben, venter 1/2 sekund, så slukker for benet, venter 1/2 sekund og går tilbage ti starten.

Grunden er: Så kan du lige afprøve at compiler virker og at du kan sende programmet til din ATtiny44.

Dernæst: Lav den del af programmet, du vil kunne teste om virker. Dvs. lav noget, der giver en slags respons fra microcontrolleren.

Citér
Lige en anden ting. er der nogle fuses eller andet der skal sættes i 44 til at starte med ?

Hvis du ikke ændrer fuses, så vil den køre 1MHz, hvilket vil være fint til at starte med.
Du kan ændre fuse-bits, så den kører 8MHz, og det kan være det er en god idé at gøre, når du lige har lavet de første ting og checket at de fungerer.

Selv kører jeg helst 8MHz eller hvis jeg har eksternt krystal kører jeg helst 20MHz, med mindre andet er nødvendigt. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 01, 2011, 18:46:45
WEEEEEEEEEEEEEEEEEEEeeeeeeeeeeeeeeeeeeeeee............................. det virker
lavede den her
http://www.ladyada.net/make/usbtinyisp/use.html (http://www.ladyada.net/make/usbtinyisp/use.html)
og den virker med avrdude og læser min 44 uden problemer phew
nu skal der leges langt om længe
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 01, 2011, 19:25:41
WEEEEEEEEEEEEEEEEEEEeeeeeeeeeeeeeeeeeeeeee............................. det virker

Skønt!! :)
Citér
lavede den her http://www.ladyada.net/make/usbtinyisp/use.html (http://www.ladyada.net/make/usbtinyisp/use.html)

Nåda, jeg regnede med at du købte en færdig AVRISPmkII ... Men hvis den virker, så er det jo fint. ;)
-Jeg turde simpelthen ikke anbefale dig andre end Atmels egen, efter de fejlslagne forsøg.
Ikke om jeg forstår, hvorfor parallel-port udgaven ikke virkede.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 01, 2011, 19:33:43
det kan jo være at jeg er kommet til at brænde noget af da jeg satte 25'ern i forkert, men ved det ikke.

men nu virker det under win 7 64 bit og avr dude så det er perfekt
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 01, 2011, 19:37:55
men nu virker det under win 7 64 bit og avr dude så det er perfekt

Jeg må indrømme at jeg også har det bedre med en USB brænder, fordi den virker uanset hvad du kører med. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 01, 2011, 19:49:59
har lige et hurtigt spørgsmål. jeg måler 7 v på vcc fra programmer. skal jeg smide en modstand ind og få den ned på 5 v eller kan det godt gå med de 7 v ?
Der står godt nog den leverer mellem 3.5 og 5 volt men det er altså 7 den spytter ud når jeg smider jumperen på
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 01, 2011, 19:55:41
har lige et hurtigt spørgsmål. jeg måler 7 v på vcc fra programmer. skal jeg smide en modstand ind og få den ned på 5 v eller kan det godt gå med de 7 v ?
Der står godt nog den leverer mellem 3.5 og 5 volt men det er altså 7 den spytter ud når jeg smider jumperen på

7V kan AVR'en ikke tåle ifølge databladet.

Faktisk må programmerings-enheden ikke sende strøm ud, strømmen skal komme fra kredsløbet.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 01, 2011, 19:59:02
nej ok.

så trækker jeg bare de små 4 volt fra der hvor jumperen sidder. det er kun når jumperen sidder på at programmeren smider strøm ud
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 01, 2011, 21:10:04
så trækker jeg bare de små 4 volt fra der hvor jumperen sidder. det er kun når jumperen sidder på at programmeren smider strøm ud.

Hmm, jeg ved ikke hvad jumperens funktion er. På en AVRISPmkII er der nemlig ingen jumper.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 01, 2011, 23:04:37
hvis jumperen sættes på leverer programeren strøm til enheden via programeringskablet. hvis den ikke er på gør den ikke, men så kan jeg trække 4 volt på de 2 jumperpins. kan selvfølgelig også bare leverer strøm til enheden via ekstern forsyning.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 02, 2011, 05:05:17
hvis jumperen sættes på leverer programeren strøm til enheden via programeringskablet. hvis den ikke er på gør den ikke, men så kan jeg trække 4 volt på de 2 jumperpins. kan selvfølgelig også bare leverer strøm til enheden via ekstern forsyning.

OK.. Så må jeg bare anbefale at du altid bruger ekstern strømforsyning.
En AVR kan programmeres på 3.3V, muligvis ned til 1.8V, hvis den kan køre på så lav spænding (se datasheet for den pågældende chip).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 02, 2011, 13:40:00
wahooo skrev  og slettede mit første prog på attiny weeee. F..k Niel Armstrong he he
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 03, 2011, 13:10:37
Nå men nu har jeg læst koden igennem. tillader mig lige at poste den her

Main.h
Kode:
#ifndef __MAIN_H__
#define __MAIN_H__
#define F_CPU 1000000
void initTimer0();
void initDosing();

#endif /* __MAIN_H__ */

Main.c
Kode:
#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) */
}

Kan ikke se nogle problemer med de to main

Timer0.h
Kode:
#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__ */

Timer0.c
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>

#include "Timer0.h"
#include "Main.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 waitSeconds(uint8_t aSeconds)
{
   aSeconds = (aSeconds + seconds); /* 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 */
   }
   while(aSeconds != seconds) /* wait until seconds has the same value as aSeconds */
   {
   }
}
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 */
{
    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' */
}

Kan ikke se nogle problemer med de to timer0

ADC.h
Kode:
#ifndef __ADC_h__
#define __ADC_h__

void waitUntilADCStable();
uint16_t getADC2Value();                                    /* this routine returns the low 10 bits of the ADC2's value, no matter if you use 8-bit or 10-bit ADC */
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__ */

ADC.c
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>

#include "ADC.h"

#ifndef inb
#define inb(sfr)    _SFR_BYTE(sfr)
#endif

#define ADC_SIZE    5                                                                   /* number of reads to average the ADC channel (we write one, and average over last 4) */
#define ADC_STABLE  (ADC_SIZE + 3)

#define ADC_FIRST   2                                                                   /* first ADC channel to read */
#define ADC_LAST    3                                                                   /* last ADC channel to read */


static volatile uint16_t    adcValue[ADC_LAST - ADC_FIRST][ADC_SIZE];                   /* this buffer holds a lot of conversion results, enough for us to average the values */
static volatile uint8_t     adcReadIndex = 0;                                           /* this is the index we start reading values from (up to, but excluding writeIndex) */
static volatile uint8_t     adcWriteIndex = 0;                                          /* this is the index we write values to */
static volatile uint8_t     adcCounter = 0;                                             /* just a counter, that counts how many times we've read all the ADC channels */
static volatile uint8_t     adcChannel = 0;                                             /* current channel we're reading the ADC value from */
static uint8_t              adcBits = 8;

void waitUntilADCStable()
{
    while(adcCounter < ADC_STABLE)                                                      /* keep waiting, until ADC is reliable */
    {
    }
}

uint16_t getADCValue(uint8_t aADC)
{
    uint16_t    result;
    uint8_t     i;
    uint8_t     idx;

    idx = adcReadIndex;                                                                 /* read from this index; avoiding reading at the 'write position' */
    i = ADC_SIZE - 1;                                                                   /* number of values to read (eg. if ADC_SIZE is 10, we only read 9 values) */
    result = 0;                                                                         /* zero our result */
    while(i--)
    {
        result += adcValue[aADC - ADC_FIRST][idx];                                      /* add the one value we've just read from the index */
        idx = idx >= (ADC_SIZE - 1) ? 0 : idx + 1;                                      /* next index */
    }
    return(result / (ADC_SIZE - 1));                                                    /* return the averaged result */
}

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

/* getADC3Value slettes*/
uint16_t getADC3Value()
{
    return(getADCValue(3));
}


SIGNAL (SIG_ADC)
{
    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8)                                                            /* using 8-bit precision */
    {
        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) */
        }
    }
    else                                                                           /* using 10-bit precision */
    {
        adLo = inb(ADCL);                                                          /* read lowbyte before highbyte! */
        adHi = inb(ADCH);                                                          /* read lowbyte before highbyte! */
    }
    adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo;          /* save the value we've read above */
    ADCSRA |= (1 << ADSC);                                                         /* start another conversion */

    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 */
}

void initADC(uint8_t aBits)
{
    adcCounter = 0;                                                                                    /* this is so we can see when the ADC conversions are stable */
    adcWriteIndex = 0;                                                                                 /* start writing at index 0 */
    adcReadIndex = adcWriteIndex + 1;                                                                  /* read right after the write-index */
    adcChannel = ADC_FIRST;                                                                            /* initialize ADC channel number to read */
    adcBits = aBits;

    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07);                                         /* VCC used as analog reference, first channel */
    ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR);                                /* free running mode, result is right aligned */
    ADCSRA |= (1 << ADSC);                                                                             /* start conversion */
}

Kan ikke sige at jeg helt har forstået ADC.c så har svært ved at gennemskue om den er rigtig, men alt hvad der har med adc3 slettes da dette potmeter er sløjfet og defineres af software

dosing.h
Kode:
#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__ */

dosing.c
Kode:
#include <avr/io.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "Timer1.h"

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

int8_t adc1;
int8_t adc2;
int8_t a;
int16_t rotation;
int8_t repeats=1; /*Must be altered to represent the dip for repeats*/

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()
{
    uint8_t a;
    uint16_t adc2Value;
    uint16_t adc3Value;

    adc2Value = getADC2Value();
    adc3Value =0; /* Value 0 - 256 since the pot2 is removed and unload is defined by software*/

    for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        startServo(200, adc3Value);

        /* unload: */
        waitSeconds(10);
        startServo(200, adc2Value);
    }
}

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

Her har jeg et par spørgsmål
ADC3_CALIBRATION   bliver dette ikke gjort i ADC.c (getADCValue)
Repeats funktionen kan jeg lave den på samme måde som set dosing?
men mangler jeg ikke at vide hvilke værdier compared til vcc, der afgører om det er case 1...4 ?

Timer1.h
Kode:
#ifndef __Timer1_h__
#define __Timer1_h__

uint8_t isServoRunning();
void stopServo();
void startServo(uint16_t aServoCountdown, uint16_t aRotation);
void initTimer1();
void waitSeconds(uint8_t aSeconds);

#endif /* __Timer1_h__ */

Timer1.c
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>

#include "Timer1.h"
#include "Main.h"
static volatile uint16_t    servoCountdown = 0;                 /* variables that are changed by an interrupt, *MUST, MUST* be volatile! */
const uint16_t              servoFrequency = F_CPU / 50;        /* frequency is every 20ms = 50 times per second (50Hz) */

uint8_t isServoRunning()
{
    return(servoCountdown != 0);
}

SIGNAL (SIG_OUTPUT_COMPARE1B)
{
    if(servoCountdown)
    {
        if(0 == --servoCountdown)
        {
            stopServo();                                        /* turn off servo-timer (including interrupt) */
        }
    }
}

void stopServo()
{
    TCCR1B = 0;                                                 /* CS12 : CS11 : CS10 = 0, no clock source (Timer/Counter stopped) */
    TCCR1A = 0;
    TCNT1 = 0;
    OCR1A = 0;
    OCR1B = 0;
    ICR1 = 0;
    TIMSK1 = 0;
    TIFR1 = 0xff;
}

void startServo(uint16_t aServoCountdown, uint16_t aRotation)
{
    servoCountdown = aServoCountdown;                           /* number of pulses to send to servo, before turning it off */

    TCCR1A = 0;                                                 /* disable all PWM on Timer1 whilst we set it up */
    TCCR1B = 0;                                                 /* (disable clock-source, so the timer is frozen) */
    TIMSK1 = 0;                                                 /* disable all Timer1 interrupts */

    ICR1 = servoFrequency;                                      /* frequency is every 20ms, 50 times per second (50Hz) */

    /* select fast PWM (mode 14) and no prescaler */
    TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);      /* enable output COMpare 1 A, output COMpare 1 B, set WGM to Fast PWM  */
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);         /* set WGM to fast PWM, choose clock source CS12:CS11:CS10 = 1, clk/1 (no prescaling) */

    OCR1A = servoFrequency * aRotation / 20;                    /* pulse to load or unload servo on PA7 depending on the argument aRotation */

TIMSK1 |= (1 << OCIE1B);                                    /* enable Output Compare Interrupt 1 B */
}

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

    DDRB |= (1 << PA7);                                         /* set OC0B as output */

    stopServo();                                                /* initially, the servo is not running */
}

Kan heller ikke se nogle problemer i Timer1

undskyld for den lange post, håber du har tid og lyst til at se på det  :o

Jeg har lidt svært ved at se hvordan jeg skal gribe debugging an, da alle delene er vævet ind i hinnanden og afhængige af hinnanden. Min plan var at speede timer0 funktionen op så 24 timer blev til eks 24 minutter. Har testet timerfunktionerne inde i avrstudio vha breaks der retunerer aktuelle værdier og det ser ud til at timer0 tæller og agerer som den skal.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 03, 2011, 14:17:23
Her har jeg et par spørgsmål
ADC3_CALIBRATION   bliver dette ikke gjort i ADC.c (getADCValue)

Nej, getADCValue aflæser kun spændingen. Den laver dog en lille smule stabilisering af tallet, så det ikke flik-flakker for meget frem og tilbage - det er det, while-løkken gør.

Fx. har vi valgt ADC_SIZE=5, vil de sidste 4 resultater blive lagt sammen og divideret med 4.
Det er praktisk at have ADC_SIZE en af følgende værdier:
 3:  1+2
 5:  1+2*2
 9:  1+2*2*2
17:  1+2*2*2*2

(og så fremdeles; men ikke for stor, for så er der ikke plads i microcontrolleren's RAM til resultaterne)

Citér
Repeats funktionen kan jeg lave den på samme måde som set dosing?

Er den ikke 'indbygget' i timer0Elapsed ?

Citér
men mangler jeg ikke at vide hvilke værdier compared til vcc, der afgører om det er case 1...4 ?

Jo. Her er du nødt til at 'tillade' nabo-værdierne også.
Lad os antage at du får følgende resultater ved 4 indstillinger:

Indstilling 1: værdi 0
Indstilling 2: værdi 127
Indstilling 3: værdi 191
Indstilling 4: værdi 223

(Ovenstående er bare vilde gæt)

Så kan du...
Kode:
if(value >= 0 && value < ((0 + 127) / 2))
{
  /* setting 1 */
}
else if(value >= ((0 + 127) / 2) && value < ((128 + 191) / 2))
{
  /* setting 2 */
}
else if(value >= ((128 + 191) / 2) && value < ((192 + 223) / 2))
{
  /* setting 3 */
}
else if(value >= ((192 + 223) / 2) && value < ((224 + 255) / 2))
{
  /* setting 4 */
}

Igen: Ovenstående er kun skud/idéer til hvordan du har en rimelig god/nem chance for at ramme rigtigt.
-Grunden til at du bør have lidt tolerance, er fordi vi har med modstande at gøre. Tolerancen på disse, gør at resultatet ikke altid bliver nøjagtig det samme.

Citér
Jeg har lidt svært ved at se hvordan jeg skal gribe debugging an, da alle delene er vævet ind i hinnanden og afhængige af hinnanden. Min plan var at speede timer0 funktionen op så 24 timer blev til eks 24 minutter. Har testet timerfunktionerne inde i avrstudio vha breaks der retunerer aktuelle værdier og det ser ud til at timer0 tæller og agerer som den skal.

Debugging er smartest/nemmest, hvis du tester ét modul ad gangen.

Lad os antage at du vil teste ADC-aflæsningen. Umiddelbart lyder det som noget, der er svært, for man kan 'ikke se noget resultat'.

Men hvis du har opstillingen på breadboard, kan du bruge nogle lysdioder (husk en modstand i serie der er større end 330 ohm, fx. 1k er udemærket)

Da kan du sige...
Kode:
val = getADC2Value();
if(val >= 128)
{
  setLED1(1);  /* turn LED1 on */
  val = val - 128;
}
else
{
  setLED1(0);  /* turn LED1 off */
}
if(val >= 64)
{
  setLED2(1);  /* turn LED2 on */
  val = val - 64;
}
else
{
  setLED2(0);  /* turn LED2 off */
}

Her er et eksempel på hvis man sætter lysdiodens negative ben fra PA0-benet på IC'en og dens positive ben til gennem en 1k modstand og videre til +5V:
Kode:
void setLED1(uint8_t aState)
{
    PORTA = aState ? (PORTA & ~(1 << PA0)) : (PORTA | (1 << PA0));
}

Samme måde for setLED2, setLED3, osv. (du må selv bestemme hvilken port du vil bruge; PA0...PA7 hører til PORTA, PB0...PB7 hører til PORTB)

Du kan så prøve dig lidt frem. Jo flere lysdioder du sætter på, desto nemmere/hurtigere vil du kunne finde ud af hvad resultaterne er.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 03, 2011, 14:41:40
Citér
Er den ikke 'indbygget' i timer0Elapsed ?

jo men skal også lige have defineret antallet repeats (1,2,5,10)
det må jeg bare kunne gøre på samme måde som setDosing

Citér
Nej, getADCValue aflæser kun spændingen.
ok hvad er det så der skal calibreres? er det det samme som dit eks med
Citér
Indstilling 1: værdi 0
Indstilling 2: værdi 127
Indstilling 3: værdi 191
Indstilling 4: værdi 223

Citér
Men hvis du har opstillingen på breadboard
Det har jeg ikke. det er loddet og det hele, men jeg må vel også kunne måle mig ud af det med mit multimeter

Min hex fil fylder 6 kb og der er brugt avrstudio's default makefile. ved ikke om indholdet af sidstnævnte har inflydelse på hex filens størrelse
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 03, 2011, 15:22:26
Citér
Er den ikke 'indbygget' i timer0Elapsed ?

jo men skal også lige have defineret antallet repeats (1,2,5,10)
det må jeg bare kunne gøre på samme måde som setDosing

Ups, jeg hørte ikke ordenligt efter. Jo, selvfølgelig.

Citér
ok hvad er det så der skal calibreres? er det det samme som dit eks med
Citér
Indstilling 1: værdi 0
Indstilling 2: værdi 127
Indstilling 3: værdi 191
Indstilling 4: værdi 223

Jeps, lige præcist. Systemet er egentlig det samme, hvadenten du måler tryk-knapper eller om du måler potmetret.

Så det, du har brug for, er at finde ud af hvad spændingen på hver knap ligger på.

Du kan prøve at holde en knap nede, og så måle spændingen med multimetret.
Så dividerer du spændingen med 5 (da vi har 5 volt) og ganger den med enten 1023 eller 255, alt efter om du bruger 10-bit eller 8-bit.
Det nemmeste er nok at bruge 10-bit (Jeg husker ikke lige om jeg lavede koden, så den ganger 8 bit resultatet med 4; det mener jeg at jeg ikke gjorde).

Fx. lad os antage at du måler omkring 2.3V
Så kan du forvente et ADC-resultat der ligger omkring (2.3 / 5)*1023 = 470.
Værdien vil dog køre lidt op og ned, da spændingen i kredsløbet varierer lidt.
Så der er nødt til at være tolerance på målingen også.

Jeg vil derfor anbefale at du først måler spændingen ved alle knapper individuelt, og skriver dem ned på et stykke papir.
Derefter omregn dem til en ADC-værdi mellem 0 og 1023 med ovenstående formel.
Sortér dem så, fra 'mindste værdi' til 'største værdi', og brug kalibrerings-tolerancen nævnt højere oppe.


Citér
Men hvis du har opstillingen på breadboard
Det har jeg ikke. det er loddet og det hele, men jeg må vel også kunne måle mig ud af det med mit multimeter
[/quote]

Det kan du selvfølgelig. :)

Nogle gange har jeg 2 opstillinger; en med lysdioder og kontakter, og så en med 'the real thing'.
Så bruger jeg lysdiode-udgaven til at lave prøver og tests med.

Citér
Min hex fil fylder 6 kb og der er brugt avrstudio's default makefile. ved ikke om indholdet af sidstnævnte har inflydelse på hex filens størrelse

Hmm, 6k er vældig stort mener jeg. En ATtiny44 har 4k program-hukommelse; det burde være rigeligt til dit projekt.

-Så du er nok nødt til at fjerne nogle af de ting, der fylder.
Først og fremmest er det vigtigt at der ikke sniger sig 'floating point' matematik ind, men at alle beregninger bruger heltal.

Dvs. undgå at bruge disse to keywords...
float
double

Undgå også at bruge C++, for det laver koden kæmpemæssig. Ren C fylder ikke ret meget.

Du kan evt. prøve at sende mig en e-mail med hele projektet pakket i en zip fil, så kan jeg se om der kan fjernes noget fyld.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 03, 2011, 20:27:03
det er vist lidt mere kompliceret at compile med gcc end den knap man trykker på i avrstudio.
kan jeg bruge den make file jeg sendte med i zip pakken ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 03, 2011, 20:33:42
det er vist lidt mere kompliceret at compile med gcc end den knap man trykker på i avrstudio.
kan jeg bruge den make file jeg sendte med i zip pakken ?

Hmm, er det ikke bare at droppe .c filerne ind i WinAVR og få denne til at generere en Makefile ?
-Ellers har jeg en Makefile som du måske kan bruge (den virker ihvertfald på Unix/Linux, men det er meningen den også skulle kunne bruges med WinAVR).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 04, 2011, 13:21:40
Hej igen. jeg får samme størrelser som dig altså 1180 + 26 BSS
Men størrelsen på .hex tilen står stadig som 4 kb når jeg ser på den i explore.
men nu vil jeg prøve at smide den over og se om den kommer med nogen fejl.

Jeg får meget lave volt på dipswitches mellem 0,06 og 0,1 volt fordelt over 15 indstillinger og så 1 måling på 4.98 når alle dips er off

jeg måler mellem vcc og ben 12 som dips går ind på. hvis jeg måler mellem ben 12 og gnd så bliver forskellen tilsvarrende lille bare mellem 4,7 og 5 volt ca,
når jeg måler modstanden mellem plus 5 volt og ben 12, passer det med de ohm jeg har sat ind og når jeg beregner summen af de paralelle modstande der fremstår ved flere dips on, bliver resultatet også som man forventer. Alt i alt vil det sige at jeg ligger pånogle meget lave værdier efter formlen (volt ben 12 / 5) *1023. eks 1.3 , 1.4 , 1.6 , 1.7 osv og det kan jeg vel ikke rigtigt bruge til noget

strømforsyning er 5 volt 450 mA
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 04, 2011, 17:09:23
Hej igen. jeg får samme størrelser som dig altså 1180 + 26 BSS
Men størrelsen på .hex tilen står stadig som 4 kb når jeg ser på den i explore.
men nu vil jeg prøve at smide den over og se om den kommer med nogen fejl.

Størrelsen på hex-filen har intet at sige.
Det er Text+Data og BSS der har betydning. :)

Citér


Jeg får meget lave volt på dipswitches mellem 0,06 og 0,1 volt fordelt over 15 indstillinger og så 1 måling på 4.98 når alle dips er off

Hmm, jeg må hellere lige prøve at lave din switch-opstilling, det kan være at værdierne skal rettes til.

Citér
jeg måler mellem vcc og ben 12 som dips går ind på. hvis jeg måler mellem ben 12 og gnd så bliver forskellen tilsvarrende lille bare mellem 4,7 og 5 volt ca,

Du bør altid måle mellem GND og målepunkt, for ellers får du ikke korrekte resultater.

Citér
når jeg måler modstanden mellem plus 5 volt og ben 12, passer det med de ohm jeg har sat ind og når jeg beregner summen af de paralelle modstande der fremstår ved flere dips on, bliver resultatet også som man forventer. Alt i alt vil det sige at jeg ligger pånogle meget lave værdier efter formlen (volt ben 12 / 5) *1023. eks 1.3 , 1.4 , 1.6 , 1.7 osv og det kan jeg vel ikke rigtigt bruge til noget

Nej, det har du ret i. Jeg kigger lidt på værdierne og forbindelsen. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 04, 2011, 18:24:00
kan jeg ikke splitte dippen op i 2 og så køre antal doseringer pr dag ind på pa1 og repeats ind på pa4 hvis jeg så bruger 300 k og 150k samt en 150k fra pb2 og en fra pa1 til gnd, så får jeg da en foreskel i værdier fra 1.6 volt til 3 og kan nøjes med 4 cases for hver funktion istedet for 16 cases på 1 funktion ??

er dog ikke sikker på om jeg kan bruge pa4 til formålet, da det også er et programmerings ben

syntes godt nok det sidste kode der mangler er temmeligt hardcore
har 3 eller 4 adc kanaler der skal aflæses (alt efter om dippen bliver splittet op i to)
ADC 1 er til dip (antal doseringer pr dag)
ADC 2 er til potmeter (antal ml pr repeat. Længden på high ( 0.9 til 2.2 ms) i 20 ms cyclen)
ADC 3 er til start knap
ADC 4 er til dip (antal repeats)

sådan her ser min adc.c ud, men som skrevet tidligere har jeg mere end svært ved at gennemskue den. det eneste jeg tror jeg kan se er at define adc first og last nok skal ændres til 1 og 4.
(jeg ville gerne have en DDRa = 0x61; og så også en getADCxValue for hver af de fire ADC, hvor x er 1-4) ind men kan ikke gennemskue om nuværende kode sætter nogle input pins
og så dit eksempel med indstillinger for hver af de 4 ADC'er, hvis de ikke skal i dosing.c filen. Jeg håber du kan give mig et hint for jeg er godt nok helt blank lige her og nu.
Den tutorial jeg skrev om tidligere beskriver kun et potmeter der aflæses, men der er der ikke noget om kalibrering eller values. er mere end forvirret  :-[

Kode:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ADC.h"
#ifndef inb
#define inb(sfr)    _SFR_BYTE(sfr)
#endif
#define ADC_SIZE    5                                                                   /* number of reads to average the ADC channel (we write one, and average over last 4) */
#define ADC_STABLE  (ADC_SIZE + 3)
#define ADC_FIRST   2                                                                   /* first ADC channel to read */
#define ADC_LAST    3                                                                   /* last ADC channel to read */
static volatile uint16_t    adcValue[ADC_LAST - ADC_FIRST][ADC_SIZE];                   /* this buffer holds a lot of conversion results, enough for us to average the values */
static volatile uint8_t     adcReadIndex = 0;                                           /* this is the index we start reading values from (up to, but excluding writeIndex) */
static volatile uint8_t     adcWriteIndex = 0;                                          /* this is the index we write values to */
static volatile uint8_t     adcCounter = 0;                                             /* just a counter, that counts how many times we've read all the ADC channels */
static volatile uint8_t     adcChannel = 0;                                             /* current channel we're reading the ADC value from */
static uint8_t              adcBits = 8;
void waitUntilADCStable()
{
    while(adcCounter < ADC_STABLE)                                                      /* keep waiting, until ADC is reliable */
{
}
}
uint16_t getADCValue(uint8_t aADC)
{
    uint16_t    result;
    uint8_t     i;
    uint8_t     idx;

    idx = adcReadIndex;                                                                 /* read from this index; avoiding reading at the 'write position' */
    i = ADC_SIZE - 1;                                                                   /* number of values to read (eg. if ADC_SIZE is 10, we only read 9 values) */
    result = 0;                                                                         /* zero our result */
    while(i--)
{
        result += adcValue[aADC - ADC_FIRST][idx];                                      /* add the one value we've just read from the index */
        idx = idx >= (ADC_SIZE - 1) ? 0 : idx + 1;                                      /* next index */
}
    return(result / (ADC_SIZE - 1));                                                    /* return the averaged result */
}
uint16_t getADC2Value()
{
    return(getADCValue(2));
}
uint16_t getADC3Value()
{
    return(getADCValue(3));
}
SIGNAL (SIG_ADC)
{
    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8)                                                                    /* using 8-bit precision */
{
        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) */
}
}
    else
{
        adLo = inb(ADCL); /* read lowbyte before highbyte! */
        adHi = inb(ADCH); /* read lowbyte before highbyte! */
}
    adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo; /* save the value we've read above */
    ADCSRA |= (1 << ADSC); /* start another conversion */

    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 */
}
void initADC(uint8_t aBits)
{
    adcCounter = 0; /* this is so we can see when the ADC conversions are stable */
    adcWriteIndex = 0; /* start writing at index 0 */
    adcReadIndex = adcWriteIndex + 1; /* read right after the write-index */
    adcChannel = ADC_FIRST; /* initialize ADC channel number to read */
    adcBits = aBits;

    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07); /* VCC used as analog reference, first channel */
    ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR); /* free running mode, result is right aligned */
    ADCSRA |= (1 << ADSC); /* start conversion */
}

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 08, 2011, 01:56:40
Jeg har nu prøvet følgende i mit breadboard.
Du er nok nødt til at modificere dit kredsløb en lille smule.

Den 100k modstand jeg tidligere snakkede om bør være mindre end 10k. Se vedhæftede kredsløb.

Her er nogle værdi-udlæsninger.
Hvis vi kalder SW4 for A, SW3 for B, SW2 for C og SW1 for D, skulle der gerne være følgende resultater:


(ingen) 5V
A       257x mV
B       1721 mV
AB      1296 mV
C       1039 mV
AC      867 mV
BC      743 mV
ABC     651 mV
D       580 mV
AD      522 mV
BD      474 mV
ABD     435 mV
CD      402 mV
ACD     373 mV
BCD     348 mV
ABCD    326 mV


Det ville selvfølgelig være mest perfekt med en 4K modstand (der findes fx. en 4k02), men jeg har valgt en 3k9, fordi den er forholdsvis let at få fat i.
Du vil muligvis også kunne bruge en 3k9 i stedet for de 2 stk 2K der sidder i serie, og en 499 ohm i stedet for de 2 stk 1K der sidder i parallel.

Det vil være smart at bruge 5% modstande på dine prototyper, men på produktions-modellen 1% modstande, så er du rimelig sikker på at det fungerer korrekt uanset hvad; lav evt. en 5% udgave og en 1% udgave.


Dine ADC-resultater vil på vedhæftede kredsløb cirka blive følgende (kan variere alt efter spænding og modstands-værdier/tolerance):

1024 / 5000 mV * 2575 mV = 527
1024 / 5000 mV * 1721 mV = 352
1024 / 5000 mV* 1296 mV  = 265
1024 / 5000 mV * 1039 mV = 212
1024 / 5000 mV * 867 mV = 177
1024 / 5000 mV * 743 mV = 152
1024 / 5000 mV * 651 mV = 133
1024 / 5000 mV * 580 mV = 118
1024 / 5000 mV* 522 mV  = 106
1024 / 5000 mV* 474 mV  = 97
1024 / 5000 mV* 435 mV  = 89
1024 / 5000 mV* 402 mV  = 82
1024 / 5000 mV* 373 mV  = 76
1024 / 5000 mV* 348 mV  = 71
1024 / 5000 mV* 326 mV  = 66

Igen gælder kalibrerings-metoden jeg har nævnt tidligere.
Fx. er dit resutat mellem ((71+76) / 2) og ((66+71)/2) bør du regne med at du har værdien 71.

Giver det bedre mening nu ? :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 09, 2011, 22:00:54
Citér
Giver det bedre mening nu ? :)

Jeg forstår godt metoden med at finde værdien (eks 71), men aner ikke hvordan jeg skal kode det, og får jeg ikke en masse floating med alle de divisioner?
værdien i nedenstående er så konstanten #define ADC2_CALIBRATION; eller hva?   

eks.
Kode:
if(value >= 0 && value < ((0 + 127) / 2))
{
  /* setting 1 */
}
else if(value >= ((0 + 127) / 2) && value < ((128 + 191) / 2))
{
  /* setting 2 */
}
else if(value >= ((128 + 191) / 2) && value < ((192 + 223) / 2))
{
  /* setting 3 */
}
else if(value >= ((192 + 223) / 2) && value < ((224 + 255) / 2))
{
  /* setting 4 */
}
Denne kode er til kalibrering af eks adc2
værdien value hvor kommer den fra? for hvis getADCvalue er en aflæsning af spænding (som du skrev for nogle posts siden) så skal jeg jo have en omregning til 10 bit værdien et eller andet sted.
Skal det så gøres ved en beregning der f.eks ser således ud
Kode:
 
void calculation (int16_t value)
{
calc = 0,2048 * getADC2Value;
return(calc);
}
(de 0,204 er en omregning af 1024 / 5000 til en konstant, for at undgå divisioner i programmet til gengæld er det et komma tal som jo også er noget skidt)

og i tilfælde af at det skulle være så heldigt at være denne måde hvorpå jeg skal gøre det. bør det så gøres i min adc.c eller i min dosing.c
Jeg beklager og er ked af hvis jeg er lidt tung i det her lige nu (hader at føle mig så tabt bag vognen)  :o he he.

og lige et spørgsmål mere, jeg er ikke sikker på om du så det jeg skrev i min tidligere post så tillader mig lige at gentage spørgsmålet her
kan jeg ikke splitte dippen op i 2 og så køre antal doseringer pr dag ind på pa1 og repeats ind på pa4 hvis jeg så bruger 300 k og 150k samt en 150k fra pb2 og en fra pa1 til gnd, så får jeg da en foreskel i værdier fra 1.6 volt til 3 og kan nøjes med 4 cases for hver funktion istedet for 16 cases på 1 funktion ??




Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 09, 2011, 22:22:23
og tusind tak for arbejdet med dip readings
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 10, 2011, 03:10:00
Advarsel: Meget langt indlæg.

Citér
Giver det bedre mening nu ? :)

Jeg forstår godt metoden med at finde værdien (eks 71), men aner ikke hvordan jeg skal kode det, og får jeg ikke en masse floating med alle de divisioner?
Hvis du får floating point kode med de viste divisioner, har du en dårlig compiler, for den skal for det første selv reducere konstante tal, dvs. tal, som den kan regne værdien ud af på forhånd.
Compileren kan fx. reducere udtrykket
Kode:
uint16_t plads;

plads = ((4 + 12) / 2) * 3.
Dette kan du nemlig også selv reducere.

Så uanset om du skriver ovenstående, eller...
Kode:
plads = 24;
...vil resultat-koden være nøjagtig den samme.

Men compileren kan ikke reducere udtrykket
Kode:
uint16_t plads;

plads = ((kaniner + elefanter) / marsvin) * salater.
Dog kan intelligente compilere reducere følgende:
Kode:
uint16_t kaniner;
uint16_t elefanter;
uint16_t marsvin;
uint16_t salater;
uint16_t plads;

plads = ((kaniner + elefanter) / marsvin) * salater;

Det kan være svært i starten, at gennemskue hvad der foregår i en compiler, men efterhånden som du bruger den, vil du få en bedre fornemmelse af 'hvordan de tænker'. ;)

Bemærk: Koden til at finde disse konstante tal er kun beregnet til dip-switches og knapper med modstande, ikke potmetrene.
Citér

værdien i nedenstående er så konstanten #define ADC2_CALIBRATION; eller hva?   

Denne kode er til kalibrering af eks adc2
værdien value hvor kommer den fra? for hvis getADCvalue er en aflæsning af spænding (som du skrev for nogle posts siden) så skal jeg jo have en omregning til 10 bit værdien et eller andet sted.

Inden nævnte kode, skal du bare aflæse ADC'en på denne måde...
Kode:
value = getADC#value();
if(value >= 0 && value < ((0 + 127) / 2))
{
  /* setting 1 */
}
else ...


Citér
Skal det så gøres ved en beregning der f.eks ser således ud
Kode:
 
void calculation (int16_t value)
{
calc = 0,2048 * getADC2Value;
return(calc);
}
(de 0,204 er en omregning af 1024 / 5000 til en konstant, for at undgå divisioner i programmet til gengæld er det et komma tal som jo også er noget skidt)

I ovenstående kode returnerer du void (ingenting), hvilket vil sige at du kan ikke returnere et tal.
calc er ikke defineret. Hvis calc er en float, så vil du få floating-point kode, hvilket du ikke ønsker.
value bliver ikke brugt til noget, den kan udelades fra argumenterne.
getADC2Value skal have paranteser på, for ellers får du adressen på funktionen (dvs. du får at vide hvor i hukommelsen funktionen ligger).
Derimod, hvis calc er et heltal, vil du altid få resultatet 0, da 0.2048 vil blive rundet ned af compileren før der ganges med getADC2Value().

Denne stump burde kunne virke:
Kode:
 
uint16_t calculation()
{
    uint32_t calc;
    /* simpel: */
    calc = (5000 * getADC2Value()) >> 10;
/* eller med op/nedrunding: */
/*  calc = (((5000 * getADC2Value()) >> 9) + 1) >> 1; */
    return(calc);
}

Desværre kommer vi helt op på 32 bits midlertidigt, men det må så være det, det er.
Her får du så resultatet i millivolt.

Men du kunne også gøre det omvendte, nemlig regne millivolt om til ADC-værdi:

Kode:
if(value > (1023 * 1500 / 5000))
{
    /* value is 1.5V */
}

På den måde vil din kode blive mindre og hurtigere, fordi compileren kan reducere de konstante tal.
Bemærk: Vi ganger før vi dividerer, for at vores resultat skal blive så præcist som muligt.
Dette gør vi pga. at vi regner med heltal.
1023 / 5000 = 0.
1023 * 1500 = 1534500
1534500 / 5000 = 306

Man kan lave et hjælpeværktøj til dette...
#define MILLIVOLT2ADC(a) (1023 * (a) / 5000)

Eller endnu bedre, et, som kan runde op eller ned til nærmeste heltal:

#define MILLIVOLT2ADC(a) (((1023 * (a) / 2500) + 1) / 2)

Her lægger jeg 1 til, og dividerer med 2; det er det samme som hvis man kunne lægge 0.5 til det færdige resultat.
Man kan bruge bitskift til at dividere med 2:

#define MILLIVOLT2ADC(a) (((1023 * (a) / 2500) + 1) >> 1)

...Så de sidste 2 MILLIVOLT2ADC vil give de samme resultater.

Citér
og i tilfælde af at det skulle være så heldigt at være denne måde hvorpå jeg skal gøre det. bør det så gøres i min adc.c eller i min dosing.c

Jeg anbefaler at lave det i dosing.c, for adc.c er stort set kun aflæsning. Prøv at forestil dig det som om adc.c bruges i 10 andre programmer der har med ADC at gøre.
-På den måde vil det være lettere for dig at se hvor du bør lægge tingene.


Citér
Jeg beklager og er ked af hvis jeg er lidt tung i det her lige nu (hader at føle mig så tabt bag vognen)
Helt iorden. ;)

Citér
og lige et spørgsmål mere, jeg er ikke sikker på om du så det jeg skrev i min tidligere post så tillader mig lige at gentage spørgsmålet her
kan jeg ikke splitte dippen op i 2 og så køre antal doseringer pr dag ind på pa1 og repeats ind på pa4 hvis jeg så bruger 300 k og 150k samt en 150k fra pb2 og en fra pa1 til gnd, så får jeg da en foreskel i værdier fra 1.6 volt til 3 og kan nøjes med 4 cases for hver funktion istedet for 16 cases på 1 funktion ??

Det kan du godt, men modstandenes værdier bør ikke ændres. 150K og 300K er nok for store.
Du bør normalt bruge modstande under 10K, da støj ellers kan påvirke dit kredsløb.
Jeg anbefaler stadig at køre med de nævnte værdier: 0.5K, 1K, 2K, 4K.

Jeg vil tro at hvis du sætter 1K på den ene switch og 2K på den anden switch og 2K på output (istedet for 3k9), så ville det kunne fungere. -Og så lave to stk af dem i alt.

Jeg tror du har fejl i dine værdier (0 + 127), (128 + 191), osv.
Grunden er at vores modstands-netværk ikke leverer linære værdier.
Derfor kan vi ikke bare 'dividere med 2' hele vejen; ellers havde der været en simplere metode. ;)

Men i stedet for den lange 'if/else if' kode, kan du gøre koden kortere, ved at aflæse en tabel.
Udførslen tager et par ekstra clock-cycles (hvilket ikke betyder noget i dette tilfælde).
Mit skud er at denne kode vil fylde lidt over 48 bytes, hvilket er en hel del kortere end tidligere nævnte kode:

Følgende #include bør indsættes i toppen af dosing.c, fx. nede under #include <avr/io.h>:
Kode:
#include <avr/pgmspace.h>

Dernæst, et eller andet sted, du synes er passende:

Kode:
uint8_t calculateSetting(uint16_t aValue)
{
    const uint16_t convTab[] PROGMEM = { ((1023 + 523) / 2), ((523 + 349) / 2), ((349 + 262) / 2), ((262 + 209) / 2),
        ((209 + 174) / 2), ((174 + 149) / 2), ((149 + 131) / 2), ((131 + 116) / 2), ((116 + 105) / 2), ((105 + 95) / 2),
        ((95 + 87) / 2), ((87 + 80) / 2), ((80 + 75) / 2), ((75 + 70) / 2), ((70 + 65) / 2), 0 }; /* 3K9, 5% */
    uint8_t i;

    i = 0;
    while(aValue <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}

Tabellen er beregnet efter VCC=5.00V, men den er checket op ad VCC=5.05V med en 3K9, 5% modstand (3k86), og værdierne er ikke langt fra hinanden.

Include-filen pgmspace.h indeholder macroer, som gør det nemt at læse tabeller der ligger i Flash-memory, frem for at de først lægges over i RAM. Dette sparer både RAM og reducerer kode-størrelsen.

... Koden er afprøvet som program på min Mac, og giver korrekte resultater.
Tabellen er baseret på en 3K9 modstand.

Her er en tabel, som er baseret på en 4K/0% modstand. Du kan fx. bruge 2 stk. 2K modstande på 1% ved udgangen:
Kode:
    const uint16_t convTab[] PROGMEM = { ((1023 + 512) / 2), ((512 + 341) / 2), ((341 + 256) / 2), ((256 + 205) / 2), 
        ((205 + 171) / 2), ((171 + 146) / 2), ((146 + 128) / 2), ((128 + 114) / 2), ((114 + 102) / 2), ((102 + 93) / 2),
        ((93 + 85) / 2), ((85 + 79) / 2), ((79 + 73) / 2), ((73 + 68) / 2), ((68 + 65) / 2), 0 }; /* 4K, 0% */

Tabellen er beregnet efter VCC=5.00V, men den er checket op ad en 4K, 1% modstand.


Det er bedst at bruge de beregnede tabeller, frem for en tabel baseret på målte værdier, fordi hvis du har en modstand der ligger på -5%, og du baserer værdien på denne, vil du få fejl, den dag du bruger en modstand på +5%. Er tabellen baseret på +0%, vil du undgå fejlen.

Her er et par små formler, som du kan bruge til at beregne tabellerne:

voltage = VCC * 1000 / ((r1 + r2) / 8) / (setting + 1)

* 1000 er for at lave volt om til millivolt
r1 er din udgangs-modstand i ohm, fx. 3900.
r2 er værdien på den største modstand der sidder til en switch i ohm, fx. 4000.
setting er et tal mellem 0 og 15.
Her går jeg selvfølgelig ud fra, at modstandsværdierne bliver halveret efterhånden som der sættes flere switches på.

Formlen kan skrives om til en lidt mere lommeregner-venlig udgave:
voltage = VCC * 1000 * 8 / (r1 + r2) / (setting + 1)

Du kan så omregne voltage til ADC værdi:
adcValue = 1023 * voltage / 5

Formlerne kan reduceres yderligere og de kan også kombineres til én formel der giver dig adcValue.

Citér
og tusind tak for arbejdet med dip readings

Velbekomme. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 10, 2011, 16:19:06
oki går igang med det samme  :P.
Citér
Hvis du får floating point kode med de viste divisioner, har du en dårlig compiler
Den ene sætning gjorde mig meget klogere på compilers ha ha. troede at compileren bare lavede c om til maskinkode og skænkede ikke det en tanke at den også går ind og reducerer og udregner konstanter så når jeg skrev 200/11 eks så troede jeg at den smed samme regnestykke ind i maskinkoden og ikke resultatet afrundet til heltal  ;D

Jeg har lavet dips som du foreslog i diagrammet på forrige side. har dog brugt 2k modstande til at lave 4k fra +5 til dips og det har jeg også der hvor der skal være 4k fra dip. havde også en 500 ohm så det skulle være på plads nu. nu vil jeg så lige måle igennem. Min strømforsyning leverer 5.28V så det skal der jo også tages højde for, altså at det ikke er 5v rent. skal jeg så ikke regne med 5280 mv istedet for 5000 rent ?
 
Hov hvor skal ADC benet ind i det diagram du har lavet? før havde jeg fra dip til adc og adc til jord via en modstand. den er nu sløjfet og sat over på +5v siden men jeg kan jo ikke kortslutte adc til jord med en lus, så kan jeg hvertfald ikke måle fra adc til jord
Tror jeg fandt du af det adc benet skal på efter 3k9 modstanden fra +5v og så skal adc benet ikke føres til jord. er det ikke sådan ? gg var det ikke noget med pull up eller pull down modstand ?

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 10, 2011, 23:14:55
oki går igang med det samme  :P.
Citér
Hvis du får floating point kode med de viste divisioner, har du en dårlig compiler
Den ene sætning gjorde mig meget klogere på compilers ha ha. troede at compileren bare lavede c om til maskinkode og skænkede ikke det en tanke at den også går ind og reducerer og udregner konstanter så når jeg skrev 200/11 eks så troede jeg at den smed samme regnestykke ind i maskinkoden og ikke resultatet afrundet til heltal  ;D
Det gjorde C-compilere engang, så du er faktisk ikke helt forkert på den.
Frem til 1988 lavede man C-compilere, så de lavede rigtig god klodset kode, hvor man kunne disassemble koden og derefter nemt fjerne 1/4 af alle de ligegyldige ting. Men i dag er det vældig svært at slå compilernes optimeringer, fordi der netop er programmører der har siddet og lavet avancerede optimerings-algoritmer og kigget på resultatet. Ofte kan det ikke betale sig at optimere en compiler's output i dag.

Men nogle gange får man en skør idé, til hvordan man kan gøre lave et bestemt stykke kode i maskinkode; og netop dér kan C-compileren muligvis ikke bruges. Dette gælder fx. noget som har præcis timing (her snakker vi nanosekunder).

Citér
Jeg har lavet dips som du foreslog i diagrammet på forrige side. har dog brugt 2k modstande til at lave 4k fra +5 til dips og det har jeg også der hvor der skal være 4k fra dip. havde også en 500 ohm så det skulle være på plads nu. nu vil jeg så lige måle igennem. Min strømforsyning leverer 5.28V så det skal der jo også tages højde for, altså at det ikke er 5v rent. skal jeg så ikke regne med 5280 mv istedet for 5000 rent ?

Det bedste ville være at sætte din egen spændings-regulator på, så du véd at du har en fast 5V spænding, som ikke ændrer sig.
Men da denne Atmel chip måler i forhold til VCC, burde du ikke få noget vrøvl. :)
Husk at Atmel chippen ikke kan tåle mere end 5.5V (dette står beskrevet i databladet (http://www.atmel.com/dyn/resources/prod_documents/doc8183.pdf) - husk at downloade dette, hvis du ikke allerede har det).

Citér
Hov hvor skal ADC benet ind i det diagram du har lavet? før havde jeg fra dip til adc og adc til jord via en modstand. den er nu sløjfet og sat over på +5v siden men jeg kan jo ikke kortslutte adc til jord med en lus, så kan jeg hvertfald ikke måle fra adc til jord
Tror jeg fandt du af det adc benet skal på efter 3k9 modstanden fra +5v og så skal adc benet ikke føres til jord. er det ikke sådan ? gg var det ikke noget med pull up eller pull down modstand ?

Lige præcist. Den 3k9 modstand (som bør være så tæt på 4k00 som muligt), kaldes en pull-up, fordi den er sat til VCC. Var den sat til GND, blev det til en pull-down. :)
Og jo, det er netop på ikke-VCC siden af denne pull-up modstand du bør sætte dit ADC-ben. =)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 11, 2011, 01:29:26
Jeg ved ikke hvorfor jeg ikke kan få metoden ind i hovedet.
Jeg forstår godt de enkelte elementer men kan ikke se hvordan jeg får dem til at arbejde sammen.
skriver lige et eksempel som jeg vil have det til at hænge sammen i mit hoved

Først laver jeg en linje der hedder
Kode:
#define ADC1_CALIBRATION;
jeg går ud fra at der skal stå et eller andet efter ADC1_CALIBRATION der på en eller anden måde skal kædes en værdi mellem 0 og 1023 til dette
denne værdi kan jeg finde ved eks den value der beregnes på nedenstående linje.

Kode:
int16_t value = ((1023 * getADC1Value()) / 5000)

meeen så giver det ikke mening for mig at skulle bruge #define ADC1_CALIBRATION for den er vel ikke mere konstant end Int16_t value

nå men videre med mine tanker nu har jeg så fundet en værdi mellem 0 og 1023 og så mener jeg at kunne forstå at den så skal kædes til en case
som eks
Kode:
uint8_t calculateSetting(uint16_t aValue)
{
    const uint16_t convTab[] PROGMEM = { ((1023 + 523) / 2), ((523 + 349) / 2), ((349 + 262) / 2), ((262 + 209) / 2),
        ((209 + 174) / 2), ((174 + 149) / 2), ((149 + 131) / 2), ((131 + 116) / 2), ((116 + 105) / 2), ((105 + 95) / 2),
        ((95 + 87) / 2), ((87 + 80) / 2), ((80 + 75) / 2), ((75 + 70) / 2), ((70 + 65) / 2), 0 }; /* 3K9, 5% */
    uint8_t i;

    i = 0;
    while(aValue <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
uden at væer sikker på det skulle jeg så mene at uint16_t aValue er et tal mellem 0 og 15 (har husket #include <avr/pgmspace.h> i starten )

her efter må jeg så skulle have nogle if/else sætninger der forbinder  uint16_t aValue til antal doseringer og antal repeats og dem kan jeg godt finde ud af at lave
er det helt ude i skoven ?? jeg har svært ved at se hvad jeg skal bruge linjen #define ADC1_CALIBRATION; til
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 11, 2011, 01:40:39
du må godt bande ad mig he he  :-[
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 11, 2011, 01:57:33
Jeg ved ikke hvorfor jeg ikke kan få metoden ind i hovedet.

Vi prøver da lige at kigge på det. :)

Først får du lige to #defines
Kode:
#define ADC_TO_MILLIVOLT(a) ((5000 * (a)) / 1023)
#define MILLIVOLT_TO_ADC(a) ((1023 * (a)) / 5000)

Den første tager en værdi du får fra ADC'en og konverterer den til millivolt.
Nummer to tager en millivolt-værdi og konverterer den til en ADC-værdi (denne kan fx. bruges til sammenligninger).

Fx. hvis du vil se om ADC'en måler over 2500 mV:
Kode:
if(getADC#Value() >= MILLIVOLT_TO_ADC(2500))
{
  /* 2500 mV or more */
}
else
{
  /* less than 2500 mV */
}

Citér
Jeg forstår godt de enkelte elementer men kan ikke se hvordan jeg får dem til at arbejde sammen.
skriver lige et eksempel som jeg vil have det til at hænge sammen i mit hoved

Jeg tror du er kommet ind i lidt forvirring, derfor springer jeg lidt frem.

Citér
nå men videre med mine tanker nu har jeg så fundet en værdi mellem 0 og 1023 og så mener jeg at kunne forstå at den så skal kædes til en case

getADC#Value() giver dig en værdi mellem 0 og 1023. Denne kan du overføre direkte til calculateSetting uden at skulle regne den om.

Citér
som eks
Kode:
uint8_t calculateSetting(uint16_t aValue)
{
    const uint16_t convTab[] PROGMEM = { ((1023 + 523) / 2), ((523 + 349) / 2), ((349 + 262) / 2), ((262 + 209) / 2),
        ((209 + 174) / 2), ((174 + 149) / 2), ((149 + 131) / 2), ((131 + 116) / 2), ((116 + 105) / 2), ((105 + 95) / 2),
        ((95 + 87) / 2), ((87 + 80) / 2), ((80 + 75) / 2), ((75 + 70) / 2), ((70 + 65) / 2), 0 }; /* 3K9, 5% */
    uint8_t i;

    i = 0;
    while(aValue <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
uden at væer sikker på det skulle jeg så mene at uint16_t aValue er et tal mellem 0 og 15 (har husket #include <avr/pgmspace.h> i starten )
Rettelse:
Du giver et tal til calculateSetting, som er mellem 0 og 1023. Den giver dig et stabilt resultat som ligger mellem 0 og 15.
Citér

her efter må jeg så skulle have nogle if/else sætninger der forbinder  uint16_t aValue til antal doseringer og antal repeats og dem kan jeg godt finde ud af at lave

Fint. :)

Citér
er det helt ude i skoven ?? jeg har svært ved at se hvad jeg skal bruge linjen #define ADC1_CALIBRATION; til

ADC1_CALIBRATION har jeg erstattet med MILLIVOLT_TO_ADC og ADC_TO_MILLIVOLT, i tilfælde at du vil bruge dem til potmetret.
-Men faktisk vil det nok være en god idé, at lave en funktion der ligner calculateSetting, bare med andre værdier, som passer til potmetret, så nej, du behøver ikke de to macroer.

Hvis du har sat 2 switches på ADC1, burde du kunne gøre noget i stil med:
Kode:
    uint8_t setting;

    setting = calculateSetting(getADC1Value());
    switch(setting)
    {
      case 0:
        ...
        break;
      case 1:
        ...
        break;
      case 2:
        ...
        break;
      case 3:
        ...
        break;
    }


Hvis du har de 4 switches på en og samme ADC, burde du kunne gøre følgende:

Kode:
    uint8_t setting;
    uint8_t repeats;
    uint8_t dosingCount;

    setting = calculateSetting(getADC1Value());
    dosingCount = (setting >> 2) % 0x03;
    repeats = setting & 0x03;

    ...
    ...

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 11, 2011, 15:42:39
Oki så prøver jeg.
kan jeg gøre det på denne måde (kun lavet for dips og StartDosint skal også laves om) ?
Kode:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "Timer1.h"
#define ADC_TO_MILLIVOLT(a) ((5000 * (a)) / 1023)
#define MILLIVOLT_TO_ADC(a) ((1023 * (a)) / 5000)
int8_t a;
int8_t repeats=1; /*Must be altered to represent the dip for repeats*/
uint8_t setting;
int16_t starting = getADC3Value(); /* controlls if startbutton is pushed*/
uint16_t aValue = getADC1Value();

/*ADC TABELS START*/
uint8_t calculateSettingDip(uint16_t aValue)
{
    const uint16_t convTab[] PROGMEM = { ((1023 + 512) / 2), ((512 + 341) / 2), ((341 + 256) / 2), ((256 + 205) / 2),
        ((205 + 171) / 2), ((171 + 146) / 2), ((146 + 128) / 2), ((128 + 114) / 2), ((114 + 102) / 2), ((102 + 93) / 2),
        ((93 + 85) / 2), ((85 + 79) / 2), ((79 + 73) / 2), ((73 + 68) / 2), ((68 + 65) / 2), 0 }; /* 4K, 0% */
    uint8_t i;

    i = 0;
    while(aValue <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
/*ADC TABELS END*/


/* CONDITIONS START*/
setting = calculateSetting(getADC1Value());
/* REPEATS */
if (setting == 1)||(setting == 5)||(setting == 9)||(setting == 13)
{
repeats = 10
}
else if (setting == 2)||(setting == 6)||(setting == 10)||(setting == 14)
{
repeats = 4
}
else if (setting == 3)||(setting == 7)||(setting == 11)||(setting == 15)
{
repeats = 2
}
else if (setting == 4)||(setting == 8)||(setting == 12)
{
repeats = 1
}

/* DOSINGS */
if (setting == 4)||(setting == 5)||(setting == 6)||(setting == 7)
{
setMinuteCountdown(24 * 60);
}
else if (setting == 8)||(setting == 9)||(setting == 10)||(setting == 11)
{
setMinuteCountdown(12 * 60);
}
else if (setting == 12)||(setting == 13)||(setting == 14)||(setting == 15)
{
setMinuteCountdown(6 * 60);
}
else if (setting == 1)||(setting == 2)||(setting == 3)
{
setMinuteCountdown(2 * 60);
}
/* CONDITIONS END*/

/*FUNCTIONS START*/
void startDosing() /* this routine should be called when the 'start' button is pressed */
{
   int16_t adcValue;
    int8_t  dosing;
    adcValue = getADC2Value(); /* read value of ADC channel 2 */
    adcValue = adcValue + ADC2_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()
{
    uint8_t a;
    uint16_t adc2Value;
    uint8_t Unload;
    Unload =0; /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/
    for(a = 0; a < repeats; a++)
{
        /* load: */
        waitSeconds(10);
        startServo(200, adc2Value);
        /* unload: */
        waitSeconds(10);
        startServo(200, Unload);
}
}
void initDosing()
{
    startDosing(); /* in case of power failure, automatically restart with the current value */
}

Citér
Men faktisk vil det nok være en god idé, at lave en funktion der ligner calculateSetting
også når opløsningen skal være minimum 256, så bliver det jo noget af en tabel

(jeg ved godt at kommentarene ikke er alignet, men det er de i avrstudio)  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 11, 2011, 16:08:58
Oki så prøver jeg.
kan jeg gøre det på denne måde (kun lavet for dips og StartDosint skal også laves om) ?

Det ser rimelig fornuftigt ud, du er på rette kurs.
Du har dog ikke 'if(setting == 0)' med, hvilket du nok gerne vil have, så du er sikker på at have en indstilling for alle de mulige dip-switch kombinationer der er.

Selvfølgelig skal du også have conditions lagt ind i de rigtige funktioner, men det regner jeg med at du har styr på.

Hvis du vil have variabler liggende udenfor funktioner, vil jeg anbefale at du skriver 'volatile' foran dem, for ellers kan du få bøvl med at 'de ikke altid virker'. Dette har med at gøre, at de er cached, og hvis de bliver ændret af et interrupt, så vil cachen ikke blive opdateret.

Så...
Kode:
int8_t a;
int8_t repeats=1;
uint8_t setting;
int16_t starting = getADC3Value();
uint16_t aValue = getADC1Value();
bør så ændres til...
Kode:
volatile int8_t a;
volatile int8_t repeats=1;
volatile uint8_t setting;
volatile int16_t starting = getADC3Value();
volatile uint16_t aValue = getADC1Value();


Men jeg regner med, at du egentlig ikke ønsker at have disse som globale variabler.

Grunden til at jeg et sted har kaldt en variable for 'aValue' i stedet for 'value', er at A'et står for "Argument".
Dette er en kode-standard, som jeg lærte da jeg arbejdede på samme kode som omkring 20 andre programmører, så jeg vil anbefale at du starter alle argumenter med lille 'a' og derefter laver 'kamel-pukler' med uppercase for hver gang der starter et nyt ord, fx.
Kode:
int16_t myFunction(uint8_t *aMessageText, uint16_t aMessageLength)
{
...
}

Og derfor også undgår at variabler, der ikke er argumenter, ikke starter med lille a efterfulgt af stort bogstav, fx...
Kode:
int16_t myFunction(uint8_t *aMessageText, uint16_t aMessageLength)
{
    uint8_t apples = 5;       /* good naming convention */
    uint8_t aLotOfTrees = 1;  /* bad naming convention */
}

Citér
Citér
Men faktisk vil det nok være en god idé, at lave en funktion der ligner calculateSetting
også når opløsningen skal være minimum 256, så bliver det jo noget af en tabel

Uhm, jeg regnede ikke med at dit potmeter skulle have så fin indstilling. Men det er muligt at det stadig vil være en god idé.
Du vil finde ud af om det er nødvendigt eller ej, for jeg husker ikke om potmetret er linært eller logaritmisk.

Citér
(jeg ved godt at kommentarene ikke er alignet, men det er de i avrstudio)  :P

Gør ikke mig noget. Jeg alignede dem i mine eksempler, så du kan se at det bliver pænt læsbart, når de er det. :)

Husk: Hvis du får compile-fejl, så er du nødt til at rette den første fejl, som bliver rapporteret først. For fejl, som følger efter første fejl, kan være forårsaget af netop den første fejl.
Det kan være en god idé, at ændre 5-10 linier ad gangen, for ikke at blive overfuset af fejl-meddelelser.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 11, 2011, 20:57:45
Lige et hurtigt spørgsmål
kan lokale variabler godt erklæres ude i starten så?
eks int8_t a;
virker den så godt nok i den rutine hvor den skal bruges (og der hvor værdien tillægges)?

eller med andre ord er det kun når værdien af variabler skal bruges i rutiner at det er et problem
eks int8_t a = 10;
så bør det være volatile  int8_t a = 10;

Prøver lige igen  :P
Kode:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "Timer1.h"
/* #define ADC_TO_MILLIVOLT(a) ((5000 * (a)) / 1023)*/ /* maby use tabel instead*/
/* #define MILLIVOLT_TO_ADC(a) ((1023 * (a)) / 5000)*/ /* maby use tabel instead*/
int8_t a;
int16_t starting = getADC3Value();      /* controlls if startbutton is pushed*/
volatile uint16_t aValue = getADC1Value();    /* value assigned to aValue for use in calculateSettingDip*/
volatile int8_t setting = calculateSetting(getADC1Value()); /*Declare the global var setting for use in start dosing and timer0elapsed*/

if (starting > 0)           /* if start button is pressed the system starts by calling startDosing*/
{
startDosing();
}
/*ADC TABELS START*/
uint8_t calculateSettingDip(uint16_t aValue)
{
    const uint16_t convTab[] PROGMEM = { ((1023 + 512) / 2), ((512 + 341) / 2), ((341 + 256) / 2), ((256 + 205) / 2),
        ((205 + 171) / 2), ((171 + 146) / 2), ((146 + 128) / 2), ((128 + 114) / 2), ((114 + 102) / 2), ((102 + 93) / 2),
        ((93 + 85) / 2), ((85 + 79) / 2), ((79 + 73) / 2), ((73 + 68) / 2), ((68 + 65) / 2), 0 }; /* 4K, 0% */
    uint8_t i;

    i = 0;
    while(aValue <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
/*ADC TABELS END*/

/*FUNCTIONS START*/
void startDosing() /* this routine starts when the 'start' button is pressed */
{      /* setMinuteCountdown initiated corrosponding to dip setting*/
if (setting == 4)||(setting == 5)||(setting == 6)||(setting == 7)
{
setMinuteCountdown(24 * 60);
}
else if (setting == 8)||(setting == 9)||(setting == 10)||(setting == 11)
{
setMinuteCountdown(12 * 60);
}
else if (setting == 12)||(setting == 13)||(setting == 14)||(setting == 15)
{
setMinuteCountdown(6 * 60);
}
else if (setting == 1)||(setting == 2)||(setting == 3)
{
setMinuteCountdown(2 * 60);
}
timer0Elapsed(); /* Calls timer0Elapsed to perform first dosing */
    setDosing(dosing); /* when this routine is called, the dosing countdown starts */
}

void timer0Elapsed()   /* the dosing rutine*/
{
if (setting == 1)||(setting == 5)||(setting == 9)||(setting == 13)
{
repeats = 10
}
else if (setting == 2)||(setting == 6)||(setting == 10)||(setting == 14)
{
repeats = 4
}
else if (setting == 3)||(setting == 7)||(setting == 11)||(setting == 15)
{
repeats = 2
}
else if (setting == 4)||(setting == 8)||(setting == 12)||(setting == 0)
{
repeats = 1
}
    uint8_t a;
    uint16_t adc2Value;
    uint8_t Unload;
    Unload =0; /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/
    for(a = 0; a < repeats; a++)
{
        /* load: */
        waitSeconds(10);
        startServo(200, adc2Value);
        /* unload: */
        waitSeconds(10);
        startServo(200, Unload);
}
}

void initDosing()
{
    startDosing(); /* in case of power failure, automatically restart with the current value */
}
/*FUNCTIONS END*/
er i tvivl om værdien setMinuteCountdown bliver sendt til Timer0.c
og så mangler jeg self lige pot reading men den tygger jeg lige på for 256 er måske nok i overkanten.
skal maks dosere 5 ml så det må være riligt med en opløsning på 20 svarende til ca 0,25 ml og med en tabel er det jo let at sætte range (de ms svarende til at rykke servoen) med andre ord så kan jeg sætte range på potten til kun at inkluderer værdier der giver mening i forhold til de grader der er til rådighed for den begrænset bevægelse af servoen i forhold til fuldt udsving på 180o jeg skal jo kun bruge en bevægelse på max 90o Håber det gav mening  :P

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 12, 2011, 04:45:02
Lige et hurtigt spørgsmål
kan lokale variabler godt erklæres ude i starten så?
eks int8_t a;
virker den så godt nok i den rutine hvor den skal bruges (og der hvor værdien tillægges)?

Lokale variabler erklæres inde i den funktion de skal bruges.
Erklæres variabler udenfor en funktion er de altid globale.

Citér
eller med andre ord er det kun når værdien af variabler skal bruges i rutiner at det er et problem
eks int8_t a = 10;
så bør det være volatile  int8_t a = 10;

Hvis en variabel er erklæret global, og den bruges af 2 forskellige rutiner, er det en god idé at have den volatile.
Hvis den kun bruges af én rutine, er der normalt ikke grund til at have den som global.

Men hvis du vil have den tekniske forklaring, vil jeg bruge dette program som eksempel:

Kode:
uint8_t seconds;
uint8_t minutes;
uint8_t hours;

void clock()
{
    if(seconds++ >= 60)
    {
        seconds = 0;
        if(minutes++ >= 60)
        {
            hours++;
        }
    }
}

void wait()
{
    uint8_t oldSeconds;

    oldSeconds = seconds;
    while(oldSeconds == seconds)
    {
    }
}

Vores rutine 'clock' er kaldt under udførsel af interrupt. Om den er kaldt direkte af interruptet, eller af interrupt-funktionen er ligegyldigt, resultatet vil blive det samme.
Vores 'wait' rutine læser værdien 'seconds' og gemmer værdien i 'oldSeconds', for at vi kan se hvornår der er sket en ændring.
Næste ting, er at vi venter til seconds har ændret sig.
Compileren er så smart, at den optimerer vores program.
Da den kan se, at vi aflæser 'seconds' to gange lige efter hinanden, vil den for det første sige: Fint, dette tager jeg som én aflæsning, så det vil være det samme som:
Kode:
    uint8_t temp;

    temp = seconds;
    oldSeconds = temp;
    while(oldSeconds != temp)
    {
    }

-Fordi compileren ved ikke at der nu og da sker et interrupt, som ændre i seconds.
Men hvis vi nu ovenover erklærer seconds som volatile, vil koden virke som forventet.

Dvs. hvis en variabel ændrer værdi udenfor den funktion, som den aflæses i, imens denne funktion køres, bør den være volatile.
Dette sker normalt kun i interrupts, men der er faktisk et andet eksempel.
Alle microcontrollerens porte er erklæret volatile, fordi ellers ville første aflæsning blive cached, og så har vi et input-ben som ikke ser ud til at virke. ;)

Sidebemærkning:
Du har sikkert set at der står...
Kode:
    if(seconds++ >= 60)

Og måske undret dig lidt over hvornår 'seconds' bliver sammenlignet med 60.
Når ++ står efter variablen, hedder det post-increment.
Når -- står efter variablen, hedder det post-decrement.
Når ++ står før variablen, hedder det pre-increment.
Når -- står før variablen, hedder det pre-decrement.

(increment = tælle opad, decrement = tælle nedad)

I while og for-løkker bruger man normal post-increment eller post-decrement.
Ved pointere bruger man normal post-increment og pre-decrement; det er sjældent at det er logisk/smart at gøre andet; men der kan komme situationer, hvor det er praktisk at bruge pre-increment eller post-decrement.

Konklusion. Vi kunne have lavet koden ovenover anderledes, fx.
Kode:
    if(++seconds >= 61)
eller
Kode:
    if(++seconds > 60)

...men personligt synes jeg det andet giver bedre læsbarhed/pænere kode.

Et eksempel på post-decrement og pre-decrement i en while-løkke:
Kode:
i = 10;
while(i--) /* post-decrement */
{
    /* Here, i has the values 9, 8, 7, 6, 5, 4, 3, 2, 1, 0. */
}

i = 10;
while(--i) /* pre-decrement */
{
    /* Here, i has the values 9, 8, 7, 6, 5, 4, 3, 2, 1. */
}

Citér
Prøver lige igen  :P
Kode:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "Timer1.h"
/* #define ADC_TO_MILLIVOLT(a) ((5000 * (a)) / 1023)*/ /* maby use tabel instead*/
/* #define MILLIVOLT_TO_ADC(a) ((1023 * (a)) / 5000)*/ /* maby use tabel instead*/
int8_t a;
int16_t starting = getADC3Value();      /* controlls if startbutton is pushed*/
volatile uint16_t aValue = getADC1Value();    /* value assigned to aValue for use in calculateSettingDip*/
volatile int8_t setting = calculateSetting(getADC1Value()); /*Declare the global var setting for use in start dosing and timer0elapsed*/

if (starting > 0)           /* if start button is pressed the system starts by calling startDosing*/
{
startDosing();
}

Her er et par ting, som du måske ikke har lagt mærke til:

1: Hvornår skal 'starting' aflæses ?
2: Hvornår skal 'aValue' aflæses ?
3: Hvornår skal koden 'if(starting > 0)' bruges ?

Hvis du kunne få lov til at lave ovenstående kode, ville starting blive indstillet én gang, aValue ville blive indstillet én gang, og disse ville så begge være indstillet i starten af dit program, og derefter vil de kun ændre værdi, hvis du har en funktion, som ændrer værdien.
Koden 'if(starting > 0)' ville (igen, hvis du fik lov til det), kun udføres én gang, nemlig under opstart.

Hvis du har globale variabler, som skal tilskrives en startværdi (initialiseres), bør det være en konstant, for at du ikke kommer ud i noget skidt.
Altså, en god idé ville være enten:
Kode:
uint16_t gStarting = 0;         /* uint16_t, since getADC1Value() returns an uint16_t */
uint16_t gValue = 0;

Læg mærke til at jeg har ændret 'prefix', dvs. starten på 'starting' og 'aValue'. g står for 'global'.
Fordi: Hvis du nu havde en funktion, fx. 'calculateSettingDip(uint16_t aValue)', og du skulle bruge ovenstående 'aValue', ville du ikke kunne 'få fat i den', da argumentet har samme navn som din globale variabel.

Citér
Kode:
void timer0Elapsed()												  /* the dosing rutine*/
{
    if (setting == 1)||(setting == 5)||(setting == 9)||(setting == 13)
    {
        repeats = 10
    }
    else if (setting == 2)||(setting == 6)||(setting == 10)||(setting == 14)
    {
        repeats = 4
    }
    else if (setting == 3)||(setting == 7)||(setting == 11)||(setting == 15)
    {
        repeats = 2
    }
    else if (setting == 4)||(setting == 8)||(setting == 12)||(setting == 0)
    {
        repeats = 1
    }
    uint8_t a;
    uint16_t adc2Value;
    uint8_t Unload;
    Unload =0; /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/
    for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        startServo(200, adc2Value);
        /* unload: */
        waitSeconds(10);
        startServo(200, Unload);
    }
}

Compileren vil sikkert brokke sig her.
Prøv at holde alle erklæringer i toppen af dine rutiner/funktioner.
Fx.

Kode:
void timer0Elapsed()												  /* the dosing rutine*/
{
    uint8_t     a;
    uint16_t    adc2Value;
    uint8_t     Unload;

    if (setting == 1)||(setting == 5)||(setting == 9)||(setting == 13)
    {
        repeats = 10
    }
    else if (setting == 2)||(setting == 6)||(setting == 10)||(setting == 14)
    {
        repeats = 4
    }
    else if (setting == 3)||(setting == 7)||(setting == 11)||(setting == 15)
    {
        repeats = 2
    }
    else if (setting == 4)||(setting == 8)||(setting == 12)||(setting == 0)
    {
        repeats = 1
    }
    Unload =0; /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/
    for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        startServo(200, adc2Value);
        /* unload: */
        waitSeconds(10);
        startServo(200, Unload);
    }
}

-For så er du sikker på at det vil virke med alle compilere.
Dette er fordi der gøres plads til variabler når funktionen starter.
Enkelte compilere tillader dette som standard, men de fleste compilere skal have særlige indstillinger til at tillade dette, hvis de er i stand til at håndtere det.


Citér
er i tvivl om værdien setMinuteCountdown bliver sendt til Timer0.c

Tarveligt spørgsmål: Hvorfor er du i tvivl om dette ? :)

Citér
og så mangler jeg self lige pot reading men den tygger jeg lige på for 256 er måske nok i overkanten.
skal maks dosere 5 ml så det må være riligt med en opløsning på 20 svarende til ca 0,25 ml og med en tabel er det jo let at sætte range (de ms svarende til at rykke servoen) med andre ord så kan jeg sætte range på potten til kun at inkluderer værdier der giver mening i forhold til de grader der er til rådighed for den begrænset bevægelse af servoen i forhold til fuldt udsving på 180o jeg skal jo kun bruge en bevægelse på max 90o Håber det gav mening  :P

Jep. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 12, 2011, 13:15:07
Og her troede jeg jeg stillede et simpelt og hurtigt spørgsmål ha ha. tak for det fyldestgørende svar ;D

Citér
1: Hvornår skal 'starting' aflæses ?
2: Hvornår skal 'aValue' aflæses ?
3: Hvornår skal koden 'if(starting > 0)' bruges ?
Citér
kun udføres én gang, nemlig under opstart.
min ide var faktisk at atarting bliver aflæst og udført når jeg trykker på start knappen. værdien af denne er 0 når den ikke er trykket ned, så jeg sænkte at en if sætning der kontrolerer for en vrdi større end 0 ville være nok til at registrerer dette. aValue var min mening at denne kun skal sttes ved opstart. systemet skal ikke ændre sig med mindre at dips bliver stillet anderledes og der på ny trykkes på startknappen.
Den eneste værdi der løbende skal kunne opdateres er faktisk potmeteret. alle de andre der har med dosering og repeats at gøre skal sættes ved tryk på start og derefter forblive konstante. Det troede jeg faktisk at jeg havde opnået ved den kode jeg havde skrevet, men lurer lige på den for at se  om jeg kan finde Holger  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 12, 2011, 13:42:04
Og her troede jeg jeg stillede et simpelt og hurtigt spørgsmål ha ha. tak for det fyldestgørende svar ;D

Jeg kunne nok have valgt at give et kort svar, men du ville nok bedre kunne bruge at have baggrunden med.

Citér
Citér
1: Hvornår skal 'starting' aflæses ?
2: Hvornår skal 'aValue' aflæses ?
3: Hvornår skal koden 'if(starting > 0)' bruges ?
Citér
kun udføres én gang, nemlig under opstart.
min ide var faktisk at atarting bliver aflæst og udført når jeg trykker på start knappen.
værdien af denne er 0 når den ikke er trykket ned, så jeg sænkte at en if sætning der kontrolerer for en vrdi større end 0 ville være nok til at registrerer dette.

Det vil være bedst, at lave benet digitalt, hvis du kun har 1 knap på.
Så vil du kunne lave et pin-change interrupt.
Således vil denne pin-change interrupt rutine blive kaldt, så snart der er en ændring på start-knappen.
Bemærk: Jeg skriver ændring. :)
I dit pin-change interrupt bør du så finde ud af om knappen lige er blevet trykket ned, eller om den er sluppet.

Jeg vil vende tilbage til disse ting senere, for der indgår sikring mod prel i denne lille del af programmet. Det kan laves på flere måder.

Citér
aValue var min mening at denne kun skal sttes ved opstart. systemet skal ikke ændre sig med mindre at dips bliver stillet anderledes og der på ny trykkes på startknappen.

OK, så vil jeg bestemt anbefale at du ikke kalder den 'aValue', men noget som passer bedre, fx. gDipSwitches.

Men du bør gøre disse ting i din 'main' rutine, efter du har lavet alle initialiseringer, ellers får du slet ikke noget brugbart resultat, idét fx. ADC'en ikke er initialiseret, i/o-benet er sat til at være et digitalt input-ben, mm.

Desuden skal du lige have en forskrækkelse: 8)
Når du sætter strøm på microcontrolleren, starter den med at udføre noget tilfældigt (af din) kode, som du slet ikke har kontrol over.
Først efter nogle millisekunder, hoppes til starten af dit program.
Og hvad endnu værre er: Før starten af dit program udføres, kan alle variabler have fuldstændig tilfældige tossede værdier, selvom du har sagt at de skal starte med at være 0.
Men så snart den første linie i main() udføres, som er dét sted, dit program starter, så er der styr på tingene.

Citér
Den eneste værdi der løbende skal kunne opdateres er faktisk potmeteret. alle de andre der har med dosering og repeats at gøre skal sættes ved tryk på start og derefter forblive konstante. Det troede jeg faktisk at jeg havde opnået ved den kode jeg havde skrevet, men lurer lige på den for at se  om jeg kan finde Holger  :P

Dét er en ganske god måde at gøre det på. Godt design.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 12, 2011, 14:25:13
Citér
Men du bør gøre disse ting i din 'main' rutine

Ok så rykker jeg alle dip rutinerne samt startknap og hvad dertil hører over i main, efter initialiseringen. resultatet af repeats gør jeg så til en global variabel der kan bruges i dosing.c
Potmeter rutinen lader jeg blive i dosing.c

Citér
Desuden skal du lige have en forskrækkelse
havde regnet med noget i den stil men var ikke klar over om den gik ind i og udførte rutiner også. regnede bare med at den holdt sig uden for disse for det går jo ikke at den laver en eller anden tilfældig dosering eller for den sags skyld trækker et par tilfældige antal ml op i sprøjten, inden programmet "starter"

Citér
så vil jeg bestemt anbefale at du ikke kalder den 'aValue', men noget som passer bedre, fx. gDipSwitches.
Yup  :D

Citér
Jeg kunne nok have valgt at give et kort svar, men du ville nok bedre kunne bruge at have baggrunden med.
helt sikkert. tak  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 12, 2011, 17:09:31
Citér
Desuden skal du lige have en forskrækkelse
havde regnet med noget i den stil men var ikke klar over om den gik ind i og udførte rutiner også. regnede bare med at den holdt sig uden for disse for det går jo ikke at den laver en eller anden tilfældig dosering eller for den sags skyld trækker et par tilfældige antal ml op i sprøjten, inden programmet "starter"

Du kan selvfølgelig også være heldig at den nogle gange vil starte op i noget junk-kode som ikke har med din kode at gøre. :)
(dvs. resten af Flash-hukommelsen, hvor din kode ikke ligger), men hver gang microcontrolleren startes, udføres kode et tilfældigt sted i Flash-hukommelsen.


Chancen for at den laver tilfældige doseringer er nu ikke så stor.

Men der er en løsning, en rigtig god og sikker løsning, endda.

I dokumentationen for ATtiny24/44/84 står at det aller første som sker, når en ATtiny starter/resettes, er at alle I/O-registre bliver indstillet til en fast start-værdi. (Fx. alle i/o-porte bliver sat til input, så de ikke pludselig 'lægger arm' med noget andet hardware).

Kigger vi i ATtiny24/44/84's I/O-register liste, finder vi lidt forskellige registre, som ikke skal bruges i dit tilfælde.
Dem kunne vi selvfølgelig bruge, men der er noget endnu bedre, for Atmel har nemlig reserveret 3 registre helt til dig.

Disse 3 registre hedder GPIOR0, GPIOR1 og GPIOR2. Det er således dig selv, som bestemmer hvad disse skal bruges til.

Til at starte med, sættes disse til værdien 0 af microcontrolleren, før noget kode køres.

I Servo.h indsætter du følgende #define:
Kode:
#define SERVO_ENABLED  0xa8  /* our lucky number or something else, just not zero! */

I main.c, lige under #include "main.h", bør du så have...
Kode:
#include "Servo.h"

Kode:
void startButtonPushed()
{
    gSettings = calculateSettings(getADC1Value());  /* update our settings */
    /* ... perform other needed actions as needed ... */
}

int main()
{
    /* ... declared variables ... */

    GPIOR2 = SERVO_ENABLED;     /* This must be the first code executed; no code goes before it, and GPIOR2 is not to be changed from now on. */

    /* initialize global variables after the above line, but before the main loop, and ofcourse, before they're used. */

    /* ... initialization code: initADC(); initServo(); initTimer0(); etc... */

    /* Now we can use the ADC to get our initial settings: */
    startButtonPushed();    /* this line must be placed after the ADC is initialized, otherwise you won't get the right value. */

    /* ...main loop... */
}

Og så i rutinen startServo (som jeg regner med ligger i Servo.c), finder du den linie, som er årsag til at servoen starter (servoen må ikke kunne starte uden den linie), og sætter følgende kode rundt om:

Kode:
    if(GPIOR2 == SERVO_ENABLED)
    {
        /* the line of code that starts the servo, and nothing else. */
    }

Lidt forklaring:
Lad os antage at tilfældig kode bliver udført.
Rammer vi ind i den allerførste linie, som udføres, kan skaden ikke blive ret stor, fordi så bliver alt initialiseret som det skal, og alting kører som vi forventer.
Det kan være en rigtig god idé, at undgå at tilegne globale variabler en start-værdi, og så i stedet indstille denne start-værdi *efter* GPIOR2 = SERVO_ENABLED; - derved er du 100% sikker på at intet går galt.

Men hvis nu GPIOR2 = SERVO_ENABLED; står efter al initialisering, så er der mulighed for at kun denne linie bliver udført, og så har vi faktisk ikke fået initialiseret vores program, men i stedet har vi fået 'fortalt en løgn'. Derfor er det nødvendigt at der aldrig skrives noget kode før GPIOR2 = SERVO_ENABLED; linien.

Det samme med if(GPIOR == SERVO_ENABLED) - inde i denne if-sætning, bør der være så lidt kode som overhovedet muligt. Helst kun lige den linie, som er årsagen til at servoen starter, dvs. hvis du bruger PWM, så den enkelte kommando der skriver til I/O-registret der starter PWM'en.

Du kunne sådan set sætte if(GPIOR == SERVO_ENABLED) omkring hver eneste linie, som ændrer ved et I/O-register der har med servo'en at gøre.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 12, 2011, 17:15:25
Lige en ting til... GPIOR2 må ikke ændres andre steder i programmet; den må kun indstilles én gang, nemlig i starten af main. ;)
-Ellers bliver virkningen ødelagt.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 12, 2011, 19:30:13
Det vil jeg lige kigge på med det samme, og prøver at holde tungen lige i munden.

Og tænk, jeg troede bare det var et par linjer kode, da jeg startede det hele ha ha det var sq lettere i comal80 dagene  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 13, 2011, 17:10:13
Nu har jeg lavet en masse ændringer og mistet overblikket totalt  :-[.

Ville du have noget imod at gennemgå det med mig og så hjælpe mig med at lave en liste over hvad der mangler.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 13, 2011, 17:53:32
Nu har jeg lavet en masse ændringer og mistet overblikket totalt  :-[.

Sådan noget sker, selv for øvede. ;)
Derfor er det vigtigt at navngive tingene godt, og lave et godt system i hvor du lægger hvad.
Det er også godt med kommentarer ud for hver linie som laver et eller andet.
(Kommentarer er faktisk gode, når man skal finde fejl, for dér ser man, hvad hensigten med koden var, og så kan man checke efter om dén linie rent faktisk gør, som den skal).

Citér
Ville du have noget imod at gennemgå det med mig og så hjælpe mig med at lave en liste over hvad der mangler.

Nej, det vil jeg gerne. Prøv at pakke hele din mappe som .zip fil, og send den til mig via email.
Jeg kan dog nok ikke bruge så vældig meget tid på det lige nu, for jeg har noget haste-arbejde, der skal være færdigt i aften.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 14, 2011, 18:41:34
Tusind tak
Ville lige hører om du har fået min mail denne gang  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 14, 2011, 19:50:34
Ville lige hører om du har fået min mail denne gang  ;D

Jeps, du skulle på nuværende tidspunkt have modtaget et svar.
(Jeg havde vældig meget arbejde at lave; det trak helt ud til i dag, men nu har kunden fået det).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 17, 2011, 00:08:45
Perfekt takker mange gange. fedt du gad at lave en pdf , giver helt sikkert bedere mening.  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 17, 2011, 11:18:36
Perfekt takker mange gange. fedt du gad at lave en pdf , giver helt sikkert bedere mening.  :P

Sig til hvis der er noget, som stadig ikke rigtigt vil.

Det er forresten en god idé at compile efter hver ændring du laver, dvs. skriver du en ny rutine, gælder det for én ændring. Retter du en fejl, gælder det for én ændring, osv. :)
På den måde skulle du ikke komme ud i for stort bøvl. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 17, 2011, 14:55:44
Så fik jeg lavet rettelserne og der dukkede et par nye op i compileren, men de er rettet og den compiler nu uden fejl næsten.  ;D

i dosing.c  har jeg tilføjet linjen
volatile uint8_t gSettings;

men får fejlen
Error   1 conflicting type qualifiers for 'gSettings'
med henvisning til en anden rettelse i dosing.h hvor du skriver jeg bør sætte følgende.
extern uint8_t gSettings;

hvis jeg fjerner volatile foran uint8_t forsvinder fejlen.

endvidere får jeg også en fejl i main.c
gSettings = calculateSettingsDip(getADC1Value());
undefined reference to `calculateSettingsDip'   og det samme til getADC1Value
i funktione
void startButtonPushed()
{
    gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
    /* ... perform other needed actions as needed ... */
}
så kommenterer den lige ud til jeg ved hvorfor.
calculateSettingsDip bliver jo defined i dosing.c og uint16_t getADC1Value(); i adc.h

Citér
Du vil sikkert gerne have tallet i grader, så vidt jeg kan forstå.
nej det behøver ikke at være i grader. tallet repræsenterer bare grader men skal vel egentligt være en definition på længden af high (0.8 - 2.2 ms) i 20 ms cyclen




Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 17, 2011, 17:19:14
Så fik jeg lavet rettelserne og der dukkede et par nye op i compileren, men de er rettet og den compiler nu uden fejl næsten.  ;D

i dosing.c  har jeg tilføjet linjen
volatile uint8_t gSettings;

men får fejlen
Error   1 conflicting type qualifiers for 'gSettings'
med henvisning til en anden rettelse i dosing.h hvor du skriver jeg bør sætte følgende.
extern uint8_t gSettings;

hvis jeg fjerner volatile foran uint8_t forsvinder fejlen.

Kan du i Dosing.h lave følgende...
Kode:
extern volatile uint8_t gSettings;

og i Dosing.c ...
Kode:
volatile uint8_t gSettings;

-Hvis den godtager dette, vil jeg anbefale det på dén måde.

Citér
endvidere får jeg også en fejl i main.c
gSettings = calculateSettingsDip(getADC1Value());
undefined reference to `calculateSettingsDip'   og det samme til getADC1Value
i funktione
void startButtonPushed()
{
    gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
    /* ... perform other needed actions as needed ... */
}
så kommenterer den lige ud til jeg ved hvorfor.
calculateSettingsDip bliver jo defined i dosing.c og uint16_t getADC1Value(); i adc.h

Prøv at se om den i Dosing.h hedder noget andet end calculateSettingsDip.
Det kan være den dér også skal rettes.
Hvis compileren derefter brokker sig over calculateSettingsDip i Dosing.c, skal denne så også rettes, så de passer til hinanden.
Bemærk, at i headerfilen skal linien have et semikolon til slut, fx.
Kode:
uint8_t calculateSettingsDip(uint16_t gDipSwitches);

Citér
Citér
Du vil sikkert gerne have tallet i grader, så vidt jeg kan forstå.
nej det behøver ikke at være i grader. tallet repræsenterer bare grader men skal vel egentligt være en definition på længden af high (0.8 - 2.2 ms) i 20 ms cyclen

Jeg er desværre ikke helt klar i hovedet i dag; jeg har gået influenza, så jeg kan ikke så nemt koncentrere mig om disse ting...  :-\
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 17, 2011, 20:15:06
ØV da. men det er jo ved at være sæsson for det skidt.
det hjalp med rettelserne nu er det kun undefined reference to `getADC1Value'    men har efterhånden gennemskuet hvad det betyder, så skal nok finde den  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 17, 2011, 21:32:15
det hjalp med rettelserne nu er det kun undefined reference to `getADC1Value' men har efterhånden gennemskuet hvad det betyder, så skal nok finde den  :P

Jeg synes faktisk du har klaret det rigtig godt; når der kun er én fejl tilbage. Det betyder at du har lært rigtig meget omkring hvad du skal kigge efter når der er compile-fejl. :)

"Prototypen" på getADC1Value() burde være i ADC.h.
Selve koden bør så ligge i ADC.c.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 22, 2011, 18:52:49
der skete lige en katastrofe. Ophænget på min HQI lampe knækkede og lampen faldt i baljen. Og som elektrikker kan jeg jo så sidde og være bagklog, og sige at jeg måske burde have haft jord på noget der hænger over 400 l vand  :o
Pinligt men den lå altså i ca 4 timer i vandet inden jeg kom hjem, uden at trække hpfi eller baller sikringer. ikke godt. mange døde koraller og andre sager. øv øv
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 22, 2011, 19:49:29
der skete lige en katastrofe. Ophænget på min HQI lampe knækkede og lampen faldt i baljen.

Det er jeg ked af at høre. :(

Citér
Og som elektrikker kan jeg jo så sidde og være bagklog, og sige at jeg måske burde have haft jord på noget der hænger over 400 l vand  :o
Pinligt men den lå altså i ca 4 timer i vandet inden jeg kom hjem, uden at trække hpfi eller baller sikringer. ikke godt. mange døde koraller og andre sager. øv øv

Vand er faktisk ikke elektrisk ledende. Det er først når der er tilsat mineraler (fx. i postevand er der ofte mineraler, men ikke altid ret mange - det kan variere kraftigt fra boring til boring). Hvis man tilsætter salt, bliver ledeevnen i vandet straks meget stærkere.

-Så det er ikke engang sikkert at en korrekt HPFI installation ville hjælpe dér.

Men uanset - så er det vældig ærgeligt.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 24, 2011, 14:00:35
Så. Nu fik jeg nogenlunde balance i akvariet igen, og der er kun tilbage at krydse fingre for at der er noget der overlever. Til gengæld vil jeg simpelthen blive færdig med den prototype nu, så arbejder fuldtid på den fra i dag igen.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 25, 2011, 03:43:53
Så. Nu fik jeg nogenlunde balance i akvariet igen, og der er kun tilbage at krydse fingre for at der er noget der overlever. Til gengæld vil jeg simpelthen blive færdig med den prototype nu, så arbejder fuldtid på den fra i dag igen.

Jeg håber selvfølgelig at alt går godt. Jeg vil være travlt optaget en uge frem, da jeg arbejder på en hasteopgave, så jeg vil nok ikke være så hurtig til at sende svar tilbage.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 25, 2011, 22:41:02
Citér
da jeg arbejder på en hasteopgave
Jobbet skal selvfølgelig passes  :D

Det jeg mener jeg mangler er:
1. at få lavet pot conversion og få den til at leverer en værdi der ændre high i 20 ms PWM cyclen jf.
(http://winavr.scienceprog.com/sites/default/files/images/stories/2007/Servo/servo_pulse_width.jpg)
ergo værdier fra 0.8 ms til 2.2
(skal nok kun bruge værdier fra 1.2 - 1.8 men er ikke sikker endnu)

2. få lavet startknappen således at programmet starter med 1 dosering når denne trykkes ned, og der efter ud fra hvordan det er defineret i dips.
3.
Citér
Men med henblik på dette, har jeg en forbedring af dette system; mere herom senere.
Ud over dette, så mangler vi stadig argumenterne til startServo.
Jeg mener vi helt skal tømme 'initServo()', så den bliver helt tom.
fra den pdf du sendte (fejl nr 17)
4.
Citér
Vi har ikke beregningen af frekvensen endnu, så jeg har udkommenteret linierne den bruges i, indtil videre.
fra den pdf du sendte (fejl nr 19)

i forhold til førstnævnte er det svært at finde tutorials der ikke bare er lavet i assembly, men leder videre.


Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 27, 2011, 13:35:14
Jeg er stadig igang med det tidligere nævnte projekt, men vil lige sende dig lidt...

Da jeg kiggede på Dosing.c, kom jeg til at tænke på at koden kan reduceres en smule:

Kode:
void timer0Elapsed()
{
    static const uint8_t repTable[] PROGMEM = { 1, 10, 4, 2 };
    uint8_t repeats;
    uint8_t a;
    uint16_t rotation;
    uint8_t unload;

    unload = 0;    /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/

    repeats = pgm_read_byte(&repTable[gSettings & 0x03]);

    for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        rotation = getADC2Value();
        startServo(200, rotation);
        /* unload: */
        waitSeconds(10);
        startServo(200, unload);
    }
}

Som du ser, er alle 'if' sætningerne erstattet med et enkelt tabel-opslag.
Dette kan vi gøre, da vi med bit-AND filtrerer de to nederste bits ud (dvs. bit 0 og bit 1).

Det samme system kan bruges i startDosing:
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 };

    setMinuteCountDown(pgm_read_word(&timeTable[(gSettings >> 2) & 0x03]));
    timer0Elapsed();
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 28, 2011, 12:54:27
ahh smart  :P

Håber du når din hasteopgave. det er altid rart at blive presset lidt he he
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 31, 2011, 20:33:08
Hej igen. Det er godt nok ved at blive en lang tråd det her. Ved ikke helt om det er pinligt he he

har prøvet at se på pin change interrupt, til startknappen, og her er hvad jeg kom frem til.
Har smidt det hele i main.c

Kode:
int main()
{
    GPIOR2 = SERVO_ENABLED; /* This must be the first code executed; no code goes before it, and GPIOR2 is not to be changed from now */
initADC(8);     /* initialize ADC, we'll use the 8-bit precision for now */
    initTimer0();
    initDosing();
    initServo();
sei();       /* globally enable interrupts */
   
PCMSK0 |= (1<<PCINT3);                          /*Set PA3 as the pin to use*/
MCUCR = (1<<ISC01);                             /*interrupt on INT0 pin falling edge*/
GIMSK  |= (1<<INT0);                            /*turn on interrupts*/

while(1)
{
/* we don't really need to do anything here. Everything is handled by the interrupts */
}
    return(0);      /* (never reached) */
}
SIGNAL (SIG_PCINT3)
{
   gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
}

Vil det virke ??
Er ikke lige sikker på det med rising, faling eller any logical change, i forhold til MCUCR

Læste et andet sted at man brugte en internal pull up og så havde knappen på fra jord til PA3 men ved ikke om attiny også kan det og om det overhovedet kan betale sig.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Oktober 31, 2011, 22:05:54
Hej igen. Det er godt nok ved at blive en lang tråd det her. Ved ikke helt om det er pinligt he he
Det synes jeg ikke. Tværtimod; der vil nok være mulighed for at andre kan få løst deres problemer, ved at kigge lidt i tråden. :)

Desuden er du snart kommet hele turen rundt i microcontrolleren. Der er selvfølgelig stadig nogle ting du ikke har prøvet, fx. UART/USART (serielt interface) og nogle andre småting, men det meste af hvad microcontrolleren kan, har du snuset til nu; og så har du også prøvet at bruge interrupts, hvilket er noget de fleste venter med, til der er gået lidt over et år.
-Men interrupts er gode at bruge, hvis man har muligheden.

Citér
har prøvet at se på pin change interrupt, til startknappen, og her er hvad jeg kom frem til.
Har smidt det hele i main.c

Kode:
	PCMSK0 |= (1<<PCINT3);                          /*Set PA3 as the pin to use*/
MCUCR = (1<<ISC01);                             /*interrupt on INT0 pin falling edge*/
GIMSK  |= (1<<INT0);                            /*turn on interrupts*/


Åbn først dette datablad (http://www.atmel.com/dyn/resources/prod_documents/doc8183.pdf).

PCMSK0 ... ben 10 (PA3) enables, dette er som det skal være.
PCMSK0 finder du på side 52, dér står noget interessant omkring GIMSK.
GIMSK INT0 (ben 5, PB2) enables. Fint, men der er flere interrupts, som du gerne vil enable i dette I/O-register.
På side 50 finder du GIMSK, men det er først øverst på side 51, der står noget du skal bruge. :)


MCUCR ... bør ikke OR'es. Denne bør skrives på denne måde:
Kode:
MCUCR = (1 << ISC01) | (0 << ISC00);     /* interrupt on INT0 pin, falling edge */
-Fordi... Hvis MCUCR's laveste bit bliver sat et andet sted i koden, vil du få rising edge i stedet for falling.
(Det er ikke tilfældet i dette program, men hvis du senere plukker noget kode ud og bruger et andet sted, vil der gå ged i det).

Citér
Kode:
SIGNAL (SIG_PCINT3)
{
   gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
}

På side 47 ser du en oversigt over interrupt-vektorerne.
SIG_PCINT3 bliver aldrig kaldt. Se side 47 i databladet, der vil du se at der er kun PCINT0 og PCINT1 (dvs. SIG_PCINT0 og SIG_PCINT1). Hvilken én skal bruges ? :)

Derudover... Hvor er SIG_INTERRUPT0 ?

[/quote]Vil det virke ??[/quote]

Mjae, men ikke efter hensigten. ;)

Citér
Er ikke lige sikker på det med rising, faling eller any logical change, i forhold til MCUCR

Der er en ting mere omkring PINCHANGE interrupts...
Du bør sikre mod prel (glitches), for når brugeren trykker på knappen, vil du få mellem 10 og 50 interrupts!
Dette er fordi der springer gnister mellem kontakt-fladerne på knappen.

Du kan løse det på en let måde, eller en avanceret måde. Til at starte med, tror jeg det er bedst med den lette måde.
For at sikre mod prel, er det en god idé at finde ud af om knappen er trykket ned eller sluppet, derefter vente 5 ... 10 millisekunder, og så læse igen om den er trykket ned eller sluppet. Har den ændret værdi, så glem at der skete noget.

Pin-change interruptet bliver kaldt både når en knap trykkes ned, og når knappen slippes.
Derfor skal vi læse om benet er LOW, når vi kommer ind i vores pin-change interrupt, og derefter vente 5...10 millisekunder, og derefter læse benets værdi og se om det stadig er LOW...

Kode:
SIGNAL (SIG_PCINT?)
{
    uint8_t pinValue;

    pinValue = PINA & (1 << PINA3);                             /* read value of input-pin */
    if(0 == pinValue)                                           /* we're only interested if button is pressed */
    {
        _delay_ms(10);                                          /* wait 10 ms */
        pinValue = PINA & (1 << PINA3);                         /* read value of input-pin */
        if(0 == pinValue)                                       /* only update settings when button value is stable */
        {
            gSettings = calculateSettingsDip(getADC1Value());   /* update our settings */
        }
    }
}


Citér
Læste et andet sted at man brugte en internal pull up og så havde knappen på fra jord til PA3 men ved ikke om attiny også kan det og om det overhovedet kan betale sig.

Det er faktisk dét de ar lavet til, så det kan du godt. :)

Dér skal du så sige...
Kode:
DDRA &= (1 << DDRA3);  /* set pin as input (you probably already set it to be input) */
PORTA |= (1 << PA3);   /* enable internal pull-up resistor */

Det kan altid betale sig at spare komponenter (hvis altså kvaliteten af produktet ikke forringes) - for selv en SMD-modstand til 0.02 øre koster 1 kr. at montere for en maskine. Dertil kommer prisen på printet. Her koster hver kvadratmillimeter penge. Du finder ud af på et tidspunkt, at printplader er dyre at få lavet, og derfor vil du gerne have lavet dem så små som muligt; derved kan du få lavet en hel masse boards på samme plade (dette kaldes panelizing).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Oktober 31, 2011, 23:12:39
Citér
SIG_PCINT3 bliver aldrig kaldt. Se side 47 i databladet, der vil du se at der er kun PCINT0 og PCINT1 (dvs. SIG_PCINT0 og SIG_PCINT1). Hvilken én skal bruges ? :)
Det er SIG_PCINT0. Den er til alle PA ben mens PCINT1 er til PB benene

Citér
Derudover... Hvor er SIG_INTERRUPT0 ?
Her forstår jeg ikke hvad du mener ?
Jeg troede at
SIGNAL (SIG_PCINT0)
{
   gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
}

Var nok til at registrerere om der er et interrupt

Citér
derefter vente 5...10 millisekunder
Smart !

Citér
Det kan altid betale sig at spare komponenter
Det kan være at jeg ændre det på en senere version. lige nu bruger jeg bare den knap jeg har lavet med "ekstern" pull down

Citér
GIMSK INT0 (ben 5, PB2) enables. Fint, men der er flere interrupts, som du gerne vil enable i dette I/O-register.
ændret til GIMSK  |= (1<<PCINT3);

Læser og læser side 50-52  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 01, 2011, 06:39:22
Citér
SIG_PCINT3 bliver aldrig kaldt. Se side 47 i databladet, der vil du se at der er kun PCINT0 og PCINT1 (dvs. SIG_PCINT0 og SIG_PCINT1). Hvilken én skal bruges ? :)
Det er SIG_PCINT0. Den er til alle PA ben mens PCINT1 er til PB benene

Korrekt. :)
Så nu ved du, at man kan bruge ét Pin-Change interrupt til at holde styr på 8 indgange. Ulempen er at man er nødt til selv at læse indgangene og undersøge hvad der er 1 og hvad der er 0, men alt i alt er det et fint system, at man kan have interrupt på hvert i/o-ben. :)

Citér
Citér
Derudover... Hvor er SIG_INTERRUPT0 ?
Her forstår jeg ikke hvad du mener ?
Jeg troede at
SIGNAL (SIG_PCINT0)
{
   gSettings = calculateSettingsDip(getADC1Value()); /* update our settings */
}

Var nok til at registrerere om der er et interrupt

Jep, det er korrekt. Men du sætter INT0 op, som er ben 5, PA2. INT0 er ikke et PCINT, men et selvstændigt interrupt (som har prioritet over PCINTs). Derudover kan du bestemme hvordan INT0 skal trigges. :)
Jeg går ud fra at du ikke er interesseret i at trigge et interrupt på ben 5; dette vil sige at du ikke behøver INT0.

Grundlæggende for AVR er:
1: Skriv en interrupt-rutine
2: Eventuelt clear interrupt-flag, så interruptet ikke udføres med det samme (se TIFR0, TIFR1 på side 84)
3: Hvis det fx. er et timer-interrupt, så sæt timer-delen op (TCNTx, OCRxA, OCRxB, opførsel: TCCRxA, TCCRxB)
4: Sæt Enable-bitten for det valgte interrupt (fx. GIMSK for generelle interrupts eller TIMSK for timer interrupts)
5: Hvis I-bitten ikke er sat, udfør da en SEI instruktion, som enabler interrupts (dette gør vi efter alt init, så denne del er iorden). -Så skulle det køre. Generelle interrupts er således lette at sætte op, mens timere og andet kræver lidt konfiguration.

Citér
Citér
Det kan altid betale sig at spare komponenter
Det kan være at jeg ændre det på en senere version. lige nu bruger jeg bare den knap jeg har lavet med "ekstern" pull down

OK, det er helt fint, men hvis du har pulldown på, vil den normalt ligge LOW, hvilket vil sige at du skal kigge i dit PCINT0 om den er HIGH. :)
Citér
ændret til GIMSK  |= (1<<PCINT3);

Fint, dette er korrekt.

Citér
Læser og læser side 50-52  :P

Lige netop de sider er rigtig guf, for der står meget information omkring interrupts. Det er ikke så indviklet, når det kommer til stykket.

Med hensyn til PA3, kan man gøre noget der er endnu smartere, men dette er foreløbig kun teori. :D

Hvis du kigger på databladet's side 2, ser du at PA3 også har en anden funktion, nemlig T0. Prøv at se på side 113, her står at T0 (og T1) kan bruges som ekstern clock-source til Timer0 (T1 til Timer1).

Hvad betyder så det?
-Jo, hvis vi kan få Timer0 til automatisk at starte, hver gang T0 ændres, fx. fra LOW til HIGH, kan vi starte en timer, der venter 10 ms. Når denne timer når fx. sit maks overflow kunne vi så få den til at starte SIG_OVERFLOW0 interruptet.
Det betyder at vi kan indbygge prel-sikring på denne måde, og derfor behøver vi ikke at vente de 10 ms med _delay_ms(10), men kan få interruptet til at klare den sag.

Det 'kedelige' ved at bruge _delay_ms(10), er at microcontrolleren er optaget med at tælle en variabel ned i de 10 ms. Det gør selvfølgelig ikke noget i dette tilfælde, da vi ved at brugeren jo sidder og holder knappen inde, så det er ikke kritisk at bruge interrupt på dette sted.
...Hvorfor skriver jeg så at det foreløbig kun er teori ?
Jo, for vi bruger allerede Timer0 til at tælle sekunder, minutter og timer. Derfor vil det være meget godt at lade den være som den er. ;)
Vi vil helst ikke bruge Timer1 til at tælle sekunder, minutter og timer, fordi Timer1 er en 16-bit timer, som kan bruges til langt bedre ting (fx. servo-PWM), men jeg synes du lige skulle have at vide at man kunne bruge T0 på denne måde.

I mit lille spil-konsol (http://avr.bruger.mine.nu/Circuit.png), har jeg lavet en forbindelse fra OC1A til T0, hvilket vil sige at jeg bruger Timer1 til at lave en 31kHz frekvens, og Timer0 tæller så hver puls som Timer1 giver.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 02, 2011, 14:25:55
Hej igen
Har lige et spørgsmål klidt uden for emnet.
Jeg skal jo have noget nyt lys over mit akvarie, da hqi er aaaalt for dyrt og da jeg ikke vil risikerer at der sker et uheld igen.
Jeg har bestilt 5 10w led Forward voltage: 9-12V DC, Forward current: 1000mA.
Jeg har tænkt mig selv at lave drivers til dem, men vil lige spørge om der er noget jeg skal være særligt opmærksom på.
Jeg ved at det er et helt anden projekt, men er lige nød til at have lys over baljen igen. Til at starte med skal der ikke være nogen form for styrring, men når dosering systemet er færdigt har jeg tænkt mig at prøve at overføre alle principper til en styrring af lyset, til at simulerer sol op og ned -gang. men til at starte med skal det bare være en driver der kan drive 10w leds, enten 1 driver til alle 5 eller en driver pr stk.
Det ville være lettest at driveren kan kobles på 230v
har du et godt forslag
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 02, 2011, 15:21:33
Jeg har bestilt 5 10w led Forward voltage: 9-12V DC, Forward current: 1000mA.

Dvs. hver LED bruger 1A, i alt 5A lagt sammen.

Det er egentlig meget simpelt. Til at starte med skal du bare have fundet en strømforsyning på 10V/5A (eller højere antal ampere), for vi kan ikke have at strømforsyningen futter af, pga. der trækkes for meget strøm.

Hos RS kan man købe nogle switch-mode strømforsyninger til fornuftige priser. Prøv at se denne side (http://dk.rs-online.com/web/c/stroemforsyninger/stroemforsyninger-dc-til-dc-konvertere-generatorer/eksterne-stroemforsyninger/). Desværre har jeg lidt bøvl med at se netop denne side selv, da den ikke virker i Safari.
Klik ude i venstre side på udgangsspænding, vælg udgangsspænding, derefter klik på udgangsstrøm og vælg 5A og alt over 5A. Så burde du få nogle fornuftige resultater.

Alternativt kan du prøve at se om du falder over en strømforsyning til en bærbar PC, som er på 12V/5A. Chancen for dette er nok minimal. Der er selvfølgelig også mulighed for at rippe en gammel PC der er på vej på lossepladsen; der sidder nemlig ofte en kraftig strømforsyning i sådan nogle gutter.

Hvis vi antager at du senere skal lave en styring disse LEDs, kan du sætte en TIP127 transistor på (klarer lige akkurat 5A), eller en BDX34C eller BDW46G. Men du skal lige have en BC546/BC547/BC548 på inden da; tilbage til dette senere.
Det er en god idé altid at have et par TIP127 liggende. Du kan eventuelt lave individuel styring på alle 5 LEDs, så behøver du kun at bruge TIP127; eller to stk. TIP127 til at styre 2 og 3 LEDs, så er du sikker på ikke at trække for meget strøm gennem transistoren.

Tilbage til BC547 (og lignende)...
Fra microcontrolleren's i/o-ben sætter du en 1K modstand over til basis på BC547. Emitter sætter du til GND. På collector sætter du en 47K modstand til +12V. Yderligere fra collector sætter du en 1K modstand til TIP127's basis.
TIP127's emitter sætter du til +12V. Fra TIP127's collector sætter du en 1N400x, så anoden's ende er mod collector, og kathoden's ende er på +12V.
Output får du mellem GND og collector på TIP127. :)

Nu kan du styre jævnspænding op til 45V/5A med en microcontroller (hvis du bruger BC547).
Har du brug for op til 65V, bør du bruge BC548.
Så kan du bare gange op med det antal udgange du vil styre. =)
Du kan sætte en DC-motor direkte på denne udgang (da den er beskyttet af 1N400x; og også en intern diode i TIP127).

Og ups. På diagrammet nedenfor har jeg glemt at angive +12V; det er selvfølgelig øverst i højre hjørne. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 02, 2011, 15:59:23
Citér
Det er egentlig meget simpelt. Til at starte med skal du bare have fundet en strømforsyning på 10V/5A

ok

Har aldrig helt forstået hvorfor man ikke bare smider en omformer på, istedet for en driver. er det bare et salgstrik at de vil have os til at købe drivers frem for en alm strømforsyning.
Er det ikke sådan at en led trækker al den strøm den har til rådighed, også selv om at det er mere end den kan tåle, og det vil jo være spild af watt at have modstande til at styrre dette
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 02, 2011, 16:11:06
Citér
Det er egentlig meget simpelt. Til at starte med skal du bare have fundet en strømforsyning på 10V/5A

ok

Har aldrig helt forstået hvorfor man ikke bare smider en omformer på, istedet for en driver. er det bare et salgstrik at de vil have os til at købe drivers frem for en alm strømforsyning.
Er det ikke sådan at en led trækker al den strøm den har til rådighed, også selv om at det er mere end den kan tåle, og det vil jo være spild af watt at have modstande til at styrre dette

Mht. LED der trækker strøm. Både ja og nej. Jeg har set folk sætte en LED direkte på en 3V forsyning uden at deres LED brænder af - men det kan være det er et spørgsmål om tid.

Har du en alm. LED på 3V/20mA og en 5V forsyning, så er dit officielle max-output med en modstand på 100 ohm, da der skal ligge 3V over LED'en og 2V over modstanden, og der går 20mA gennem begge.
2V / 20mA = 100 ohm.

Nogle lysdioder er lavet til at køre på 12V og har 'indbyggede modstande'.

En LED driver er sådan set et vidt begreb.
Fx. en microcontroller der skal styre et 7-segment display med 4 cifre, kunne have gavn af en driver, for driveren gør det nemmere at holde lys i alle cifre på én gang.
Med andre ord: Her er driverens opgave at give ampere nok til LED'ne.

Men jeg kan forestille mig at der findes LED drivere, som jeg ikke har nogen forstand på. For eksempel kan man købe nogle kraftige LED-moduler, og disse har brug for en eller anden type driver siges der. Nu har jeg aldrig selv brugt sådanne moduler, så i dette tilfælde bliver jeg dig svar skyldig.
Jeg kunne forestille mig at sådanne drivere pulser LEDne og skifter hurtigt mellem hver LED, så i alt bliver der kun brugt 1A selvom alle LEDs lyser 'på samme tid'. Lyset bliver en smule svagere, med mindre man båler lidt op for spændingen. Se datablad på LED-modulet for at se hvor meget man kan give den i overspænding. (Dette gælder også almindelige 3mm, 5mm og SMD LEDs)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 02, 2011, 16:32:23
ok.
Så vidt jeg har kunnet læse mig til så er driverens formål at sikre at der ikke bliver leveret mere end eks 1 amp til  10w led
det kan jo gå hen og koste temmelig mange penge at brænde dem af specielt hvis man kører med cree
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 05, 2011, 15:54:45
Citér
OK, det er helt fint, men hvis du har pulldown på, vil den normalt ligge LOW, hvilket vil sige at du skal kigge i dit PCINT0 om den er HIGH.

vil det sige at MCUCR skal være rising edge ?
eller skal pinValue sættes til at være > 0
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 05, 2011, 22:45:44
Citér
OK, det er helt fint, men hvis du har pulldown på, vil den normalt ligge LOW, hvilket vil sige at du skal kigge i dit PCINT0 om den er HIGH.

vil det sige at MCUCR skal være rising edge ?

Du kan ikke sætte MCUCR til at være rising edge på andet end INT0.
INT0 og PCINT0 er to forskellige ting.
PCINT0 og PCINT1 er af samme type. Disse to interrupts håndterer flere hver pins på samme tid.
INT0 interruptet har højere prioritet end PCINT interrupts. Du kan også styre det mere nøjagtigt, men der er kun én pin der er forbundet til dette interrupt, nemlig ben 5.

Citér
eller skal pinValue sættes til at være > 0

Jeg anbefaler at lave if-sætningen således (dvs. mit fokus er kun på den ene linie med 'if'):

Kode:
if(pinValue)
{
    /* pin is high, button is pressed */
}
else
{
    /* pin is low, button not pressed */
}

-Undgå altså at bruge større-end, som nedenstående, når du sammenligner værdier du laver bit-operationer på...

Kode:
if(pinValue > 0)
{
    /* pin is high, button is pressed */
}

-Det først-nævnte er renere / bedre logik, for pinValue kan enten være nul eller ikke-nul.
Det har vi sikret os ved at lave en 'bitwise and' tidligere.

(Det er selvfølgelig ikke en katastrofe, da vi er ovre i bagatel-afdelingen, men efterhånden som man arbejder med kode, finder man mere og mere ud af, hvordan man undgår uheldige - næsten usynlige - fejl der sniger sig ind. Årsagen til min anbefaling er baseret på at man senere ændrer lidt i koden).

Hvis det er helt rigtigt, ville det være mest korrekt at sætte pinValue således:
Kode:
    pinValue = (PORTA >> PCINT3) & 1;

Så vil pinValue enten være 0 eller 1.
-Men den færdige binære fil vil fylde mere, end hvis du gør følgende:

Kode:
    pinValue = PORTA & (1 << PCINT3);

-Fordi compileren kan reducere (1 << PCINT3) til tallet 8, hvor der ellers skal indsættes ekstra maskinkode, for at få bitten ned på nederste position; her afhænger kodestørrelsen af hvor mange bitpladser bitten skal flyttes.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 07, 2011, 22:11:27
Jeg fik en fejl på Prel funktionen så lagde følgende linje ind i starten af main.c
#include <util/delay.h>

Det gav mig så en fejl om at F_CPU bliver redefined, da den  bliver defined både i <util/delay.h> og <main.h>
så jeg lagde #include <util/delay.h> ned under #include <main.h>

Startkanp funktionen lavede jeg om til flg.
Kode:
SIGNAL (SIG_PCINT0)
{
    uint8_t pinValue;

    pinValue = PINA & (1 << PINA3);                             /* read value of input-pin */
    if(pinValue)                                                 /* we're only interested if button is pressed */
    {
        _delay_ms(10.);                                         /* wait 10 ms */
        pinValue = PINA & (1 << PINA3);                         /* read value of input-pin */
        if(pinValue)                                            /* only update settings when button value is stable */
        {
            startDosing();
        }
    }
}

Eneste ændring er at if sætningerne er ændret til
if(pinvalue)
istedet for
if(0==pinvalue)
samt at jeg smed et kald til startdosing() ind

Går ud fra at det løser problemet med at jeg bruger pull down og ikke pull up

Jeg går også ud fra at flg. bliver overflødigt i ADC.c
Kode:
uint16_t getADC1Value()
{
    return(getADCValue(1)); /* ADC value of startbutton */
}

Hvis ovenstående er korrekt så tror jeg kun at jeg mangler pot til PWM funktionen til servoen
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 07, 2011, 22:28:19
Jeg fik en fejl på Prel funktionen så lagde følgende linje ind i starten af main.c
#include <util/delay.h>

Det gav mig så en warning (nogen gange) om at F_CPU bliver redefined, da den også bliver defined i <util/delay.h>
Ved ikke lige hvad jeg skal gøre ved den, for hvis jeg fjerner den fra main.c er der andre dele der brokker sig. Jeg kan self lave en #include <util/delay.h> i de andre .c som gør brug af F_CPU, men det virker som en lidt "beskidt" metode.

Det rigtige er at gå ind i din Makefile og definere den dér.
Godt råd:Lav en backup først!

Toppen af min Makefile ser nogenlunde sådan ud:

Kode:
TARGET     = LightControl-Test1
DEVICE     = atmega164p
CLOCK      = 8000000

Af disse linier skal du kun indsætte 'CLOCK = (frekvens)' i din Makefile.

Senere er der et sted, hvor compileren får sine parametre, linien kunne se nogenlunde således ud, men det er ikke sikkert...

Kode:
COMPILE = avr-gcc -Wall -Os -mmcu=$(DEVICE)

Hvis den gør det, så indsæt '-DF_CPU=$(CLOCK)' nogenlunde således...

Kode:
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE)

Citér
Startkanp funktionen lavede jeg om til flg.
{snip}
Går ud fra at det løser problemet med at jeg bruger pull down og ikke pull up

Det ser fint ud og burde løse det..

Hvis du ikke kan få defineret F_CPU i din Makefile, så kan du definere den før du inkluderer <avr/delay.h>; men det er korrekt at definere den i din Makefile, for så kan alle dele af source-koden se den.

Her er lidt advarsel om Makefile...
Der er forskel på hvad space og tab betyder, så hvis der er mellemrum, må du ikke erstatte dem med tabuleringer og er der tabuleringer må de ikke erstattes af mellemrum!
-Vældig uintuitivt, men gutterne der engang for længe siden opfandt Make mente at det var smart på det tidspunkt (hvilket det sikkert også var, så jeg vil ikke slå dem oveni hovedet).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 07, 2011, 22:39:39
Super.
jeg lagde #include <util/delay.h> ned under #include <main.h>
Det løste det, men ændre dette igen så det stemmer overens med det du siger om make filen

så tror jeg kun at jeg mangler pot til PWM funktionen til servoen :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 10, 2011, 21:29:24
Kan kun finde assemble eksempler på hvordan den servo funktion skal laves, så er faktisk lidt blank syntes jeg  :-[
Har du et forslat til hvor jeg skal kigge ??
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 10, 2011, 23:14:04
Kan kun finde assemble eksempler på hvordan den servo funktion skal laves, så er faktisk lidt blank syntes jeg  :-[
Har du et forslat til hvor jeg skal kigge ??

Prøv at sende mig nogle links til de assembler-ting du har fundet, måske kan jeg 'konvertere' noget af det til C.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 11, 2011, 16:07:54
Tusind tak. her er de links jeg har kigget på
http://winavr.scienceprog.com/comment/52 (http://winavr.scienceprog.com/comment/52)
http://blog.roderickmann.org/2006/01/atmega32-pwm/ (http://blog.roderickmann.org/2006/01/atmega32-pwm/)
http://www.societyofrobots.com/member_tutorials/node/231 (http://www.societyofrobots.com/member_tutorials/node/231)

Den øverste kan jeg ikke helt greje om den er i c
De er alle 3 tutorials til en at mega men det er vel bare et spørgsmål om hvordan der addresseres

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 11, 2011, 17:49:12
Advarsel: Forfærdeligt langt indlæg, uha-uha-uha...
Tusind tak. her er de links jeg har kigget på
http://winavr.scienceprog.com/comment/52 (http://winavr.scienceprog.com/comment/52)
http://blog.roderickmann.org/2006/01/atmega32-pwm/ (http://blog.roderickmann.org/2006/01/atmega32-pwm/)
http://www.societyofrobots.com/member_tutorials/node/231 (http://www.societyofrobots.com/member_tutorials/node/231)

Den øverste kan jeg ikke helt greje om den er i c
De er alle 3 tutorials til en at mega men det er vel bare et spørgsmål om hvordan der addresseres

:) Sådan set er alle 3 i C, ikke assembler. =)

Jeg kan ikke selv afprøve noget kode, for jeg har ikke en servo-motor.

Men det, som er vigtigt, er at du finder ud af at regne frekvensen ud korrekt.
Derefter er det forholdsvis enkelt at sætte en timer op; så vidt jeg husker, valgte vi at have en 16-bit timer fri til PWM, hvilket vil sige at der er gode muligheder for rimelig præcise frekvenser.

Du skal altså have en rutine der regner frekvensen ud, når denne rutine får en eller anden form for input.
Du skal så også have en rutine, som starter PWM'en.

Hvis du kigger på det 3. eksempel (http://www.societyofrobots.com/member_tutorials/node/231) du sendte, vil du se den nederste kode-blok.

Han har skrevet koden til ATmega8, så hvis vi kigger i ATmega8's datablad, vil vi kunne finde ud af hvad det er han sætter op.

Det første han gør, er at slå PWM fra, mens det sættes op, det gør han her...
TCCR1A = 0;

Med andre ord: Han sætter disse bits til 0 i TCCR1A:
COM1A1, COM1A0, COM1B1, COM1B0, FOC1A, FOC1B, WGM11, WGM10

At han sætter alle COM1xx bit til 0, betyder at COMpare- (sammenlignings-) registrene slåes fra.
Jeg mener der er en bedre måde at gøre dette på, nemlig at sætte prescaleren til off (timer stopped), men det kommer lidt an på om man ønsker at timeren kører hele tiden.

Det næste han gør, er:
Kode:
ICR1 = 19999;

Dette sætter i hans tilfælde TOP-grænsen hvis man bruger Fast PWM (mode 14).
Han sætter så sin timer op til at køre Fast PWM:
Kode:
TCCR1A = (1 << WGM11);  /* WGM10 er her samtidig blevet sat til 0 */
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);

Han sætter så samtidig CS10 til 1, og alle andre CSxx til 0, dvs...
CS12=0, CS11= 0, CS10=1: clk/1 (no prescaling)

Derefter sætter han PB1 og PB2 til at være outputs.
Kode:
DDRB |= _BV(1) | _BV(2);
...Dette kan skrives lidt mere forståeligt:

Kode:
DDRB |= (1 << DDB1) | (1 << DDB2);
(DDB1 betyder Data Direction for pin B1, DDB2 betyder så Data Direction for pin B2)

Efter det, enabler han COM1xx registrene:
Kode:
TCCR1A |= 2 << 6;
TCCR1A |= 2 << 4;

Dette kunne skrives mere forståeligt sådan:

Kode:
TCCR1A |= (1 << COM1A1) | (1 << COM1B1);

Så indstiller han sine Output Compare Registers...
Kode:
OCR1A = ICR1 * 2 / 20;
OCR1B = ICR1 * 2 / 20;

Det ene outputben (OC1A) får så resultatet af OCR1A's indstilling i forhold til ICR1
Det andet outputben (OC2A) får så resultatet af OCR2A's indstilling i forhold til ICR1

Efter det, så lader han sit program gå i loop med en
Kode:
while(1)
{
}

-Timeren ordner resten.

Man kan lave en slags grafisk illustration på denne måde:


+------------------------------------------------+
                    ^                            ^ ICR (top)
                    OCR1A (40% 'duty cycle' af ICR)


Så resultatet af ovenstående illustration kunne være...


____________________                               (on)
                    ______________________________ (off)




Se, det du så ønsker er...

1: At kunne beregne hvilken duty-cycle du vil have, altså forholdet mellem 'tændt' og 'slukket'.
Man kunne fx. sige du giver et tal i procent, så ville formlen være....
Kode:
OCRxx = (TOP * procent) / 100;

Eller hvis du hellere vil give en byte...
Kode:
OCRxx = (TOP * byte) / 256;
(kan skrives om til)...
Kode:
OCRxx = (TOP * byte) >> 8; /* at bitskifte til venstre 8 gange er det samme som at dividere med 256, bare hurtigere og kortere */

-Find eventuelt selv på flere. :)

2: At indstille Timer1. Prøv at se på databladet, side 85, "Sektion 12. 16-bit Timer/Counter1".
-Der står en hel masse som du ikke gider læse lige nu.
Bladrer vi frem til side 106, finder vi beskrivelse af TCCR1A. Her er et lille overblik over dens bits:

COM1A1, COM1A0, COM1B1, COM1B0, -, -, WGM11, WGM10

Godt at huske til om lidt.

TCCR1B bliver beskrevet på side 108. På denne side står også lidt omkring de forskellige modes. Det er lige det vi skal bruge.

Vi vil gerne have det ligesom ham gutten i den tutorial; vi sætter selv vores TOP-værdi, og vi bestemmer selv hvor vores PWM skal tænde og hvor den skal slukke.
Mode 14 ser ud til at være fin til det brug; det virker til at det er samme mode som han brugte i sin tutorial.

Så kigger vi på hvad vi skal indstille WGM tll. Det er i nabo-kolonnen til Mode. Der står WGM1[3:0] hvilket betyder at rækkefølgen er WGM13, WGM12, WGM11, WGM10.
Dvs. for at få mode 14, skal vi sætte , WGM13=1, WGM12=1, WGM11=1 og WGM10=0.

Godt. Vi skal også indstille ICR1 til at være top-værdi.

WGM11 og WGM10 indstilles i TCCR1A, mens WGM13 og WGM12 indstilles i TCCR1B (fjollet, men det kan vi ikke lave om på).

Vi skal også finde en passende prescaler værdi. Om du vil køre 8MHz eller 1MHz, det ved jeg ikke lige nu, men vi kan prøve at starte med 1MHz.
På side 109 finder vi en oversigt over prescaler værdierne:
CS12=0, CS11=0, CS10=1 giver en prescaler på clk/1, dette giver 8MHz.
CS12=0, CS11=1, CS10=0 giver en prescaler på cllk/8, dette giver 1MHz.

OK, så godt, så langt. ;)

På side 107, ser vi en oversigt over hvad Timer1 kan gøre med OC1A og OC1B benene.
Jeg fortalte dig vidstnok noget tidligere, med at det ville være praktisk at sætte servoen på et OCxx-ben, desværre tror jeg at jeg fik overbevist dig til at bruge OC0x og ikke OC1x.
Det kan derfor være du 'bliver nødt til' at flytte servoen til fx. ben 7 som er OC1A, eller ben 8, som er OC1B.
Det kan være at servo-motoren går amok, når du så programmerer chippen, men det må den så gøre.

Altså på side 107 er der 2 tabeller. Den første er "non-PWM", den vil vi ikke kigge på.
Den anden tabel, "Table 12-3. Compare Output Mode, Fast PWM" viser noget vi kan bruge.

Vi er nok mest interesseret i at tænde OC1A først, derefter slukke den når vi rammer sammenlignings-værdien som står i OCR1A. Det ser ud til at COM1A[1:0] så skal være 11.
(Det gør ikke noget, hvis vi samtidig sætter COM1B, så kan vi flytte servo-motoren derover hvis vi har lyst).

Det bliver nogenlunde til følgende kode, som kunne ligge i PWM.c:

Kode:
#define PWM_TOP_VALUE    65535  /* choose any value that suits you. */
void initPWM()
{
    /* First we stop our timer: */
    TCCR1B = 0;  /* CS12=0, CS11=0, CS10=0: No clock source (Timer/Counter stopped). */

    ICR1 = PWM_TOP_VALUE;

    if(SERVO_ENABLED == GPIOR2)
    {
        TCCR1A = (1 << WGM11) | (1 << WGM10) | (1 << COM1A1) | (COM1A0) | (1 << COM1B1) | (1 << COM1B0);
    }
    TCCR1B = 0;  /* safety, to ensure PWM is not started by accident during RESET */
    if(SERVO_ENABLED == GPIOR2)
    {
        TCCR1B = (0 << CS12) | (1 << CS11) | (0 << CS10) | (1 << WGM13) | (1 << WGM12);
    }
    /* PWM is now running! */

    DDRA |= (1 << DDA6) | (1 << DDA5); /* set both OC1A and OC1B to be output pins */
}

Et eller andet sted i programmet kan du så...
Kode:
    OCR1A = (PWM_TOP_VALUE * 17) / 100;   /* 17% on, 83% off */
    OCR1B = (PWM_TOP_VALUE * 61) / 100;   /* 61% on, 39% off */

Dette kan skrives om til noget lidt mere fleksibel kode, som kunne ligge i PWM.c:

Kode:
- (void)setDutyCyclePercentage(uint8_t aPercentage)
{
    OCR1A = (PWM_TOP_VALUE * aPercentage) / 100;
}

-Men bemærk: Dette er sikkert slet ikke en præcis nok beregning.
Du vil sikkert gerne have nogle forud-definerede (forud-beregnede) 16-bit værdier, fx. én værdi til 'load' og én værdi til 'unload'.

Jeg ved dette indlæg ikke er udtømmende, men det skulle kunne give dig en nogenlunde pejling på hvordan PWM sættes op.

Hvis du har datablad på servoen, der fortæller dig noget om hvordan duty-cycle/frekvenserne beregnes, så kan det være til hjælp.
Det kan være, at det ikke er nok, kun at ændre OCR1A, men at du også er nødt til at kunne ændre ICR1 når du styrer servoen.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 14, 2011, 17:41:44
men men men har vi ikke lavet det i servo.c, altså selve pwm så det bare er omregningen fra pot til % on time der mangler ?
Citér
/*
 * servo.c
 *
 * Created: 12-10-2011 19:12:27
 *  Author: jascore
 */
#include <avr/io.h>
#include "servo.h"
#include "Timer1.h"
void initServo()
{

}
void startServo(uint16_t aServoCountdown, uint16_t aRotation)
{
    /*servoCountdown = aServoCountdown;*/                  /* number of pulses to send to servo, before turning it off */
    TCCR1A = 0;                                                                  /* disable all PWM on Timer1 whilst we set it up */
    TCCR1B = 0;                                                                  /* (disable clock-source, so the timer is frozen) */
    TIMSK1 = 0;                                                                  /* disable all Timer1 interrupts */
    ICR1 = servoFrequency;                                               /* frequency is every 20ms, 50 times per second (50Hz) */
    /* select fast PWM (mode 14) and no prescaler */
    if(GPIOR2 == SERVO_ENABLED)
   {
      TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);      /* enable output COMpare 1 A, output COMpare 1 B, set WGM to Fast PWM  */
   }
   
    if(GPIOR2 == SERVO_ENABLED)
   {
      TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);               /* set WGM to fast PWM, choose clock source CS12:CS11:CS10 = 1, clk/1 (no prescaling) */   
   }
   OCR1A = servoFrequency * aRotation / 20;                                           /* pulse to load or unload servo on PA7 depending on the argument aRotation */
   TIMSK1 |= (1 << OCIE1B);                                                                     /* enable Output Compare Interrupt 1 B */
}

Og mange tak for linket til fritzing i en anden tråd. det var jo lige hvad en amatør havde brug for  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 14, 2011, 20:52:06
men men men har vi ikke lavet det i servo.c, altså selve pwm så det bare er omregningen fra pot til % on time der mangler ?

Hmm, jouw, jeg kunne bare ikke huske at den var så komplet. =)

Citér
Og mange tak for linket til fritzing i en anden tråd. det var jo lige hvad en amatør havde brug for  :P

Velbekomme. Jeg håber den bliver til gavn. =)
Hvis du skal lave print-layout og diagram-tegning, er der 2 programmer som har fået fornuftig karakter på Windows:
Eagle (http://www.cadsoftusa.com/) og DesignSpark (http://www.designspark.com/).
Hvis du kun skal lave print-layout og ikke vil lave diagram-tegning, kan du bruge Pad2Pad (http://pad2pad.com/), men det kræver at du bruger pad2pad.com til at lave print for dig, så du skal betale import-afgift også (ofte ca. 5% oveni).
Det er nok mest praktisk at bruge Eagle (Gratis for print-plader på under 160 mm x 100 mm), hvis du kan vænne dig til den. Hvis du beslutter dig for Eagle, så følg nogle online-tutorials; det er en lidt langsom process, men det vil nok være til gavn i sidste ende.
DesignSpark fra RS Components er også gratis.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 15, 2011, 21:08:06
Perfect :P
Her har jeg så lige et par spørgsmål til det sidste.
(kan mærke målet er nært, men alligevel så langt væk hehe)

Citér
Det næste han gør, er:

ICR1 = 19999;
Dette sætter i hans tilfælde TOP-grænsen hvis man bruger Fast PWM (mode 14).

giver det samme resultat som det vi gør når vi siger
ICR1 = servoFrequency;
hvor
servoFrequency = F_CPU / 50;
eller bør vi sige
servoFrequency = (F_CPU / 50)-1;
for at få 19999 eller har det ingen betydning?

Citér
1: At kunne beregne hvilken duty-cycle du vil have, altså forholdet mellem 'tændt' og 'slukket'.
Man kunne fx. sige du giver et tal i procent, så ville formlen være....

OCRxx = (TOP * procent) / 100;
Eller hvis du hellere vil give en byte...

OCRxx = (TOP * byte) / 256;(kan skrives om til)...

OCRxx = (TOP * byte) >> 8; /* at bitskifte til venstre 8 gange er det samme som at dividere med 256, bare hurtigere og kortere */
-Find eventuelt selv på flere. :)

hvis potten retunerer en værdi mellem 0 og 255 ville det så ikke være en ide med en tabel der bare giver OCRxx en konstant? (ligesom dipswitch)
som sagt har jeg skal jeg ikke bruge det fulde udsving på servoen men kun ca 60 - 90 grader, så de 100% udsving der ligger over potten skal fordeles i en top på f.eks mellem 1.2-1.8 ms i duty cyclen.
men er en tabel på 256 muligheder for stor sådan rent byte mæssigt?

Citér
vi bestemmer selv hvor vores PWM skal tænde og hvor den skal slukke.
opnår vi det ved følgende (uddrag af kode) 10 sek til at køre en dutycycle der trækker servoen ud og efterfølgende 10 sek der køre servoen modsat?
 for(a = 0; a < repeats; a++)
    {
        /* load: */
        waitSeconds(10);
        aRotation = getADC2Value();
        startServo(200, aRotation);
        /* unload: */
        waitSeconds(10);
        startServo(200, unload);
    }
sammenlagt med
OCR1A = servoFrequency * aRotation / 20;            
   TIMSK1 |= (1 << OCIE1B);

Selvfølgelig skal getADC2Value() erstattes med en værdi fra tabellen (hvis det kan betale sig med en sådan jf fpørgsmålet længere oppe)

Citér
Jeg mener der er en bedre måde at gøre dette på, nemlig at sætte prescaleren til off (timer stopped), men det kommer lidt an på om man ønsker at timeren kører hele tiden.
Jeg tror det er en fordel at den kører hele tiden. servoer har det med at have en "støj" bevægelse hvis man slukker og tænder dem så det ville ikke gøre noget at servoen
hele tiden får af vide hvor den skal stå indtil næste dosering. Det belaster den ikke hvis den får samme input, med mindre den skal arbejde for at komme til den possition den får besked på.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 15, 2011, 23:44:58
Citér
ICR1 = 19999;
Dette sætter i hans tilfælde TOP-grænsen hvis man bruger Fast PWM (mode 14).

giver det samme resultat som det vi gør når vi siger
ICR1 = servoFrequency;
hvor
servoFrequency = F_CPU / 50;
eller bør vi sige
servoFrequency = (F_CPU / 50)-1;
for at få 19999 eller har det ingen betydning?

Det er korrekt at trække 1 fra resultatet efter divisionen, men vores beregning skal være korrekt også.

Hvis vi har F_CPU / 50, og F_CPU er 8000000, så får vi et resultat der hedder 160000.
Dette tal kan ikke være i ICR1. Det kan tallet - 1 (159999( heller ikke.

Hvad er det så egentlig for en opløsning vi skal bruge ? -Dette giver du svar på her...

Citér
skal fordeles i en top på f.eks mellem 1.2-1.8 ms i duty cyclen

Da vi har 8000000 clock cycles per sekund, vil det sige at vores opløsning med en clk / 1 prescaler vil være 1 / 8000000 sekund = 0.000000125 sekunder = 125 nS (125 nanosekunder).
Vi vil maks. kunne sætte vores TOP til 65535.
65535 * 125 nS = 0.008191875 sekunder, altså 8.19 mS, hvilket er det vindue vi har til rådighed.
(minimum 125 nS, maksimum 8.19 mS - og både 1.2 mS og 1.8 mS ligger indenfor dette område)

Med andre ord:
Timeren vil køre 8000000 / 65536 = 122.07 gange i sekundet (cirka), hvilket vi kan regne efter med...
122.07 * 0.008191 sek = (cirka) 1. Vores beregning er god nok. =)

Altså, tilbage til vores indstilling af ICR1. Denne sætter vi på højest mulige værdi, for at få finest mulige opløsning, nemlig værdien 65535.

Lad os så se på hvad værdien 1.2 mS og 1.8 mS hedder, når de er skaleret op, så de passer til ovenstående...
1.2 mS = 0.0012 sekunder
1.8 mS = 0.0018 sekunder

Der går 8000000 clock-cycles på 1 sekund.
8000000 * 0.0012 = 9600
8000000 * 0.0018 = 14400

Altså bør din duty-cycle ligge mellem værdien (9600 - 1) og (14400 - 1)

OK. Nu har vi så det tal, som potmetret egentlig skal regnes om til.

Selve ADC-værdien er en værdi mellem 0 og 1023.

Vi kan så derfor gøre følgende:

Kode:
uint16_t freq
...
...
freq = (uint16_t) (((14400 - 9600) * ((uint32_t) adcValue)) >> 10) + (9600 - 1);

Denne værdi burde vi så kunne lægge direkte ind i vores OCR1x register.

Bemærk: Det er i dette tilfælde vigtigt at indsætte (uint32_t) typecasting; for ellers kan vores tal blive 'klippet', da 16 bits ikke vil være nok til beregningen:
(14400 - 9600) * 1023 = 4910400 (som er højere end 65535, det maksimale der kan være i en 16-bit variabel).

Du ser også at jeg bitskifter med 10. Dette er en måde at dividere med 1024 hurtigt.

Men ovenstående har for mange konstante værdier. Dette kan vi ikke lide, for hvad hvis vi en dag vil ændre på prescaleren eller på F_CPU ?

Derfor...


Kode:
#define LOWER_US (1200)    /* 1.2 mS in microseconds */
#define UPPER_US (1800)    /* 1.8 mS in microseconds */
#define LOWER_LIMIT (F_CPU * LOWER_US / 1000000)
#define UPPER_LIMIT (F_CPU * UPPER_US / 1000000)

uint16_t freq;
...
freq = (uint16_t) (((UPPER_LIMIT - LOWER_LIMIT) * ((uint32_t)adcValue)) >> 10) + (LOWER_LIMIT - 1);

OCR1x = freq;

Læg mærke til at vi stadig regner i heltal, men ganger vi før vi dividerer, taber vi ikke noget i disse beregninger.


Citér
hvis potten retunerer en værdi mellem 0 og 255 ville det så ikke være en ide med en tabel der bare giver OCRxx en konstant? (ligesom dipswitch)...
...men er en tabel på 256 muligheder for stor sådan rent byte mæssigt?

En tabel ville være temmelig stor til en ATtiny.
Altså ville en sådan tabel fylde 256 stk 16-bit værdier, hvilket er 512 bytes.
Beregner vi resultatet, vil det fylde meget mindre.

En fordel ved at bruge en beregnings-rutine, er at man nemt kan lave værdierne, så de tilpasses, hvis fx. F_CPU skal ændres på et tidspunkt.

Citér
Citér
vi bestemmer selv hvor vores PWM skal tænde og hvor den skal slukke.
opnår vi det ved følgende (uddrag af kode) 10 sek til at køre en dutycycle der trækker servoen ud og efterfølgende 10 sek der køre servoen modsat?

Æh, nej. Her mente jeg på frekvens-kurven.
For du sender nogle pulser mange gange i sekundet til din servo.
Hvad jeg forsøgte at sige, var noget i stil med at vi selv bestemmer om den skal starte med at sætte i/o-benet højt eller om den skal starte med at sætte i/o-benet lavt. :)

Citér

Citér
Jeg mener der er en bedre måde at gøre dette på, nemlig at sætte prescaleren til off (timer stopped), men det kommer lidt an på om man ønsker at timeren kører hele tiden.
Jeg tror det er en fordel at den kører hele tiden. servoer har det med at have en "støj" bevægelse hvis man slukker og tænder dem så det ville ikke gøre noget at servoen
hele tiden får af vide hvor den skal stå indtil næste dosering. Det belaster den ikke hvis den får samme input, med mindre den skal arbejde for at komme til den possition den får besked på.

OK, så skal den da selvfølgelig være tændt. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 16, 2011, 22:17:47
Ok så prøver jeg lige det her og hører hvad du siger

først sætter jeg PWM op i servo.c
Kode:
#include <avr/io.h>
#include "servo.h"
#include "Timer1.h"
#include "ADC.h"
#include "Dosing.h"
void initServo()
{

}
void startServo(uint16_t aServoCountdown, uint16_t aRotation)
{
    /*servoCountdown = aServoCountdown;*/ /* number of pulses to send to servo, before turning it off */
    TCCR1A = 0; /* disable all PWM on Timer1 whilst we set it up */
    TCCR1B = 0; /* (disable clock-source, so the timer is frozen) */
    TIMSK1 = 0; /* disable all Timer1 interrupts */
    ICR1 = servoFrequency; /* frequency is every 20ms, 50 times per second (50Hz) */
    /* select fast PWM (mode 14) and no prescaler */
    if(GPIOR2 == SERVO_ENABLED)
{
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); /* enable output COMpare 1 A, output COMpare 1 B, set WGM to Fast PWM  */
}

    if(GPIOR2 == SERVO_ENABLED)
{
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); /* set WGM to fast PWM, choose clock source CS12:CS11:CS10 = 1, clk/1 (no prescaling) */
}
OCR1A = freq; /* pulse to load or unload servo on PA7 depending on the argument aRotation */
TIMSK1 |= (1 << OCIE1B); /* enable Output Compare Interrupt 1 B */
}

OCR1A = freq; hvor freq bliver beregnet i min dosing.c som følger her

Kode:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "Timer1.h"
#include "servo.h"
#define LOWER_US (1200) /* 1.2 mS in microseconds */
#define UPPER_US (1800) /* 1.8 mS in microseconds */
#define LOWER_LIMIT (F_CPU * LOWER_US / 1000000)
#define UPPER_LIMIT (F_CPU * UPPER_US / 1000000)
/*a number that rep the pos zero when servo is unloaded*/
uint16_t freq;
volatile uint8_t gSettings;
uint8_t repeats =0;

/*ADC TABELS START*/
uint8_t calculateSettingsDip(uint16_t gDipSwitches)
{
    static const uint16_t convTab[] PROGMEM = { ((1023 + 512) / 2), ((512 + 341) / 2), ((341 + 256) / 2), ((256 + 205) / 2),
        ((205 + 171) / 2), ((171 + 146) / 2), ((146 + 128) / 2), ((128 + 114) / 2), ((114 + 102) / 2), ((102 + 93) / 2),
        ((93 + 85) / 2), ((85 + 79) / 2), ((79 + 73) / 2), ((73 + 68) / 2), ((68 + 65) / 2), 0 }; /* 4K, 0% */
    uint8_t i;

    i = 0;
    while(gDipSwitches <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
/*ADC TABELS END*/

/*FUNCTIONS START*/
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 };

    setMinuteCountdown(pgm_read_word(&timeTable[(gSettings >> 2) & 0x03]));
    timer0Elapsed();
}

void timer0Elapsed()
{
    static const uint8_t repTable[] PROGMEM = { 1, 10, 4, 2 };
    uint8_t repeats;
    uint8_t a;
    uint16_t aRotation;
    uint8_t unload; /* Value 0 - 256 since the pot2 is removed and unload is defined by constant*/


    unload = 0;   
    repeats = pgm_read_byte(&repTable[gSettings & 0x03]);

    for(a = 0; a < repeats; a++)
    {
        /* load: */
freq = (uint16_t) (((UPPER_LIMIT - LOWER_LIMIT) * ((uint32_t)adcValue)) >> 10) + (LOWER_LIMIT - 1); /* sets how much to load, read from pot*/
        waitSeconds(10);

        /* unload: */
freq = unload;
waitSeconds(10);
    }
}

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

Her får jeg en compiler fejl på adcvalue undeclared when first used
adcvalue bruger jeg jo i adc.c
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ADC.h"
#ifndef inb
#define inb(sfr)    _SFR_BYTE(sfr)
#endif
#define ADC_SIZE    5                                                                   /* number of reads to average the ADC channel (we write one, and average over last 4) */
#define ADC_STABLE  (ADC_SIZE + 3)
#define ADC_FIRST   1                                                                   /* first ADC channel to read (ADC1) */
#define ADC_LAST    3                                                                   /* last ADC channel to read (ADC4)*/
static volatile uint16_t    adcValue[ADC_LAST - ADC_FIRST][ADC_SIZE];                   /* this buffer holds a lot of conversion results, enough for us to average the values */
static volatile uint8_t     adcReadIndex = 0;                                           /* this is the index we start reading values from (up to, but excluding writeIndex) */
static volatile uint8_t     adcWriteIndex = 0;                                          /* this is the index we write values to */
static volatile uint8_t     adcCounter = 0;                                             /* just a counter, that counts how many times we've read all the ADC channels */
static volatile uint8_t     adcChannel = 0;                                             /* current channel we're reading the ADC value from */
static uint8_t              adcBits = 8;
void waitUntilADCStable()
{
    while(adcCounter < ADC_STABLE)                                                      /* keep waiting, until ADC is reliable */
{
}
}
uint16_t getADCValue(uint8_t aADC)
{
    uint16_t    result;
    uint8_t     i;
    uint8_t     idx;

    idx = adcReadIndex;                                                                 /* read from this index; avoiding reading at the 'write position' */
    i = ADC_SIZE - 1;                                                                   /* number of values to read (eg. if ADC_SIZE is 10, we only read 9 values) */
    result = 0;                                                                         /* zero our result */
    while(i--)
{
        result += adcValue[aADC - ADC_FIRST][idx];                                      /* add the one value we've just read from the index */
        idx = idx >= (ADC_SIZE - 1) ? 0 : idx + 1;                                      /* next index */
}
    return(result / (ADC_SIZE - 1));                                                    /* return the averaged result */
}

/* uint16_t getADC1Value()
{
    return(getADCValue(1)); /* ADC value of startbutton */
/*}*/

uint16_t getADC2Value()
{
    return(getADCValue(2)); /* ADC value of pot */
}

SIGNAL (SIG_ADC)
{
    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8)                                                                    /* using 8-bit precision */
{
        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) */
}
}
    else
{
        adLo = inb(ADCL); /* read lowbyte before highbyte! */
        adHi = inb(ADCH); /* read lowbyte before highbyte! */
}
    adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8) | adLo; /* save the value we've read above */
    ADCSRA |= (1 << ADSC); /* start another conversion */

    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 */
}
void initADC(uint8_t aBits)
{
    adcCounter = 0; /* this is so we can see when the ADC conversions are stable */
    adcWriteIndex = 0; /* start writing at index 0 */
    adcReadIndex = adcWriteIndex + 1; /* read right after the write-index */
    adcChannel = ADC_FIRST; /* initialize ADC channel number to read */
    adcBits = aBits;

    ADMUX = (0 << REFS1) | (0 << REFS0) | (adcChannel & 0x07); /* VCC used as analog reference, first channel */
    ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR); /* free running mode, result is right aligned */
    ADCSRA |= (1 << ADSC); /* start conversion */
}
da det er adc2 jeg læser fra, kan jeg så lave sætningen i dosing.c om til
req = (uint16_t) (((UPPER_LIMIT - LOWER_LIMIT) * ((uint32_t)getADC2Value())) >> 10) + (LOWER_LIMIT - 1);

desuden er jeg i tvivl om hvorvidt
waitSeconds(10);
gør at servoen har 10 sec til at bevæge sig fra freq unload til freq load, eller om jeg hellere skal have en for løkke ind



Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 17, 2011, 01:29:30
Citér
da det er adc2 jeg læser fra, kan jeg så lave sætningen i dosing.c om til
req = (uint16_t) (((UPPER_LIMIT - LOWER_LIMIT) * ((uint32_t)getADC2Value())) >> 10) + (LOWER_LIMIT - 1);

Ja, det mener jeg er korrekt. :)

Citér
desuden er jeg i tvivl om hvorvidt
waitSeconds(10);
gør at servoen har 10 sec til at bevæge sig fra freq unload til freq load, eller om jeg hellere skal have en for løkke ind

Det burde fungere fint med waitSeconds(10);.
En for-løkke ville fungere på stort set samme måde, men ulempen ved en for-løkke er at hvis du skifter CPU-frekvens, vil for-løkken ikke længere vente 10 sekunder, men mindre, hvis CPU-frekvensen er sat op, eller mere, hvis CPU-frekvensen er sat ned. Det er bedre at bruge waitSeconds i dette tilfælde.


Jeg har et forslag til lidt ændringer i Servo.c og Dosing.c...

Servo.c:
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "servo.h"

void initServo()
{
    cli(); /* (disable all interrupts) */
    TCCR1A = 0; /* disable all PWM on Timer1 */
    TCCR1B = 0; /* disable clock-source, so the timer is frozen */
    TIMSK1 = 0; /* disable all Timer1 interrupts */

    DDRA |= (1 << DDA7); /* set OC1A as output */

    ICR1 = 65534; /* we want our top to be as large as possible, for best resolution, but we'll keep it, so there's one value the OCR1x registers cannot reach. */

    OCR1A = 65535; /* make sure this has a known value */
    OCR1B = 65535; /* make sure this has a known value */

    if(GPIOR2 == SERVO_ENABLED)
    {
        TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); /* set WGM to fast PWM, choose clock source CS12:CS11:CS10 = 1, clk/1 (no prescaling) */
    }
    /* select fast PWM (mode 14) and no prescaler */
    if(GPIOR2 == SERVO_ENABLED)
    {
        TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); /* enable output COMpare 1 A, output COMpare 1 B, set WGM to Fast PWM  */
    }
}

void startServo(uint16_t aRotation)
{
OCR1A = aRotation; /* pulse to load or unload servo on PA7 depending on the argument aRotation */
}

Jeg har ovenover flyttet alt, der kun skal gøres én gang op i initServo().
Jeg har sat initialiseringen af output-benet ind i initServo() også.
Jeg har fjernet initialiseringen af Timer1 interruptet, da det nok ikke skal bruges.
Så har jeg også initialiseret OCR1A og OCR1B til 65535, for at undgå at der bliver bøvl med dem mens vi arbejder med koden.

Derudover har jeg sat top-grænsen for PWM til 65534 (ikke 65535), fordi hvis vi gør dette, så kan vi 'fryse PWM' ved at sætte PWM-værdien til 65535! -Da vil benet ikke skifte værdi mellem høj/lav.

Jeg har også ændret OCR1A = freq; til OCR1A = aRotation;

-Så giver du nemlig denne parameter som argument til funktionen.
(Prøv så vidt muligt at undgå globale variabler).

Du vil sikkert også bemærke at jeg har fjernet alle referencer til andre filer, dvs. header-filer som Main.h, Dosing.h, osv.
Det er fordi, hvis man tænker på koden som selvstændige enheder der kan tages ud og sættes ind, bør man ikke lave snore 'baglæns' i systemet, men kun forlæns. Man kunne sige det er som en 'uro'. hver dims der hænger i en snor, kan ikke pludselig side over den dims som den hænger ned fra. ;)

Jeg har smidt Timer1.c helt ud, da der ikke rigtigt er noget brugbart i den længere; Servo.c har sådan set overtaget dens funktion. :)
-Så Timer1.h skal ikke længere inkluderes i andre filer (som fx. Main.h).

Du er nok også nødt til at ændre prototypen for startServo i Servo.h:
Kode:
void startServo(uint16_t aRotation);


Dosing.c:
Kode:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "Dosing.h"
#include "Timer0.h"
#include "ADC.h"
#include "servo.h"

#define LOWER_US (1200) /* 1.2 mS in microseconds */
#define UPPER_US (1800) /* 1.8 mS in microseconds */
#define LOWER_LIMIT (F_CPU * LOWER_US / 1000000)
#define UPPER_LIMIT (F_CPU * UPPER_US / 1000000)
#define UNLOAD 0 /*a number that rep the pos zero when servo is unloaded*/
#define LOAD(a) (uint16_t) (((UPPER_LIMIT - LOWER_LIMIT) * ((uint32_t) a)) >> 10) + (LOWER_LIMIT - 1)

volatile uint8_t gSettings;

/*ADC TABELS START*/
uint8_t calculateSettingsDip(uint16_t gDipSwitches)
{
    static const uint16_t convTab[] PROGMEM = { ((1023 + 512) / 2), ((512 + 341) / 2), ((341 + 256) / 2), ((256 + 205) / 2),
        ((205 + 171) / 2), ((171 + 146) / 2), ((146 + 128) / 2), ((128 + 114) / 2), ((114 + 102) / 2), ((102 + 93) / 2),
        ((93 + 85) / 2), ((85 + 79) / 2), ((79 + 73) / 2), ((73 + 68) / 2), ((68 + 65) / 2), 0 }; /* 4K, 0% */
    uint8_t i;

    i = 0;
    while(gDipSwitches <= pgm_read_word(convTab[i]))
    {
        i++;
    }
    return(i);
}
/*ADC TABELS END*/

/*FUNCTIONS START*/
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 };

    setMinuteCountdown(pgm_read_word(&timeTable[(gSettings >> 2) & 0x03]));
    timer0Elapsed();
}

void timer0Elapsed()
{
    static const uint8_t repTable[] PROGMEM = { 1, 10, 4, 2 };
    uint8_t repeats;
    uint8_t a;


    repeats = pgm_read_byte(&repTable[gSettings & 0x03]);

    for(a = 0; a < repeats; a++)
    {
        /* load: */
        startServo(LOAD(getADC2Value())); /* sets how much to load, read from pot */
        waitSeconds(10);

        /* unload: */
        startServo(UNLOAD);
        waitSeconds(10);
    }
}

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

I toppen af filen...
Jeg har fjernet den globale variabel 'uint16_t freq;'
Jeg har fjernet den globale variabel 'uint8_t repeats =0;'
Jeg har indsat en #define der definerer en konstant værdi for unload (den hedder UNLOAD).
Jeg har indsat en macro, dvs. en #define der beregner værdien for load (den hedder LOAD).

I timer0Elapsed()...
Jeg har fjernet uint16_t aRotation;
Jeg har fjernet uint8_t unload;
Jeg har ændret freq = unload; til at være startServo(UNLOAD);
Jeg har ændret freq = ...; til at være startServo(LOAD(getADC2Value()));
Jeg har således i beregningen erstattet adcValue med getADC2Value()

Muligvis får du nogle compile-fejl pga. ændringerne, så må du bare sige til. :D

Jeg mener selv at koden skulle være blevet lidt mere overskuelig, da den en del steder er blevet kortere; men jeg kan selvfølgelig tage fejl her. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 17, 2011, 23:54:42
Tusind tak.

så fik jeg den compilet
og nu laver den da hex filen men stadig lidt problemer med nogle warnings.
prøvede alligevel at smide den på avr men virkede self ikke  :P
Citér
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c Main.c -o Main.o
Main.c:36: warning: 'SIG_PCINT0' appears to be a misspelled signal handler
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c ADC.c -o ADC.o
ADC.c:54: warning: 'SIG_ADC' appears to be a misspelled signal handler
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c Dosing.c -o Dosing.o
Dosing.c: In function 'timer0Elapsed':
Dosing.c:67: warning: implicit declaration of function 'waitSeconds'
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c Timer0.c -o Timer0.o
Timer0.c:39: warning: 'SIG_OVERFLOW0' appears to be a misspelled signal handler
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c servo.c -o servo.o
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a  -o aquadose.elf Main.o ADC.o Dosing.o Timer0.o servo.o
rm -f aquadose.hex
avr-objcopy -j .text -j .data -O ihex                                              aquadose.elf aquadose.hex
if [ -e aquadose.elf ]; then { avr-size aquadose.elf; } elif [ -e aquadose.hex ]; then { avr-size aquadose.hex; } fi
   text      data       bss       dec       hex   filename
   1188         2        32      1222       4c6   aquadose.elf

Har sådan et multimeter
http://australianrobotics.com.au/products/dm830d-lcd-digital-multimeter (http://australianrobotics.com.au/products/dm830d-lcd-digital-multimeter)
så kan ikke rigtigt måle frekvensen "tror jeg"

Desuden har jeg konstateret at servoen skal have strøm fra samme enhed som leverer til microcontroleren.
jeg troede at jeg kunne smide en anden strømforsyning på servoen og så bare få impulserne fra avr men det har jeg testet med en servotester og det kan tilsyneladende ikke lade sig gøre. ved ikke lige hvorfor.
Men skaber det problemer når servoen går igang? jeg mener vil det ikke lave en lille forstyrrelse på strømmen til avr, når servo lige pludselig trækker 5 volt?
med mindre jeg kan lave et eller andet trick med f.eks at samle alle gnd
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 18, 2011, 07:20:17
så fik jeg den compilet
og nu laver den da hex filen men stadig lidt problemer med nogle warnings.
prøvede alligevel at smide den på avr men virkede self ikke  :P

Når jeg programmerer en AVR, har jeg slet ikke nogle simulator-værktøjer.
Min fremgangsmåde er cirka følgende:
1: Skriv et lille program, som gør en simpel ting.
2: Få det til at compile.
3: Brænd det over på AVR'en.
4: Se om det fungerer som jeg forventede.
5: Hvis der er fejl, ret fejlene, tilbage til 2
6: Ingen fejl, udvid med næste funktion, tilbage til 2.

I andre tilfælde, når jeg har et større program, hvor jeg skal lave ny funktionalitet, skriver jeg et lille prøve-program, som kun gør den ene ting, og når det virker, fører jeg princippet over i det større program.

Citér
avr-gcc -Wall -Os -DF_CPU=1000000 -mmcu=attiny44a -c Main.c -o Main.o
Main.c:36: warning: 'SIG_PCINT0' appears to be a misspelled signal handler

Ups, min fejl; jeg fik blandet interrupt-navnene sammen, fordi hvis man bruger den ene type erklæring, skal de navngives i én stil, hvis man bruger en anden type erklæring, skal de navngives i en anden stil.
ISR( ... ) er den anbefalede type erklæring, så den vil jeg så lære fra mig... ;)

Prøv i Main.c, at ændre...
Kode:
SIGNAL (SIG_PCINT0)
...til...
Kode:
ISR(PCINT0_vect)

Citér
ADC.c:54: warning: 'SIG_ADC' appears to be a misspelled signal handler

Prøv i ADC.c, at ændre...
Kode:
SIGNAL (SIG_ADC)
...til...
Kode:
ISR(ADC_vect)

Citér
Dosing.c:67: warning: implicit declaration of function 'waitSeconds'

Hvor ligger funktionen 'waitSeconds' ?
-Det kunne være en god idé at lægge den ud i sin egen fil, fx. "Wait.c", og så lave prototypen på funktionen i "Wait.h"


Citér
Timer0.c:39: warning: 'SIG_OVERFLOW0' appears to be a misspelled signal handler

Prøv i Timer0.c at ændre...
Kode:
SIGNAL (SIG_INT0)
...til...
Kode:
ISR(INT0_vect)

Forklaring:
Da ingen af disse interrupt-navne er genkendt, vil de ikke køre.
Derfor vil programmet ikke kunne virke...
1: Timer0-interruptet kører ikke; dvs. sekunderne tæller ikke.
2: ADC-interruptet kører ikke, dvs. vi får ikke værdien fra ADC'en beregnet/opdateret
3: Interrupt0 er ikke installeret, hvilket vil sige at vores start-knap ikke bliver aflæst.

-Med de korrekte navne, skulle det dog have en chance for at blive lidt bedre. :)

Citér
   text      data       bss       dec       hex   filename
   1188         2        32      1222       4c6   aquadose.elf
[/quote]

TEXT + DATA = 1190 bytes: Selve programmet kan fint ligge i Flash hukommelsen.
DATA + BSS = 34 bytes: Der er SRAM nok på chippen til både data og stack.

TEXT bliver lagt kun i Flash-hukommelsen.
DATA bliver lagt i Flash-hukommelsen, men når programmet starter op, kopierer det DATA fra Flash over i SRAM'en.
BSS er værdier der starter på 0. Der bliver reserveret plads til dem i SRAM'en.

Citér
Har sådan et multimeter
http://australianrobotics.com.au/products/dm830d-lcd-digital-multimeter (http://australianrobotics.com.au/products/dm830d-lcd-digital-multimeter)
så kan ikke rigtigt måle frekvensen "tror jeg"
Citér

Hvis du kigger mellem 'diode-symbolet' og 'hFE', er dette så ikke 'frekvens' ? - Det
Sjovt, jeg har selv et DT830B, jeg bruger en del, men det har ikke det symbol.
...Men jeg vil nok prøve at holde udkig og se om jeg kan få fat i et DM830D, da det jo er lidt bedre end mit nuværende (jo, jeg har en Fluke, men den fylder og vejer cirka det dobbelte).

Citér
Desuden har jeg konstateret at servoen skal have strøm fra samme enhed som leverer til microcontroleren.

Det kan være jeg tager fejl, men jeg mener det ikke burde være nødvendigt. Hvad der er vigtigt, er at du har sat microcontrolleren's GND til servoens GND. :)

Citér
jeg troede at jeg kunne smide en anden strømforsyning på servoen og så bare få impulserne fra avr men det har jeg testet med en servotester og det kan tilsyneladende ikke lade sig gøre. ved ikke lige hvorfor.

...Hvis man ikke kan, så kan man ikke, men det ville undre mig hvis det er sådan... ;)

Men skaber det problemer når servoen går igang? jeg mener vil det ikke lave en lille forstyrrelse på strømmen til avr, når servo lige pludselig trækker 5 volt?
med mindre jeg kan lave et eller andet trick med f.eks at samle alle gnd

Det kommer helt an på hvor mange Ampere servoen trækker.
Du bør dimensionere din strømforsyning, så den har ampere nok til at trække servoen plus microcontroller.
Et hurtigt gæt er det antal Ampere servoen trækker plus 50 mA til microcontrolleren, plus 50 mA ekstra til dårlige tider. ;)
-Og så skal du nok have en elektrolyt kondensator på før din spændings-regulator, og en efter din spændings-regulator.
Hvis jeg trækker 50 mA på mit board, plejer jeg at bruge 33uF før spændings-regulatoren, og 10uF efter.
Men det vil nok være en god idé at sætte nogle større på.
Hvad jeg ville gøre, er noget i stil med... Start med to stk. 10uF. Det burde ikke være nok til at trække apparatet.
Skift værdien på kondensatorerne op til 33uF, derefter 56 uF, så 82uF, 100uF, ... med lidt spring ind imellem.. Når den så begynder at kunne trække, så hop nogle værdier op, det gør ikke noget du dobler op, med mindre, selvfølgelig at kondensatorerne kommer til at fylde 10 cm i højden og vejer en bondegård. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 18, 2011, 18:40:57
Fantastisk  :P
Citér
Timer0.c:39: warning: 'SIG_OVERFLOW0' appears to be a misspelled signal handler
Prøv i Timer0.c at ændre...

SIGNAL (SIG_INT0)...til...

ISR(INT0_vect)

Har ikke en SIGNAL (SIG_INT0), men en SIGNAL (SIG_OVERFLOW0) /*This interrupt occurs when TCNT0 wraps to 0*/
hvis jeg ændre den til ISR(INT0_vect) får jeg stadig samme fejl.
men hvis det er TCNT0 så er det vel timer/counter 0 der checkes for overflow. vil det så være rigtigt at bruge
ISR(TIM0_OVF_vect) istedet for SIGNAL (SIG_OVERFLOW0)?
TIM0_OVF er iflg data arket for 44'ern Timer/Counter0 Overflow

De andre fejl er rettet og fungerer fint.
lavede en void waitSeconds(uint8_t aSeconds); i timer0.h
waitSeconds er jo en del at timerfunktionen der holder øje med døgnet så syntes ikke den skulle fjernes fra timer0.c hvor den bruges.
og fejlen forsvandt da jeg lavede linjen i timer0.h
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 18, 2011, 18:56:47
Citér
Timer0.c:39: warning: 'SIG_OVERFLOW0' appears to be a misspelled signal handler
Prøv i Timer0.c at ændre... {snip}
Har ikke en SIGNAL (SIG_INT0), men en SIGNAL (SIG_OVERFLOW0) /*This interrupt occurs when TCNT0 wraps to 0*/
hvis jeg ændre den til ISR(INT0_vect) får jeg stadig samme fejl.

Alle gode gange to-og-en-halv...

-Jeg forvirrede mig selv med at jeg på et tidspunkt havde brugt INT0 til start-knap. :D

Prøv TIM0_OVF_vect - den er måske bedre... ;)
Citér

De andre fejl er rettet og fungerer fint.
lavede en void waitSeconds(uint8_t aSeconds); i timer0.h
waitSeconds er jo en del at timerfunktionen der holder øje med døgnet så syntes ikke den skulle fjernes fra timer0.c hvor den bruges.
og fejlen forsvandt da jeg lavede linjen i timer0.h

Dette er det korrekte sted. :)

Du kan se en oversigt over interrupt-vektorer og navne på AVR-GCC's side (http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html#gad28590624d422cdf30d626e0a506255f).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 18, 2011, 19:15:19
det var jeg også kommet frem til i min post på tidligere side he he men tak for svaret på mit spørgsmål  :P

Min strømforsyning er 5v 2 amp så den klarer nok jobbet
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 18, 2011, 23:30:01
kan jeg gøre flg.
lave en led.c med flg
Kode:
void setLED1(uint8_t aState)
{
    PORTA = aState ? (PORTA & ~(1 << PA7)) : (PORTA | (1 << PA7));
}
void setLED2(uint8_t aState)
{
    PORTA = aState ? (PORTA & ~(1 << PA6)) : (PORTA | (1 << PA6));
}
void setLED3(uint8_t aState)
{
    PORTA = aState ? (PORTA & ~(1 << PA5)) : (PORTA | (1 << PA5));
}
void setLED4(uint8_t aState)
{
    PORTA = aState ? (PORTA & ~(1 << PA4)) : (PORTA | (1 << PA4));
}

og en led.h med
prototypes på de 4 setLED1(uint8_t aState)

Så laver jeg en #include "led.h" i alle *.c
alt det lader jeg bare være en fast del af programmet, så det er der når og hvis der skal udvides

for at teste kan jeg så ikke bare redigerer i den *.c hvor der er noget jeg vil teste, og tilføje
Kode:
uin16_t val = det_der_skal_testes();
void toggleled()
{
uint16_t val = getADC2Value();
if(val >= 1)
{
setLED1(1);  /* turn LED1 on */
val = val - 1;
}
else
{
setLED1(0);  /* turn LED1 off */
}
if(val >= 2)
{
setLED2(1);  /* turn LED2 on */
val = val - 2;
}
else
{
setLED2(0);  /* turn LED2 off */
}
if(val >= 3)
{
setLED3(1);  /* turn LED3 on */
val = val - 3;
}
else
{
setLED3(0);  /* turn LED3 off */
}
if(val >= 4)
{
setLED4(1);  /* turn LED4 on */
val = val - 4;
}
else
{
setLED4(0);  /* turn LED4 off */
}
}

jeg har svært ved at se hvordan keg kan compile og teste 1 modul ad gangen da de alle er vævet sammen og er afhængige af værdier fra andre end sig selv

Når jeg gør det på den måde, ser det ud til at selve start knap funktionen ikke virker.
jeg kan tænde og slukke led 1 på pa7 ved at skrive setLED1(1); eller setLED1(0); i starten af main.c (som det sidste i init main) men hvis jeg skriver setLED1(1); nede i ISR(PCINT0_vect) funktionen så sker der intet når jeg trykker på start knappen. er dog ikke helt sikker på at min led rutiner er globale

Min main.c ser således ud
Kode:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "main.h"
#include <util/delay.h>
#include "Servo.h"
#include "ADC.h"
#include "Timer0.h"
#include "Dosing.h"
#include "leds.h"
int main()
{
    GPIOR2 = SERVO_ENABLED; /* This must be the first code executed; no code goes before it, and GPIOR2 is not to be changed from now */
initADC(8); /* initialize ADC, we'll use the 8-bit precision for now */
    initTimer0();
    initDosing();
    initServo();
sei(); /* globally enable interrupts */
    PCMSK0 |= (1<<PCINT3); /*Set PA3 as the pin to use*/
MCUCR = (1 << ISC01) | (0 << ISC00); /* interrupt on INT0 pin, falling edge */
GIMSK  |= (1<<PCINT3);
setLED1(1);
while(1)
{
/* we don't really need to do anything here. Everything is handled by the interrupts */
}
    return(0); /* (never reached) */
}
ISR(PCINT0_vect)
{
    uint8_t pinValue;
    pinValue = PINA & (1 << PINA3);                             /* read value of input-pin */
    if(pinValue) /* we're only interested if button is pressed */
    {
        _delay_ms(10.);                                          /* wait 10 ms */
        pinValue = PINA & (1 << PINA3);                         /* read value of input-pin */
        if(pinValue) /* only update settings when button value is stable */
        {
setLED1(0);  /* turn LED1 off */
            startDosing();   
        }
    }
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 06:33:22
kan jeg gøre flg.
lave en led.c med flg
{snip}
og en led.h med prototypes på de 4 setLED1(uint8_t aState)
Så laver jeg en #include "led.h" i alle *.c

Ser fint ud.

Det kunne være godt med...
Kode:
void initLED()
{
    DDRA |= (1 << DDA4) | (1 << DDA5) | (1 << DDA6) | (1 << DDA7);
}

og så kalde denne fra main(), fx. lige efter GPIOR2 = ...;


Citér
for at teste kan jeg så ikke bare redigerer i den *.c hvor der er noget jeg vil teste, og tilføje
{snip}

God idé. :)

Mit forslag til ovennævnte rutine er...

1: undgå at bruge globale variabler, men i stedet giv parametre (argumenter) til rutinen.
2: en smart lille forkortelse:
Kode:
void setLEDs(uint8_t aValue)
{
    PORTA = (PORTA & ~(1 << PA4) | (1 << PA5) | (1 << PA6) | (1 << PA7)) | (aValue << PA4);
}


PA4 har så værdi 1, PA5 har værdi 2, PA6 har værdi 4, PA7 har værdi 8.
Når de lyser, lægger du værdierne for dem sammen, fx. vil...
setLEDs(11);
få PA4 + PA5 + PA7 til at lyse, hvilket giver...
1 + 2 + 8 = 11...
[/quote]

jeg har svært ved at se hvordan keg kan compile og teste 1 modul ad gangen da de alle er vævet sammen og er afhængige af værdier fra andre end sig selv
[/quote]

Forståeligt nok. =)

Hvis jeg selv har rodet mig ud i store problemer, laver jeg et nyt selvstændigt program, og i dette selvstændige program laver jeg den del jeg vil teste.

Fx. til at starte med, ville jeg tage et selvstændigt modul (noget der ikke har andet vævet ind i sig), nemlig ADC'en.
ADC.h og ADC.c er selvstændigt bygget op (det er med vilje at heg har presset dig til at holde det hele modulært opbygget).

ADC.c og ADC.h kan indbygges i et andet program, og når de er testet og virker, så kan man gå videre til næste modul, fx. Timer0.c og Timer0.h.

Citér
Når jeg gør det på den måde, ser det ud til at selve start knap funktionen ikke virker.
jeg kan tænde og slukke led 1 på pa7 ved at skrive setLED1(1); eller setLED1(0); i starten af main.c (som det sidste i init main) men hvis jeg skriver setLED1(1); nede i ISR(PCINT0_vect) funktionen så sker der intet når jeg trykker på start knappen. er dog ikke helt sikker på at min led rutiner er globale

Min main.c ser således ud
Kode:
/* {snip} */
int main()
{
    GPIOR2 = SERVO_ENABLED; /* This must be the first code executed; no code goes before it, and GPIOR2 is not to be changed from now */
initADC(8); /* initialize ADC, we'll use the 8-bit precision for now */
    initTimer0();
    initDosing();
    initServo();
sei(); /* globally enable interrupts */
    PCMSK0 |= (1<<PCINT3); /*Set PA3 as the pin to use*/
MCUCR = (1 << ISC01) | (0 << ISC00); /* interrupt on INT0 pin, falling edge */
GIMSK  |= (1<<PCINT3);
setLED1(1);
while(1)
{
/* we don't really need to do anything here. Everything is handled by the interrupts */
}
    return(0); /* (never reached) */
}
ISR(PCINT0_vect)
{
    uint8_t pinValue;
    pinValue = PINA & (1 << PINA3);                             /* read value of input-pin */
    if(pinValue) /* we're only interested if button is pressed */
    {
        _delay_ms(10.);                                          /* wait 10 ms */
        pinValue = PINA & (1 << PINA3);                         /* read value of input-pin */
        if(pinValue) /* only update settings when button value is stable */
        {
setLED1(0);  /* turn LED1 off */
            startDosing();   
        }
    }
}

Ikke at det er noget der får programmet til ikke at virke, men jeg vil anbefale at rokere lidt om, plus at ændre linien MCUCR = ...:

Kode:
    	PCMSK0 |= (1<<PCINT3);								/*Set PA3 as the pin to use*/
MCUCR = MCUCR & ~((1 << ISC01) | (1 << ISC00)) | (1 << ISC01) | (0 << ISC00); /* interrupt on INT0 pin, falling edge */
GIMSK  |= (1<<PCINT3);
sei(); /* globally enable interrupts */

linien som skriver i MCUCR ændrer nu ikke ved de andre bits i dette register (de var 0 i forvejen, men hvis du en dag kigger tilbage på koden, trækker du ikke en ting med over i et nyt progam, som kan give dig bøvl).
sei(); er sat sidst, fordi PCINT0 er et interrupt, og vi vil gerne 'have ro' mens vi sætter interrupts op.

Når så det er gjort, skal du vide at....
MCUCR registret har intet med Pin Change interrupt at gøre.
Den har kun med INT0, altså Pin B2 at gøre, så fjern den linie fuldstændig. :)

Derudover...
Kode:
	GIMSK  |= (1<<PCINT3);
[code]

Se side 50 i databladet. :)
Derefter se side 52.

(Den slags har jeg selv haft meget bøvl med, [fnis])

Prøv så følgende...

I main's while(1):
[code]while(1)
{
    setLED0(0);
    setLED1(0);
    setLED2(0);
    setLED3(0);
}

...i PCINT0:
Kode:

ISR(PCINT0_vect)
{
    uint8_t pinValue;
    pinValue = PINA & (1 << PINA3);                             /* read value of input-pin */
    setLED0(1);
    if(pinValue) /* we're only interested if button is pressed */
    {
        setLED1(1);
        _delay_ms(10.);                                          /* wait 10 ms */
        pinValue = PINA & (1 << PINA3);                         /* read value of input-pin */
        if(pinValue) /* only update settings when button value is stable */
        {
            setLED2(1);
            startDosing();   
        }
    }
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 15:45:58
 :D
Citér
   GIMSK  |= (1<<PCINT3);
Se side 50 i databladet. :)
Derefter se side 52.

(Den slags har jeg selv haft meget bøvl med, [fnis])

skal GIMSK hedde
GIMSK  |= (1<<PCINT0);
og er ikke helt sikker på om SREG er noget jeg skal sætte op?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 15:51:15
skal GIMSK hedde
GIMSK  |= (1<<PCINT0);

Nej. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 16:41:51
gg så prøver jeg lige den her istedet
GIMSK  |= (1<<PCIE0);

Hvis GIMSK kun har 3 muligheder int0 PCIE1 og PCIE0 hvorfor melder compiler så ikke fejl når jeg skriver andet.

WEEEEEEEE der sker noget. men den mangler at registrerer led 3. men den tænder godt nok led 4 i startDosing();   (dog ikke altid. men 90% af gangene) og altid 2. gang hvis ikke første

pinValue = PINA & (1 << PINA3);
if(pinValue)
          {
      setLED3(1);
      setLED2(0);                              /* turn LED1 off */
                startDosing();   
          }
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 17:47:55
gg så prøver jeg lige den her istedet
GIMSK  |= (1<<PCIE0);

Meget bedre. :)

Citér
Hvis GIMSK kun har 3 muligheder int0 PCIE1 og PCIE0 hvorfor melder compiler så ikke fejl når jeg skriver andet.

Dette skyldes at PCIE1 og PCIE1 kun er talværdier.
Du kunne i teorien også skrive...

GIMSK = 172;

Men det er noget mere forståeligt at bruge de macroer / definitioner, som tilhører GIMSK ifølge databladet.


Citér
WEEEEEEEE der sker noget. men den mangler at registrerer led 3. men den tænder godt nok led 4 i startDosing();   (dog ikke altid. men 90% af gangene) og altid 2. gang hvis ikke første

Lyder godt. Fejlene må vi lige kigge på, den er nødt til at gøre det samme hver gang, så man kan stole på den. ;)

Hvis nu din programmerings-enhed er koblet på, samtidig med at du tester, kan den være årsag til at den ene LED ikke tændes.
Prøv at koble programmerings-enheden fra, for lige at afprøve teorien. ;)

Citér

pinValue = PINA & (1 << PINA3);
if(pinValue)
          {
      setLED3(1);
      setLED2(0);                              /* turn LED1 off */
                startDosing();   
          }

Det kan være det er tid til at du sender mig en opdatering af hvordan filerne ser ud nu.
Det er bedst, hvis du højre-klikker på mappen og vælger at komprimere den til et zip-arkiv.
-På den måde får du også en backup af hvordan det hele ser ud på nuværende tidspunkt, hvis nu der skulle gå ged i et eller andet. :)

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 17:52:20
Det vil jeg gøre. tusind tak.

lige et spørgsmål mens jeg pakker og sender.
er der en hurtig måde man kan toggle et led så den tænder og slukker hver gang sekund skifter ? noget bit shift eller noget
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 19:47:18
lige et spørgsmål mens jeg pakker og sender.

Du skulle på nuværende tidspunkt have modtaget en mindre modifikation af koden - ikke noget afsindig vigtig, men bare 'housekeeping', og så en rettelse af Makefile, som havde en fejl i 'clean' funktionen.

Citér
er der en hurtig måde man kan toggle et led så den tænder og slukker hver gang sekund skifter ? noget bit shift eller noget

AVR har sådan en smart feature (som jeg mener at PIC også har, for den sags skyld), at skriver man til INPUT porten, vil alle de bits, man skrive, blive togglet til det modsatte.

Så du kan...
Kode:
    PINA |= (1 << PA4);  /* toggle LED on/off */

(PINA - også kaldet PORTINA - er dér, hvor du læser værdier, mens PORTA er dér, hvor du normalt skriver værdier)

Den stump kode kan du prøve at sætte ind i ISR(TIM0_OVF_vect), lige efter sSeconds++;
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 20:13:42
tusind tusind tak  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 20:17:17
tusind tusind tak  :P

Bare hyggelig (dette er den norske måde at sige velbekomme)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 20:26:08
 :)
men den toggler desværre ikke hvert sek. den lyser bare konstant det betyder vel at timeren ikke kører som den skal  :o
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 19, 2011, 23:06:03
:)
men den toggler desværre ikke hvert sek. den lyser bare konstant det betyder vel at timeren ikke kører som den skal  :o

Hmm, det kan være den bare er vældig langsom.
Prøv at vente 8-10 sekunder, og se så om den slukker...

Ihvertfald har jeg lige fundet en lille fejl:

Prøv at åbne Timer0.c...
I ISR(TIM0_OVF_vect) står noget med F_CPU / 64, dvs, her regner vi med at vi bruger prescaler clk/64!
Går vi ned i initTimer0, og kigger på TCCR0B = ..., ser vi at CS02, CS01 og CS00 er sat til 010, dvs. prescaler = clk / 8.
Derfor skal vi lige have rettet (0 << CS00) til (1 << CS00), og kommentaren 2 linier ovenover skal hedde PRESCALER64 istedet for PRESCALER8.

Dette burde få timeren til at køre i korrekt hastighed.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 19, 2011, 23:12:25
super. fantastisk.
prøver det fluks


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 ?!?!  :-[
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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());
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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' */
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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();
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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);
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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));
}
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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:

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.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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


Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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...
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter 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
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter 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)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 18:53:39
Du er genial.
Nu sker der da noget.
hvis jeg smider toggleLED1(); ind lige efter sSeconds++;
så slukker led når jeg trykker på start. og så sker det fantastiske at led tænder igen efter x antal sek. nogle gange. andre gange bliver led lidt skarpere lige når der trykkes  :P

men forsinkelsen er altid mellem 10 og 26 sek og startknappen kan derefter aktiveres igen og enten gøre led skarpere eller slukke den i x sek. for det meste omkring 15 sek
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 21, 2011, 19:00:07
Du er genial.
Nu sker der da noget.
hvis jeg smider toggleLED1(); ind lige efter sSeconds++;
så slukker led når jeg trykker på start. og så sker det fantastiske at led tænder igen efter x antal sek. nogle gange. andre gange bliver led lidt skarpere lige når der trykkes  :P

men forsinkelsen er altid mellem 10 og 26 sek og startknappen kan derefter aktiveres igen og enten gøre led skarpere eller slukke den i x sek. for det meste omkring 15 sek

Prøv at have toggleLED1(); inde lige efter sSeconds++, og vent, se hvor lang tid der går mellem hver gang den går fra tændt til slukket eller slukket til tændt.
Der skulle helst gå 1 sekund, dvs. 2 sekunder mellem hver 'tænd'.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 19:13:53
det er der jeg har den nu og den gør som beskrevet ovenfor. den køre kun 1 cycle pr tryk på startknappen og mellem 5 og 25 sek

dette sker kun hvis der er en startDosing() lige efter sei i main, og samtidig inde i startknap funktionen fjerner jeg den efter sei i main sker der intet.
så for mig giver det ikke lige mening
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 19:18:10
ok fjernede startdosing efter sei, i main.
smed en setLES ind i startknapfunktionen så jeg er sikker på den slukker når jeg trykker.
der efter er der en toggleLED lige efter sSecond++

den slukker når jeg trykker på strtknap og tænder x antal sek efter igen. men så forbliver den tændt
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 21, 2011, 19:22:08
ok fjernede startdosing efter sei, i main.
smed en setLES ind i startknapfunktionen så jeg er sikker på den slukker når jeg trykker.
der efter er der en toggleLED lige efter sSecond++

den slukker når jeg trykker på strtknap og tænder x antal sek efter igen. men så forbliver den tændt

Har du prøvet at vente på den i mere end 1 minut, for at se om den blinker med lange mellemrum ?
-Det kan nemlig godt være at Timer0 interruptet kører en forkert hastighed.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 19:30:21
har prøvet at lade den stå i flere minutter og den togler ikke igen.
tiden der går før den togler når jeg har slukket den ved at trykke på start er random men ændre jeg på dip indstillingen så ændres det interval til noget meeeget længere
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 21, 2011, 20:18:02
har prøvet at lade den stå i flere minutter og den togler ikke igen.
tiden der går før den togler når jeg har slukket den ved at trykke på start er random men ændre jeg på dip indstillingen så ændres det interval til noget meeeget længere

Hmm, det kan selvfølgelig være den blinker meget hurtigt. Prøv at sætte toggleLED ind lige før sSeconds = 0;
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 21:03:58
Den kommer desværre slet ikke derned har ventet 5 min nu så det er hvertfald ikke fordi timeren kører for hurtigt
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 21, 2011, 23:08:26
nu prøvede jeg for sjovt at hive hele timer funktionen fra ISR(TIM0_OVF_vect) uden for i sin egen funktion som jeg ikke starter nogle steder.
i ISR(TIM0_OVF_vect) satte jeg så en toggleLED ind og den står og pulserer så ISR(TIM0_OVF_vect) må jo virke
smider jeg så en waitSeconds(1) ind foran toggleLED() så blinker led med et interval på ca ½sek så waitsecond funktionen må jo også virke
dog ikke helt for den er ureglmæssig og der bliver ikke længere interval hvis den skal vente længere



Hvis jeg så trykker på startknappen så halveres intervallet ca. nogle gange. det er meget tilfældigt. andre gange starter den igen med samme interval. men der går altid x sek før den starter igen
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 22, 2011, 02:10:53
nej jeg kan simpelthen ikke gennemskue det.
det sidste jeg har prøvet er at sætte hele timeren ind i ISR(TIM0_OVF_vect) igen så den er som du har sendt den.
hvis jeg så sætter TCNT0 = 255; så flasher ledden faktisk helt nede i if(sSeconds >= 60)   funktionen
men det går meget stærkt og lige under sSeconds++; lyser den konstant, så det må køre sindsygt hurtigt systemet.
hvilket også bliver bekræftet ved at ledden blinker langsomere hvis jeg sætter if(sSeconds >= 255)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 22, 2011, 08:16:26
hvis jeg så sætter TCNT0 = 255; så flasher ledden faktisk helt nede i if(sSeconds >= 60)   funktionen
men det går meget stærkt og lige under sSeconds++; lyser den konstant, så det må køre sindsygt hurtigt systemet.
hvilket også bliver bekræftet ved at ledden blinker langsomere hvis jeg sætter if(sSeconds >= 255)

Du har lige fundet ud af noget vigtigt. :)

Prøv at sætte TCNT0 til 0, og hav en toggleLED lige efter.
Kan du se om lysdioden blinker (hurtigt) nu ?


Hmm, vent nu lige lidt... Har du på noget tidspunkt ændret chippens fuse-bits ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 22, 2011, 10:24:00
Citér
Hmm, vent nu lige lidt... Har du på noget tidspunkt ændret chippens fuse-bits ?

Det har jeg selv tænkt på men aner det faktisk ikke.
Jeg kan ikke huske om jeg nogensinde fik den til at compile med avrstudio5 makefile, den er pr default 8mhz. Men jeg mener aldrig at jeg fik den til at compile med denne
og så har jeg kun brugt den som jeg fik af dig.

når jeg køre avrdude skriver den avrdude: safemode: Fuses OK. og det er når der er compilet med den makefile hvor fuses sat til H:0xdf og L:0x62

Citér
Kan du se om lysdioden blinker (hurtigt) nu ?
Ja, når TCNT0 = 0 så blinker den hurtigt

Har også prøvet den interne _delay_ms(10); sammen med en toggleLED
hvis TCNT0 = 255 og _delay_ms(1000) så er den ca tændt 1 sek og derfter slukket 1 sek så det er jo rigtigt nok men 1000 ms er jo 1 sek ligemeget om den køre 1 Mhz eller 8Mhz så det kan jo ikke bruges til så meget
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 22, 2011, 12:38:29
når jeg køre avrdude skriver den avrdude: safemode: Fuses OK. og det er når der er compilet med den makefile hvor fuses sat til H:0xdf og L:0x62

Jeg husker ikke om den altid gør dette, eller om den kun gør det ved skrivning.

Hvis du har mulighed for at skrive følgende...

make fuse

Vil det indstille fuses som de er i Makefile. Denne kommando køres nemlig ikke normalt ved almindelig flashing.

Citér

Citér
Kan du se om lysdioden blinker (hurtigt) nu ?
Ja, når TCNT0 = 0 så blinker den hurtigt.

Har også prøvet den interne _delay_ms(10); sammen med en toggleLED
hvis TCNT0 = 255 og _delay_ms(1000) så er den ca tændt 1 sek og derfter slukket 1 sek så det er jo rigtigt nok men 1000 ms er jo 1 sek ligemeget om den køre 1 Mhz eller 8Mhz så det kan jo ikke bruges til så meget
[/quote]


Prøv at lave denne smule test-kode...

Kode:
while(1)
{
    _delay_ms(250);
    _delay_ms(250);
    toggleLED1();
}

Hvis microcontrolleren kører 1MHz, vil ovenstående LED blive tændt med 1 sekunds mellemrum, dvs. fra tænd-til-tænd vil være 1 sekund.

Derimod, hvis den blinker ca. 8 gange så hurtigt, kører microcontrolleren 8MHz.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 22, 2011, 14:16:54
Citér
Prøv at lave denne smule test-kode...
den er en lille smule langsomere end et sek. men et delay på 250ms er det ikke 250 ms ligemeget om den køre 8 mhz eller 1 mhz

hvor skal jeg skrive det der med make fuse henne ?  ;D
taber ca 4 sek på et minut
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 22, 2011, 15:41:26
Citér
Prøv at lave denne smule test-kode...
den er en lille smule langsomere end et sek. men et delay på 250ms er det ikke 250 ms ligemeget om den køre 8 mhz eller 1 mhz

Næh, ikke på en microcontroller, for det måles nemlig i forhold til clock-frekvensen.
Og hvis microcontrolleren står på 8MHz, og F_CPU's værdi er defineret til 1000000, så vil den blinke 8 gange i sekundet i stedet for 1 gang.

Citér

hvor skal jeg skrive det der med make fuse henne ?  ;D
taber ca 4 sek på et minut

Den er sådan set iorden, så du behøver ikke make fuse. Hvis du bruger WinAVR, kan du prøve at skrive det nede i bunden af vinduet, dér, hvor du har log og fejl-meddelelser, men jeg ved ikke om det vil fungere. -Jeg bruger jo selv et lidt anderledes system.

-Nu har vi konstateret at den kører 1MHz, som vi gerne vil have den til.
Hvorfor den så opfører sig så fjollet at køre interruptet alt for hurtigt, må vi lige finde ud af.

Jeg har prøvet at gå opsætningen igennem endnu en gang (og prøvet at skrive en ny opsætning, for at se hvordan jeg ville gøre det i dag), jeg fik samme resultat af opsætning, så jeg er ved at tro at der kan være noget andet, som påvirker interruptets tids-indstilling.

Jeg er nok nødt til lige at bruge lidt mere tid på det, inden jeg sender et kvalificeret svar. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 22, 2011, 15:46:17
kan man ikke risikere at man køge en cli mere end sei eller?
jeg tænker bare at hvis man f.eks køre en sei i main og så kører alle interrupts derud af men i setMinuteCountdown(uint16_t aMinuteCountdown) kører man så en cli uden en sei. har den så ikke stoppet interrupts og setMinuteCountdown bliver kaldt fra startDosing() som igen kaldes hver gang startknappen trykkes ned eller når tiden løber ud og timer0Elapsed kaldes
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 22, 2011, 16:10:02
kan man ikke risikere at man køge en cli mere end sei eller?
jeg tænker bare at hvis man f.eks køre en sei i main og så kører alle interrupts derud af men i setMinuteCountdown(uint16_t aMinuteCountdown) kører man så en cli uden en sei. har den så ikke stoppet interrupts og setMinuteCountdown bliver kaldt fra startDosing() som igen kaldes hver gang startknappen trykkes ned eller når tiden løber ud og timer0Elapsed kaldes

setMinuteCountdown skylder jeg en forklaring på...

Først: I setMinuteCountdown skulle der gerne være én cli og én sei. :)
Her er formålet at sikre at vi ikke får læst halvdelen af sMinuteCountdown eller halvdelen af sMinuteCoundownRestart, imens vi skriver værdierne.
Dette kan nemlig ske, fordi vores microcontroller er 8-bit, og kun læser/skriver én byte ad gangen, og på et hvilket som helst tidspunkt i programmet kan der ske et interrupt.

Dernæst, skal du have en lidt mere uddybende forklaring af hvordan timer og interrupt egentlig fungerer.

1: En timer sættes op til at køre en bestemt hastighed.
2: Hver timer kan give os nogle oplysninger, fx...
  A: Når timeren's tæller får 'overløb', dvs. når TCNT0 skifter fra 255 til 0 ved at den tæller én op.
    Når dette sker, sættes TOV0 bitten i TIFR0.
  B: Når timerens tæller rammer OCR0A (hvis vi altså har koblet COM0A0 og COM0A1 til), vil OCF0A bitten blive sat i TIFR0.
  C: Når timerens tæller rammer OCR0B (hvis vi altså har koblet COM0B0 og COM0B1 til), vil OCF0B bitten blive sat i TIFR0.
3: Hvis vi har koblet et fx. overflow interrupt på, ved at sætte TOIE0 bitten i TIMSK0, vil der ske et interrupt når TIFR0's TOV0 bit bliver sat.
4: Samme med OCIE0A og OCIE0B bittene i TIMSK0, de kobler Output Compare Interrupt's til, når de er 'sat', og disse interrupts kigger henholdsvis på OCF0A og OCF0B (Output Compare Flag 0 A / B).

På den måde har man mulighed for at kun have en timer kørende og ikke få interruptet til at udføre noget, selvom timeren kører. En timer kan også lave PWM uden at have et interrupt koblet på.
Man kan også manuelt få et interrupt til at blive kørt, ved at sætte en bit der hedder FOC0A/FOC0B (Force Output Compare 0 A/B)..

Hvis nu vi så antager at vi slukker for alle interrupts, så kører timerne videre, og de sætter flag som de plejer at gøre.
Tænder vi så for interrupts nogen tid efter, så vil disse interrupts straks blive udført, fordi flagene er allerede sat, og derfor går vi ikke glip af kørslerne, med mindre vi fx. er flere sekunder om at tænde for interrupts igen.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 23, 2011, 21:23:33
så nu er det nok gg (er der et maks for hvor mange gange man kan skrive til en avr?)
nu prøver jeg at teste det del for del.

har fået timeren til at køre på denne måde
Kode:


ISR(TIM0_OVF_vect)
{
volatile uint8_t count = 0 ;
count++;
if (count==30)
{
toggleLED1();
count=0;
TCNT0 =0;
}
}

Samtidig har jeg kommenteret initADC(8); ud i main
count er sat til 30 for (f_cpu/64=15622)/256 = 61 hvis tnct0 tæller op til 256 så må count tælle op til 61 på 1 sek, så jeg togler hvert ½ sek.

så nu vil jeg se om jeg kan finde ud af hvor i ADC det går galt for mig gg og så lige i ADC  :o gg

Har lige et spørgsmål til en linje i adc
   ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
så vidt jeg kan læse bør adc ligge mellem 50 og 200 Khz er jeg så ikke nød til at køre med en prescaler på  8-16 altså ADPS2, ADPS1, ADPS0 = 100 eller 011 ? lige nu er den 128, altså helt nede på 7,8 khz. men jeg er absålut ikke sikker. ADC'en er somsagt den jeg har flest problemer med at tyde

et andet spørgsmål.
Hvis vi køre 8 bit opløsning på adv skal det så ikke være left aligned?
ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR); her er den right
og i
ISR(ADC_vect)
if(ADCSRB & (1 << ADLAR)) er den left

Jeg er på meget usikker grund for jeg prøver bare at læse alle mulige tutorials og de er både fra atmega men mest fra tiny13

Så fandt jeg en lille ting som jeg er helt sikker på --- næsten  :o
i adc skal vi ikke bruge eller læse adc3value da den er sat op som ISR(PCINT0_vect) i main.c så retter #define ADC_FIRST og LAST til 1 og 2
samtidig fjerner jeg uint16_t getADC3Value() funktionen.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 14:40:56
så nu er det nok gg (er der et maks for hvor mange gange man kan skrive til en avr?)

Ja, 10000 gange.. :)
-Så du har nok rigeligt med forsøg endnu.
Personligt har jeg ikke prøvet at skrive så mange gange at jeg har brugt en AVR op.

Citér
nu prøver jeg at teste det del for del.

god idé.

Citér
har fået timeren til at køre på denne måde
{snip}

Jeg havde egentlig planer om at sætte en AVR op selv, men har i øjeblikket vældig meget der presser fra alle sider, så jeg ved ikke om jeg kan få overskud / tid lige nu.

Citér
Samtidig har jeg kommenteret initADC(8); ud i main
count er sat til 30 for (f_cpu/64=15622)/256 = 61 hvis tnct0 tæller op til 256 så må count tælle op til 61 på 1 sek, så jeg togler hvert ½ sek.

Hmm, jeg tror jeg blev forvirret tidligere.

Prøv følgende:
Kode:
ISR(TIM0_OVF_vect)
{
    volatile uint8_t count = 0;
    if(0 == count--)
    {
        TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125));
        count = 125 - 1;
        sSeconds++;
        toggleLED1(); 
    }
}

Det er fordi...

F_CPU er 1000000.
F_CPU / 64 = 15625.
15625 / 125 = 125.
TCNT0 skal sættes til 256 - 125 = 131, fordi TCNT så tæller op fra 131 til 256.
Dette skal den gøre 125 gange for at ramme 1 sekund (derfor skal count resettes når den rammer 125).

Citér
Har lige et spørgsmål til en linje i adc
   ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
så vidt jeg kan læse bør adc ligge mellem 50 og 200 Khz er jeg så ikke nød til at køre med en prescaler på  8-16 altså ADPS2, ADPS1, ADPS0 = 100 eller 011 ? lige nu er den 128, altså helt nede på 7,8 khz. men jeg er absålut ikke sikker. ADC'en er somsagt den jeg har flest problemer med at tyde

Ja, side 135 - det tror jeg du har ret i, ups. :)

Du kan roligt sætte den ned. ;)

Citér

et andet spørgsmål.
Hvis vi køre 8 bit opløsning på adv skal det så ikke være left aligned?
ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (0 << ADLAR); her er den right
og i
ISR(ADC_vect)
if(ADCSRB & (1 << ADLAR)) er den left

IF-sætningen kigger om den er left-aligned. Hvis ikke, så går den til else, hvor den håndterer at den er right-aligned. (Det er ihvertfald idéen, om den så gør hvad den får besked på...)

Vi vil nok helst have den right-aligned; det er nemmere i vores tilfælde.

Citér
Jeg er på meget usikker grund for jeg prøver bare at læse alle mulige tutorials og de er både fra atmega men mest fra tiny13

Du er nu ved at blive vældig skrap til AVR. =)

Citér
Så fandt jeg en lille ting som jeg er helt sikker på --- næsten  :o
i adc skal vi ikke bruge eller læse adc3value da den er sat op som ISR(PCINT0_vect) i main.c så retter #define ADC_FIRST og LAST til 1 og 2
samtidig fjerner jeg uint16_t getADC3Value() funktionen.

Jo, hvis det er en switch (startknap) der er koblet på PA3, så vil det være mest praktisk at læse den digitalt. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 14:47:15
Citér
-Så du har nok rigeligt med forsøg endnu.
gg du skulle bare vide

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 15:35:23
Citér
Jeg havde egentlig planer om at sætte en AVR op selv
Nej det skal du da ikke. lære også meget ved at prøve mig frem, så er mere end tilfreds med at du svare på mine spørgsmål og kommer med forslag. syntes selv de sidste par dage har bragt mig tættere på at forstå specielt adc delen. men har stadig ikke fundet ud af hvorfor den stopper/fryser derinde   :o
har for øvrigt også måske en design ændring der vil gøre det en del mere præcist, samtidig med at aflæsningerne af adc'er bliver lettere, da der ikke er brug for pot og dips.
jeg vil lige lufte det så jeg kan høre hvad du siger.

Jeg har modificeret en servo, så den kan køre kontinuerligt
hvis jeg så monterer en gevindstang på servoen så kan jeg jo få en møtrik til at køre frem og tilbage alt efter servoens omdrejningsretning, og der ved trække eller skubbe sprøjte stemplet.
giver det mening?
jeg mister godt nok positionsbestemmelse men får servoens fulde krafter og hastighedskontrol så det jeg mangler er egentlig bare en måde at bestemme hvor langt og hvordan.
dette kan jeg enten gøre ved kontakttryk, som kan indstilles på x antal ml og et når det er i bund. ellers kan jeg måske gøre det ved at instille pwm til at køre x antal ml i sek og så styre det på den måde.
Men den største fordel er at jeg får en linier bevægelse med langt flere krafter frem for servoarmens cirkel bevægelse

programmet er det samme stort set men når prototypen programmet er lavet kan man jo ændre det hele til at blive styrret vha 3 knapper og et visuelt feedback
1 plus knap, en minus knap og en vælg knap.

vil bare lige lufte det. har stadig tænkt mig at lave den her del færdig, for det kan godt være at det er den mest praktiske, og den anden kræver et visuelt feedback og derfor også nok en anden chip med flere ben
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 15:55:11
har lige et spørgsmål til forståelse af tabeller
hvor fleksible er de?
hvis der f.eks i en tabel står (1024+512)/2, (512+414)/2 skal adc værdien så ramme et af disse tal, for hvad så hvis værdien er +-10 eller mere
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 16:05:43
har lige et spørgsmål til forståelse af tabeller
hvor fleksible er de?
hvis der f.eks i en tabel står (1024+512)/2, (512+414)/2 skal adc værdien så ramme et af disse tal, for hvad så hvis værdien er +-10 eller mere

Tabellerne er beregnet sådan at de dækker et stykke ud over modstandenes idéelle værdier.

Dette vil sige, at jeg har taget forbehold for at modstands-netværket ikke giver en præcis værdi, og så har jeg gået så langt til hver side, som muligt.
Værdierne skulle være sikre hvis du bruger modstande med 1% tolerance, hvilket også skulle være til at få fat i. :)

Den tabel du har fået, er beregnet, hvilket vil sige, at den ikke er baseret på målinger, som mine første tabeller var, så den er nok så korrekt som den kan blive.

Med andre ord: Tabellen er forberedt på at modstands-værdierne ikke er helt præcise. =)

Med hensyn til modifikation af servo kan jeg ikke vejlede dig, da jeg ikke kender så meget til servoer. Jeg har ikke selv prøve at bruge dem endnu, men det kan være det kommer en dag. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 17:52:22
Citér
Med hensyn til modifikation af servo kan jeg ikke vejlede dig
har modificeret den. servoen har et internt potmeter, som bruges til at bestemme pos sammen med de impulser, så det eneste der sker er at man stiller det potmeter i midterpos og disconnecter det fra den mekaniske del. Når man så sender impulser til servoen (de samme pwm som vi bruger nu) så vil servoen på grund af det disconnected pot ikke vide om possitionen er nået, og derfor blive ved med at køre. hastigheden bestemmes af hvor mange ms high er fra 1.5ms som er midterpos.

Citér
Tabellerne er beregnet sådan at de dækker et stykke ud over modstandenes idéelle værdier.
Oki super. det var bare fordi jeg ikke lige forstod hvordan den aflæses. Jeg går ud fra at de tal der fremkommer mellem hvert komma er de enkelte værdier som passer med en adc værdi, og tabellen retunerer dermed et tal der svare til den komma plads adc værdien svare til. men jeg forstår ikke at hvis min adc værdi nu aflæses til at være 1001 hvordan ved den så hvilken plads det er når ingen af tabel værdierne giver 1001?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 18:17:10
Citér
Med hensyn til modifikation af servo kan jeg ikke vejlede dig
har modificeret den. servoen har et internt potmeter, som bruges til at bestemme pos sammen med de impulser, så det eneste der sker er at man stiller det potmeter i midterpos og disconnecter det fra den mekaniske del. Når man så sender impulser til servoen (de samme pwm som vi bruger nu) så vil servoen på grund af det disconnected pot ikke vide om possitionen er nået, og derfor blive ved med at køre. hastigheden bestemmes af hvor mange ms high er fra 1.5ms som er midterpos.

Det har du totalt styr på. Den dag hvor jeg har brug for at spørge om servo, ved jeg hvem jeg skal spørge. ;)
Citér

Citér
Tabellerne er beregnet sådan at de dækker et stykke ud over modstandenes idéelle værdier.
Oki super. det var bare fordi jeg ikke lige forstod hvordan den aflæses. Jeg går ud fra at de tal der fremkommer mellem hvert komma er de enkelte værdier som passer med en adc værdi, og tabellen retunerer dermed et tal der svare til den komma plads adc værdien svare til. men jeg forstår ikke at hvis min adc værdi nu aflæses til at være 1001 hvordan ved den så hvilken plads det er når ingen af tabel værdierne giver 1001?

Kort fortalt:
Den starter  i den ene høje af tabellen, og bliver ved med at vandre mod den lave ende, indtil den finder en værdi der er mindre end den værdi som du søger.

Hvis en modstand leverede værdien 1000, så vil der være 2 tabel-'entries' for denne værdi; fx. kunne den ene være 1300, den anden 850. Jo nærmere man kommer den lave ende, desto mere tæt ligger værdierne.

Først laves en tabel med 16 resultater med følgende formel:
i = værdi fra 1 til 16...

voltage[i] = (spænding * 1000 / i);

Dér skulle værdierne (rundet op) være...
    5000, 2500, 1667, 1250, 1000, 833, 714, 625, 556, 500, 455, 417, 385, 357, 333, 313.

Dernæst laves en tabel med ADC-resultaterne...
    adc_result[i] = 1023 * voltage[i] / 5000;
1023, 512, 341, 256, 205, 171, 146, 128, 114, 102, 93, 85, 79, 73, 68, 64.

Så laves en bundgrænse...
    adc_bottom[i] = (adc_result[i] + adc_result[i + 1]) / 2;
767, 426, 298, 230, 188, 158, 137, 121, 108, 98, 89, 82, 76, 71, 66, 32.

..og en top-grænse...
    adc_top[i] = (i > 0) ? ((adc_result[i - 1] + adc_result[i]) / 2) : 1023;
1023, 767, 426, 298, 230, 188, 158, 137, 121, 108, 98, 89, 82, 76, 71, 66.

Det er således top- og bund-grænserne du ser i tabellen.
Selvom de er beregnet til 5.0V, vil de være præcise selv hvis du kører 5.1V.
Dette er fordi ADC'ens reference-spænding er VCC, hvilket vil sige at den ikke kender forskel på VCC=5.0V og VCC=5.1V; den kender kun forskel på spænding i forhold til hvad VCC er. :)
Man kan sige at spændingen 5.0V er en midlertidig værdi for at vi mennesker bedre kan finde rundt i det, vi kunne lige så godt have valgt 1V eller 1000V... ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 20:11:08
nu har jeg jo lige et lille spørgsmål mere.
hvis jeg har forstået det rigtigt så gør et interrupt at avr stopper med det den er i gang med og udføre det der nu skal udføres i forbindelse med interruptet.
er det så ikke et problem hvis ISR(ADC_vect) fyrre 6000 interrupts af i sekundet og kigger på adc'erne så der samtidig er en ISR(TIM0_OVF_vect) der står og tæller løs på tnct0, bliver der ikke kamp om hvilket interrupt der har prioritet?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 20:28:03
det er linjen ADCSRA |= (1 << ADSC);
der skaber problemer i initADC
kommenterer jeg den ud starter uret med at køre inittimer
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 20:30:10
nu har jeg jo lige et lille spørgsmål mere.
hvis jeg har forstået det rigtigt så gør et interrupt at avr stopper med det den er i gang med og udføre det der nu skal udføres i forbindelse med interruptet.
er det så ikke et problem hvis ISR(ADC_vect) fyrre 6000 interrupts af i sekundet og kigger på adc'erne så der samtidig er en ISR(TIM0_OVF_vect) der står og tæller løs på tnct0, bliver der ikke kamp om hvilket interrupt der har prioritet?

Det er egentlig rigtigt observeret.

Men 6000 interrupts i sekundet er indenfor den sikre grænse. :)

Derudover har den ene type interrupt nemlig prioritet over den anden type interrupt. Fx. INT0 har meget høj prioritet; så vidt jeg husker er der noget med rækkefølgen af interrupt-vektorerne stemmer overens med interrupt-prioriteten, så "reset" har højest prioritet (hvilket absolut giver mening).

Men husk hvad jeg nævnte tidligere, nemlig at der bliver sat et flag til interruptet.
Så du går faktisk aldrig glip af et interrupt, fordi flaget bliver først clear'et (af hardware) når dit interrupt startes.
-Der er derfor ingen grund til at være bekymret, med mindre du presser den op på over 200000 interrupts per sekund på en 1MHz frekvens. :)

Timer-interrupt 0 vil blive udført 125 gange i sekundet (når du indstiller den til TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125)); )
Antager vi at ADC-interruptet tager omkring 50 clock cycles, kan vi maks. udføre...
1MHz / 50 clock cycles = 20000 interrupts pr. sekund.

-Så du burde uden bøvl kunne sætte ADC'en til at køre op til 18000 interrupts per sekund, vil jeg anslå.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 20:31:27
det er linjen ADCSRA |= (1 << ADSC);
der skaber problemer i initADC
kommenterer jeg den ud starter uret med at køre inittimer

Hmm, måske har vi stadig for mange ADC-interrupts per sekund. Vil lige kigge lidt på det.

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 20:40:22
kan man ikke lave en løsning hvor den kun aflæser adc værdierne når der trykkes på start knappen? der er jo ingen grund til at den kigger på dem når programmet er startet op, med mindre mam selvfølgelig vil ændre doseringen, men så ma man trykke på start når det er gjort. så skal ADC interruptne jo kun køres enten ved tryk på start, eller ved timer0elapsed
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 20:53:29
kan man ikke lave en løsning hvor den kun aflæser adc værdierne når der trykkes på start knappen? der er jo ingen grund til at den kigger på dem når programmet er startet op, med mindre mam selvfølgelig vil ændre doseringen, men så ma man trykke på start når det er gjort. så skal ADC interruptne jo kun køres enten ved tryk på start, eller ved timer0elapsed

Selvfølgelig. Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz.
Men du kan til at starte med, prøve at kalde initADC(10) fra main().
Og så i ADC-interruptet lave følgende lille ændring, det skulle give lidt mere CPU-tid:

Kode:
ISR(ADC_vect)
{
uint8_t adLo;
uint8_t adHi;

#if 0
if(adcBits <= 8) /* using 8-bit precision */
{
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) */
}
}
else
{
adLo = inb(ADCL); /* read lowbyte before highbyte! */
adHi = inb(ADCH); /* read lowbyte before highbyte! */
}
#else /* always 10-bit */
adLo = inb(ADCL); /* read lowbyte before highbyte! */
adHi = inb(ADCH); /* read lowbyte before highbyte! */
#endif
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 */
}

Her har jeg sat #if 0, #else og #endif ind. Jeg har også kopieret de 2 linier, som håndterer 10-bit konvertering.
Der spares nu omkring 10 ... 11 clock cycles i interruptet, og derfor burde det køre en smule bedre. Om det er nok, vil en prøve vise.

Jeg har en lille modifikation til Timer0.c...

I TIM0_OVF_vect:
Kode:
#if (F_CPU > 2000000)
TCNT0 = 256 - ((uint8_t) ((F_CPU / 256) / 125)); /* interrupt occurs 125 times per second. */
#else
TCNT0 = 256 - ((uint8_t) ((F_CPU / 64) / 125)); /* interrupt occurs 125 times per second. */
#endif

I initTimer0:
Kode:
#if (F_CPU > 2000000)
TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (1 << CS02) | (0 << CS01) | (0 << CS00)); /* using PRESCALER256 */
#else
TCCR0B = (0 | (0 << FOC0A) | (0 << FOC0B) | (0 << WGM02) | (0 << CS02) | (1 << CS01) | (1 << CS00)); /* using PRESCALER64 */
#endif

-For så kan du nemlig skifte mellem 1MHz og 8MHz som du har lyst. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 21:04:02
Citér
Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz
ja der er rigtigt. regnede også med at der var derfor at adc prescaleren var sat til 128.
mht at køre 8 mhz. den eneste grund til ikke at gøre dette er at jeg har læst at det skulle være sværre at lave den 20 ms cycle der skal bruges til servoen. ellers er der ikke nogen grund. til ikke at gøre det
og et eller andet sted er det vel også tåbeligt ikke at køre alt hvad den kan trække.
prøver at smide ændringerne ind.
ved ikke hvad jeg skulle have gjort uden din hjælp. det er jo en helt ny verden der åbner sig, hvis man kan lide at lege med sådan noget  :P
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 21:15:45
Citér
Det var egentlig forberedt på at skulle læse 2 potmetre og 2 sæt DIP-switches. ;)
...Derudover regnede jeg med at du ville køre microcontrolleren på 8MHz
ja der er rigtigt. regnede også med at der var derfor at adc prescaleren var sat til 128.
mht at køre 8 mhz. den eneste grund til ikke at gøre dette er at jeg har læst at det skulle være sværre at lave den 20 ms cycle der skal bruges til servoen. ellers er der ikke nogen grund. til ikke at gøre det

I øjeblikket kører Timer1 på clk / 1; den kan bare sættes til clk/8, så kører den samme hastighed som nu. :)
-Vi har jo gemt 16-bit timeren til det vigtige. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 21:17:44
det hjalp desværre ikke. men er det nødvendigt med ADCSRA |= (1 << ADSC); i initADC kan jeg ikke bare flytte den der er i bunden af ISR(ADC_vect) op i toppen af ISR(ADC_vect) ? vil det ikke give det samme?
hvis det er ok så køre timeren hvertfald

Da vil ADC'en aldrig køre, for det er netop ADCSRA's ADSC, der starter ADC'en. (Analog-to-Digital-Start-Conversion).
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 21:26:57
I øjeblikket kører Timer1 på clk / 1; den kan bare sættes til clk/8, så kører den samme hastighed som nu. :)
-Vi har jo gemt 16-bit timeren til det vigtige. ;)

Her er lidt forberedelse på at skifte frekvens til Servo.c, plus forhåbentlig bliver koden lidt mere læsbar...
Kode:
#include "leds.h"

#define PRESCALER1 ((0 << CS12) | (0 << CS11) | (1 << CS10)) /* clk / 1 (no prescaling) */
#define PRESCALER8 ((0 << CS12) | (1 << CS11) | (0 << CS10)) /* clk / 8 */
#define PRESCALER64 ((0 << CS12) | (1 << CS11) | (1 << CS10))
#define PRESCALER256 ((1 << CS12) | (0 << CS11) | (0 << CS10))
#define PRESCALER1024 ((1 << CS12) | (0 << CS11) | (1 << CS10))

#if (F_CPU <= 1000000)
#define PRESCALER PRESCALER1
#else
#define PRESCALER PRESCALER8
#endif

void initServo()

Længere nede, nemlig i initServo():
Kode:
	if(GPIOR2 == SERVO_ENABLED)
{
TCCR1B = (1 << WGM13) | (1 << WGM12) | PRESCALER; /* set WGM to fast PWM, choose clock source */
}

Jeg har ændret (1 << CS10) til PRESCALER
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 22:34:01
mht til ADCSRA |= (1 << ADSC);
kan jeg så ikke lade den ligge i initADC og så en i startknappen. så i ISR(PCINT0_vect) fjerne ADCSRA |= (1 << ADSC);
lave en
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}
hvis jeg gør det på den måde så køre timeren hvertfald.   
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 22:41:51
mht til ADCSRA |= (1 << ADSC);
kan jeg så ikke lade den ligge i initADC og så en i startknappen. så i ISR(PCINT0_vect) fjerne ADCSRA |= (1 << ADSC);
lave en
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}
hvis jeg gør det på den måde så køre timeren hvertfald.   

Hele denne blok...
Kode:
if(adcChannel == ADC_LAST)
{
     ADCSRA |= (0 << ADSC);
}

...gør ingenting - bortset fra at bruge CPU-tid. :)

Det vil være bedre at sætte microcontrolleren op på 8MHz, eller gå bort fra at bruge ADC-interrupt.
-Da skal vi til at kigge på at aflæse ADC'en manuelt; dvs. lave 4 aflæsninger manuelt i streg.
Det kan så gøres i getADCxValue().

...Men bemærk; én aflæsning vil nok være for upræcist / ustabil, for den vil nok virke nogle gange, men andre gange vil den slå fejl.
Det er derfor bedst at tage 4 aflæsninger (eller 8) og så lægge alle aflæsningerne sammen, og sidst dividere med antallet af aflæsninger.
...Jeg siger 4 eller 8, fordi man så kan bruge bitskift operationer, hvilket er langt mere CPU-venligt end almindelige divisioner. :)

-Men da skal initADC være lidt anderledes.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 25, 2011, 22:45:02
Citér
Hele denne blok...
gg ok  :-[
men skal der være en ADCSRA |= (1 << ADSC);
både i initADC og i ISR(PCINT0_vect)
er det ikke nok at starte den et sted ?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 25, 2011, 22:54:59
Citér
Hele denne blok...
gg ok  :-[
men skal der være en ADCSRA |= (1 << ADSC);
både i initADC og i ISR(PCINT0_vect)
er det ikke nok at starte den et sted ?

Den starter kun én konvertering ad gangen. :)
-Den kører nemlig ikke kontinuerligt, men skal sættes igang manuelt hver gang.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 26, 2011, 03:39:27
prøvede lige en sidste ting inden sove til
Kode:
ISR(ADC_vect)
{

if(ADCL > 128)
   {
setLED1(1);
setLED2(0);

   }
     
   else
   {
setLED1(0);
setLED2(1);
 
   }
ADCSRA |= (1 << ADSC);
}
void initADC(uint8_t aBits)
{

ADMUX = (0 << REFS1) | (0 << REFS0);
ADCSRA = (1 << ADEN) | (1 << ADIF) | (1 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
sei();
ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0) | (1 << ADLAR);

ADCSRA |= (1 << ADSC);
 }

Når jeg gør sådan så skifter led kun efter jeg ændre på dips og pot (ADCL) slukker strøm og tænder igen.
den vil ikke skifte mens der er tændt og jeg skifter. alle andre init er kommenteret ud.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 26, 2011, 23:23:31
nu har jeg simpelthen været ISR(ADC_vect) igennem fra a-z (det siger jeg hvertfald til mig selv :o ).
har enda haft lavet et komplet tomt program der kun tog sig af adc interrupt i free running mode og lige meget hvad
jeg gør så kræver det at jeg slukker og tænder for strømmen til avr, før den registrerer ændringer på adc'en. jeg kan ikke forstå det.

Lige et hurtigt spørgsmål.
hvis jeg vil ændre f_cpu kan jeg godt bare nøjes med at ændre clock i makefilen?

og lige en ting til. ved ikke om det har betydning for hvordan chippen har det, men device signature er som den skal være.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter November 26, 2011, 23:53:05
nu har jeg simpelthen været ISR(ADC_vect) igennem fra a-z (det siger jeg hvertfald til mig selv :o ).
har enda haft lavet et komplet tomt program der kun tog sig af adc interrupt i free running mode og lige meget hvad
jeg gør så kræver det at jeg slukker og tænder for strømmen til avr, før den registrerer ændringer på adc'en. jeg kan ikke forstå det.

Mærkeligt. Der må være noget vi har glemt i opsætningen, for det skal kunne virke.

Citér

Lige et hurtigt spørgsmål.
hvis jeg vil ændre f_cpu kan jeg godt bare nøjes med at ændre clock i makefilen?
Nej.
lfuse skal ændres til 0xe2, hvilket sætter frekvensen til 8MHz (bit 7) plus CLOCK skal ændres så den passer til den nye frekvens. -Hvis du kun ændrer F_CPU, vil det virke som om microcontrolleren kører 8 gange langsommere.

Citér
og lige en ting til. ved ikke om det har betydning for hvordan chippen har det, men device signature er som den skal være.

Nogle gange laver Atmel nye chips, og de laver derfor nye 'Device Signatures'.
I sådanne tilfælde skal man lave en konfiguration til den nye chip i sin avrdude.conf (hvor den så end befinder sig).
avrdude brokker sig hvis device-signature er forkert; ellers oplyser den bare hvad device-signature er, derfor kan du bare ignorere denne besked. :)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter November 27, 2011, 18:17:55
Hej igen.
nu bliver det lidt mere konkret gg
det er denne linie der fryser systemet i ISR(ADC_vect)
adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (adHi << 8 ) | adLo;            /* save the value we've read above */
og den hænger jo sammen med if (adcBits <= 8 )

ISR(ADC_vect)
{
    toggleLED1();

    uint8_t        adLo;
    uint8_t        adHi;

    if(adcBits <= 8 )                                                /* using 8-bit precision */
   {
        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) */
      }
   }
    else
   {
        adLo = inb(ADCL);                                             /* read lowbyte before highbyte! */
        adHi = inb(ADCH);                                             /* read lowbyte before highbyte! */
   }

så længe jeg køre 8 bit kan jeg jo reducere den til at fjerne alle else og når jeg ved at jeg har sat ADLAR i initADC kan jeg vel ogso fjerne if condition og det samme når jeg ved at adc er 8 bit sat i main.c fjerner jeg også den sidste if lige for en stund, og ender ud med en værdi for adLo og adHI. dem smider jeg så ind i linien der skaber problemer og den kommer til at hedde

adcValue[adcChannel - ADC_FIRST][adcWriteIndex] = (inb(ADCH) << 8 ) | 0;

er det korrekt reduceret?
hvordan den linie så fungerer har jeg ingen ide om endnu, men tror den har noget med de værdier der skal bruges i tabellen, og hvad det er der får den til at fryse har jeg heller ikke gennemskuet endnu  :o
Men erstatter jeg det før = tegnet med en anden variabel, så virker det godt og så må det være adcValue[adcChannel - ADC_FIRST][adcWriteIndex] der fryser systemet men det kan selvfølgelig også være værdien den vil skrive der er noget galt med

ved godt der er et mellemrum for meget i 8 ) men det er for at slippe for smily
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter December 10, 2011, 17:54:09
Har fundet ud af at hvis jeg istedet for freerunning mode sætter den til singleconversion mode og så starter en ny conversion med ADCSRA |= (1 << ADSC); inde i ISR(ADC_vect) så konverterer den der ud af.

HAr også haft servoen til at køre dog ikke ved hjælp af adc værdierne, men med konstante værdier.
MEN - -  er der en metode der elimere støj på pwm. for servoen står og sitre når den egentlig skulle stå stille. Så der må være en eller anden form for støj i pwm signalet eks vil værdien 1,2 ikke være konstant men nogle gange eks 1.21 og 1.19

og den eneste måde jeg kan få den til at køre 8 mhz er ved at sætte CLOCK til 1mhz og lfuse til e2 tror jeg
jeg tester det ved at hvis jeg lader lfuse være som den burde til 8 mhz, altså e2 og så sætter clock til 8mhz så kører blinker min timer langsommere
sætter jeg den som den skal i 1 mhz altså ifuse 62 så er den 8 gange langsomere med 8mhz clock end 1 mhz clock
kan dog kun se forskellen med en delay.
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter December 11, 2011, 02:41:23
fandt lige en bummert mere jeg har lavet.
det nytter jo ikke noget at jeg køre 8 bit adc og søger resultatet i en 10 bit tabel eller tager jeg fejl
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter December 23, 2011, 16:50:03
Man bliver jo helt bekymret når du ikke er på så lang tid. Men går ud fra at du har haft en vanvittig travl december.
Jeg har fået systemet til at virke som det skal, men har lavet lidt om i koden, for jeg kunne simpelthen ikke få tabellerne til at virke. Desuden var der ret meget støj på de laveste bits så var nød til at bruge målte værdier der. men når nu julen engang er overstået ville det være dejligt hvis du fik tid til at hjælpe med optimere koden, jeg er endt ud med ca. 18k. Til gengæld har jeg lært sindsygt meget med learning by doing metoden gg.
Men tusind tak for hjælpen indtil nu, og kan du have en FANTASTISK jul

Mange hilsner herfra.

Ps he he jeg har en bims der ligner en clock krystal. der står txc 8.00g9nf er det det eller ??
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Januar 09, 2012, 19:24:32
Man bliver jo helt bekymret når du ikke er på så lang tid. Men går ud fra at du har haft en vanvittig travl december.

Jeg beklager at jeg ikke har været herinde så meget.
Der skete det, at jeg brændte ud. Stort set hele december forsvandt.

Nu kører jeg på stand-by mode, hvilket betyder at jeg ikke binder mig til opgaver eller giver nogle løfter.
Det ærgrer mig lidt, det er simpelthen nødvendigt. :(

Citér
Jeg har fået systemet til at virke som det skal, men har lavet lidt om i koden, for jeg kunne simpelthen ikke få tabellerne til at virke. Desuden var der ret meget støj på de laveste bits så var nød til at bruge målte værdier der. men når nu julen engang er overstået ville det være dejligt hvis du fik tid til at hjælpe med optimere koden, jeg er endt ud med ca. 18k. Til gengæld har jeg lært sindsygt meget med learning by doing metoden gg.
Men tusind tak for hjælpen indtil nu, og kan du have en FANTASTISK jul

Jamen i lige måde, og godt Nytår. :)

Citér
Ps he he jeg har en bims der ligner en clock krystal. der står txc 8.00g9nf er det det eller ??

Hmm.. Det kunne være en resonator.
En resonator er en modstand og kondensator der giver en cirka-frekvens.
Den er billigere end et krystal, men ikke så præcis.
Men hvis den er indpakket i et metalhus, så er det nok et krystal.
Har den 4 ben, er det nok en oscillator, hvilket vil sige at den har 1 ben der giver dig frekvensen.

Jeg er glad for at høre at du klarede at få det til at fungere.
...Men jeg er nødt til at holde en pause fra opgaver, så jeg må nok vente med at optimere koden.
Lidt ærgeligt at ADC'en var for upræcis med de nederste bits. -Var den stadig upræcis målt over flere gange og derefter taget gennemsnit?
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Januar 09, 2012, 19:52:34
Dejligt at høre fra dig.
Citér
Men jeg er nødt til at holde en pause fra opgaver
Du skal da passe på dig selv.
Jeg er gået videre med en udvidet udgave med display (16X2) og et menu system hvor jeg bruger knapper til at ændre værdier, og det går meget godt indtil videre.
Jeg bruger den atmega164pv10pu som du sendte med. og tror jeg har rimeligt styr på det indtil videre.
har endvidere udvidet med en forstærker det til at måle ph værdier og lidt andet.

"krystallen" er i et metal hus og har 2 ben. har bare forbundet den til de to xtal og smidt nogle 12 nf på også.
har været lidt i tvivl om hvorledet refference spæmdingen fungerer på atmega, men har gjort det at jeg har smidt en 10 nf mellem jord og vcc. vcc har jeg ført videre til avcc og også der smidt en 10 nf på mellem avcc og den gnd der ligger ved siden af avcc. slutteligt har jeg også smidt en 10 nf mellem aref og jord. det syntes jeg kunne læse mig til.

Men nok om det. jeg koder løst og har faktisk lært en del ved at "stå på egne ben" så at sige.  :o

Pas nu på dig selv. Jeg poster lidt en gang imellem, men forventer ikke at du binder dig eller noget. Det er jo heller ikke meningen at du skal være problem knuser for hele sitet.
Mange hilsner herfra  ;D
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: pacman efter Januar 09, 2012, 20:22:57
Du skal da passe på dig selv.

J-j-ja, jeg ska'nok, jeg ska'nok.. (Kjeld fra Olsen-banden)

Citér
Jeg er gået videre med en udvidet udgave med display (16X2) og et menu system hvor jeg bruger knapper til at ændre værdier, og det går meget godt indtil videre.
Jeg bruger den atmega164pv10pu som du sendte med. og tror jeg har rimeligt styr på det indtil videre.
har endvidere udvidet med en forstærker det til at måle ph værdier og lidt andet.

Ikke tosset. :)

Citér
"krystallen" er i et metal hus og har 2 ben
Det er nok et krystal.. Mht. valg af kondensatorer til krystaller, så bør de nok oftest ligge mellem 12pF og 27pF (begge inklusive); helst ikke udenfor disse værdier. Jeg selv bruger gerne 18pF. (Jeg går ud fra at du brugte 12pF og ikke 12nF; forskellen er "x 1000").

Citér
Men nok om det. jeg koder løst og har faktisk lært en del ved at "stå på egne ben" så at sige.  :o

Man lærer meget ved at prøve sig lidt frem. Du har jo lidt pejling på hvad du gør, så du kommer aldrig til at sidde fast nogle steder. :)

Citér
Pas nu på dig selv. Jeg poster lidt en gang imellem, men forventer ikke at du binder dig eller noget. Det er jo heller ikke meningen at du skal være problem knuser for hele sitet.

Jeg har hele mit liv kørt mig selv hårdt og presset mig til det yderste. Det er ikke en god idé, så jeg vil ikke anbefale det videre til andre. ;)
Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Januar 21, 2012, 02:14:42
Hej igen.
Jeg håber du kan give mig et hurtigt hint der ikke kræver for meget tid på flg.

jeg har koden
Kode:
	

switch (eDose1)
{
case 1: lcd_puts("Bal1 CaCl2-2H2O"); break;
case 2: lcd_puts("Bal2 NaHCO3"); break;
case 3: lcd_puts("Bal3 mineralsalt"); break;
case 4: lcd_puts("Kh buffer"); break;
case 5: lcd_puts("Ca Buffer"); break;
case 6: lcd_puts("Mg buffer"); break;
case 7: lcd_puts("Sporeelement 1"); break;
case 8: lcd_puts("Sporeelement 2"); break;
case 9: lcd_puts("Sporeelement 3"); break;
case 10: lcd_puts("Aminosyre"); break;
case 11: lcd_puts("VSV"); break;
case 12: lcd_puts("Jod"); break;
case 13: lcd_puts("Strontium"); break;
case 14: lcd_puts("Phyto"); break;
case 15: lcd_puts("Zoo"); break;
case 16: lcd_puts("Diverse1"); break;
case 17: lcd_puts("Diverse2"); break;
case 18: lcd_puts("Diverse2"); break;
}

Jeg skal bruge den 12 forskellige steder, men uafhængigt af hinnanden og kan jo bare bruge forskellige switch, men det fylder jo helt vildt hvis jeg laver 12 kodestumper.
Men jeg kan simpelthen ikke greje hvordan jeg kan lave en variabel der består af bogstaver f.eks a = "thomas";
for så kunne jeg bare definerer dem som så og så kalde den variabel jeg skal bruge.
Har også kigget på avr/pgmspace, men ligesom sidst her jeg ikke helt styr på det tabel halløj.
Håber du kan give et hint
 :o
fik det løst på flg måde.
Kode:
prog_char eName0[] = "";
prog_char eName1[] = "Bal1 CaCl2-2H2O";
prog_char eName2[] = "Bal2 NaHCO3";
prog_char eName3[] = "Bal3 mineralsalt";
prog_char eName4[] = "Kh buffer";
prog_char eName5[] = "Ca Buffer";
prog_char eName6[] = "Mg buffer";
prog_char eName7[] = "Sporeelement 1";
prog_char eName8[] = "Sporeelement 2";
prog_char eName9[] = "Sporeelement 3";
prog_char eName10[] = "Aminosyre";
prog_char eName11[] = "VSV";
prog_char eName12[] = "Jod";
prog_char eName13[] = "Strontium";
prog_char eName14[] = "Phyto";
prog_char eName15[] = "Zoo";
prog_char eName16[] = "Diverse1";
prog_char eName17[] = "Diverse2";
prog_char eName18[] = "Diverse3";
PROGMEM const char *eString_table[] =    
{   
eName0, eName1, eName2, eName3, eName4, eName5, eName6, eName7, eName8, eName9, eName10, eName11, eName12, eName13, eName14,
eName15, eName16, eName17, eName18
};
char eDose1buf[16];
char eDose2buf[16];
char eDose3buf[16];
char eDose4buf[16];
char eDose5buf[16];
char eDose6buf[16];


og nede hvor det skal bruges
Kode:
	
strcpy_P(eDose1buf, (char*)pgm_read_word(&(eString_table[dosing1num])));
lcd_puts(eDose1buf);

Titel: Sv: hjælp til servo kontrol med timer
Indlæg af: jascore efter Februar 13, 2012, 10:07:24
fandt en løsning  ;D