Forum: Mikrocontroller und Digitale Elektronik ATmega48 mit USART als SPI zum MCP3208


von thinking (Gast)


Lesenswert?

Nahmd Gemeinde,

in nutze die USART-Schnittstelle des ATmega48 als SPI, weil die 
eigendliche SPI schon besetzt ist. Ich möchte einen MCP3208 damit 
ansteuern. Im Datenblatt des MCP3208 ist zwar diese Sende/Befehlssequenz 
beschrieben, aber er reagiert nicht darauf. Ich wähle den MCP3208 per 
/CS an und sende meine 3Byte und sehe auf dem Oszi keine Antwort.
Die Taktfrequenz des XCK ist 500kHz. USART ist im SPI-Mastermode (Mode 
0). Rx und Tx sind aktiv, DDRD = 0b11111110 und PORTD=0b11101110, 
Flaggen und Interrupts auch alle aktiv. Senden klapt ja, aber ich 
erhalte keine Antwort.
Irgend 'was mache ich falsch, sonst würde es ja funzen.
Wenn jemand eine Idee hat, was ich machen kann, wüerde mich das sehr 
freuen.

MfG

Hagen

von Hagen G. (thinking)


Lesenswert?

Hier ist der Quell-Code für meine Schwierigkeit

; 
************************************************************************ 
*
; Timer 1 Test
; Datum: 30.09.2008
; Letzte Änderung: 21.10.2008
; Hagen Großmann
; 
************************************************************************ 
*
/*********************************************************************** 
***
  Einstellung für AVRstudio
Main:  ATmega48
  ISP mode
Program:
Fuses:  BODLEVEL  brown-out detection disable
  SUT_CKSEL  Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 16K 
CK/14 CK + 4.1 ms
LockBits:no memory lock feattures enable (lockbit 0xff) Mod1


************************************************************************ 
***/
;*********************************************************************** 
***

; Anschlußbelegung für ATmega48
;
;
;oder weil USART nicht 8 bit synchron ohne Start und Stopbit übertragen 
kann:
;Port B:
;  0 -> DE Daten
;  1 -> /RE Daten/Takt
;  2 -> DE Takt und /SS
;  3 -> MOSI
;  4 -> MISO
;  5 -> CLK
;  6 -> XTAL
;  7 -> XTAL

; Port C:
;  0 -> frei
;  1 -> frei
;  2 -> frei
;  3 -> frei
;  4 -> frei
;  5 -> frei
;  6 -> Reset
;
;
; Port D:
;  0 -> RxD -> Dout
;  1 -> TxD -> Din
;  2 -> /CS -> ext.ADC0  Spannungseingänge 0-7
;  3 -> /CS -> ext.ADC1  Stromeingänge 0-7
;  4 -> CLK
;  5 -> LED onBoard+ext.
;  6 -> frei
;   7 -> frei

;*********************************************************************** 
*********
;
; Konfigurations- und Sicherheitsbits
; an in Ponyprog(programmiert, bei Atmel -> 0) 
WDTON,SUT0,CKSEL2,CKSEL1,CKSEL0

.include "m48def.inc"

.def   Empf    =r9
.def   Send    =r10
.def  ADC_high  =r11
.def  ADC_low    =r12
.def  Lese_Zeiger  =r13
.def  Zeitgeber1  =r14
.def  Kanal_Zeiger  =r15
.def  Temp1    =r16
.def  Temp2    =r17
.def  Temp3    =r18
.def  Temp4    =r19
.def  ZP_b    =r20      ;byte-Zähler für RS485-Schnittstelle
.def  ZP_p    =r21      ;Paketzähler für RS485-Schnittstelle
.def  status    =r22
.def  PIND_filter  =r23
.def  Z_l    =r24
.def  Z_h    =r25

;**********************************************************************
;Aufteilung vom RAM

.equ lesen=SRAM_START      ; Rechner liest vom Modul
.equ schreiben=lesen+32      ; Rechner schreib auf Modul
.equ sendesequenz=schreiben+32    ; 3Byte für Befehlsfolge an ADCs
.equ pininterupt=sendesequenz+3  ;
.equ schleifendurchlauf1=pininterupt+1 ;

;**********************************************************************

;*************** Macro Definition *************************************

.MACRO LED_ON
    sbi PORTD, 5
.ENDMACRO

.MACRO LED_OFF
    cbi PORTD, 5
.ENDMACRO

.MACRO LED_toggle
    in Temp1, PORTD
    ldi Temp2, 0x20
    eor Temp1, Temp2
    out PORTD,Temp1
.ENDMACRO

;************** Macro Definition Ende *********************************
.cseg
;*********************************************************************** 
****
;Interuptverteiler ab Adresse 0

.org $0000
; AVR mega168 vectors starten bei Addresse 0
; und haben lange absolute Sprünge
  rjmp reset      ;reset-Sprung
  rjmp ext_int0    ;nicht benutzt
  rjmp ext_int1    ;nicht benutzt
  rjmp PCINT_0    ;nicht benutzt
  rjmp PCINT_1    ;nicht benutzt
  rjmp PCINT_2    ;nicht benutzt
  rjmp WDT      ;nicht benutzt
  rjmp TIM2_compA    ;nicht benutzt
  rjmp TIM2_compB    ;nicht benutzt
  rjmp TIM2_ovf    ;nicht benutzt
  rjmp TIM1_capt    ;Zeitmessung zwischen 2 Flanken an B0
  rjmp TIM1_compA    ;nicht benutzt
  rjmp TIM1_compB    ;nicht benutzt
  rjmp TIM1_ovf    ;innere Uhr (1ms)
  rjmp TIM0_compA    ;Kontroll-Leuchtdiode
  rjmp TIM0_compB
  rjmp TIM0_ovf    ;Kontroll-Leuchtdiode
  rjmp SPI_int    ;Übnertragung zum Hauptrechner
  rjmp USART_rxc    ;UART Empfang fertig (Befehle)
  rjmp USART_dre     ;nicht benutzt
  rjmp USART_txc    ;nicht benutzt
  rjmp ADC_int
  rjmp EE_rdy      ;nicht benutzt
  rjmp ANA_comp    ;nicht benutzt
  rjmp TWI
  rjmp SPM_rdy


PCINT_1:
  push R0
  in R0,SREG
  push R0
  push Temp2

;  ldi Temp4,0x05      ; 5-mal blinken
  in Temp1,PINC      ; welcher Pin ist low
  ldi Temp2,0xFF      ; Schiebemaske mit Carry
  ldi Temp4,0x00      ; SchleifenZähler für Anzahl Blinken
  ori Temp1,0xC0      ; Bit 7 & 6 setzen, weil Port C nut 7 Bit breit 
und Bit 6 als Ausgang
;  out PORTD,Temp1      ; Kontrollausgabe
  clc
  rcall welcher_pin
  rcall s4

  pop Temp2
  pop R0
  out SREG,R0
  pop R0
  reti


; ******************************************************************

;Timer1 compare
TIM1_compA:

  ldi YH,high(sendesequenz+3)
  ldi YL,low(sendesequenz+3)
  ldi Temp2, 0x03
  mov Lese_Zeiger,Temp2

  rcall sendeByte

  pop Temp1
  pop R0
  out SREG,R0
  pop R0

  reti

USART_rxc:
  push R0
  in R0,SREG
  push R0

  pop R0
  out SREG,R0
  pop R0
  reti

USART_dre:
  push R0
  in R0,SREG
  push R0

  pop R0
  out SREG,R0
  pop R0
  reti

;USART Sende-Interrupt
USART_txc:
  push R0
  in R0,SREG
  push R0

  pop R0
  out SREG,R0
  pop R0
  reti
;----------------------------------------------------------------------- 
------------------
;*** Ende Interruptprogramme ***
;*********************************************************************** 
****************


/*********************************************************************** 
**
  initialisieren
************************************************************************ 
**/

RESET:

  ldi Temp1,high(RAMEND)    ;Stabel auf Ende (stapelt abwärts)
  out SPH,Temp1
  ldi Temp1,low(RAMEND)
  out SPL,Temp1

  rcall PORTB_konfigurieren
  rcall PORTC_konfigurieren
  rcall PORTD_konfigurieren
;  rcall SPI_konfigurieren
  rcall USART_als_SPI_konfigurieren
  rcall Sendesequenz_Werte
;  rcall USART_konfigurieren
;  rcall Timer0_konfigurieren
  rcall Timer1_konfigurieren

  ldi Temp4,3      ; erstmal 3-mal blinken
;  ldi Temp4,1      ; erstmal 1-mal blinken
  rcall s4

  sbi PIND,PIND2      ; Testzwecke ADC0 aktiv

  sei

; 
************************************************************************ 
*
; Hauptprogramm
; 
************************************************************************ 
*

Rhein_Schleife:

  nop
  rjmp Rhein_Schleife

; ***** ENDE Hauptprogramm 
*************************************************

/*********************************************************************** 
****
   Controller konfigurieren
************************************************************************ 
***/

PORTB_konfigurieren:
  ldi Temp1,0b00010010  ;B0 ist DE Daten, kommt bei Kommunikation auf 1
        ;B1 ist /RE Daten/Takt, kommt normalerweise immer auf 0
        ;B2 ist DE Takt und /SS,
        ;kommt normalerweise immer auf 0, wenn Modul Slave ist
        ;B4 ist MISO (Datenausgang Kommunikation);
  out DDRB,Temp1    ;Datenrichtungsregister
  ldi Temp1,0b00000000  ;
  out PORTB,Temp1
  ret

PORTC_konfigurieren:
  ldi Temp1, 0x40
  ldi Temp2, 0x3F
  out DDRC,Temp1    ; Input
  out PINC, Temp2    ;

  ldi Temp1,0x02    ; PinInterupt Port C eingeschaltet
  ldi Temp2,0x3F    ; PinInteruptMaske Port C eingeschaltet
  sts PCICR,Temp1
  sts PCMSK1,Temp2

  ret

PORTD_konfigurieren:

  ldi Temp1,0b11111110
;  ldi Temp1,0x00
  out DDRD,Temp1
  ldi Temp1,0b11101100
  out PORTD,Temp1
  ret


SPI_konfigurieren:

  ret



USART_als_SPI_konfigurieren:

  clr Temp1
  sts UBRR0H,Temp1
  sts UBRR0L,Temp1

  sbi PIND, XCK    ; Setting the XCKn port pin as output, enables master 
mode.

  clr Temp1
  ldi Temp1,(1<<UMSEL1 | 1<<UMSEL0 | 0<<UCPHA0 | 0<<UCPOL0)
  sts UCSR0C,Temp1  ; MSPIM MasterMode, MSP first out, SPI-Mode 0

  clr Temp1
  ldi Temp1,(1<<RXCIE0 | 1<<TXCIE0 | 0<<UDRIE0 | 1<<RXEN0 | 1<<TXEN0) 
;
  sts UCSR0B,Temp1  ; RX Interrupt Enable, USART Data Register Empty 
Interrupt Enable, Receiver Enable, Transmitter Enable


  clr Temp1
  ldi Temp2, 0x13    ; Taktteiler für XCK = 20MHz/40
  sts UBRR0H,Temp1
  sts UBRR0L,Temp2
  ret

Sendesequenz_Werte:
  ldi Temp4, 0x07        ; Sequenz für ADC
  ldi Temp3, 0xC0        ; Platzhalter für XCK
  ldi Temp2, 0x00        ; Platzhalter für XCK
  sts sendesequenz+2,Temp4
  sts sendesequenz+1,Temp3
  sts sendesequenz,Temp2
  ret

USART_konfigurieren:

  clr Temp1
  sts UBRR0H,Temp1
  sts UBRR0L,Temp1

  ldi Temp1,(1<<RXCIE0 | 1<<TXCIE0| 1<<UDRIE0 | 1<<RXEN0 | 1<<TXEN0) 
;
  sts UCSR0B,Temp1    ; RX Interrupt Enable, USART Data Register Empty 
Interrupt Enable, Receiver Enable, Transmitter Enable

  clr Temp1
  ldi Temp1,(1<<USBS0 | 1<<UCSZ01 | 1<<UCSZ00)
  sts UCSR0C,Temp1    ; MSPIM MasterMode, MSP first out,

  ldi Temp1,0x02
  ldi Temp2, 0x08    ; Taktteiler für BAUD=2400 bei 20 MHz
;  clr Temp1
;  ldi Temp2, 0xcf    ; Taktteiler für BAUD=2400 bei 8 MHz
  sts UBRR0H,Temp1
  sts UBRR0L,Temp2
  ret

Timer0_konfigurieren:

  ret

Timer1_konfigurieren:

  ldi Temp1, 0x00    ; normale Port-Operation, Kein Ausgang auf 
OC1A/OC1B
  sts TCCR1A, Temp1  ; Timer/Counter1 Control Register A

  ldi Temp1, 0x09    ; Übereinstimmung mit 
VergleichsregisterA,Rücksetzen bei Gleichheit,Taktteiler 1
;  ldi Temp1, 0x0D    ; Übereinstimmung mit 
VergleichsregisterA,Rücksetzen bei Gleichheit,Taktteiler 1024
  sts TCCR1B, Temp1  ; Timer/Counter1 Control Register B

  ldi Temp1, 0x80    ; Match für Channel A & B
  sts TCCR1C, Temp1  ; Timer/Counter1 Control Register C

  clr Temp1
  sts TCNT1H,Temp1  ; Zählregister löschen
  sts TCNT1L,Temp1  ; Zählregister löschen

;  ldi Temp1, 0x4E    ; Vergleichsregister wird mit Vergelichswert
;  ldi Temp2, 0x1F    ; 0x4E20 gefüllt entspricht 20k Takte = 0.001sec
  ldi Temp1, 0x4C    ; Testweise 1024*19531=19999744 Takte
  ldi Temp2, 0x4B    ; Testweise
  sts OCR1AH, Temp1
  sts OCR1AL, Temp2

  clr Temp1
  sts ICR1H,Temp1
  sts ICR1L,Temp1

  ldi Temp1, 0x27    ; Capture Interrupt ist an,Compare B Match 
Interrupt an, Compare A Match Interrupt an, Overflow Interrupt an
  sts TIMSK1, Temp1
  ret

/*********************************************************************** 
**
   Ende  Controller konfigurieren
************************************************************************ 
**/

/*********************************************************************** 
**
   Unterprogramme
************************************************************************ 
**/

LED_toggle_Schleife:
  LED_toggle
  clr Zeitgeber1
  clr Temp3
  ldi Temp3,(1 << OCF1B | 1 << OCF1A)
  out TIFR1, Temp3
  ret

Werte_holen:

  ret

Kanal_abfragen:

  ret

sendeByte:
  lds  Temp1,UCSR0A
  sbis 0x10,UDRE0      ; wenn SendeRegister leer, dann kein Rücksprung
; sbis nimmt keinen "Temp1"-Bezeichner an, nur die reale Adresse von 
Temp1 -> Bug

  rjmp sendeByte      ; Rücksprung, wenn SendeRegister voll

  ld  Temp1, -Y      ; Testzwecke
  sts UDR0, Temp1      ; Testzwecke
  dec Lese_Zeiger
  brne sendeByte

  LED_toggle

  ret

S4:  LED_ON
  rcall pause
  LED_OFF
  rcall pause
  dec Temp4
  brne S4
  ret

pause:
  ldi Temp3,30
;  ldi Temp3,1
S3:
  ldi Temp2,255
;  ldi Temp2,1
S2:
  ldi Temp1,255
;  ldi Temp1,1
S1:  dec Temp1
  brne S1
  dec Temp2
  brne S2
  dec Temp3
  brne S3
  ret

welcher_pin:
  rol Temp2      ; Rollen links mit Carry -> PinMaske bewegen
  inc Temp4      ; Schleifendurchlauf = entsprechender Pin
  cpse Temp1,Temp2    ; Pins mit Maske vergleichen und bei Gleichheit 
Schleife abbrechen
  brne welcher_pin    ; bei Ungleichheit neuer Schleifendurchlauf
  ret

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.