Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Op 30 januari 2006 16:18:14 schreef elmowww:
Ik weet dat er op een PIC een ounter module in zitDeze kan je gewoon aan je source hangen en die telt de pulsen die binnenkomen. Kan je gewoon een registertje uitlezen en resetten.
Dat kan die ATmega32 ook allemaal (zie datasheet), daar hoef je geen PIC voor te promoten.
Op 30 januari 2006 18:14:05 schreef xtreme_8ball
[...]
Ja okay, maar krijg je hier dan geen last met puls verlies doordat de uC ook met andere opdrachten bezig is? Zoals communicatie en aansturing van LCD en andere poorten? Ben nog niet zo heel ervaren met de uC. Kan hem opzich wel programmeren. Maar ben voornamelijk bezig met vb. Nog iets anders trouwens, weet iemand waar ik een goede en uitgebreidde handleiding en uitleg over assembler kan vinden? Werk nu met C maar wil overstappen.
Dat ligt er aan. Gebruik je daar ook interrups voor. Het kan een probleem zijn als je interrups tegelijkertijd krijgt.
Overstappen waarop en waarom?
Je kan prima 1 van de 8- of 16-bit counters van de ATmega32 gebruiken. De AVR bevat allerleihande IO chips, inclusief counters. Dus je hebt helemaal geen externe counter nodig. 1 opmerking hier, als je externe pulsjes wil tellen, dan mag de frequentie niet hoger zijn dan je systeem frequentie gedeeld door 2.5 CLKsys / 2.5. Dit vanwege interne synchronisatie.
De timer als CTC configureren en je kunt gaan pulsjes tellen. Dit zal nauwkeurig gaan, het is een hardware teller. Als 'ie je ingestelde waarde heeft bereikt, zal 'ie een interrupt afgeven waar je dan verdere verwerking in kan doen. Het maakt niet uit wat de UC aan het doen is tijdens het tellen.
Heel raadzaam om assembler te gaan leren. Op die manier kom je precies te weten hoe zo'n AVR en IO's op bitnivo werken, waardoor je het ding alleen maar beter leert begrijpen.
Even op de Atmel site zoeken naar "asm tutorial" dan komen er wel wat results naar boven.
De communicatie (usart) werkt nu ook met interrupts (int0 en int1). Kan dit geen problemen geven?
De timer als CTC configureren en je kunt gaan pulsjes tellen. Dit zal nauwkeurig gaan, het is een hardware teller. Als 'ie je ingestelde waarde heeft bereikt, zal 'ie een interrupt afgeven waar je dan verdere verwerking in kan doen. Het maakt niet uit wat de UC aan het doen is tijdens het tellen.
Neem aan dat die ingestelde waarde variabel is? Dat is namelijk wel noodzakelijk.
Heel raadzaam om assembler te gaan leren. Op die manier kom je precies te weten hoe zo'n AVR en IO's op bitnivo werken, waardoor je het ding alleen maar beter leert begrijpen.
is het trouwens mogelijk om een bestaand C programma om te zetten dmv van een prog ofzo naar assembler?
elektron_
beetje gek
Ja, als je een Compiler gebruikt die specifiek voor AVR
(of Pic) gemaakt is. Wat bedoel je met bestaand ?
geef eens in in google: AVR Compiler
[Bericht gewijzigd door elektron_ op ]
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Die compiler zet niet om naar ASM, maar direct naar machinecode. Maar je kan machinecode wel weer disassembleren naar ASM. Echt leesbare code houd je dan niet over.
Edit:
In AVR Studio 4 in combinatie met WINAVR (AVRGCC), laat de debugger samen met de disassembler precies zien welke C code resulteerd in welke assembler code.
[Bericht gewijzigd door Marcel op ]
1 opmerking hier, als je externe pulsjes wil tellen, dan mag de frequentie niet hoger zijn dan je systeem frequentie gedeeld door 2.5 CLKsys / 2.5. Dit vanwege interne synchronisatie.
2.5 maal iets en dan delen door 2.5 is toch gewoon hetzelfde???¿¿¿
Maar jullie hebben mij overtuigd. Ik ga de counter direct aan de uC hangen. Is het dan trouwens wel nodig om de pulsen te bufferen ofzo?
Of kan ik hem direct eraan hangen?
groeten en bedankt!
1 opmerking hier, als je externe pulsjes wil tellen, dan mag de frequentie niet hoger zijn dan je systeem frequentie gedeeld door 2.5. Dit vanwege interne synchronisatie.
Of te wel: CLKsys / 2.5.
Zo is 't misschien wat duidelijker. Als je systeem klok 2.5MHz is, kun je een puls tot maximaal 1MHz op de teller aanleggen.
P.S. Wat bedoel je met de 'teller er aan hangen' ? De teller zit al in de AVR, welke je direct met I/O poorten kan aansturen. Even in de datasheet kijken welke pen hoort bij de teller ingang van de teller die je wil gebruiken.
Je hoeft pulsen niet te bufferen. Er moet gewoon een TTL/CMOS compatible puls op komen. Je hebt dus wel eventuele conversie electronica nodig, als je bijvoorbeeld een licht sensor als ingang gebruikt.
[Bericht gewijzigd door MagicBox op ]
Denk ook dat het scheelt als je eerst eens de datasheet van dat ding leest; het roept veel vragen op, maar beantwoord er ook veel.
Overigens is het niet de bedoeling dat interrupt routines veel doen, ook niet voor je UART. Die paar clock ticks moet je kunnen missen, anders zit je wel heel kritisch in de timing. Je zou nog trucen met re-entrant code uit kunnen halen, maar verdiep je eerst maar eens in assembly.
Een tutorial... eh... Ben zelf gewoon met de Atmel 'tutorial' begonnen. Heb daarvoor wel veel assembly gedaan op uP's, scheelt uiteraard. Maar daar ook gewoon vanuit de datasheet...
Als je 'van scratch' begint, probeer dan niet teveel tegelijk. Zorg dat je UART werkt (dan kun je wat 'laten zien'), zorg dat je LCD werkt (heb daar wel het een en ander van in assembly), en begin dan met de rest. Zo houd je een beetje controle en voorkom je dat je op een gegeven moment met meerder zaken die elkaar in de weg zitten bezig bent.
Succes!
Zo is 't misschien wat duidelijker. Als je systeem klok 2.5MHz is, kun je een puls tot maximaal 1MHz op de teller aanleggen.
De systeemklok gaat op 16MHz en de pulsen komen op maximaal 2kHz binnen... Geen probleem dus!
P.S. Wat bedoel je met de 'teller er aan hangen' ?
De encoder bedoel ik.
Je hoeft pulsen niet te bufferen. Er moet gewoon een TTL/CMOS compatible puls op komen. Je hebt dus wel eventuele conversie electronica nodig, als je bijvoorbeeld een licht sensor als ingang gebruikt.
Zijn idd geen TTL signalen, tenminste zwakke... Ben bang dat het niet voldoende is om het de uC het te laten herkennen.
Nou, ik ga me best doen..
Bedankt voor de hulp!
Ennu, hoezo naar schoolvragen???????
Als je last hebt van een te zwak signaal op de ingangen van je poorten kun je de interne pull-up weerstanden van de atmega32 activeren.
De encoder is nu aangesloten op de interrupt (int0 / pd2) van de uC. Hbe getracht om deze te programmeren, maar dat wilde dus niet lukken...
Hier is m'n code:
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include "lcd.h"
#include "stdafx.h"
//Timer initialiseren
void initTimer(void)
{
TCNT0 = 0x00; //Preloaden
TCCR0 = 0x02; //Prescaler
}
//Interrupt initialiseren
void initInterrupt(void)
{
/* falling edge on Int0 or Int1 generates an interrupt */
GIMSK |= 0x40;
MCUCR = 0x00;
sei(); // enable interrupts
}
INTERRUPT (SIG_INTERRUPT0)
{
lcd_clrscr();
lcd_puts("Check");
}
int main(void)
{
DDRD = 0xFF;
initTimer();
initInterrupt();
sei();
INTERRUPT (SIG_INTERRUPT0);
lcd_init(LCD_DISP_ON);
lcd_puts("Encoder test...");
}Het idee is nu, dat als er een signaal op pd2 komt dat het display "check" weergeeft. Dit is alleen voor het testen.
Wat doe ik hier niet goed of wat ontbreekt?
Het idee is dat hij nu dus in de interrupt routine de pulsen gaat tellen en bij een bepaalde waarde het totaal aantal pulsen reset en een signaal geeft dat er een okay naar de pc gestuurd kan worden via usart.
Het kan geen kwaad om wat te experimenteren. Elke opdracht eens nalopen, de datasheets nalezen, kijken of er gebeurt wat er moet gebeuren e.d. Haal een instructie weg, verander een waarde. Je moet een beetje creatief denken bij het 'probleem-oplossen'.
Vast één zet in de richting:
DDRD moet 0x00 zijn. Zoek in de datasheet maar op waar om 
Dit is overigens voor timing toepassingen precies hoe het niet moet: complete display writes in een interrupt routine ARGH! Zijn die dingen uberhaupt wel reentrant?
Waar gaat je main heen?
dat schrijven naar het display is maar voor tijdelijk. Alleen om te proberen.
Hoe bedoel je, "waar gaat je main heen"? Wat de werking daarvan wordt ofzo??
Diverse functies. Aansturen in en outputs OF gebruik van de encoder. Versturen via usart, pulsen van encoder tellen. Aansturen van display.
Hoezo?
Nou, die main eindigt ergens. Op DOS of UNIX (zal op winshit ongetwijfeld net zo zijn) exit je programma dan dus (denk dat de compiler impliciet iets van 'exit(0)' toevoegt). Geen idee hoe dat op een uC zit (een return to OS wil daar zo beroerd bij gebrek aan een OS...). Heb er nooit C op geprogrammeerd. Kan me zo voorstellen dat die compiler het ook niet weet en die uC tot het einde van z'n geheugen excecute (zolang daar niet ergens per ongeluk een jump of zo staat gaat dat vast goed), wrapt en dan weer op 0 begint (soort van reset, maar niet helemaal). Wellicht is die compiler handiger en looped die zelf, maar dan heb je nog steeds niet wat je hebben moet.
Zelf laat ik het ding lekker slapen als-ie op een interrupt staat te wachten (wel even sleep enablen), zal in C ook vast wel kunnen. Maar dan nog steeds moet je een loop maken en niet in het niets eindigen.
Nou, ben weer ff bezig geweest, maar kom er nog niet uit...
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include "lcd.h"
#include "stdafx.h"
uint8_t i=0;
//Timer initialiseren
void initTimer(void)
{
TCNT0 = 0x00; //Preloaden
TCCR0 = 0x02; //Prescaler
}
//Interrupt initialiseren
void initInterrupt(void)
{
/* falling edge on Int0 or Int1 generates an interrupt */
GIMSK |= 0x40;
MCUCR = 0x00;
sei(); // enable interrupts
}
INTERRUPT (SIG_INTERRUPT0)
{
i++;
}
int main(void)
{
DDRD = 0x00;
initTimer();
initInterrupt();
sei();
INTERRUPT (SIG_INTERRUPT0);
lcd_init(LCD_DISP_ON);
lcd_puts("Encoder test...");
for(;;)
{
if((i%10)==1)
{
lcd_puts("ok");
}
}
}
Ik zal waarschijnlijk wel weer iets niet goed doen, maar ken er iemand mij een hint geven wat of waar....
Thanx!!!
Ik probeer GICR toe te voegen, maar hierop krijg ik de error: 'GICR' undeclared, thirst use in this function.
Hoe kan dat? Die moet ik toch gewoon kunnen neerzetten?
[edit] Heeft niemand een idee???? Kan ik de encoder wel gewoon op int0 (pd2) aansluiten? Kan ik in ieder geval verder met het schema!
[Bericht gewijzigd door xtreme_8ball op ]
Je hebt dus nog problemen om de interrupt aan de praat te krijgen?
Probeer eens dit simpele stukkie code:
void main (void)
{
DDRD = 0x00; /* poort D = input */
PORTD = 0x00; /* poort D alles laag */
GICR = 0x40; /* Enable INT0 op D2 */
MCUCR = 0x00; /* Low level generates interrupt */
sei(); /* enable interrupts */
lcd_init(LCD_DISP_ON);
lcd_puts("Encoder test...");
while(1);
}
INTERRUPT (SIG_INTERRUPT0)
{
lcd_puts("OK");
}
doet de interrupt het nu wel?
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
waarschijnlijk een rare vraag, maar hoort de interrupt nu te gaan "tellen". Heb trouwens van INTERRUPT SIGNAL gemaakt. Heb er een schakelaar aan gehangen en als de schakelaar verbroken is loopt de waarde snel op. Als ik de schakelaar maak blijft de waarde stil staan...
Hoe kan dit ewn hoe kan ik dit verhelpen???
[edit]
Het probleem is al verholpen. Aantal aanpassingen gedaan.
Nu nog een laatste vraag, is het mogelijk om ergens in het programma, onafhankelijk van de positie, de interrupts te enabelen en disabelen?? Door mioddel van sei() en cli(). Heb het geprobeerd, maar het werkte helaas niet.
[Bericht gewijzigd door xtreme_8ball op ]
