PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Neuling braucht hilfe bei Software I²C-Routine



dringo
29.03.2007, 15:07
Hi, ich möchte ein Sprut programm von 10Mhz Pic Takt auf 20MHz Pic Takt
umschreiben. Ich benutze den Pic 16F84A, und möchte wie gesagt ein Lernbeispiel von Sprut umschreiben. Aber irgendwie klappt das nicht. Ich habe die warte schleifen verändert und hab Nop befehle eingefügt, was aber ja bei einem Taktunteschied von 10MHz ne menge sind(also geht nicht). Weiß nicht wie ich das sonst noch lösen könnte habt ihr da eine idee, oder einen Vorschlag. Hier ma das unveränderte prog.

list p=16f628
;************************************************* *************
;* Pinbelegung
;* ----------------------------------
;* PORTA: 0 SDA out
;* 1 CLK in
;* 2 SDA in
;* 3 CLK out
;* 4 -
;* 5 -
;* 6 -
;* 7 -
;*
;* PORTB: 0 LCD Display E
;* 1
;* 2 LCD Display RS
;* 3 LCD Display R/W
;* 4 LCD Display D4
;* 5 LCD Display D5
;* 6 LCD Display D6
;* 7 LCD Display D7
;*
;*
;************************************************* *************
;
;sprut (zero) Bredendiek 12/2003
;
; Temperaturmessung mit LM75
; Anzeige am LCD-Display
;
; Prozessor 16F628
;
; Prozessor-Takt 10 MHz
;
; IIC am PortA
; LCD am PortB
;
; Temperaturanzeige mit 0,5°C Genauigkeit
;
;
;************************************************* *********
; Includedatei für den 16F628 einbinden

#include <P16f628.INC>

ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES


; Configuration festlegen:
; Power on Timer, kein Watchdog, HS-Oscillator, kein Brown out, kein LV-programming
__CONFIG _PWRTE_ON & _WDT_OFF & _HS_OSC & _BODEN_OFF & _LVP_OFF



; Variablen festlegen

buf equ 0x22 ; puffer für I2C
Temp_h equ 0x23 ; Temperatur in grad
Temp_l equ 0x24 ; 0.5°C auf Bit 7
count equ 0x2B ; universeller zähler
loops equ 0x2C ; timer für wait
loops2 equ 0x2D ; timer für wait
LcdStatus equ 0x2E ;
LcdDaten equ 0x2F ;

; 8-Bit Rechenregister
xw0 EQU 0x32 ;LSB

; 8-Bit Rechenregister
f0 EQU 0x3A ;LSB

; Dezimalstellen
HdH EQU 0x4B ;3 Hunderter
HdZ EQU 0x4C ;2 Zehner
HdE EQU 0x4D ;1 Einer
HdX EQU 0x4E ; Puffer für eine Dezimalstelle

BcdDaten equ 0x4F
BcdDaten1 equ 0x50


; Konstanten festlegen
; für LCD-Pins
#define LcdE PORTB,0 ; enable Lcd
#define LcdRw PORTB,3 ; read Lcd
#define LcdRs PORTB,2 ; Daten Lcd (nicht control)
#define LcdPort PORTB ; Datenbus des LCD (obere 4 Bit)
; für I2C
#define SDAo PORTA,0 ;Daten output
#define SDAi PORTA,2 ;Daten input
#define SCL PORTA,3 ;Takt
#define SCLo PORTA,3 ;Takt
#define SCLi PORTA,1 ;Takt input


Ini_con Equ B'00000000' ; TMR0 -> Interupt disable
Ini_opt Equ B'00000010' ; pull-up

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

org 0
goto Init

;************************************************* *******
; Das Programm beginnt mit der Initialisierung

Init bsf STATUS, RP0 ; Bank 1
movlw Ini_opt ; pull-up on
movwf OPTION_REG
movlw B'00000000' ; PortB alle outputs
movwf TRISB
movlw B'11100110' ; PortA alle input außer RA0,3,4
movwf TRISA
bcf STATUS, RP0 ; Bank 0
clrf PORTA
clrf PORTB
movlw Ini_con ; Interupt disable
movwf INTCON

; 16F628 alle Comparatoreingänge auf Digital umschalten
BSF CMCON, CM0
BSF CMCON, CM1
BSF CMCON, CM2

;Display initialisieren
call InitLcd

call i2c_reset
nop
nop

; Temp register einstellen
call i2c_on ; Bus aktiv

movlw H'90' ; 1001 0000
call i2c_tx ; LM75 zum schreiben adressieren

movlw 0
call i2c_tx ; Temp adressieren

call i2c_off ; Bus freigeben

mainloop
; Cursor home
movlw 1
call OutLcdControl

; Temp messen
bsf PORTA,4 ; DEBUG
call i2c_on ; Bus aktiv

movlw H'91' ; 1001 0001
call i2c_tx ; LM75 zum lesen adressieren

call i2c_rxack
movwf Temp_h ; Byte in Speicherzelle Datenpuffer retten

call i2c_rx
movwf Temp_l ; Byte in Speicherzelle Datenpuffer retten

call i2c_off ; Bus freigeben

bcf PORTA,4 ; DEBUG

; Temp anzeigen
movfw Temp_h
movwf f0
call OutDez8 ; Anzeige der Grad

movlw '.'
movwf LcdDaten
call OutLcdDaten
movlw '0'
btfsc Temp_l, 7
movlw '5'
movwf LcdDaten
call OutLcdDaten

call OutGC


movlw D'250' ; 250 ms Pause
movwf loops
call WAIT

goto mainloop


;************************************************* ****************
; Routinen für I2C
; Bus übernehmen i2c_on
; W senden i2c_tx
; Byte empfangen i2c_rx (nach w und RXData und SSPBUF)
; Bus freigeben i2c_off
;************************************************* ****************
i2c_reset
bsf SDAo
bsf SCLo
nop
movlw 9
movwf buf
i2c_reset1
nop
bcf SCLo
nop
nop
nop
nop
nop
bsf SCLo
nop
decfsz buf, f
goto i2c_reset1
nop
call i2c_on
nop
bsf SCLo
nop
nop
bcf SCLo
nop
call i2c_off
return

i2c_on
; wenn SDA und SCL beide High, dann SDA auf Low ziehen
bsf SCL ; failsave
bsf SDAo ; failsave

;testen, ob der Bus frei ist
btfss SCLi
goto i2c_on ; Taktleitung frei?
btfss SDAi
goto i2c_on ; Datenleitung frei?

bcf SDAo
nop
bcf SCL
return


i2c_tx
; w über i2c senden
; takt ist unten
; daten sind unten
call WrI2cW ; 8 Bit aus W nach I2C
; ACK muß nun empfangen werden
; Takt ist low
bsf SDAo ;Datenleitung loslassen

bsf SCL ; ACK Takt high
i2c_tx2
btfss SCLi
goto i2c_tx2

nop
;i2c_tx1
; btfsc SDAi ; ACK empfangen?
; goto i2c_tx1 ; nein SDA ist high
bcf SCL ; ja , Takt beenden
bcf SDAo
return


i2c_rxack
; takt ist unten
; daten sind unten
call RdI2cW ; 8 von I2C nach W
; Takt ist unten
; ACK muß nun gesendet werden
bcf SDAo
nop
nop
nop
nop
bsf SCL
i2c_rxack1
btfss SCLi
goto i2c_rxack1

nop
bcf SCL
bcf SDAo
return

i2c_rx
; takt ist unten
; daten sind unten
call RdI2cW ; 8 von I2C nach W
; Takt ist unten
; kein ACK
nop
nop
bsf SDAo
nop

bsf SCL
i2c_rx1
btfss SCLi
goto i2c_rx1

nop
bcf SCL
bcf SDAo
return


i2c_off
; SCL ist Low und SDA ist Low
nop
nop
bsf SCL
nop
bsf SDAo
return



;************************************************* ****
; I2C-Peride ist 2,5 µs
; PIC-Zyklus ist 4/10MHz = 0,4µs
; -> Takt muß für 3 Zyklen H und für 3 Zyklen L sein
; + 1 Zyklus Reserve


;schiebt das Byte aus W in den I2C
; MSB zuerst
; 78 Takte
WrI2cW
; Takt unten, Daten unten
; Datenbyte in w
movwf buf
movlw 8
movwf count ; 8 Bits
WrI2cW1

; Datenleitung setzen
bcf SDAo
rlf buf,f
btfsc STATUS,C ; 0?
bsf SDAo ; nein, 1
nop

bsf SCL ; Taht high
WrI2cW2
btfss SCLi
goto WrI2cW2

bcf SCL ; Takt low
decfsz count,f ; 8 Bits raus?
goto WrI2cW1 ; nein
return ; ja



;liest das Byte aus I2C nach W
; takt ist unten
; daten sind unten
RdI2cW
clrf buf
movlw 8
movwf count
bsf SDAo ;failsave
RdI2cW1
nop
clrc
btfsc SDAi
setc
rlf buf,f

bsf SCL ; Takt high
RdI2cW2
btfss SCLi
goto RdI2cW2

bcf SCL ; Takt low
decfsz count,f ; 8 Bits drinn?
goto RdI2cW1 ; nein
movfw buf ; ja fertig
return


;************************************************* ****************
;Zeitverzögerung um loops * 1 ms
; 10 MHz externer Takt bedeutet 2,5 MHz interner Takt
; also dauert 1 ms genau 2500 Befehle
; 250 Schleifen a 10 Befehle sind 2500 Befehle = 1 ms

WAIT
top movlw .250 ; timing adjustment variable (1ms)
movwf loops2
top2 nop ; sit and wait
nop
nop
nop
nop
nop
nop
decfsz loops2, F ; inner loops complete?
goto top2 ; no, go again
;
decfsz loops, F ; outer loops complete?
goto top ; no, go again
retlw 0 ; yes, return from subWAIT


;************************************************* ****
;+++LCD-Routinen**************************************
;************************************************* ****
;LCD initialisieren, Begrüßung ausgeben

InitLcd
movlw D'255' ; 250 ms Pause nach dem Einschalten
movwf loops
call WAIT

movlw B'00110000' ; 1
movwf LcdPort
bsf LcdE
nop
bcf LcdE

movlw D'50' ; 50 ms Pause
movwf loops
call WAIT

movlw B'00110000' ; 2
call Control8Bit
movlw B'00110000' ; 3
call Control8Bit
movlw B'00100000' ; 4
call Control8Bit

movlw B'00000001' ; löschen und cusor home
call OutLcdControl
movlw B'00101000' ; 5 function set, 4-bit 2-zeilig, 5x7
call OutLcdControl
movlw B'00001000' ; 6 display off
call OutLcdControl
movlw B'00000110' ; 7 entry mode, increment, disable display-shift
call OutLcdControl
movlw B'00000011' ; 8 cursor home, cursor home
call OutLcdControl
movlw B'00001111' ; 9 display on
call OutLcdControl
return

;************************************************* ****
; ein Steuerbyte 8-bittig übertragen
Control8Bit
movwf LcdPort
bsf LcdE
nop
bcf LcdE
movlw D'10'
movwf loops
call WAIT
return

;************************************************* ****
; darauf warten, daß das Display bereit zur Datenannahme ist
LcdBusy
bsf STATUS, RP0 ; make Port B4..7 input
movlw B'11110000'
iorwf TRISB, f
bcf STATUS, RP0
BusyLoop
bcf LcdRs
bsf LcdRw ; Lesen
bsf LcdE
nop
movf LcdPort, w
movwf LcdStatus
bcf LcdE
nop
bsf LcdE ; Enable
nop
bcf LcdE
btfsc LcdStatus, 7 ; teste bit 7
goto BusyLoop
bcf LcdRw
bsf STATUS, RP0 ; make Port B4..7 output
movlw B'00001111'
andwf TRISB, f
bcf STATUS, RP0
return

;************************************************* ****
; aus W ein Byte mit Steuerdaten zum Display übertragen
OutLcdControl
movwf LcdDaten
call LcdBusy
movf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Hi-teil Daten schreiben
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
swapf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Lo-teil Daten schreiben
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
return

;************************************************* ****
; aus W ein Datenbyte zum Display übertragen
OutLcdDaten
movwf LcdDaten
call LcdBusy
movf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Hi-teil Daten schreiben
bsf LcdRs ; Daten
bsf LcdE ; Enable LcdBus
nop
bcf LcdE ; Disable LcdBus
swapf LcdDaten, w
andlw H'F0'
movwf LcdPort ; Lo-teil Daten schreiben
bsf LcdRs ; Daten
bsf LcdE
nop
bcf LcdE ; Disable LcdBus
bcf LcdRs ;
return

;************************************************* ******************************
; String ' °C' am LCD ausgeben
OutGC
movlw ' '
movwf LcdDaten
call OutLcdDaten
movlw B'11011111' ; °
movwf LcdDaten
call OutLcdDaten
movlw 'C'
movwf LcdDaten
call OutLcdDaten
return



;************************************************* ****
;+++Mathematik-Routinen*******************************
;************************************************* ****

;************************************************* *************
; 8 Bit Wert (f1,f0) auf LCD dezimal anzeigen
OutDez8 ;8-bit (f0) als Dez zum Lcd
call Hex2Dez8

movfw HdH
Call Bcd4Bit
movfw HdZ
Call Bcd4Bit
movfw HdE
Call Bcd4Bit
return


; 100 = 0000 0064 h
; 10 = 0000 000A h
; 1 = 0000 0001 h


Hex2Dez8 ; 8-bit (f1) in 3-stellen BCD
movlw 0x64
movwf xw0
call Hex2Dez1 ; 100er
movfw HdX
movwf HdH

movlw 0x0A
movwf xw0
call Hex2Dez1 ; 10er
movfw HdX
movwf HdZ

movfw f0
movwf HdE
return


Hex2Dez1
clrf HdX
decf HdX, f
HdLoop
incf HdX, f

movf xw0, w ; f0=f0-xw0
subwf f0, f

btfsc STATUS, C ;Überlauf
goto HdLoop ;Stelle 1 mehr

movf xw0,W ; low byte
addwf f0,F ; low byte add

return


Bcd4Bit ;low-4 Bit als BCD ausgeben
movwf BcdDaten
movlw B'00110000'
ADDwf BcdDaten, f ;ASCII-wandeln (+48)
movlw B'00111010'
subwf BcdDaten, w
btfss STATUS, C ;Test auf A ... F
goto BcdOk
movlw .7
addwf BcdDaten, f ;korrigiere A...F (+7)
BcdOk
movfw BcdDaten
call OutLcdDaten
return



end


Der Seiten link ist:

http://www.sprut.de/electronic/pic/programm/thermo75/thermo75.htm

Bitte helft mir, möchte das das Projekt ein erfolg wird. Danke!!!!!