PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Beginner Code korrigieren



onion
18.07.2008, 21:24
Hallo erstmal.
Habe mir das AVR Board von Pollin zusammengebaut und wollte nun mal meine ersten Gehversuche in Assembler machen. Was ich bis dato hinbekommen habe ist eine brennende LED. Nun wollte ich mal die LED per Taster einschalten (ein wenn gedrückt, aus wenn nicht gedrückt).
Das funktioniert nun aber leider nicht wie gewünscht.
Hier ist erst mal der Link zum Schaltplan: http://www.pollin.de/shop/downloads/D810038B.PDF

Ich benutze einen Atmega8.

Und nun mein Code. Wäre sehr freundlich wenn mir jemand sagen könnte was da nicht stimmt:

;+++++++++++++++++++++++++++
;My first AVR ASSEMBLY CODE
;+++++++++++++++++++++++++++

;################
.NOLIST
.DEVICE ATMEGA8
.LIST
.CSEG
;################

.EQU PORTD = 0x12
.EQU DDRD = 0x11
.EQU Taster = 2
.EQU LED1 = 5

RJMP main

main:
loop:
LDI R16,0x00
OUT DDRD,R16 ;PORT D auf Input setzen
SBIS PORTD,Taster ;BIT 2 prüfen (Taster1 liegt auf PD2)
BREQ led_on ;springen wenn Taster gedrückt

LDI R16,0xFF
OUT DDRD,R16 ;PORT D auf Output setzen
CBI PORTD,LED1 ;LED1 ausschalten (PD5)
RJMP loop
led_on:
LDI R16,0xFF
OUT DDRD,R16 ;PORT D auf Output setzen
SBI PORTD,LED1 ;LED1 anschalten (PD5)
RJMP loop

fhs
18.07.2008, 21:59
Hallo,

beim Schaltplan ist mir nicht klar, wo genau der Taster liegt und ob er gegen Masse schaltet. Das würde man normalerweise tun und gleichzeitig den internen Pullup-Widerstand (an PD2) aktivieren.

Anstelle von <pre>SBIS PORTD,Taster</pre> willst Du doch sicher PIND prüfen, oder?

Zudem: mach es Dir am Anfang einfach, indem Du für Ein- und Ausgabe getrennte Ports verwendest.

Was für einen Assembler benutzt Du? Jeder AVR-Assembler sollte eigentlich die symbolischen Port-Namen kennen, so dass kein ".equ" dafür nötig ist.

Ein ".org 0" ist vermutlich nicht unbedingt erforderlich, würde aber nach dem ".cseg" alles klarer machen.

Viele Grüße und viel Erfolg beim Debugging

Fred

P.S. Falls Du Windoof benutzt, installiere Dir doch das AVRStudio -- dann kannst Du Deinen Code simulieren und damit leichter debuggen! Das bedeutet zwar, dass Du noch eine Entwicklungsumgebung "lernen" musst, aber so ist das halt am Anfang. Und man lernt schneller, wenn man seine Software-Fehler selbst findet.

onion
18.07.2008, 22:55
Ok wo fang ich an..

Also im Schaltplan Ist es Taster1 verbunden mit PD2 (IC4 ist der atmega8) und LED 1 verbunden mit PD5. Der Taster ist gegen 5V geschaltet und die LED ist mit einem Widerstand auf Masse geschaltet. Externer Pulldown Widerstand für den Taster ist auch da wenn ich das richtig Verstanden habe und der Kondensator ist wohl wegen dieser Prell Problematik...
Aber so weit bin ich eigentlich noch nicht.

Nun mal zum Programm.
Wegen der vorgegebenen Beschaltung kann ich halt leider keine 2 verschiedenen Ports verwenden und so muss ich dann halt direkt mal lernen wie es mit nur einem Port geht.
Kann man einen Port eigentlich auf verschiedenen Pins gleichzeitig als EIn- und Ausgang verwenden?

Als Assembler nutze ich zur Zeit AVRA unter Linux (Ubuntu) der konnte das irgendwie nicht ohne .EQU. Auch habe ich es nicht geschafft .include "m8def.inc" zu benutzen.
Vielleicht sollte ich besser einen anderen Assembler nutzen?

Was bewirkt denn ein .ORG 0?

Achso, bei der Sache mit dem PIND hast du natürlich recht. Werde ich jetzt mal probieren.

Besserwessi
18.07.2008, 23:11
Bis auf ein paar Ausnahmen bei alten großen Controllern (Mega103 oder so) kann man alle Port-Pins unabhängig auf ein oder Ausgang setzen.

Das Komando .org 0 sorgt dafür, das das Program an den Anfang ( Addresse o ) des Flashspeichers geschrieben wird.

Es ist wirklich hilfreich wenn man die Prots nicht alle von Hand definieren muß. Da sollte man wirklich versuchen ob man nicht die Includefiles nutzen kann. Assembler ist ohnehin schon Fehler anfällig genug, und Fehler bei den Addressen sind wirklich schwer zu finden.

onion
18.07.2008, 23:29
Hm, also wenn ich das include file einbinde kommt immer der fehler
Cannot find include file: m8def.inc

Warum ist es so wichtig an den Anfang des Flashspeichers zu schreiben? Wobei ich mich gerade auch mal gefragt habe wie oft ich den Chip überhaupt flashen kann bevor ich einen neuen brauche.

Leider läuft mein Programm noch nicht. Aber ich habe herausgefunden dass

LDI R16,0b00100000
OUT PORTD,R16
die LED anschaltet

SBI PIND,5
aber nicht

sternst
18.07.2008, 23:45
Abgesehen von dem, was bereits gesagt wurde, funktioniert dein logischer Programmablauf auch nicht.
Es hakt an dieser Stelle:
SBIS PORTD,Taster ;BIT 2 prüfen (Taster1 liegt auf PD2)
BREQ led_on ;springen wenn Taster gedrückt

Ändere es in:
SBIC PIND, Taster
RJMP led_on


Warum ist es so wichtig an den Anfang des Flashspeichers zu schreiben?
Weil der AVR nach einem Reset (oder Power-Up) bei Adresse 0 anfängt den Code auszuführen.


SBI PIND,5 aber nicht
Weil PIND das Input-Register ist. Dort kannst du den aktuellen "externen" Zustand der Pins abfragen. Für Ausgaben (z.B. LED schalten) nimmst du PORTD.

izaseba
18.07.2008, 23:45
Hallo,
anbei die m8def.inc



;************************************************* **************************
;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y
;*
;* Number :AVR000
;* File Name :"m8def.inc"
;* Title :Register/Bit Definitions for the ATmega8
;* Date :07.09.2001
;* Version :1.00
;* Support E-mail :avr@atmel.no
;* Target MCU :ATmega8
;*
;* DESCRIPTION
;* When including this file in the assembly program file, all I/O register
;* names and I/O register bit names appearing in the data book can be used.
;* In addition, the six registers forming the three data pointers X, Y and
;* Z have been assigned names XL - ZH. Highest RAM address for Internal
;* SRAM is also defined
;*
;* The Register names are represented by their hexadecimal address.
;*
;* The Register Bit names are represented by their bit number (0-7).
;*
;* Please observe the difference in using the bit names with instructions
;* such as "sbr"/"cbr" (set/clear bit in register) and "sbrs"/"sbrc"
;* (skip if bit in register set/cleared). The following example illustrates
;* this:
;*
;* in r16,PORTB ;read PORTB latch
;* sbr r16,(1<<PB6)+(1<<PB5) ;set PB6 and PB5 (use masks, not bit#)
;* out PORTB,r16 ;output to PORTB
;*
;* in r16,TIFR ;read the Timer Interrupt Flag Register
;* sbrc r16,TOV0 ;test the overflow flag (use bit#)
;* rjmp TOV0_is_set ;jump if set
;* ... ;otherwise do something else
;************************************************* **************************

;***** Specify Device
.device ATmega8

;***** I/O Register Definitions
.equ SREG =$3f
.equ SPH =$3e
.equ SPL =$3d
.equ GIMSK =$3b
.equ GICR =$3b ; new name for GIMSK
.equ GIFR =$3a
.equ TIMSK =$39
.equ TIFR =$38
.equ SPMCR =$37
.equ I2CR =$36
.equ TWCR =$36
.equ MCUCR =$35
.equ MCUSR =$34 ; For compatibility,
.equ MCUCSR =$34 ; keep both names until further
.equ TCCR0 =$33
.equ TCNT0 =$32
.equ OSCCAL =$31
.equ SFIOR =$30
.equ TCCR1A =$2f
.equ TCCR1B =$2e
.equ TCNT1H =$2d
.equ TCNT1L =$2c
.equ OCR1AH =$2b
.equ OCR1AL =$2a
.equ OCR1BH =$29
.equ OCR1BL =$28
.equ ICR1H =$27
.equ ICR1L =$26
.equ TCCR2 =$25
.equ TCNT2 =$24
.equ OCR2 =$23
.equ ASSR =$22
.equ WDTCR =$21
.equ UBRRH =$20 ; Note! UCSRC equals UBRRH
.equ EEARH =$1f
.equ EEARL =$1e
.equ EEDR =$1d
.equ EECR =$1c
.equ PORTB =$18
.equ DDRB =$17
.equ PINB =$16
.equ PORTC =$15
.equ DDRC =$14
.equ PINC =$13
.equ PORTD =$12
.equ DDRD =$11
.equ PIND =$10
.equ SPDR =$0f
.equ SPSR =$0e
.equ SPCR =$0d
.equ UDR =$0c
.equ UCSRA =$0b
.equ UCSRB =$0a
.equ UCSRC =$20 ; Note! UCSRC equals UBRRH
.equ UBRRL =$09
.equ ACSR =$08
.equ ADMUX =$07
.equ ADCSR =$06
.equ ADCSRA =$06
.equ ADCH =$05
.equ ADCL =$04
.equ I2DR =$03
.equ I2AR =$02
.equ I2SR =$01
.equ I2BR =$00
.equ TWDR =$03
.equ TWAR =$02
.equ TWSR =$01
.equ TWBR =$00



;***** Bit Definitions
;GICR (former GIMSK)
.equ INT1 =7
.equ INT0 =6
.equ IVSEL =1 ; interrupt vector select
.equ IVCE =0 ; interrupt vector change enable

;GIFR
.equ INTF1 =7
.equ INTF0 =6

;TIMSK
.equ TOIE0 =0
.equ TOIE1 =2
.equ OCIE1B =3
.equ OCIE1A =4
.equ TICIE1 =5
.equ TOIE2 =6
.equ OCIE2 =7

;TIFR
.equ TOV0 =0
.equ TOV1 =2
.equ OCF1B =3
.equ OCF1A =4
.equ ICF1 =5
.equ TOV2 =6
.equ OCF2 =7

;SPMCR
.equ SPMIE =7
.equ RWWSB =6
.equ RWWSRE =4
.equ BLBSET =3
.equ PGWRT =2
.equ PGERS =1
.equ SPMEN =0

;MCUCR
.equ SE =7
.equ SM2 =6
.equ SM1 =5
.equ SM0 =4
.equ ISC11 =3
.equ ISC10 =2
.equ ISC01 =1
.equ ISC00 =0

;MCUCSR
.equ WDRF =3
.equ BORF =2
.equ EXTRF =1
.equ PORF =0

;TCCR0
.equ CS02 =2
.equ CS01 =1
.equ CS00 =0

;TCCR1A
.equ COM1A1 =7
.equ COM1A0 =6
.equ COM1B1 =5
.equ COM1B0 =4
.equ FOC1A =3
.equ FOC1B =2
.equ PWM11 =1 ; OBSOLETE! Use WGM11
.equ PWM10 =0 ; OBSOLETE! Use WGM10
.equ WGM11 =1
.equ WGM10 =0
;TCCR1B
.equ ICNC1 =7
.equ ICES1 =6
.equ CTC11 =4 ; OBSOLETE! Use WGM13
.equ CTC10 =3 ; OBSOLETE! Use WGM12
.equ WGM13 =4
.equ WGM12 =3
.equ CTC1 =3 ; Obsolete - Included for backward compatibility
.equ CS12 =2
.equ CS11 =1
.equ CS10 =0

;TCCR2
.equ FOC2 =7
.equ PWM2 =6 ; OBSOLETE! Use WGM20
.equ WGM20 =6
.equ COM21 =5
.equ COM20 =4
.equ CTC2 =3 ; OBSOLETE! Use WGM21
.equ WGM21 =3
.equ CS22 =2
.equ CS21 =1
.equ CS20 =0

;SFIOR
.equ ADHSM =4
.equ ACME =3
.equ PUD =2
.equ PSR2 =1
.equ PSR10 =0

;WDTCR
.equ WDCE =4
.equ WDTOE =4
.equ WDE =3
.equ WDP2 =2
.equ WDP1 =1
.equ WDP0 =0

;EECR
.equ EERIE =3
.equ EEMWE =2
.equ EEWE =1
.equ EERE =0

;PORTB
.equ PB7 =7
.equ PB6 =6
.equ PB5 =5
.equ PB4 =4
.equ PB3 =3
.equ PB2 =2
.equ PB1 =1
.equ PB0 =0

;DDRB
.equ DDB7 =7
.equ DDB6 =6
.equ DDB5 =5
.equ DDB4 =4
.equ DDB3 =3
.equ DDB2 =2
.equ DDB1 =1
.equ DDB0 =0

;PINB
.equ PINB7 =7
.equ PINB6 =6
.equ PINB5 =5
.equ PINB4 =4
.equ PINB3 =3
.equ PINB2 =2
.equ PINB1 =1
.equ PINB0 =0

;PORTC
.equ PC6 =6
.equ PC5 =5
.equ PC4 =4
.equ PC3 =3
.equ PC2 =2
.equ PC1 =1
.equ PC0 =0

;DDRC
.equ DDC6 =6
.equ DDC5 =5
.equ DDC4 =4
.equ DDC3 =3
.equ DDC2 =2
.equ DDC1 =1
.equ DDC0 =0

;PINC
.equ PINC6 =6
.equ PINC5 =5
.equ PINC4 =4
.equ PINC3 =3
.equ PINC2 =2
.equ PINC1 =1
.equ PINC0 =0

;PORTD
.equ PD7 =7
.equ PD6 =6
.equ PD5 =5
.equ PD4 =4
.equ PD3 =3
.equ PD2 =2
.equ PD1 =1
.equ PD0 =0

;DDRD
.equ DDD7 =7
.equ DDD6 =6
.equ DDD5 =5
.equ DDD4 =4
.equ DDD3 =3
.equ DDD2 =2
.equ DDD1 =1
.equ DDD0 =0

;PIND
.equ PIND7 =7
.equ PIND6 =6
.equ PIND5 =5
.equ PIND4 =4
.equ PIND3 =3
.equ PIND2 =2
.equ PIND1 =1
.equ PIND0 =0

;UCSRA
.equ RXC =7
.equ TXC =6
.equ UDRE =5
.equ FE =4
.equ OR =3 ; old name kept for compatibilty
.equ DOR =3
.equ UPE =2
.equ PE =2
.equ U2X =1
.equ MPCM =0

;UCSRB
.equ RXCIE =7
.equ TXCIE =6
.equ UDRIE =5
.equ RXEN =4
.equ TXEN =3
.equ CHR9 =2 ; old name kept for compatibilty
.equ UCSZ2 =2
.equ RXB8 =1
.equ TXB8 =0

;UCSRC
.equ URSEL =7
.equ UMSEL =6
.equ UPM1 =5
.equ UPM0 =4
.equ USBS =3
.equ UCSZ1 =2
.equ UCSZ0 =1
.equ UCPOL =0

;SPCR
.equ SPIE =7
.equ SPE =6
.equ DORD =5
.equ MSTR =4
.equ CPOL =3
.equ CPHA =2
.equ SPR1 =1
.equ SPR0 =0

;SPSR
.equ SPIF =7
.equ WCOL =6
.equ SPI2X =0

;ACSR
.equ ACD =7
.equ ACBG =6
.equ ACO =5
.equ ACI =4
.equ ACIE =3
.equ ACIC =2
.equ ACIS1 =1
.equ ACIS0 =0

;ADMUX
.equ REFS1 =7
.equ REFS0 =6
.equ ADLAR =5
.equ MUX3 =3
.equ MUX2 =2
.equ MUX1 =1
.equ MUX0 =0

;ADCSR
.equ ADEN =7
.equ ADSC =6
.equ ADFR =5
.equ ADIF =4
.equ ADIE =3
.equ ADPS2 =2
.equ ADPS1 =1
.equ ADPS0 =0

; TWCR
.equ TWINT =7
.equ TWEA =6
.equ TWSTA =5
.equ TWSTO =4
.equ TWWC =3
.equ TWEN =2

.equ TWIE =0

; TWAR
.equ TWA6 =7
.equ TWA5 =6
.equ TWA4 =5
.equ TWA3 =4
.equ TWA2 =3
.equ TWA1 =2
.equ TWA0 =1
.equ TWGCE =0

; TWSR
.equ TWS7 =7
.equ TWS6 =6
.equ TWS5 =5
.equ TWS4 =4
.equ TWS3 =3
.equ TWPS1 =1
.equ TWPS0 =0

;ASSR
.equ AS2 =3
.equ TCN2UB =2
.equ OCR2UB =1
.equ TCR2UB =0

.def XL =r26
.def XH =r27
.def YL =r28
.def YH =r29
.def ZL =r30
.def ZH =r31

.equ RAMEND =$45F
.equ FLASHEND =$FFF

; byte groups
; /\/--\/--\/--\
.equ SMALLBOOTSTART =0b00111110000000 ;($0F80) smallest boot block is 256
.equ SECONDBOOTSTART =0b00111100000000 ;($0F00) 2'nd boot block size is 512
.equ THIRDBOOTSTART =0b00111000000000 ;($0E00) third boot block size is 1K
.equ LARGEBOOTSTART =0b00110000000000 ;($0C00) largest boot block is 2K
.equ BOOTSTART =THIRDBOOTSTART ;OBSOLETE!!! kept for compatibility
.equ PAGESIZE =32 ;number of WORDS in a page

.equ INT0addr=$001 ; External Interrupt0 Vector Address
.equ INT1addr=$002 ; External Interrupt1 Vector Address
.equ OC2addr =$003 ; Output Compare2 Interrupt Vector Address
.equ OVF2addr=$004 ; Overflow2 Interrupt Vector Address
.equ ICP1addr=$005 ; Input Capture1 Interrupt Vector Address
.equ OC1Aaddr=$006 ; Output Compare1A Interrupt Vector Address
.equ OC1Baddr=$007 ; Output Compare1B Interrupt Vector Address
.equ OVF1addr=$008 ; Overflow1 Interrupt Vector Address
.equ OVF0addr=$009 ; Overflow0 Interrupt Vector Address
.equ SPIaddr =$00a ; SPI Interrupt Vector Address
.equ URXCaddr=$00b ; USART Receive Complete Interrupt Vector Address
.equ UDREaddr=$00c ; USART Data Register Empty Interrupt Vector Address
.equ UTXCaddr=$00d ; USART Transmit Complete Interrupt Vector Address
.equ ADCCaddr=$00e ; ADC Interrupt Vector Address
.equ ERDYaddr=$00f ; EEPROM Interrupt Vector Address
.equ ACIaddr =$010 ; Analog Comparator Interrupt Vector Address
.equ TWIaddr =$011 ; Irq. vector address for Two-Wire Interface
.equ SPMaddr =$012 ; SPM complete Interrupt Vector Address
.equ SPMRaddr =$012 ; SPM complete Interrupt Vector Address


Kopiere Dir das Ding und speicher es als m8def.inc in Deinem Projektordner.

Du meinst wohl sbi PORTB,5 oder ?

Schau mal hier (http://izaseba.roboterbastler.de/index.php?popup=Tutorial)
Vielleicht hilft Dir das Tutorial weiter.

Gruß Sebastian

fhs
19.07.2008, 01:57
Hi onion,

ich habe den Eindruck, Du hast nach meinem Posting jetzt bei Ein- und Ausgabe PORTx durch PINx ersetzt. Ich hatte Dich nur darauf hinweisen wollen, dass Du beim Abfragen eines Eingangs PINx verwenden musst!

Eine Eigenheit des AVR-Instruktionssatzes möchte ich Dir noch erklären, obwohl das momentan in Deinem Programm keine Relevanz hat, aber sehr häufig anfangs verwechselt wird:
Bei "sbr reg, bits" (setze Bit(s) in einem Register = "ori reg, bits") hat "bits" den Wertebereich 0..255, wohingegen bei der von Dir benutzten Verzweigung "sbis io, bit" "bit" den Wertebereich 0..7 hat; auch bei "sbi sfr, bit" (setze Bit in SFR) hat bit nur den Wertebereich 0..7.

@all:
Gibt es eigentlich einen unter den Linux-Varianten lauffähigen AVR-Simulator?

Gruß

Fred

onion
19.07.2008, 14:53
Danke für die Hinweise.
Wo bekommt man denn diese .inc Dateien her?

Hier mal ein funktionierender Code:

;+++++++++++++++++++++++++++
;My first AVR ASSEMBLY CODE
;+++++++++++++++++++++++++++

;################
.NOLIST
.DEVICE ATMEGA8
;.INCLUDE "m8def.inc"
.LIST
.CSEG
;################

.EQU PIND = 0x10
.EQU DDRD = 0x11
.EQU PORTD = 0x12
.EQU Taster = 2
.EQU LED1 = 5

RJMP main

main:
loop:
LDI R16,0b00100000
LDI R17,0b00000000
OUT DDRD,R16 ;PORT D auf Input setzen
SBIC PIND,Taster ;BIT 2 prüfen (Taster1 liegt auf PD2)
RJMP led_on

; CBI PIND,LED1 ;LED1 ausschalten (PD5)
OUT PORTD,R17
RJMP loop
led_on:
; LDI R16,0xFF
; OUT DDRD,R16 ;PORT D auf Output setzen
; SBI PIND,LED1 ;LED1 anschalten (PD5)
OUT PORTD,R16
RJMP loop


Habe ich das jetzt richtig verstanden: PORTD ist nur zum Ausgeben, PIND nur zum Einlesen.

Ok noch mal laut überlegen
LDI register,0b10101010
OUT PORTD,register ;alle Pins werden gesetzt
IN register,PIND ;alle Pins werden ins register eingelesen

IN register,PORTD ;das geht nicht?
OUT PIND,register ;das auch nicht?

SBI PORTD,0...7 ;Ausgangs PIN wird entsprechend dem bit auf high gesetzt

Was passiert denn wenn ich auf einen Eingangspin schreibe oder einen Ausgangspin lese?

edit: es gibt "simulavr" für linux. Als frontend benutzt man dann gdb oder insight soviel ich weiß. Wollte ich auch gestern probieren aber weiß nicht wie ich aus dem asm code ein elf file mit debug informationen mache...

fhs
19.07.2008, 15:42
Hi,


Was passiert denn wenn ich auf einen Eingangspin schreibe....
das hängt vom AVR-Typ ab: bei einigen führt das Setzen eines PINs (=PINx) zum "Togglen" (Umschalten) des zugehörigen PORT-Ausgangs.


... oder einen Ausgangspin lese?
Du liest damit genau den Wert, der im PORTx steht (also den Default-Wert bzw. den Wert, den Du reingeschrieben hast) -- steht alles in den Datenblättern; Du liest diesen Wert auch dann, wenn der PORTx nicht als Ausgang geschaltet ist (dann wird natürlich dadurch der jeweilige Pullup-R aktiviert, wenn das zugehörige PORTx-Bit gesetzt ist).


... es gibt "simulavr" für linux. Als frontend benutzt man dann gdb oder insight soviel ich weiß. ...
OK, danke, ich wollte nur wissen, ob die Nicht-Windoof-Nutzer da auch eine Möglichkeit haben.

Noch eine "Übungsaufgabe": Versuche doch mal, sowohl das Abfragen des Tasters als auch das Ein-/Ausschalten der LED einerseits nur mit "in/out"-Befehlen zu machen, und andererseits nur mit "sbic/sbis/sbi/cbi".

Soweit ganz kurz -- muss dringend zum Kaffeetrinken...

Viele Grüße

Fred

onion
19.07.2008, 15:55
Was meinst du mit Toggeln des Port-Ausgangs? Umschalten zwischen Ein- und Ausgang?
Das versteh ich nicht ganz:

Du liest diesen Wert auch dann, wenn der PORTx nicht als Ausgang geschaltet ist (dann wird natürlich dadurch der jeweilige Pullup-R aktiviert, wenn das zugehörige PORTx-Bit gesetzt ist).
Gibt es noch was anderes Als Ein- und Ausgang. Direkt nach einem Reset ist ein Port dann auf Ein- oder auf Ausgang gechaltet?

Also ich verstehe das jetzt so:
Auf Eingang schreiben -> Pullup an/aus
Am Ausgang lesen -> man bekommt den Wert den der Ausgang gerade hat

Hier mal die überarbeitete Version meines Codes:

;+++++++++++++++++++++++++++
;My first AVR ASSEMBLY CODE
;+++++++++++++++++++++++++++

;################
.NOLIST
.INCLUDE "m8def.inc"
.LIST
;################

.EQU Taster1 = 2
.EQU LED1 = 5

RJMP main

main:
LDI R16,0b00100000
OUT DDRD,R16 ;PORT D Input/Output directions setzen

SBIC PIND,Taster1 ;Taster1 prüfen
RJMP led_on ;springen wenn gedrückt

CBI PORTD,LED1 ;LED1 ausschalten
RJMP main
led_on:
SBI PORTD,LED1 ;LED1 anschalten
RJMP main

Als nächstes werde ich mal versuchen die LEDs zum blinken zu bringen.

fhs
19.07.2008, 16:35
Hallo,


Was meinst du mit Toggeln des Port-Ausgangs? Umschalten zwischen Ein- und Ausgang?
nein, Umschalten von H nach L bzw. von L nach H.


Gibt es noch was anderes Als Ein- und Ausgang. Direkt nach einem Reset ist ein Port dann auf Ein- oder auf Ausgang gechaltet?
Ich versuche es kurz zu erklären, aber diese Erklärung ersetzt nicht das Datenblatt (verlinkt!) (http://atmel.com/dyn/resources/prod_documents/doc2486.pdf), das zu Deiner Pflichtlektüre werden muss.

Laut Datenblatt ist "0" der Initialwert für DDRx und PORTx, also ist jeder Hardware-Pin zunächst einmal ein Eingang ohne Pullup-R. Du würdest von PORTD und DDRD direkt nach einem Power-On-Reset z.B. "0" lesen. Von "PIND" liest Du hingegen das, was Du hardwaremäßig an den zugehörigen Hardware-Pins liegen hast. Oft will man Pins mit z.B. Tastern auf "0" ziehen. Um einen externen Pullup-R zu sparen, aktiviert man den internen durch Schreiben von PORTx/Py (z.B. so:


clr r16 ;
out DDRD, r16 ; redundant nach einem Reset! D als Eingang
sbi PORTD,0 ; aktiviere Pullup-R für PD0
nop ; ist hier nötig, da die Änderung erst 1 Takt später erfolgt!
in r17, PIND ; r17 Bit0 ist jetzt gesetzt, wenn PD0 offen (int. Pullup)!

Achtung: nicht bei allen ATmegas kannst Du alle SFRs mit "in/out/sbi/cbi etc." ansprechen, z.T. muss man das mit LDS/STS machen, wenn das jeweilige SFR "memory mapped" ist! Wann gilt das? Siehe Datenblatt des μCs!


Auf Eingang schreiben -> Pullup an/aus
Nein, s.o., auf PORTX/PY eine "1"schreiben => Pullup-R für das Bit PY von PORTX.


Am Ausgang lesen -> man bekommt den Wert den der Ausgang gerade hat
Nein, wenn Du PORTX liest, bekommst Du den Wert, der in PORTX steht, also den Initialwert oder den Wert, den Du reingeschrieben hast. Wenn Du PINX liest, bekommst Du das, was durch PORTX und die Hardware vorgegeben ist. Wäre allerdings blöd, DDRD und PORTD auf 0xff zu setzen und alle Pins auf Masse zu legen (Kurzschluss!).

Deinen Code sehe ich mir erst an, wenn Du das Datenblatt gelesen und verdaut hast. [-(

Viele Grüße

Fred

onion
19.07.2008, 16:49
Also ich arbeite schon mit dem Datenblatt, jedoch picke ich mir eher immer die Infos raus die ich gerade brauche. Befehlsübersicht etc.
Da ich aber von manchen Dingen gar nicht weiß, dass sie exestieren, ist das dann manchmal etwas schwierig. Und so 300 Seiten arbeitet man jetzt auch nicht so in ner Stunde mal eben durch.
Ich finde als Anfänger sollte man erst mal so 2 bis 3 kleine Programme geschrieben haben z.b. mit Hilfe von Tutorials oder so netten Foren wie hier und dann kann man sich voll ins Datenblatt stürzen.

Mein Code funktioniert jetzt aber und ist denke ich auch ok so wie ich es gemacht habe.
Final Version:

;+++++++++++++++++++++++++++
;My first AVR ASSEMBLY CODE
;+++++++++++++++++++++++++++

;################
.NOLIST
.INCLUDE "m8def.inc"
.LIST
;################

.EQU Taster1 = 2
.EQU LED1 = 5

RJMP main

main:
LDI R16,(1<<LED1)
OUT DDRD,R16 ;PORT D Input/Output directions setzen
loop:
SBIC PIND,Taster1 ;Taster1 prüfen
RJMP led_on ;springen wenn gedrückt

CBI PORTD,LED1 ;LED1 ausschalten
RJMP loop
led_on:
SBI PORTD,LED1 ;LED1 anschalten
RJMP loop

fhs
19.07.2008, 17:03
..., ist das dann manchmal etwas schwierig. Und so 300 Seiten arbeitet man jetzt auch nicht so in ner Stunde mal eben durch.
Stimmt.


Mein Code funktioniert jetzt aber und ist denke ich auch ok so wie ich es gemacht habe.
Kommentierte Version:


;################
.NOLIST
.INCLUDE "m8def.inc"
.LIST

.EQU Taster1 = 2
.EQU LED1 = 5

.CSEG ;
.ORG 0 ;

RJMP main ; könntest Du in diesem Fall sogar weglassen

main:
LDI R16, (1<<LED1) ; GUT!
OUT DDRD, R16 ; GUT!
loop:
SBIC PIND,Taster1 ;Taster1 prüfen
RJMP led_on ;led_on wenn TasterPin=H
CBI PORTD,LED1 ;LED1 ausschalten wenn TasterPin=L
RJMP loop

led_on:
SBI PORTD,LED1 ;LED1 anschalten
RJMP loop


Du sagtest, Dein Taster schaltet PD2 bei Aktivierung auf Masse? Dann bekommst Du das, was ich in den Code kommentiert habe, es sei denn, die LED liegt zwischen Ausgangspin und Vcc (ich weiß nicht, wie Deine Hardware aussieht); dann wäre aber "led_on" falsch bezeichnet.

Viele Grüße und weiter viel Spaß mit Assembler!

Fred

onion
19.07.2008, 17:39
Das habe ich oben gesagt:

Also im Schaltplan Ist es Taster1 verbunden mit PD2 (IC4 ist der atmega8) und LED 1 verbunden mit PD5. Der Taster ist gegen 5V geschaltet und die LED ist mit einem Widerstand auf Masse geschaltet.
Übringens gibts den Link zum Schaltplan oben in meinem ersten Posting, falls du es dir anschauen möchtest.

fhs
19.07.2008, 17:45
Hi,

tut mir leid, dass ich das nicht berücksichtigt hatte. Im Schaltplan habe ich jetzt auch endlich den PD2-Taster gefunden; anfangs hatten mich die Tabellen mit Jumper-Settings usw. total durcheinander gebracht. So ist Dein Code richtig!

Typischer ist es, die internen Pullup-Rs zu verwenden und gegen Masse zu schalten. Was Dein Board macht, ist natürlich auch nicht verkehrt, obwohl viele über die R/C-Kombination zur "Entprellung" die Nase rümpfen würden.

BTW: Die AVRs aus "alten Zeiten" (AT90Sxxxx-Serie) konnten mehr Strom "sinken" als "sourcen", deshalb wurden dort LEDs meist vom Ausgangspin nach Vcc geschaltet.

Viele Grüße

Fred

onion
19.07.2008, 18:05
Nunja, das Board hab ich mir halt einfach mal von Pollin bestellt um einen Einstiegspunkt zu haben. Ich fand 14,95 Eur ist ein ganz guter Preis dafür.
Besser wäre natürlich noch ein USB Anschluss aber das würde dann halt direkt das 3 fache kosten und irgendwann werd ich mir das vielleicht einfach selber bauen.
Wie würde man denn überlicherweise einen Taster verschalten um ihn zu entprellen. Warum ist die Pollin Lösung schlecht?

fhs
19.07.2008, 18:18
Hi,


.... Ich fand 14,95 Eur ist ein ganz guter Preis dafür...
Sehe ich auch so!


...Wie würde man denn überlicherweise einen Taster verschalten um ihn zu entprellen.
Internen Pullup-R aktivieren und prellenden Taster gegen Masse. Dann per Software entprellen! Es gibt sogar ICs, die entprellen. Hier die "Bibel" (http://www.ganssle.com/debouncing.pdf) zum Thema Prellen und Entprellen.


Warum ist die Pollin Lösung schlecht?
1. Fehlende Flexibilität, da "fester" Pulldown-R (wird auf Deinem Board durch Jumper umgangen!)
2. Unnötiger Hardware-Aufwand (33k + 330nF)
3. Fragliche Wirksamkeit (siehe oben zitierten "Bibel"-Link)


MfG

Fred

oberallgeier
19.07.2008, 18:25
Hallo alle, hi onion,


Also ich arbeite schon mit dem Datenblatt, jedoch picke ich mir eher immer die Infos raus die ich gerade brauche. ...Ja, das kenne ich (auch von mir) - - - man weiss nur soo oft nicht, welche Stellen man kennen müsste - wenn man die nicht gelesen hat. Das ist eben das doofe an den Datenblättern - man sollte sie wenigstens einmal durchlesen. Merken kann man sich das bei späterem, nochmaligen Durchlesen.


... Wobei ich mich gerade auch mal gefragt habe wie oft ich den Chip überhaupt flashen kann bevor ich einen neuen brauche.Das steht im Datenblatt, übrigens auf Seite 1, ziemlich oben . . . .

– Write/Erase Cycles: 10,000 Flash/100,000 EEPROM

onion
20.07.2008, 20:55
Also, weiter gehts, leider will die LED partout nicht blinken.
Sie geht nur einmal an und das auch nur nach viel zu langer Zeit, eigentliche frequenz sollte 1Hz sein.
Vielleicht habt ihr ja noch mal nen Tipp, habe versucht den Code so gut wie möglich zu kommentieren:

;************************************************* *****************
;Trying to make the LED blink
;************************************************* *****************

;*******************
.NOLIST
.INCLUDE "m8def.inc"
.LIST
;*******************

.EQU Taster1 = 2
.EQU LED1 = 5
.EQU Timer_Start_Wert = 65536 - 15625

main:
LDI R16,(1<<LED1)
OUT DDRD,R16 ;PORT D Input/Output directions setzen
LDI R16,(1<<CS12)+(1<<CS10) ;Prescaller für Timer1 auf 1024 setzen, 16MHz/1024 = 15625Hz
OUT TCCR1B,R16
outer_loop:
LDI R16,HIGH(Timer_Start_Wert) ;Startwert in Timer laden, Timer soll ein mal pro Sekunde überlaufen
OUT TCNT1H,R16
LDI R16,LOW(Timer_Start_Wert)
OUT TCNT1L,R16
inner_loop:
IN R16,TIFR ;auf Overflow des Timer1 warten
SBRS R16,TOV1
RJMP inner_loop

IN R16,PORTD ;LED Zustand einlesen
COM R16 ;toggeln
ANDI R16,(1<<LED1)
OUT PORTD,R16 ;wieder ausgeben
RJMP outer_loop ;zurück zum Timer reseten

sternst
20.07.2008, 21:06
Du musst das TOV1-Bit auch wieder löschen (indem du eine 1 in das Bit schreibst).
Und was das Timing angeht: bist du dir sicher, dass der Controller überhaupt mit 16 MHz läuft? Vielleicht läuft er noch mit dem internen Oszillator. Fuses richtig gesetzt?

onion
20.07.2008, 21:47
Ok das mit dem zurücksetzen war ein super Tip.
Mit dem Thema Fuses habe ich mich allerdings noch gar nicht beschäftigt. Habe immer nur mein .hex file mit avrdude in den flashspeicher geschrieben.
Gibt es beim Thema Fuses irgendwas Wichtiges zu beachten. War das nicht so dass man damit den kompletten Chip unbrauchbar machen kann?

fhs
20.07.2008, 22:11
Hi,


... beim Thema Fuses .... War das nicht so dass man damit den kompletten Chip unbrauchbar machen kann?
man kann sich z.B. von der Möglichkeit des ISP "aussperren" oder den Controller in einen Zustand bringen, wo er nur mit einem externen Oszillator läuft usw.

Da kann ich mich nur wiederholen: Lies im Datenblatt nach, was die Standardeinstellungen (Lieferzustand) Deines μCs sind. Dann weißt Du auch, mit welcher Frequenz er im "Grundzustand" läuft und kannst Deine Software entsprechend anpassen.

Andererseits: Natürlich will man irgendwann alles nutzen, auch unterschiedliche Taktfrequenzen, und dann muss man eben die Fuses ändern und dabei alle o.g. Details (+ mehr) beachten.

Gruß

Fred

Dolfo
21.08.2008, 23:01
Hallo
danke für Eure Erläuterungen hier, bin ebenfalls Anfänger und saß grad' am gleichen Problem. So klappt es jetzt bei meinem ATtiny45:

ausschalten:
cbi PortB,0 ; Relais=aus
sbis PinB,2 ; überspringe wenn Taster=ein
rjmp ausschalten

einschalten:
sbi PortB,0 ; Relais=ein
sbic PinB,2 ; überspringe wenn Taster=aus
rjmp einschalten
rjmp ausschalten

Grüße,
Dolfo