Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

Hulp C programmeren ATMEGA

Pagina: 1
Acties:
  • 1.158 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Op school hebben we een project gekregen. Mijn taak is onderandere het programmeren van de uC. De bedoeling is om met de ATMEGA32 een DC accuboor motor aan te sturen.

Maar aangezien ik veel onderzoek heb gepleegd in de andere onderdelen die ik ook moet doen. Is dit stuk mij een beetje ontschoten. Ook beginnen we pas met de lessen voor uC, maar dit moet ik volgende week al af hebben.

Dit is hoe ik het zou willen hebben:

- 2 knoppen om de snelheid te verhogen of verlagen
- 4 knoppen met een vaste snelheid, zodat als je op 1 knop drukt hij naar die ingestelde snelheid gaat.

Dit alles realiseren met het PWM signaal van de uC en in C. Ik heb wel iets ervaring met C maar ik zou zo zelf niet op weg kunnen komen.

Ik wou het zelf eerst testen met faden van leds mbv knoppen.

Zou iemand mij hierbij kunnen helpen, of iedergeval helpen met een begin en hoe ik dit het beste kan aanpakken?

Ik begin nu een beetje te stressen.
alvast bedankt

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Wat heb je aan hardware en software? Is er een kant en klaar bordje waar je mee moet werken, of moet je alles zelf in elkaar zetten? Heb je al naar de software van Atmel (AVR Studio) gekeken? Heb je al enige ervaring met microcontrollers in het algemeen?

www.madwizard.org


  • MeMoRy
  • Registratie: Augustus 2004
  • Laatst online: 17-07 12:50
Volgende week? Of je docent vraagt het onmogelijke van je, of je bent veels te laat begonnen...
Zonder enige ervaring in dit gebied zal het waarschijnlijk niet lukken... misschien kan je iemand hier inhuren ;)

U vraagt, wij antwoorden.


  • TrailBlazer
  • Registratie: Oktober 2000
  • Laatst online: 21-11 19:09

TrailBlazer

Karnemelk FTW

ik had mijn 1e progje in assembly voor een attiny in een dag in elkaar geklust met PWM dus dat is het probleem niet. De datasheets van Atmel staan vol met voorbeelden en op avrfreaks kan je ook een hoop info vinden

  • MewBie
  • Registratie: April 2002
  • Laatst online: 14:07
Dit is echt basiskennis uC's (kijken of een pinnetje 1 is, en iets naar een register schrijven)

Wat heb je zelf al uitgezocht?

Please leave a message after the beep.
*beeeeep*


Verwijderd

Topicstarter
Ik gebruik AVR Studio en ponyprog. Mijn testboardje is gebasseerd op de schema's van ponyprog.

Enige ervaring heb ik wel in C, maar ook niet echt om naar huis te kunne schrijven. Ik heb zelf wel wat uitgezocht, maar ik weet niet zo goed hoe een begin te maken met een PWM signaal.

[ Voor 3% gewijzigd door Verwijderd op 04-12-2006 16:50 ]


  • MewBie
  • Registratie: April 2002
  • Laatst online: 14:07
Zoek in de datasheet op welke pin een pwm sgnaal kan geven.
Zoek vervolgens de bijbehorende registers op en kijk hoe je alles in moet stellen.

Test mbv een ledje ofzo of het werkt zoals jij wil dat het werkt door er een aantal verschillende waardes naatoe te schrijven (naar het juiste register).

Please leave a message after the beep.
*beeeeep*


  • TrailBlazer
  • Registratie: Oktober 2000
  • Laatst online: 21-11 19:09

TrailBlazer

Karnemelk FTW

ik heb de assembly code wel liggen voor de attiny 2313 om een PWM signaal te genereren. Ik zoek hem wel even op

Verwijderd

Verwijderd schreef op maandag 04 december 2006 @ 16:38:
Ik gebruik AVR Studio en ponyprog. Mijn testboardje is gebasseerd op de schema's van ponyprog.

Enige ervaring heb ik wel in C, maar ook niet echt om naar huis te kunne schrijven. Ik heb zelf wel wat uitgezocht, maar ik weet niet zo goed hoe een begin te maken met een PWM signaal.
Moeilijk is dat niet. Deze werkt op een Atmega8 e.d.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#  define OC1 PB1
#  define DDROC DDRB
#  define OCR OCR1A
#  define PWM10 WGM10
#  define PWM11 WGM11

#if defined(COM11)
#  define XCOM11 COM11
#elif defined(COM1A1)
#  define XCOM11 COM1A1
#else
#  error "need either COM1A1 or COM11"
#endif

void pwm_init(void)
{                              // Initialiseer de PWM-uitgang PB1
    TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(XCOM11);    // 10-bit PWM
    TCCR1B = _BV(CS10) | _BV(WGM12);               // geen prescaler; fast-PWM
    OCR = 512;                         // puls-pauze verhouding = 50%
    DDROC |= _BV(OC1);                     // PB1 = output
}

Nu kan je in OCR een waarde plaatsen tussen 1 en 1022, en daarmee de puls-pauze verhouding regelen.

Verwijderd

Topicstarter
Dit is de code die ik tot nu toe heb

C: pwm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

enum { UP, DOWN };

unsigned int pwm;
unsigned int direction;

ISR (TIMER1_OVF_vect)       /* avr/interrupt.h */
{
    static uint16_t pwm;    /* PWM signaal wordt gebruikt in 10 bit mode
                 * 16 bits variabele nodig om de huidige stand te onthouden*/
    static uint8_t direction;

    switch (direction)      /* Bepaald de nieuwe waarde van het PWM signaal */
    {
        case UP:
            if (++pwm == 1023) /* 10 bit PWM */
                direction = DOWN;
            break;

        case DOWN:
            if (--pwm == 0)
                direction = UP;
            break;
    }

    OCR1A = pwm;            /* De nieuwe waarde in het PWM register */
}

void
ioinit (void)           /* Word opgeroepen na een reset, initaliseerd PWM en zet interrupts aan */
{
    /* Timer 1 is 10-bit*/
    TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1);
    /*
     * Start timer 1.
     *
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     */
    TCCR1B |= _BV(CS10); /* volledige clock */
    /*
     * Run any device-dependent timer 1 setup hook if present.
     */
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* Zet PWM value naar 0. */
    OCR1A = 0;

    /* Zet OC1 als output. */
    DDRB = _BV (PD5);

    /* Zet timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
    sei ();
}

int
main (void)
{

    ioinit ();

    /* eeuwige loop, de interrupts doen de rest */

    for (;;)            /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

    return (0);
}


Nou moet ik hier 4 knoppen aan toevoegen met een vaste waarde eraan. Zodat als er op 1 van de knoppen gedrukt word de motor, of in dit test geval het ledje, verandert van snelheid (lichtsterkte). Hoe kan ik dit het beste doen?

Verwijderd

Je for-lus laten controleren of in het geheugen het bitje dat hoort bij het pinnetje waar je knopje aanzit geset is, en als dat zo is de betreffende actie uitvoeren? ;)
Wel opletten dat ie eerst zon 100 controles is ingedrukt, ze zijn best gevoelig voor dendering etc.

Verwijderd

Topicstarter
Verwijderd schreef op vrijdag 08 december 2006 @ 02:25:
Je for-lus laten controleren of in het geheugen het bitje dat hoort bij het pinnetje waar je knopje aanzit geset is, en als dat zo is de betreffende actie uitvoeren? ;)
Wel opletten dat ie eerst zon 100 controles is ingedrukt, ze zijn best gevoelig voor dendering etc.
Een anti dender ben ik van plan om op te lossen mbv condensatoren over de knoppen.

De code heb ik op deze manier aangepast

C: Aangepast
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

enum { UP, DOWN };

unsigned int pwm;

SIGNAL (SIG_OVERFLOW1)
{
if (PA0 == 0x01)
{
    pwm=256;
}
        
else if (PA1 == 0x02)
{
    pwm=512;
}

else if (PA2 == 0x03)
{
    pwm=768;
}

else if (PA3 == 0x04)
{
    pwm=1023;
}
 OCR1A=pwm;
}

void
ioinit (void)           /* Word opgeroepen na een reset, initaliseerd PWM en zet interrupts aan */
{
    /* Timer 1 is 10-bit*/
    TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1);
    /*
     * Start timer 1.
     *
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     */
    TCCR1B |= _BV(CS10); /* volledige clock */
    /*
     * Run any device-dependent timer 1 setup hook if present.
     */
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* Zet PWM value naar 0. */
    OCR1A = 0;

    /* Zet OC1 als output. */
    DDRB = _BV (PD5);

    /* Zet timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
    sei ();
}

int
main (void)
{
    PORTA = (1<<PA0) | (1<<PA1) | (1<<PA2) | (1<<PA3);
    ioinit ();

    /* eeuwige loop, de interrupts doen de rest */

    for (;;)            /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

    return (0);
}


Ik heb nou geen testbordje bij de hand. Maar is dit een beetje de goede manier? Graag reacties, op en/of aanmerkingen.

  • Steefph
  • Registratie: Juli 2002
  • Laatst online: 18-11 12:42
Ik zou die knop uitlezing doen via switch met mask

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
switch(PORTA & 0b00111111){

case 1 :
pwm = 256;
break;

case 2 :
pwm = 512;
break;

case 4 :
pwm = 768;
break;

case 8 :
pwm = 1023;
break;

case up:                               //PA5
if(pwm < 1023)pwm++;
break;

case down:                          //PA4
if(pwm > 0)pwm--;
break;

default :
break;
}
while((PORTA & 0b00001111) != 0); //reageer maar 1 keer op knop

OCR1A = pwm;


maar mooier zou zijn als je via een schakeling een interrupt triggert en dan in de interrupt uitleest welke knop de interrupt heeft veroorzaakt. Hierin kun je gelijk dan ook de knopjes voor je 1 stap omhoog en omlaag meenemen want nu kijkt hij daar alleen naar als de timer overflowed.

[ Voor 63% gewijzigd door Steefph op 09-12-2006 00:49 ]

Alles is terug te redeneren naar 4


Verwijderd

Topicstarter
Steef1983 schreef op zaterdag 09 december 2006 @ 00:33:
Ik zou die knop uitlezing doen via switch met mask

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
switch(PORTA & 0b00111111){

case 1 :
pwm = 256;
break;

case 2 :
pwm = 512;
break;

case 4 :
pwm = 768;
break;

case 8 :
pwm = 1023;
break;

case up:                               //PA5
if(pwm < 1023)pwm++;
break;

case down:                          //PA4
if(pwm > 0)pwm--;
break;

default :
break;
}
while((PORTA & 0b00001111) != 0); //reageer maar 1 keer op knop

OCR1A = pwm;


maar mooier zou zijn als je via een schakeling een interrupt triggert en dan in de interrupt uitleest welke knop de interrupt heeft veroorzaakt. Hierin kun je gelijk dan ook de knopjes voor je 1 stap omhoog en omlaag meenemen want nu kijkt hij daar alleen naar als de timer overflowed.
Het omhoog en omlaag idee is nu eigenlijk helemaal van de baan. Het moeten echt knoppen worden met een vaste waarde eraan.

Ik probeer nu jou code te begrijpen, maar waarom maar 1 keer reageren op een knop? En waar wordt eigenlijk gedefineerd welke ingang er gebruikt word. Ik zie dat je PA4 en PA5 erneer hebt gezet, maar dat is toch een opmerking?

Iedergeval bedankt voor je hulp

  • Steefph
  • Registratie: Juli 2002
  • Laatst online: 18-11 12:42
Ik neem aan da het switch verhaal je duidelijk is aangezien je dat zelf ook hebt gebruikt. Wat ik doe ik lees de waarde van PORTA in bij "switch(PORTA" daarna and ik dit met "& 0b00111111)" hierdoor houd je dus alleen de input waardes over van PA0 tm PA5.
Op deze manier kun je dus bijvoorbeeld PA6 en 7 nog ergens anders voor gebruiken (ADC bijvoorbeeld) maar wordt deze waarde gemaskeerd door de & waarde.

Nu heeft de switch een waarde waarmee hij kan "schakelen". Bij jouw systeem met else if is hij veel langer bezig omdat hij steeds moet testen of het waar is of niet. Ook gebruik je de waarde 3 dit betekend dat zowel pin 1 als 2 hoog worden gemaakt (dit kun je doen met behulp van diodes maar mijn manier is simpeler maar kost weer meer io pinnen).

Bij mij hebben nu de pinnen PA0 tm PA3 een vaste waarde zoals jij dat wou. En PA4 en 5 verhogen de waarde PWM met stapjes van 1. Die "reageer maar 1 keer op knop" heb ik erin gezet zodat je zeer precies stapjes kan nemen bij het verhogen dit kun je er ook uithalen en dan zal hij zo snel als dat hij langs de switch komt de pwm waarde verhogen met 1.

Tevens zou je nog bij de "default" een stukje code kunnen neerzetten. Dit zorgt ervoor dat als de switch te maken krijgt met een ongedefinieerde waarde dat hij dan maar dit doet. Je zou bijvoorbeeld een led kunnen laten oplichten als dit voorkomt. Maar is dus niet echt belangrijk.

Iets anders wat je nog moet doen bij mijn stukje code is de waarden up en down definieeren door bovenaan je code "define UP 32" en "define DOWN 16" neer te zetten zonder de "".

Wat trouwens niet goed gaat bij jouw manier is je waarde definities. PA2 bijvoorbeeld kan 1 of 0 zijn en niet 0x03. Je leest een enkele pin uit en niet een bit reeks.

btw:
die for(;;) die je gebruikt kun je ook vervangen door een while(1){ "je code" } vind ik persoonlijk netter ;)

[ Voor 3% gewijzigd door Steefph op 09-12-2006 13:49 ]

Alles is terug te redeneren naar 4


Verwijderd

Topicstarter
@Steef1983

Als ik jou code wil compilen krijg ik errors, misschien gebruik ik een andere compiler dan jij (AVR Studio gebruik ik)

Iedergeval dit is nou mijn code.
C: aangepast
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <inttypes.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define UP 32; 
#define DOWN 64;

unsigned int pwm;

SIGNAL (SIG_OVERFLOW1) 
{
switch(PORTA & 0b00111111){ 

case 1 : 
pwm = 256; 
break; 

case 2 : 
pwm = 512; 
break; 

case 4 : 
pwm = 768; 
break; 

case 8 : 
pwm = 1023; 
break; 

case up:                               //PA5 
if(pwm < 1023)pwm++; 
break; 

case down:                          //PA4 
if(pwm > 0)pwm--; 
break; 

default : 
break; 

} 
while((PORTA & 0b00001111) != 0); //reageer maar 1 keer op knop 

OCR1A = pwm;
}

void
ioinit (void)           /* Word opgeroepen na een reset, initaliseerd PWM en zet interrupts aan */
{
    /* Timer 1 is 10-bit*/
    TCCR1A = _BV(WGM10) | _BV(WGM11) | _BV(COM1A1);
    /*
     * Start timer 1.
     *
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     */
    TCCR1B |= _BV(CS10); /* volledige clock */
    /*
     * Run any device-dependent timer 1 setup hook if present.
     */
#if defined(TIMER1_SETUP_HOOK)
    TIMER1_SETUP_HOOK();
#endif

    /* Zet PWM value naar 0. */
    OCR1A = 0;

    /* Zet OC1 als output. */
    DDRB = _BV (PD5);

    /* Zet timer 1 overflow interrupt. */
    TIMSK = _BV (TOIE1);
    sei ();
}

int
main (void)
{
    PORTA = (1<<PA0) | (1<<PA1) | (1<<PA2) | (1<<PA3) | (1<<PA4) | (1<<PA5);
    ioinit ();

    /* eeuwige loop, de interrupts doen de rest */

    for (;;)            /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

    return (0);
}


En de errors:
../PWM-test3.c:31: error: `up' undeclared (first use in this function)
../PWM-test3.c:31: error: (Each undeclared identifier is reported only once
../PWM-test3.c:31: error: for each function it appears in.)
../PWM-test3.c:35: error: `down' undeclared (first use in this function)

Hoe moet ik die declareren. Ik begreep al niet hoe je "case up" en "case down" had gedeclareerd aan PA4 en PA5. Deze heb ik al geprobeerd te declareren, maar dan geeft hij weer andere errors.

[ Voor 11% gewijzigd door Verwijderd op 11-12-2006 00:27 ]


Verwijderd

Topicstarter
Ik heb maar even de "case up" en "case down" eruit gehaald en getest. Maar het werkt niet op mijn testbordje. Hij doet niks, alles blijft gewoon uit.

Heb ik misschien de pullup voor mijn knoppen verkeerd gedeclareerd?

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Verwijderd schreef op maandag 11 december 2006 @ 00:09:
...
En de errors:
../PWM-test3.c:31: error: `up' undeclared (first use in this function)
../PWM-test3.c:31: error: (Each undeclared identifier is reported only once
../PWM-test3.c:31: error: for each function it appears in.)
../PWM-test3.c:35: error: `down' undeclared (first use in this function)

Hoe moet ik die declareren. Ik begreep al niet hoe je "case up" en "case down" had gedeclareerd aan PA4 en PA5. Deze heb ik al geprobeerd te declareren, maar dan geeft hij weer andere errors.
je definieert de constanten UP en DOWN, en die zijn case sensitive. Je moet in je code dan ook niet up en down gebruiken, maar UP en DOWN.

  • Steefph
  • Registratie: Juli 2002
  • Laatst online: 18-11 12:42
Verwijderd schreef op maandag 11 december 2006 @ 00:42:
Ik heb maar even de "case up" en "case down" eruit gehaald en getest. Maar het werkt niet op mijn testbordje. Hij doet niks, alles blijft gewoon uit.

Heb ik misschien de pullup voor mijn knoppen verkeerd gedeclareerd?
Hoe is je exacte schakeling voor je knoppen? Ik heb zelf vaak gehad dat als ik mijn knopjes als pull up gebruik dat de poort geladen word en hij niet meer naar beneden gaat. Dit is simpel op te lossen door een hoog ohmige weerstand van de IO pin naar de massa te leggen.

Tevens ben ik gewend om ook de DDR registers in te stellen Data Direction Register neem aan dat dat hier ook moet gebeuren. Zie wel dat je het doet voor poort B maar voor de zekerheid ook even doen voor poort A ;)

En zoals boven vermeld let op hoofdletter gebruik en achter een define regel hoort geen ;
dus gewoon #define up 32

offtopic:
Ik gebruik zelf codevision. Ben hier een keer mee begonnen en nog niet de moeite genomen om bijv. AVR studio te gebruiken.

[ Voor 18% gewijzigd door Steefph op 11-12-2006 10:25 ]

Alles is terug te redeneren naar 4


Verwijderd

Topicstarter
De drukknoppen zitten met een weerstand aan de massa.

De code heb ik weer aangepast. Geen errors meer. En ik heb nog wat andere kleine dingetjes aangepast. Maar hij blijft niks doen
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/sleep.h>

#define up 32
#define down 64

unsigned int pwm;

SIGNAL (SIG_OVERFLOW1)
{
    switch(PORTA & 0b00111111){ 

        case 1 : 
        pwm = 256; 
        break; 

        case 2 : 
        pwm = 512; 
        break; 

        case 4 : 
        pwm = 768; 
        break; 

        case 8 : 
        pwm = 1023; 
        break; 

        case up:                               //PA5 
        if(pwm < 1023)pwm++; 
        break; 

        case down:                          //PA4 
        if(pwm > 0)pwm--; 
        break; 

        default : 
        break; 
    } 
    while((PORTA & 0b00001111) != 0); //reageer maar 1 keer op knop 

    OCR1A = pwm;
}

void ioinit (void)
{
   TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1A1); 
   TCCR1B = _BV (CS10);
   OCR1A  = 0;
   DDRD   = _BV (PD5);
   TIMSK  = _BV (TOIE1);
   sei ();
}

int main (void)
{
   DDRA = 0x00;
   ioinit ();

     for (;;)           /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

   return (0);
}

  • L0we
  • Registratie: Mei 2004
  • Laatst online: 21-11 14:56
Wat je mist in de initialisatie is de instelling of poort a in of output is (mbv DDR register) en of de pullupweerstand aan staat of niet. (PORT- register).

Verwijderd

Topicstarter
Big Daddy schreef op maandag 11 december 2006 @ 12:32:
Wat je mist in de initialisatie is de instelling of poort a in of output is (mbv DDR register) en of de pullupweerstand aan staat of niet. (PORT- register).
Dus zo?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void ioinit (void)
{
   DDRA = 0x00;
   PORTA = 0xFF;
   TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1A1); 
   TCCR1B = _BV (CS10);
   OCR1A  = 0;
   DDRD   = _BV (PD5);
   TIMSK  = _BV (TOIE1);
   sei ();
}

int main (void)
{
   
   ioinit ();

     for (;;)           /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

   return (0);
}


Of moet ik het in mijn "main" zetten.

  • L0we
  • Registratie: Mei 2004
  • Laatst online: 21-11 14:56
Verwijderd schreef op maandag 11 december 2006 @ 12:40:
[...]


Dus zo?

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void ioinit (void)
{
   DDRA = 0x00;
   PORTA = 0xFF;
   TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1A1); 
   TCCR1B = _BV (CS10);
   OCR1A  = 0;
   DDRD   = _BV (PD5);
   TIMSK  = _BV (TOIE1);
   sei ();
}

int main (void)
{
   
   ioinit ();

     for (;;)           /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();

   return (0);
}


Of moet ik het in mijn "main" zetten.
PORTA = 0xFF; dan staat de pull-up aan toch? dan zul je de pinnen moeten schakelen naar de gnd. Als de schakelaars schakelen naar de massa zul je de pull-up weerstanden uit moeten zetten. DDRA weet ik niet exact of dat goed staat, meot je ff nakijken in de datasheet

Verwijderd

Topicstarter
Big Daddy schreef op maandag 11 december 2006 @ 13:08:
[...]

PORTA = 0xFF; dan staat de pull-up aan toch? dan zul je de pinnen moeten schakelen naar de gnd. Als de schakelaars schakelen naar de massa zul je de pull-up weerstanden uit moeten zetten. DDRA weet ik niet exact of dat goed staat, meot je ff nakijken in de datasheet
Klopt, ik moet de pull-up aan hebben staan. Maar iedergeval hij doet nu nog steeds niks. Het automatisch faden gaat wel goed (ik test met een ledje) , alleen het regelen met vaste waardes werkt op de 1 of andere manier gewoon helemaal niet.

[ Voor 3% gewijzigd door Verwijderd op 11-12-2006 13:29 ]


  • L0we
  • Registratie: Mei 2004
  • Laatst online: 21-11 14:56
Verwijderd schreef op maandag 11 december 2006 @ 12:20:
De drukknoppen zitten met een weerstand aan de massa.
...en...
Verwijderd schreef op maandag 11 december 2006 @ 13:27:
[...]


Klopt, ik moet de pull-up aan hebben staan. Maar iedergeval hij doet nu nog steeds niks. Het automatisch faden gaat wel goed (ik test met een ledje) , alleen het regelen met vaste waardes werkt op de 1 of andere manier gewoon helemaal niet.
Waarom? Als je de pull-up's aan hebt staan wordt de waarde van de port altijd naar de 1 getrokken, e schakelaar moet dan naar de ground schakelen om hem te laten veranderen (0 te maken dus).

Als je in jou geval de schakelaars met een weerstand naar de massa schakelt, en de pull-ups staan aan, verandert de waarde van de poort dus nooit, of hij ingedrukt is of niet. Ergens moet je dus iets veranderen.

Tip: als je ergens eens een statement neerzet als PORTB = PORTA, en ledjes aansluit op PORTB (definieren als output dus) kan je de werking van je knopjes testen. Dan weet je of hij uberhaupt reageert op de knopjes.

  • Steefph
  • Registratie: Juli 2002
  • Laatst online: 18-11 12:42
Wat ik trouwens niet weet of dat bij AVR studio ook zo is maar,
OCR1A bestaat uit 2 delen een H en L register.

Je moet dus je waarde pwm verdelen over deze 2 registers anders doet hij niks (maar dan zou hij in de compiler daar ook op moeten hangen). Echter als hij daarom niet werkt kun je dat oplossen door

code:
1
2
OCR1AH = pwm / 0xFF;
OCR1AL = pwm % 0xFF;

Alles is terug te redeneren naar 4


  • Rowwan
  • Registratie: November 2000
  • Laatst online: 14:59
OCR1AH = (pwm >>8);
OCR1AL = (pwm&0x00FF);

[ Voor 23% gewijzigd door Rowwan op 12-12-2006 19:56 ]


Verwijderd

Topicstarter
Na veel uitzoekwerk en proberen kom ik er nog steeds maar niet uit waar de fout zit waardoor hij het niet doet. Met de simulatie lijkt hij het wel te doen, alleen op het testbordje niet.

Kan iemand misschien die code op zijn eigen testbordje uit kunnen proberen. Kan ik tenminste iets uitsluiten

[ Voor 50% gewijzigd door Verwijderd op 13-12-2006 15:07 ]


  • Rowwan
  • Registratie: November 2000
  • Laatst online: 14:59
Helaas geen tijd :)..
Wel een andere tip: Gebruik eens de simulator van VMLAB (www.amctools.com). In deze simulator kun je ook je andere HW (toetsen, weerstanden) simuleren...

Verwijderd

Verwijderd schreef op maandag 11 december 2006 @ 12:20:
De code heb ik weer aangepast. Geen errors meer. En ik heb nog wat andere kleine dingetjes aangepast. Maar hij blijft niks doen
code:
1
2
3
4
5
6
7
8
9
10
11
12
...
unsigned int pwm;

SIGNAL (SIG_OVERFLOW1)
{
    switch(PORTA & 0b00111111){ 

        case 1 : 
        pwm = 256; 
        break; 
...
}
Nog een opmerking, en wellicht de oorzaak van je problemen: als je een globale variabele (pwm in dit geval) wil gebruiken in een interrupt-routine, dien je die als "volatile" te declareren. Zo, dus:

code:
1
2
3
4
5
6
7
8
9
10
11
12
...
volatile unsigned int pwm;

SIGNAL (SIG_OVERFLOW1)
{
    switch(PORTA & 0b00111111){ 

        case 1 : 
        pwm = 256; 
        break; 
...
}

Dat heb je nou met C-magie: 1 toverwoord verkeerd uitspreken, en de geest blijft in de fles...

Verwijderd

Topicstarter
Steef1983 schreef op dinsdag 12 december 2006 @ 16:36:
Wat ik trouwens niet weet of dat bij AVR studio ook zo is maar,
OCR1A bestaat uit 2 delen een H en L register.

Je moet dus je waarde pwm verdelen over deze 2 registers anders doet hij niks (maar dan zou hij in de compiler daar ook op moeten hangen). Echter als hij daarom niet werkt kun je dat oplossen door

code:
1
2
OCR1AH = pwm / 0xFF;
OCR1AL = pwm % 0xFF;
Die 2 registers zijn voor zover ik weet niet nodig bij AVR Studio

Ik heb de code nog maar wat aangepast en die functie voor de precieze stapjes er maar even voor het gemak eruit gehaald. Eerst maar even gewoon aan de praat kunnen krijgen.

Er zat trouwens nog wel een fout in jou code. PORTA & 0b00111111 moet volgens mij PINA & 0b00111111 zijn, omdat hij toch eigelijk de waarde van PINA uit moet lezen. PORTA is bij mij altijd hoog omdat ik met pullup werk. Verder heb ik die 0b00111111 maar veranderd in 0b00001111 omdat ik toch die stap voor stap eruit heb gehaald. En die laatste while loop heb ik eruit gehaald.

zo ziet hij er nu uit
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/sleep.h>

unsigned int pwm;

SIGNAL (SIG_OVERFLOW1)
{
    switch(PINA & 0b00111111){ 

        case 0x01 : 
        pwm = 256; 
        break; 

        case 0x02 : 
        pwm = 512; 
        break; 

        case 0x04 : 
        pwm = 768; 
        break; 

        case 0x08 : 
        pwm = 1023; 
        break; 

        default : 
        break; 
    } 
    OCR1A = pwm;
}

void ioinit (void)
{
   DDRA = 0x00;
   PORTA = 0xFF;
   TCCR1A = _BV (WGM10) | _BV (WGM11) | _BV (COM1A1); 
   TCCR1B = _BV (CS10);
   OCR1A  = 0;
   DDRD   = _BV (PD5);
   TIMSK  = _BV (TOIE1);
   sei ();
}

int main (void)
{
   
   ioinit ();
    for (;;)            /* Zet de processor in slaapstand tot de volgende interrupt*/
        sleep_mode();
   return (0);
}

maar toch blijft hij niks doen op de 1 of andere manier

suggesties nog?

Verwijderd

Ja: lees mijn opmerking hierboven!

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Ik begrijp dat je de schakelaars nog steeds in combinatie met een weerstand naar GND schakelt? Dus naast de interne pull-ups ook nog een externe weerstand tussen schakelaar en GND? Dat is zoals eerder gezegd niet nodig, maar mag wel met de beperking dat de weerstand naar GND veel kleiner moet zijn dan de interne pull-up waarde, omdat de spanning anders nooit in de buurt komt van de 0V.

Hoe dan ook zijn de input pinnen in jouw geval laag als ze actief zijn (active low), maar je code doet nu alsof ze active high zijn.
C:
1
2
3
4
    switch(PINA & 0b00111111){
        case 0x01 : 
        pwm = 256; 
        break; 

Stel dat de schakelaar op bit 0 (waarde 1 dus) aan staat. De 0de bit van PINA is dan 0, alle overige bits worden door de pull-ups nog steeds omhoog getrokken. De waarde van PINA is in dat geval dus 0b11111110. Een AND met de waarde zoals in de switch staat geeft 0b00111110. Dat is dus niet gelijk aan 1, ookal is die toets wel ingedrukt. Snelle oplossing:
code:
1
2
3
unsigned char buttons = ~PINA; // PINA met bits geinverteerd
   switch(buttons & 0b00111111)
[...]


edit:@Pros797: hoewel je gelijk hebt maakt het in dit geval denk ik weinig uit dat het niet volatile is. Volatile is om te voorkomen dat de compiler verwacht dat een variabele zijn waarde behoudt in een stuk code zolang deze niet in dat stuk code wordt aangepast (in het kort: een *externe* wijziging). Als je a=4; if (a==4) doiets(); doet, zou de compiler dat kunnen vereenvoudigen tot alleen maar doeiets(), omdat a altijd 4 is bij de if. Is a echter volatile, kan deze tussen a=4 en de if aangepast worden door een extern proces (zoals een interrupt) en hoeft de if conditie niet altijd waar te zijn.
pwm wordt echter alleen in de interrupt routine gebruikt en zal dus nooit extern gewijzigd worden. In dit geval is het sowieso niet nodig er een globale variable van te maken, je stopt het toch direct in OCR1A. En dat is zelf al een globale variabele.
Evengoed is het wel een goede tip en zeker aan te raden om altijd uit voorzorg zulke variabelen volatile te maken.

[ Voor 30% gewijzigd door madwizard op 13-12-2006 20:42 ]

www.madwizard.org


Verwijderd

Topicstarter
heel raar maar nog steeds hetzelfde, doet nog steeds niks. Met het simuleren zie ik wel dat als ik een pin hoog maak dat de waarde wel veranderd (met of zonder volatile). Maar eenmaal geprogrammeerd doet hij niks. Wat ik wel heb ontdekt is dat op poort C als ik daar mijn led testbordje op aansluit pin 3,4 en 6 hoog zijn. Terwijl ik dit volgens mij nergens heb gedefineerd

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op woensdag 13 december 2006 @ 20:42:
heel raar maar nog steeds hetzelfde, doet nog steeds niks. Met het simuleren zie ik wel dat als ik een pin hoog maak dat de waarde wel veranderd (met of zonder volatile).
Zie mijn post erboven ondertussen :)
Maar eenmaal geprogrammeerd doet hij niks. Wat ik wel heb ontdekt is dat op poort C als ik daar mijn led testbordje op aansluit pin 3,4 en 6 hoog zijn. Terwijl ik dit volgens mij nergens heb gedefineerd
Grote kans dat je de JTAG interface aan hebt staan (staat ie standaard namelijk), die gebruikt een aantal pinnen van PORTC. Waarschijnlijk staan daar pull-ups aan. Via de fuse settings kun je de jtag interface uitzetten als je PORTC helemaal voor je zelf wilt.

www.madwizard.org


Verwijderd

madwizard schreef op woensdag 13 december 2006 @ 20:45:
Grote kans dat je de JTAG interface aan hebt staan (staat ie standaard namelijk), die gebruikt een aantal pinnen van PORTC. Waarschijnlijk staan daar pull-ups aan. Via de fuse settings kun je de jtag interface uitzetten als je PORTC helemaal voor je zelf wilt.
Dju, ja! Dat heeft me ook uren zoekwerk bezorgd, toen ik voor de eerste maat met een Atmega32 aan de slag ging...

Verwijderd

Topicstarter
madwizard schreef op woensdag 13 december 2006 @ 20:37:
Ik begrijp dat je de schakelaars nog steeds in combinatie met een weerstand naar GND schakelt? Dus naast de interne pull-ups ook nog een externe weerstand tussen schakelaar en GND? Dat is zoals eerder gezegd niet nodig, maar mag wel met de beperking dat de weerstand naar GND veel kleiner moet zijn dan de interne pull-up waarde, omdat de spanning anders nooit in de buurt komt van de 0V.

Hoe dan ook zijn de input pinnen in jouw geval laag als ze actief zijn (active low), maar je code doet nu alsof ze active high zijn.
C:
1
2
3
4
    switch(PINA & 0b00111111){
        case 0x01 : 
        pwm = 256; 
        break; 

Stel dat de schakelaar op bit 0 (waarde 1 dus) aan staat. De 0de bit van PINA is dan 0, alle overige bits worden door de pull-ups nog steeds omhoog getrokken. De waarde van PINA is in dat geval dus 0b11111110. Een AND met de waarde zoals in de switch staat geeft 0b00111110. Dat is dus niet gelijk aan 1, ookal is die toets wel ingedrukt. Snelle oplossing:
code:
1
2
3
unsigned char buttons = ~PINA; // PINA met bits geinverteerd
   switch(buttons & 0b00111111)
[...]
Ik krijg een compiler error nadat ik die regel heb toegevoegd.

../PWM-nieuw.c:7: error: initializer element is not constant


Doet 't al. Even proberen dan, op hoop van zegen

Net geprobeerd, en ben nu aan het simuleren. Dit is het resultaat:

- ik krijg geen output meer op PIND
- de timer (TCNT1L) eindigt elke keer op dezelfde waarde

[ Voor 7% gewijzigd door Verwijderd op 13-12-2006 21:30 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

PIND is een input geen output, dat is PORTD (maar PIND volgt bij een output wel exact de output dus bij toeval is PIND hetzelfde).

Heb je wel in de simulator de bits in PINA allemaal hoog gemaakt op 1 bit na? In plaats van precies andersom

www.madwizard.org


Verwijderd

madwizard schreef op woensdag 13 december 2006 @ 20:37:
edit:@Pros797: hoewel je gelijk hebt maakt het in dit geval denk ik weinig uit dat het niet volatile is. Volatile is om te voorkomen dat de compiler verwacht dat een variabele zijn waarde behoudt in een stuk code zolang deze niet in dat stuk code wordt aangepast (in het kort: een *externe* wijziging). Als je a=4; if (a==4) doiets(); doet, zou de compiler dat kunnen vereenvoudigen tot alleen maar doeiets(), omdat a altijd 4 is bij de if.
Ben je er zeker van, dat het niets meer is dan dat? Ik meen me te herinneren, dat een avr-programma niet deed wat ik verwachtte, louter omdat ik die "volatile" vergeten was bij het declareren van een variabele.

Verwijderd

Topicstarter
madwizard schreef op woensdag 13 december 2006 @ 21:32:
PIND is een input geen output, dat is PORTD (maar PIND volgt bij een output wel exact de output dus bij toeval is PIND hetzelfde).

Heb je wel in de simulator de bits in PINA allemaal hoog gemaakt op 1 bit na? In plaats van precies andersom
Hij doet het! Ik had even problemen met programmeren, duurde wat langer voordat ik op je kon reageren. Maar hij doet het!

Mijn dank is groot!

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op woensdag 13 december 2006 @ 22:04:
Ben je er zeker van, dat het niets meer is dan dat? Ik meen me te herinneren, dat een avr-programma niet deed wat ik verwachtte, louter omdat ik die "volatile" vergeten was bij het declareren van een variabele.
Voor zover ik weet betekent volatile dat een variabele extern gebruikt wordt (door software of hardware), of bijwerkingen heeft (wat eigenlijk op hetzelfde neerkomt omdat ie uitgelezen moet worden om ergens invloed op te hebben). Volgens mij zegt de C standaard dit ook zo, maar er zijn natuurlijk een aantal standaarden en nogal wat verschillende implementaties dus het kan wat verschillen. Als een variabele volatile is worden alle lees en schrijfacties ook daadwerkelijk uitgevoerd zoals de code zegt. Zonder volatile is de compiler vrij de aanname te maken dat een variabele niet van waarde veranderd tijdens een stukje code.

Het zou kunnen zijn je programma vanwege dit verschil in gedrag niet het verwachte resultaat gaf. Stel dat je bijvoorbeeld een delay loop maakt zoals je dat in asm zou doen:
C:
1
2
int i;
for (i=0;i<1000;i++) { }

In assembler heb je what you see is what you get. Als je daar een loop van 1000 iteraties maakt krijg je die ook. Bovenstaande code vindt de C compiler echter nutteloos. 1000 keer niets doen? Dan kan je net zo goed helemaal niets doen. De compiler gooit het weg en de hele loop verdwijnt dus uit de code. Misschien niet wat je verwachtte maar wel logisch.

Stel nou dat je i volatile maakt. Ook al gebruik je i verder nergens in je code, nu verplicht je de compiler er vanuit te gaan dat i elk moment kan wijzigen. Nu kan de compiler de loop niet meer wegoptimaliseren, want wat als een interrupt routine i telkens weer op 0 zou zetten voordat deze de kans heeft door de loop op 1000 te komen? De loop zou nooit eindigen en het programma zou hangen. De compiler moet wel 1000 keer kijken of i veranderd is, anders zou ie deze situatie missen. Alle lees en schrijf operaties van i in de code moeten daadwerkelijk plaatsvinden. Nou wordt i verder helemaal niet aangepast maar dat weet de compiler niet, hij moet er vanuit gaan dat het kan. Opeens werkt de delay routine wel (hij itereert nu echt 1000 keer).
Verwijderd schreef op woensdag 13 december 2006 @ 22:04:
Hij doet het! Ik had even problemen met programmeren, duurde wat langer voordat ik op je kon reageren. Maar hij doet het!
Mooi zo!

edit:
Nog een ander voorbeeldje. Gedrag is niet anders maar code is totaal verschillend:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main (void)
{
    int i;
    int k;
    
    k = 0;
    for (i=0;i<5;i++)
    {
        k += 2;
    }

    PORTD = k;
    return (0);
}

Gegenereerde code (met -o3 optimalisatie aan):
code:
1
2
3
4
5
6
7
8
9
10
:        {
+00000047:   E5CF        LDI     R28,0x5F         Load immediate
+00000048:   E0D8        LDI     R29,0x08         Load immediate
+00000049:   BFDE        OUT     0x3E,R29         Out to I/O location
+0000004A:   BFCD        OUT     0x3D,R28         Out to I/O location
17:        PORTD = k;
+0000004B:   E08A        LDI     R24,0x0A         Load immediate
+0000004C:   E090        LDI     R25,0x00         Load immediate
+0000004D:   BB82        OUT     0x12,R24         Out to I/O location
19:       }

Zie dat er direct 10 (0x0A) geschreven wordt naar PORTD. De compiler heeft de complete loop van 5 keer 2 optellen bij k vervangen door 1 constante. Maak je er nu volatile i van, krijg je wel de complete loop:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
:        {
+00000047:   E5CD        LDI     R28,0x5D         Load immediate
+00000048:   E0D8        LDI     R29,0x08         Load immediate
+00000049:   BFDE        OUT     0x3E,R29         Out to I/O location
+0000004A:   BFCD        OUT     0x3D,R28         Out to I/O location
11:        k = 0;
+0000004B:   E020        LDI     R18,0x00         Load immediate
+0000004C:   E030        LDI     R19,0x00         Load immediate
12:        for (i=0;i<5;i++)
+0000004D:   833A        STD     Y+2,R19          Store indirect with displacement
+0000004E:   8329        STD     Y+1,R18          Store indirect with displacement
+0000004F:   C007        RJMP    PC+0x0008        Relative jump
14:             k += 2;
+00000050:   5F2E        SUBI    R18,0xFE         Subtract immediate
+00000051:   4F3F        SBCI    R19,0xFF         Subtract immediate with carry
+00000052:   81A9        LDD     R26,Y+1          Load indirect with displacement
+00000053:   81BA        LDD     R27,Y+2          Load indirect with displacement
+00000054:   9611        ADIW    R26,0x01         Add immediate to word
+00000055:   83BA        STD     Y+2,R27          Store indirect with displacement
+00000056:   83A9        STD     Y+1,R26          Store indirect with displacement
+00000057:   8189        LDD     R24,Y+1          Load indirect with displacement
+00000058:   819A        LDD     R25,Y+2          Load indirect with displacement
+00000059:   9705        SBIW    R24,0x05         Subtract immediate from word
+0000005A:   F3AC        BRLT    PC-0x0A          Branch if less than, signed
17:         PORTD = k;
+0000005B:   BB22        OUT     0x12,R18         Out to I/O location
19:       }

[ Voor 35% gewijzigd door madwizard op 13-12-2006 22:53 ]

www.madwizard.org


Verwijderd

madwizard, mag ik je danken voor je verhelderende uitleg? Zo leert een mens nog eens wat...

Verwijderd

Big Daddy schreef op maandag 11 december 2006 @ 15:48:
Tip: als je ergens eens een statement neerzet als PORTB = PORTA, en ledjes aansluit op PORTB (definieren als output dus) kan je de werking van je knopjes testen. Dan weet je of hij uberhaupt reageert op de knopjes.
Maak er dan wel van PORTB = PINA
Steef1983 schreef op dinsdag 12 december 2006 @ 16:36:
Wat ik trouwens niet weet of dat bij AVR studio ook zo is maar,
OCR1A bestaat uit 2 delen een H en L register.
Daar maakt de AVRGCC io library een pseudo 16-bits register van. Je werkt gewoon met OCR1A en op de achtergrond maakt een macro daar twee bewerkingen van op OCR1AH en OCR1AL. Als je de io header file bekijkt zie je hoe ze dat opgelost hebben.

[ Voor 39% gewijzigd door Verwijderd op 15-12-2006 20:53 ]

Pagina: 1