; funktioniert zusammen mit gleicher Versionsnummer für ATMega8 ;------------------------------------------------------------------------------------------------------------------------------ ; Steuerung von 12 Servos durch einen Master und zwei slaves über SPI ; abgewandelte Testversion: anstelle der Servos wird ein LCD angeschlossen um die Übertragung der Pulslängen zu prüfen ; in Abwandlung des Myavr-originals wird Port D7 durch D1 ersetzt ;------------------------------------------------------------------------------------------------------------------------------ ; Funktion : ATMega8 ist SPI-Master; wählt durch SoftwareSlaveSelect (PIN B0) einen der ; ATTinys als Slave aus, dieser antwortet über Port B1; dadurch kontrollierte ; Datenübertragung per SPI ; Format der Datenübertragung: erstes Byte: oberes Nibbel=Servonummer, unteres ; Nibbel=Highbyte der zugehörigen Servopulsdauer, zweites Byte Lowbyte ; Speicherorganisation: die Positionen der Servos werden immer in der Reihenfolge Low-High ; abgelegt, somit ergibt sich die Low-Speicherstelle des Servos Nr. x (für x=1 bis 6) nach: Ramstart+2*(x-1) ; Schaltung : SPI: MOSI, SCK - ATMega8 zu ATTinys lt. Datenblatt (ohne MISO) ; ATMega8 - ATTiny2313 ; C1 - B0 ; C2 - B0 ; C3 - B1 ; ATtiny2313 auf Steckboard verbunden mit ATMega8 auf MYAVR-Board ; verbunden über SPI, ATMega als Master, ATTiny als Slave ; ATtiny mit Servos an D1 bis D6 ; Verbindung Steckboard - MYAVR-Board: +,-,MOSI, SCK, Software-SS, Bereit (2313 Pins 20,10,17,19,12,13) ;------------------------------------------------------------------------------------------------------------------------------ ; Prozessor : ATtiny2313 ; Takt : 1.000.000 Hz ; Sprache : Assembler (GNU) ; Datum : 13.10.2012 ; Version : 1.3.1 ; Autor : U.S. ;------------------------------------------------------------------------------------------------------------------------------ ; ; Registerfestlegungen: R1 Servonummer ; R2 Servopuls Highbyte ; R5 Servonummer nur zur Programmierung ; R6 Lowbyte nur zur Programmierung ; R7 Highbyte nur zur Programmierung ; R16 temporär ; R17 temporär und Zwischenspeicher für empfangene Daten ; R18 reserviert für ISR ; R19 reserviert für ISR ; R20 reserviert für Servomaske (ISR) ; R21 Zählervergleichswert low (ISR) ; R22 Zählervergleichswert high (ISR) ; r24 für lcd-Ausgabe nur zur Programmierung ; .include "avr.h" ;------------------------------------------------------------------------------------------------------------------------------ begin: rjmp main ; RESET External Reset, Power-on Reset and Watchdog Reset reti ; INT0 External Interrupt Request 0 reti ; INT1 External Interrupt Request 1 reti ; TIMER1 CAPT Timer/Counter1 Capture Event rjmp ISR_Vergl_A ; TIMER1 COMPA Timer/Counter1 Compare Match A reti ; TIMER1 OVF Timer/Counter1 Overflow reti ; TIMER0 OVF Timer/Counter0 Overflow reti ; USART, RX USART, Rx Complete reti ; USART, UDRE USART Data Register Empty reti ; USART, TX USART, Tx Complete reti ; ANA COMP Analog Comparator reti ; PCINT rjmp ISR_Vergl_B ; TIMER1 COMPB reti ; TIMER0 COMPA reti ; TIMER0 COMPB reti ; USI START USI Start Condition reti ; USI OVERFLOW USI Overflow reti ; EEPROM Ready reti ; WDT OVERFLOW Watchdog Timer Overflow ;------------------------------------------------------------------------------------------------------------------------------- main: ldi r16,lo8(RAMEND) out SPL,r16 ; Set Stack Pointer to top of RAM ldi ZL,lo8(RAMSTART) ; das Z-Register wird für Speicherzugriffe im Hauptprogramm benutzt ldi YL,lo8(RAMSTART) ; das Y-Register für Interrupts ; ldi r16,0b01111110 ; out DDRD,r16 ; Port D.1 bis D.6 als Ausgang (für Steuerimpulse) ldi r16,lo8(1500) ; Timerstartwert liegt bei 1500µS (Mittelstellung) ldi r17,hi8(1500) ; errechnet sich nach (= Impulsdauer * Prozessorfrequenz / Timerprescaler) st Z+,r16 ; jetzt wird die Tabelle für jeden Servo mit dem Wert für die Mittelstellung geladen st Z+,r17 st Z+,r16 ; Low-Byte st Z+,r17 ; High-Byte st Z+,r16 st Z+,r17 st Z+,r16 st Z+,r17 st Z+,r16 st Z+,r17 st Z+,r16 st Z,r17 ldi r16,lo8(20000) ; Timerendwert liegt bei 20ms ldi r17,hi8(20000) out OCR1AH,r17 out OCR1AL,r16 ldi r16,0b01100000 ; Interrupt OCIE1A und OCIE1B eingeschaltet out TIMSK,r16 ldi r16,0b00001001 ; CTC-Mode, Prescaler 1 out TCCR1B,r16 cbi DDRB,0 ; B0 als Eingang für Slaveselect cbi DDRB,1 ; B1 als Eingang temporär sbi PORTB,1 rcall SPI_init ; MCU als SPI-Slave initialisieren rcall warte100ms ; Warten bis alle anderen MCUs vollständig initialisiert sind rcall lcdInit ; nur zur Programmierung ;sei ; darf nicht freigegeben werden wenn LCD an Port D ! mainloop: ;wdr sbic PINB,0 ; warten bis Slaveselect, low-Pegel an SS startet den Ablauf rjmp mainloop sbi DDRB,1 ; B1 als Ausgang für die Dauer der Datenübertragung rcall SPI_Start cbi PORTB,1 ; Pegeländerung an B1 zeigt dem Master die Bereitschaft an rcall SPI_Empfang mov R16,R17 ; oberes Nibbel Servonummer, unteres Nibbel Highbyte der Pulsdauer swap r17 ; Nibbel vertauschen andi r16,0b00001111 ; oberes Nibbel ausblenden, es verbleibt das Highbyte der Servopulsdauer andi r17,0b00001111 ; vertauschtes oberes Nibbel ausblenden, es verbleibt die Servonummer mov r1,r17 ; Servonummer mov r2,r16 ; Highbyte der Servopulsdauer sbi PORTB,1 ; Pegeländerung: fertig rcall SPI_Start cbi PORTB,1 ; Pegeländerung an B1 zeigt dem Master die Bereitschaft an rcall SPI_Empfang mov r6,r17 ; nur zur Programmierung mov r5,r1 ; nur zur Programmierung mov r7,r2 ; nur zur Programmierung ldi ZL,lo8(RAMSTART) dec r1 ; Nummer x des angesprochenen Servos (abgelegt in Register R1) add ZL,r1 ; Speicheradresse des Servos ist Ramstart+2*(x-1) add ZL,r1 st Z+,r17 ; Low-Byte st Z,r2 ; High-Byte speichern rcall LCD_Ausgabe ; empfangene Werte ausgeben auf LCD nur zur Programmierung sbi PORTB,1 ; Pegeländerung: fertig cbi DDRB,1 ; B1 wieder als Eingang rjmp mainloop ;----------------------------------------------------------------------------------------------------------------------------- ; SPI-Initialisierung als Slave ;----------------------------------------------------------------------------------------------------------------------------- SPI_init: cbi DDRB,5 ; B5 als Eingang für MOSI cbi DDRB,7 ; B7 als Eingang für UCSK ldi R16,0b00011000 ; (1< Ausgabe sub R6,R16 ; ja -> subtrahieren sbc R7,R17 inc R0 ; Dezimalstelle erhöhen rjmp LCD_WiD_Div LCD_WiD_Aus:mov r16,r0 rcall lcdData ret