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

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #135 Dato: 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.

 

Offline pacman

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

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #137 Dato: Oktober 02, 2011, 13:40:00 »
wahooo skrev  og slettede mit første prog på attiny weeee. F..k Niel Armstrong he he

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #138 Dato: 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.
« Senest Redigeret: Oktober 03, 2011, 13:29:08 af jascore »

 

Offline pacman

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

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #140 Dato: 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
« Senest Redigeret: Oktober 03, 2011, 14:44:57 af jascore »

 

Offline pacman

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

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #142 Dato: 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 ?

 

Offline pacman

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

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #144 Dato: 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
« Senest Redigeret: Oktober 04, 2011, 16:46:48 af jascore »

 

Offline pacman

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

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #146 Dato: 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 */
}

« Senest Redigeret: Oktober 05, 2011, 18:00:10 af jascore »

 

Offline pacman

  • Højpas filter
  • *****
  • Indlæg: 311
  • Antal brugbare Indlæg: 8
  • Jens Bauer (Forsøgs-person)
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #147 Dato: 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 ? :)
« Senest Redigeret: Oktober 08, 2011, 01:59:57 af pacman »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #148 Dato: 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 ??




« Senest Redigeret: Oktober 09, 2011, 22:05:51 af jascore »

 

Offline jascore

  • Jordet Basic
  • **
  • Indlæg: 157
  • Antal brugbare Indlæg: 0
    • Vis profil
Sv: hjælp til servo kontrol med timer
« Svar #149 Dato: Oktober 09, 2011, 22:22:23 »
og tusind tak for arbejdet med dip readings