Forum: Mikrocontroller und Digitale Elektronik fehler bei pcf8591


von Felix Fellhauer (Gast)


Lesenswert?

Hallo Leuz!

Ich habe folgendes problem, ich möchte nen analogwert vom kanal1 von
meinem pcf8591 per uart auf meinen rechner schicken, hab auch schon den
code und ewig rumprobiert, aber ich krig imer nur leerzeichen!?!
also hier mal der code incl. i2c routine.

ich hoffer ihr könnt mir helfen, würd mich sehr freuen

THX im vorraus
===============================================================
.include "8515def.inc"



.equ scl    = 7
.equ sda    = 6

.equ  i2c_port  = PORTC
.equ  i2c_pin   = PINC
.equ  i2c_ddr   = DDRC
.def temp = r16

        ; Stackpointer initialisieren
        ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

        ; Baudrate einstellen
        ldi temp, 25
        out UBRR, temp
        sbi UCR,TXEN


    ;;;;;;;;;;;;;;;;;;;;;;;
    ;START
    ;;;;;;;;;;;;;;;;;;;;;;;Start, 145, Wert lesen + NAK, Stop

loop:
    rcall i2c_start

    ldi r16, 144
    rcall putbyte

    ldi r16, 64
    rcall putbyte

    ldi r16, 64
    rcall putbyte

    rcall i2c_stop





        rcall i2c_start

    ldi r16, 144
    rcall putbyte

    ldi r16, 64
    rcall putbyte

    rcall i2c_stop


    rcall i2c_start

    ldi r16, 145
    rcall putbyte

    rcall getbyte

    mov r17, r16

    rcall i2c_stop


        rcall serout

        rjmp loop

serout:

        out UDR, r16
; =============================
;   Warteschleifen-Generator
;     400000 Zyklen:
; -----------------------------
; warte 399999 Zyklen:
          ldi  R17, $97
WGLOOP0:  ldi  R18, $06
WGLOOP1:  ldi  R19, $92
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
; -----------------------------
; warte 1 Zyklus:
          nop
; =============================

 ret

 .include "i2c_routinen.txt"

=================================================
ROUTINE
=================================================

;*********************[ Erläuterungen ]*********************
;*
;* I2C - Routinen für Atmel AVRs
;*
;* die Routine benutzt r16. Alle anderen Register bleiben unverändert
;*
;* in der Hauptroutine müssen die Pins und Register für
;* die I2C - Schnittstelle festgelegt werden
;*
;* .equ scl    = 7
;* .equ sda    = 6
;*
;* .equ  i2c_port  = PORTC
;* .equ  i2c_pin   = PINC
;* .equ  i2c_ddr   = DDRC
;*
;* Dann kann man die I2C - Schnittstelle über die Befehle
;*
;* i2c_start    -> Stellt Startbedingung für I2C - Bus her.
;* i2c_stop    -> Stellt Stopbedingung für I2C - Bus her.
;* getbyte    -> Lies ein Byte vom I2C - Bus. Ergebnis
;*         liegt in Register r16.
;* putbyte    -> Überträgt ein Byte über den I2C - Bus. Erwartet
;*         das zu sendende Byte in Register r16.
;*
;* Das Programm könnte dann für den I2C - Portexpander PCF8754 so
aussehen:
;*
;*  rcall i2c_start
;*  ldi r16, 0x41      ; Adresse des Chips senden ( 0x41 = lesen , 0x40 
=
schreiben)
;*  rcall putbyte
;*  rcall getbyte      ; Wert vom Chip lesen
;*  rcall i2c_stop
;*
;* Das Programm liest die Eingänge des PCF8754 in r16 ein.
;*
;***********************************************************

i2c_start:
  sbi  I2C_PORT, sda
  sbi  I2C_PORT, scl

  ;Überprüfung ob Bus verfügbar

  cbi  I2C_PORT, sda
  cbi  I2C_PORT, scl
  ret

i2c_stop:        ; Stoppbedinung für den I2C-Bus generieren
  cbi  I2C_PORT, sda
  sbi  I2C_PORT, scl
  nop
  sbi  I2C_PORT, sda
  ret

putbyte:        ; ein Byte ausgeben
  push  r17
  ldi   r17, 0x08
putbyte_:
  clc        ; CarryBit löschen
  adc  r16, r16    ; Register über das Carrybit um eins nach rechts
verschieben
  brcc  carry_set    ; Wenn Carrybit gestezt springe zu carry_set
  sbi  I2C_PORT, sda    ; Setzte Datenleitung
  rjmp  put_out
carry_set:
  cbi  I2C_PORT, sda    ; Lösche Datenleitung
put_out:
  rcall pause
  sbi  I2C_PORT, scl    ; Signalpuls erzeugen
  rcall pause
  cbi  I2C_PORT, scl
  rcall pause
  dec  r17
  brne putbyte_

  cbi  I2C_DDR, sda
  sbi  I2C_PORT, sda    ; Acknowledge Puls Abwarten
  rcall pause
  sbi  I2C_PORT, scl
  rcall pause
;getack_:
;  sbic  I2C_PIN, sda
;  rjmp  getack_
  sbi  I2C_DDR, sda
  cbi  I2C_PORT, scl
  rcall pause
  pop  r17
  ret


getbyte:        ; ein Byte einlesen
  push  r17
  clr  r16
  sbi    I2C_PORT, sda    ; Datenpin hochohmig schalten (=Eingang)
  cbi  I2C_DDR, sda
  ldi   r17, 0x08
  clc
getbyte_:
  sbi  I2C_PORT, scl    ; Signalpuls erzeugen
  rcall pause
  sbic  I2C_PIN, sda    ; Datenleitung auslesen
  rjmp data_set
  clc        ; lösche Carry Flag
  rjmp get_data
data_set:
  sec        ; setzte Carry Flag
get_data:
  adc  r16,r16    ; Register über das Carrybit um eins nach rechts
verschieben
  cbi  I2C_PORT, scl    ; ( c -> r7 , r(n + 1) -> r(n) , r0 -> c )
  rcall pause
  dec  r17
  brne getbyte_
  sbi  I2C_DDR, sda    ; Datenleitung wieder zu Ausgang machen
  rcall pause

  cbi  I2C_PORT, sda    ; Acknowledge Puls erzeugen
  rcall pause
  sbi  I2C_PORT, scl
  rcall pause
  cbi  I2C_PORT, scl
  rcall pause
  pop  r17
  ret


pause:          ; eine sehr kurze Pause
  push   r16      ; Schleife wird 0x14 (=20) mal durchlaufen
  ldi  r16, 0x14
pause_:
  nop
  dec  r16
  brne  pause_
  pop  r16
  ret



GRUß Felix

von Andreas Hesse (Gast)


Lesenswert?

Hallo,

Versuch mal

serout:
   sbis  USR, UDRE  ; wait until UDR is ready
   rjmp  serout
   out   UDR, tmp
   ret

Mit welchem Programm empfängst Du denn Daten auf dem PC?


Gruss
Andreas

von Felix Fellhauer (Gast)


Lesenswert?

Ich empfange im moment mit Hypertrm unn des tut eigendlich so weit ganz
gut.
Die Uart-Sende-Routine funktioniert eigendlich auch, die hab ich soweit
mal getestet in dem ich über des uart einfach en mehrzeiligen text
rausgelassen hab, den hat des hypertrm auch empfangen und richtig
dargestellt. natürlich ist des mit dem delay-loop nich des gelbe vom ei
aber es finktioniert, der fehler muss also irgendwo anders liegen.

THX
Gruß Felix

von Uwe B. (Gast)


Lesenswert?

Mal ne Frage : Schreibst Du den Wert vom 8591 direkt als Byte auf die
serielle Schnittstelle ??

Den mußt du in ASCII umwandeln sonst siehst du mit hyperterm nix !

z.B. 8 Bit Wert Value >>

AscByte1=(Value / 0x64)+0x30;
AscByte2=((Value-((AscByte1-0x30)*0x64))/0x0A)+0x30;
AscByte3=(Value-((AscByte1-0x30)*0x64)-((AscByte2-0x30)*0x0A))+0x30;

dann die drei AscByte serielle raus und gut ist.

MfG   Uwe

von Felix Fellhauer (Gast)


Lesenswert?

aber ich müsste doch eigendlich zumindest en paar hyroglyphen aus dem
ding raus krigen oder ??



gruß Felix

von Andreas Hesse (Gast)


Lesenswert?

Hallo,

versuch doch mal mit einem Terminalprogramm, dass Hexadezimale
Darstellung verwendet. Ich verwende AVRTERM (Downloadbar unter
http://rowalt.de/mc/index.htmm, dann Tools im Menue anwählen).

Bist Du sicher, dass der Abfrageablauf am 8591 korrekt ist? Ich hab es
mit einem AVR noch nicht probiert, jedoch mal in Delphi. Da sieht der
Ablauf anders aus.

Ansonsten mal die Original TWI-Routinen von ATMEL verwenden. Damit habe
ich bisher alle Bausteine relativ schnell zum laufen gebracht.

Gruss
Andreas

von Felix Fellhauer (Gast)


Lesenswert?

ich hab des mal getestet aber da hat sich nix geändert ich krig nur 255
also lauter einsen.
ich hab die bus-leitungen vom pcf ohne irgendwas an 2 1\0-Ports vom
90s8515 gehängt, des müsste doch gehen oder ? die restliche beschaltung
vom pcf müsste auch richtig sein. kann es an der bus-beschaltung
liegen?

Danke
Felix

von Andreas Hesse (Gast)


Lesenswert?

Hallo,

also keine Pull-Up-Widerstände?
Pullup (4k7-10k) solltest Du einbauen.
Ich habe immer 10k genommen und zusätzlich noch 330Ohm in der SDA und
SCL-Leitung (die letzteren sind aber nicht nötig).


Gruss
Andreas

von Felix Fellhauer (Gast)


Lesenswert?

Ich hab jetzt die pull-ups reingesetzt und die sache mal mit nem pcf8574

ausprobiert, aber der macht genauso wenig irgend en mux, ich kann
nichtmal einen wert hinschicken, denm er dann ausgibt, ich binn kurz
vorm verzweifeln mit nem *** i2c-Bus !!
weiss einer von euch an was des sonst noch liegen könnte?
hier mal mein 2. test-code für den 8574, a0 bis a2 sind an masse.

==================================================================
.include "8515def.inc"
.include "i2c_routinen.inc"



.equ scl    = 7
.equ sda    = 6

.equ  i2c_port  = PORTC
.equ  i2c_pin   = PINC
.equ  i2c_ddr   = DDRC
.def temp = r16

        ; Stackpointer initialisieren
        ldi temp, LOW(RAMEND)
        out SPL, temp
        ldi temp, HIGH(RAMEND)
        out SPH, temp

    ldi r16, 0xff

    out DDRC, r16




    ;;;;;;;;;;;;;;;;;;;;;;;
    ;START
    ;;;;;;;;;;;;;;;;;;;;;;;
;Initialisierung (1x nach dem Einschalten):
;Start, 144, 64, 64, Stop

;ADC auslesen:
;Start, 144, 64+Kanal, Stop
;Start, 145, Wert lesen + NAK, Stop








rcall i2c_start
ldi   r16, 0x40      ; Adresse des Chips senden
        ; ( 0x41 = lesen , 0x40 = schreiben)
rcall putbyte
ldi   r16, 0xaa
rcall putbyte      ; Bytewert AA (=10101010) an den
        ; Chip senden
rcall i2c_stop

von Andreas Hesse (Gast)


Lesenswert?

Hi,

hast Du mal die Original Atmel routinen versucht?

Um zu testen, verwende ich manchmal BASCOM, weil man sich da nicht um
das Timing kümmern muss. Die freie Version reicht für einen kleinen
Test aus. Dann kannst Du wenigstens sicher sein, das es die Hardware
tut.

Gruss
Andreas

von Felix Fellhauer (Gast)


Lesenswert?

Könntest du mal nen link posten, wo ich die originalen atmel routinen
runterlanden kann?

THX felix

von Andreas Hesse (Gast)


Lesenswert?

Hallo,

ich habe den Code auf meiner Internetseite
www.andi-hesse.de/download.html ( DSM-0822a-Display) geladen.
Die Beschreibung (Atmel Application Note AVR300) hat Atmel leider vom
Netz genommen. Ich hab sie leider nicht mehr bei mir gefunden. Aber
vielleicht kommst Du mit dem Code zurecht. Du musst das Timing
anpassen.
(Im Zweifelsfall mal die Wartezeiten etwas grösser machen, das ist zum
testen wohl Ok)

Gruss
A.Hesse

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.