Hallo,

Ik heb het volgende stukje code geschreven (bij elkaar geplukt). De bedoeling was dat een tiptoets aangesloten van PA1 naar de GND met een pullup zou worden uitgelezen en aan de hand daarvan een led aan dan wel uit zou worden geschakeld (gesitueerd op PA0). Voor zover ik weet werkt de if-else statement wel. maar de rest weigert dienst.


#include <avr/io.h>
#include <util/delay.h>

int main()
{
  PORTB = 0b00000001;
  
  while(1)
  {
  
	if ( PA1 == 0 )
	{
		PORTA |= (1 << PA0);
	}
	else
	{
		PORTA &= ~(1 << PA0);
    }
  }
  
  return 0;
}

Ik denk zelf dat het fout gaat bij het instellen van de poorten (input/output instellen). Heeft er iemand een goede beschrijving over het definiëren van de poorten in C? of aanraders tot het werkend maken van mijn code?

Alvast bedankt.

Zonder ontdender code (of hardwarematige ontdender) werkt het niet goed.
Werk het wel als je eerst het tiptoets ingedrukt houdt en dan pas de AVR inschakelt? Zo ja, dan is het de dender afkomstig van de tiptoets die roet in het eten gooit.

Op 17 december 2008 18:53:53 schreef RES:
Zonder ontdender code (of hardwarematige ontdender) werkt het niet goed.
Werk het wel als je eerst het knopje ingedrukt houdt en dan pas de AVR inschakelt? Zo ja, dan is het de dender afkomstig van de schakelaar die roet in het eten gooit.

Nee. Maar ik denk dat het flink wat te maken heeft met mijn poort initialisatie. Want daar snap ik vrij weinig van.

Het valt me trouwens wel op dat er veel minder basistutorials zijn voor AVR's dan voor PIC's.

maak van PORTB maar eens DDRB

DDRB = poorten in of uitgangen maken.
PORTB = Poort Hoog of Laag maken. (*en pullups aan/uit)

Eerst stel je DDRA. De datarichtings register 0 is input en 1 is output.

Dan stel je de pull-up in met PORTA

De pull-ups worden geactiveert met een 1 te schrijven naar de juiste bit van PORTA.

Deze regsister wordt ook gebruik om output te setten.


#include <avr/io.h>
#include <util/delay.h>

int main()
{
  DDRA = 0b00000001;
  //of
  DDRA = (1<<PA0);

  //Dit moet PORTA worden
  PORTA = 0b00000001;
  //of
  PORTA = (1<<PA1);
 
  while(1)
  {
  
	if (((PINA>>PA1) & 0x01) == 0x00)
	{
		PORTA |= (1 << PA0);
	}
	else
	{
		PORTA &= ~(1 << PA0);
        }
  }
  
  return 0;
}

Als een ingang wilt uitlezen dan doe je dat met het PINA register. PA0 stelt alleen de waarde 0 voor. PA7 dus 7.


#define IsPinHigh(PORT, PIN) (((PORT>>PIN) & 0x01) == 0x01)

Dit is een macro die kijk of die pin hoog is.



  while(1)
  {
  
	if (!IsPinHigh(PINA,PA1))
	{
		PORTA |= (1 << PA0);
	}
	else
	{
		PORTA &= ~(1 << PA0);
        }
  }
  
  return 0;
}

Dit is iets leesbaarder.

MvG

Robin

Edit Ik schrijf te traag


#include <avr/io.h>
#include <util/delay.h>

#define IsPinHigh(PORT, PIN) (((PORT>>PIN) & 0x01) == 0x01)

int main()
{
  DDRA = 0b00000010; //interne pull-up aan op PA1
  PORTA = 0b00000001;	//PA0 is een output de rest is input
  
  while(1)
  {
  
	if ( !IsPinHigh(PINA,PA1) )
	{
		PORTA |= (1 << PA0);
	}
	else
	{
		PORTA &= ~(1 << PA0);
    }
  }
  
  return 0;
}

Heb ik nu, de led brand nu echter zwakjes. Zie ik iets over het hoofd?

Init is fout. Je wil dit, denk ik:


    PORTA = 0b00000010;    // Pull-up voor PA1 activeren
    DDRA = 0b00000001;     // PA0 = uitgang

Op 17 december 2008 19:01:47 schreef robint91:


#define IsPinHigh(PORT, PIN) (((PORT>>PIN) & 0x01) == 0x01)

Dit is een macro die kijk of die pin hoog is.
[/code]

Dat is geen slimme macro. De bit shift vindt namelijk pas plaats wanneer je de instructie uitvoert, de compiler kan hier niet optimaliseren. Schrijf het liever zo (ook de AVR standaard als je kijkt naar voorbeelden van Atmel)

if(PINA & (1 << PA0))

Het deel (1 << PA0) wordt tijdens compileren al bepaald en zal dus nooit door de AVR worden uitgevoerd, die hoeft alleen nog maar een bitwise and te doen.

Overigens heeft AVR libc hier zelf al een macro voor nml. bit_is_set(PORTx, Pxn)
http://www.nongnu.org/avr-libc/user-manual/group__avr__sfr.html Nog een reden om die niet zelf te schrijven.

Op 17 december 2008 19:19:22 schreef pros:
Init is fout. Je wil dit, denk ik:


    PORTA = 0b00000010;    // Pull-up voor PA1 activeren
    DDRA = 0b00000001;     // PA0 = uitgang

Nu werkt ie.

PORTX is dus om de pullups aan/uit te zetten.
DDRX = om de functie van de pinnen in te stellen

@Marcel:

Ik begrijp deze notatie echter niet helemaal (mede door mijn gebrekkige kennis van C denk ik)


if(PINA & (1 << PA0))

en

PORTA |= (1 << PA0);

en

PORTA &= ~(1 << PA0);

@marcel
Foutje gemaakt
Robin

[Bericht gewijzigd door robint91 op (88%)]

if (bit_is_set(PORTA, PA1))

Als dit klopt, dan werkt het niet zoals ik het wil laten werken.

[Bericht gewijzigd door Anoniem op (83%)]

Op 17 december 2008 19:40:40 schreef Peter Rus:
PORTX is dus om de pullups aan/uit te zetten.

Enkel als de pin als ingang geschakeld is! Anders maak je de pin "hard" hoog (of laag).

Er is ook nog een bit_is_clear(PORTx, Pxn) macro.

Op 17 december 2008 19:43:55 schreef robint91:
@marcel


  (PINA & (1 << PA0))

==


 
  (PINA == 0b00000001);

Dit is het zelfde.

Nee, dat is zeker niet hetzelfde. De eerste code is een bitwise and, de tweede een vergelijking.

Een kleine uitleg, ook voor Peter.

PA0 t/m PA7 zijn bit definities (ookwel constanten)
In de AVR libc zijn deze gedefineert als


PA0 = 0
PA1 = 1
PA2 = 2
etc...

Het zijn gewoon de bit nummers van een poort. Door het getal 1 met het bit nummer naar links te schuiven verkrijg je de bit waarde. << is in C een bitshift naar links en >> naar rechts.
Lees meer http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/bitshift.html


(1 << PA0) = 1 (0b00000001)
(1 << PA1) = 2 (0b00000010)
(1 << PA2) = 4 (0b00000100)
(1 << PA3) = 8 (0b00001000)
etc...

De bit waarde kan je gebruiken in vergelijkingen en toekenningen. In het voorbeeld and ik de bit waarde met de poort waarde. Als het bit niet aan is zal de and 0 terug geven anders geeft de and de bit waarde terug. In C is een if() waar zolang de conditie groter is dan 0.

Op 17 december 2008 19:40:40 schreef Peter Rus:
Ik begrijp deze notatie echter niet helemaal (mede door mijn gebrekkige kennis van C denk ik)


if(PINA & (1 << PA0))

en

PORTA |= (1 << PA0);

en

PORTA &= ~(1 << PA0);

In feite gaat het allemaal om spelen met bits. Lees bijvoorbeeld dit eens http://irc.essex.ac.uk/www.iota-six.co.uk/c/e4_bitwise_operators_and_o…

a |= b is een verkorte schrijfwijze voor a = a | b
a &= b is een verkorte schrijfwijze voor a = a & b

Oke, dat verheldert een hele boel.

Ik heb nu hetvolgende:


#include <avr/io.h>
#include <util/delay.h>
#define IsPinHigh(PORT, PIN) (((PORT>>PIN) & 0x01) == 0x01) //Niet gebruiken, eigenlijk...

int main()
{
  PORTA = (1 << PA1); 		//interne pull-up aan op PA1 (=0b00000010)
  DDRA = (1 << PA0);		//PA0 is een output de rest is input (=0b00000001)
  
  while(1)
  {
  
	if (!IsPinHigh(PINA, PA1)) //Niet gebruiken, eigenlijk...
	{ 
		PORTA |= (1 << PA0); 
	}
	else
	{
		PORTA &= ~(1 << PA0); 	
        }
  }
  
  return 0;
}

Ik probeer nu alleen nog bit_is_clear() onder de knie te krijgen.

ik probeerde hetvolgende:


if (bit_is_clear(PORTA, PA1))
	{ 
		PORTA |= (1 << PA0);
	}
	else
	{
		PORTA &= ~(1 << PA0);
    }

Maar dat scheen niet te werken en ik ben teruggekeerd naar de door robint91 voorgestelde IsPinHigh() die wel z'n werk doet, maar niet is zoals het hoort (deze laatste is heeft mijn voorkeur). Ook

if (bit_is_clear(PORTA, (1 << PA1)))

werkt niet.

En ook dit is opgelost.

en wel als volgt:


if (bit_is_clear(PINA, PA1))

Iedereen mag zich als bedankt beschouwen (:

Als jullie dit als correct beschouwen kan ik nog wel een commentaar-enhanced versie van de code neerzetten, dit kan makkelijk zijn voor anderen met dezelfde vragen. Uw mening graag.

Op 17 december 2008 18:57:01 schreef Peter Rus:
[...]

Het valt me trouwens wel op dat er veel minder basistutorials zijn voor AVR's dan voor PIC's.

dat is zo, in het Nederlands toch.
Op mijn site zie je enkele beginners oefeningen in het Ned.
Binnenkort komen er een heleboel bij, ook met ADC en zo.
Maar als je een beetje Engels of Duits versta zijn er enkele hele goeie tutorials bij. Kijk maar eens in mijn URL-Links.
Ook bij AVR-Freaks zul je veel vinden bij de Newbie Tutorial.
Wat ik ook opmerk is dat er weinig in AVR-Assembly geprogrammeerd wordt...nochtans vind ik dit een gemakkelijke taal eenmaal je sommige dingen beet hebt.
Maar het begin is moeilijk, da's waar.
Het beste leer je door met eenvoudige dingen te beginnen.

Op 17 december 2008 23:57:31 schreef Erelce:
[...]

dat is zo, in het Nederlands toch.
Op mijn site zie je enkele beginners oefeningen in het Ned.
Binnenkort komen er een heleboel bij, ook met ADC en zo.
Maar als je een beetje Engels of Duits versta zijn er enkele hele goeie tutorials bij. Kijk maar eens in mijn URL-Links. Ook bij AVR-Freaks zul je veel vinden bij de Newbies Tutorial.
Wat ik ook opmerk is dat er weinig in AVR-Assembly geprogrammeerd wordt...nochtans vind ik dit een gemakkelijke taal eenmaal je sommige dingen beet hebt.
Maar het begin is moeilijk, da's waar.
Het beste leer je door met eenvoudige dingen te beginnen.

Ik heb je site bekeken, maar zag toen dat je inderdaad in assembly progt, dit vindt ik zelf minder fijn (mede ook omdat ik erg veel houdt van functies en klassen).

Op avrfreaks kom ik eerlijk gezegd alleen maar de wat meer geavanceerdere projectjes tegen en basisbeginselen in alleen ASM, op het gebied van C en de basisprincipes van AVR/GCC kan ik m'n draai daar niet vinden.

Op 18 december 2008 00:05:11 schreef Peter Rus:
[...]

Ik heb je site bekeken, maar zag toen dat je inderdaad in assembly progt, dit vindt ik zelf minder fijn (mede ook omdat ik erg veel houdt van functies en klassen).

Als het zo nodig in classes moet, wat doe je dan op een μC??

Op avrfreaks kom ik eerlijk gezegd alleen maar de wat meer geavanceerdere projectjes tegen en basisbeginselen in alleen ASM, op het gebied van C en de basisprincipes van AVR/GCC kan ik m'n draai daar niet vinden.

Er staat genoeg in C. Echter, assembly is en blijft de basis.
Maar eh... wellicht een stomme vraag... Waar heb je een tutorial voor nodig? De gemiddelde AVR heeft een stevig uitgekauwde datasheet. Als je dan ook nog ergens een assembly guide vandaan plukt, heb je toch alles wat je nodig zou kunnen hebben?
Wellicht begin je te ingewikkeld. Als je helemaal geen ervaring hebt, begin dan eens met een knipperende LED. Op een nieuwe architectuur doe ik dat nog steeds, alhoewel de LED meestal vervangen wordt door een scoop.

Op 18 december 2008 06:36:59 schreef Marco69:
[...]Als het zo nodig in classes moet, wat doe je dan op een μC??[...]Er staat genoeg in C.

...

begin dan eens met een knipperende LED. Op een nieuwe architectuur doe ik dat nog steeds, alhoewel de LED meestal vervangen wordt door een scoop.

Ik zeg ook niet persee dat ik klassen wil gebruiken. Maar mijn voorkeur gaat zogezegd uit naar hogere programmeertalen vanwege de tijdsbesparing en het gemak dat het opbrengt.

Een knipperende led is overigens al gelukt :) dit was zeg maar mijn les over input op de AVR. De volgende stap wordt denk ik een LCD.

Een goed site voor de avr gcc beginner is deze http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial Daar staan al de antwoorden op die je in het begin had. (wel duits).

Voor assembly heb ik deze veel gebruikt http://www.avr-asm-tutorial.net/avr_en/index.html (engels of duits).