Hallo Leute,
ich habe da ein kleines Problem, entweder habe ich hier einen Denkfehler und sehe vor lauter Bäumen den Wald nicht mehr, aber im Moment weiss ich nicht weiter.
Ich habe einen kleinen Dallas 1307 I2C RTC-Chip. der mit TWI_BR100 laufen sollte,
eigentlich hab ich schon mit AVRco den PCA9555 und auch den RTC 8564 Chip am laufen gehabt.
Aber mit den DS1307 beisse ich mir die Zähne aus, ich frage in meinem Programm alle 205.000 Zyklen den DS1307 ab (ich brauche die Zeit ja nicht ms genau), somit spare ich mir Rechenleistung für was wichtigeres.
Dabei ist mir aufgefallen, das aus irgendeinen Grund nur alle 10-15x das I2C Telegramm wirklich an den DS1307 gesendet wird. Das deckt sich auch mit meiner Osci-Anzeige und dem Logic-Analyser.
Die Leitung IDat und ICLK sind mit 10k auf 5v gezogen.
Ich vermute wohl einen Fehler in meiner DEFINE, bis jetzt hatte ich immer nur den SOFT-I2C genutzt, bei diesem Board möchte ich aber den OnBoard I2C nutzen, vieleicht habe ich deswegen einen Denkfehler. Hier mal einen Teil des CODE's, vieleicht hat Jemand von euch einen Tip oder sieht meinen Fehler auf Anhieb:
program PVS_I2C;
{$NOSHADOW}
{ $WG} {global Warnings off}
Device = mega1280, VCC=5;
{ $BOOTRST $0F000} {Reset Jump to $0F000}
Define_Fuses
Override_Fuses;
NoteBook = E;
LockBits0 = [];
FuseBits0 = [];
FuseBits1 = [SPIEN, JTAGEN, OCDEN];
ProgMode = JTAG;
Import SysTick, SerPort, {SwitchPort1,} I2Cport, TickTimer, TWImaster, SysLEDblink, {SPIdriver,} ADCPort {, SPIdriver1};
From System Import LongWord;
Define
ProcClock = 16000000; {Hertz}
SysTick = 10; {msec}
StackSize = $0064, iData;
FrameSize = $0064, iData;
// SPIorder = MSB;
// SPIcpol = 1;
// SPIcpha = 1;
// SPIpresc = 1; // presc = 0..3 -> 4/16/64/128
// SPI_SS = true; // use SS pin as chipselect
// SPImode = 0; // 0, 1, 2, 3
SerPort = 57600, Stop1; {Baud, StopBits|Parity}
RxBuffer = 8, iData;
TxBuffer = 8, iData;
I2Cport = PortD;
I2Cdat = 1;
I2Cclk = 0;
TWIpresc = TWI_BR100;
TickTimer = Timer1;
SysLEDblink = 50;
SysLedPort = @BlinkRam, $00; // byte-var, polarity (*4*)
ADCchans = 8, iData, int2; // = [n], iData; = [m,n], iData;
ADCpresc = 128;
// SPIdriver1 = PortC, 0, 1, 2, 3; // SCK, MOSI, MISO, SS
// SPIorder1 = MSB;
// SPIcpol1 = 1;
// SPIcpha1 = 1;
Implementation
{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
type
TimeBlock = record
ok : boolean;
sekunde : byte;
minute : byte;
stunde : byte;
tag : byte;
wochentag: byte;
monat : byte;
jahr : byte;
strzeit : string[8];
strdatum : string[10];
strtag : string[3];
end;
// IO Handler
//
IOHandler = record
Input : array[0..2] of InputData; // Input
Output : array[0..2] of OutputData; // Output
InLinie : array[1..8] of InputLinie; // Alarmlinie
LinieX : integer; //AktuellerAbfragezähler
end; // Ende Record
// Onboard IO's
//
InputDataBoard = record
RunStop : InputPin;
SoftReset : InputPin;
ServTast : InputPin;
MMCInsert : InputPin;
end; // Ende Record
{--------------------------------------------------------------}
{ Const Declarations }
const
// Wochentage
wDayArr : array[0..6] of string[2] = ('SO', 'MO', 'DI', 'MI', 'DO', 'FR', 'SA');
{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
// Output
OUT_LED_ERR [@PortH, 2 ] : bit;
OUT_LED_RUN [@PortH, 3 ] : bit;
OUT_LED_COM [@PortH, 4 ] : bit;
OUT_LED_OK [@PortH, 5 ] : bit;
// Input
IN_RUNSTOP [@PINJ, 3 ] : bit;
IN_SOFTRESET [@PINJ, 4 ] : bit;
IN_SERVTAST [@PIND, 4 ] : bit;
IN_MMCINSERT [@PINB, 4 ] : bit;
// Standard VAR
sel : byte;
y : integer;
x : integer;
wert : integer;
check : boolean;
Elapsed : boolean;
w : byte;
idx, i : byte;
BLINK : boolean;
ZeitBlock : TimeBlock; // Datum Zeitblock
UhrZyklus : longint;
LinieZyklus : integer; //Abfragezyklus Alarmline
OKZyklus : integer;
COMZyklus : integer;
strBuffer : string[15];
intBuffer : integer;
byteBuffer : Byte;
IO_Reg : IOHandler; // IO Registerhandler
IO_Board : InputDataBoard;
// Sysstatusvariablen
SysRUN : boolean;
{--------------------------------------------------------------}
{ functions }
procedure UhrZeit;
var
buffer : byte;
begin
UhrZyklus:=UhrZyklus+1;
//nur alle 205000mal abfragen
if UhrZyklus >= 205000 then
UhrZyklus:=0;
// Prüfe ob RTC schon überprüft wurde
if not(ZeitBlock.ok) then
ZeitBlock.ok:= TWIstat(DS1307);
if ZeitBlock.ok then
WriteLn(serout, 'Uhr vorhanden.');
TWIout(DS1307, 00); // prepare read register 0
TWIinp(DS1307, ZeitBlock.sekunde);
buffer:= ZeitBlock.sekunde;
if not( buffer.7 ) then // low voltage bit set??
TWIout(DS1307, 00, 00);
TWIout(DS1307, 00, 00); // write to register 0, set run mode
TWIout(DS1307, 01, 00); // write to register 1, no ints
TWIout(DS1307, 02, 00); // write to register 2, reset seconds
TWIout(DS1307, 03, $12); // write to register 3, reset minutes
TWIout(DS1307, 04, $19); // write to register 4, set 18hrs
TWIout(DS1307, 05, $18); // write to register 5, set day 19
TWIout(DS1307, 06, 04); // write to register 6, set thursday
TWIout(DS1307, 07, $06); // write to register 7, set june
TWIout(DS1307, 08, 09); // write to register 8, set year 2003
endif;
endif;
else // Uhr ist vorhanden und läuft
WriteLn(serout, 'Uhr läuft schon ?.');
TWIout(DS1307, 00); // prepare read register 0 = seconds
TWIinp(DS1307, ZeitBlock.sekunde);
ZeitBlock.sekunde:= ZeitBlock.sekunde and $7F;
TWIinp(DS1307, ZeitBlock.minute);
ZeitBlock.minute:= ZeitBlock.minute and $7F;
TWIinp(DS1307, ZeitBlock.stunde);
ZeitBlock.stunde:= ZeitBlock.stunde and $3F;
TWIinp(DS1307, ZeitBlock.wochentag);
ZeitBlock.wochentag:= ZeitBlock.wochentag and $07;
TWIinp(DS1307, ZeitBlock.tag);
ZeitBlock.tag:= ZeitBlock.tag and $3F;
TWIinp(DS1307, ZeitBlock.monat);
ZeitBlock.monat:= ZeitBlock.monat and $1F;
TWIinp(DS1307, ZeitBlock.jahr);
// Erzeuge die Strings
ZeitBlock.strzeit:= ByteToHex(ZeitBlock.stunde)+':'+ByteToHex(ZeitBlock.minute)+':'+ByteToHex(ZeitBlock.sekunde);
ZeitBlock.strdatum:= ByteToHex(ZeitBlock.tag)+'.'+ByteToHex(ZeitBlock.monat)+'.20'+ByteToHex(ZeitBlock.jahr);
ZeitBlock.strtag:= wDayArr[ZeitBlock.wochentag];
endif;
WriteLn(serout, 'DEBUG: Tag: '+ZeitBlock.strtag+' Datum: '+ ZeitBlock.strdatum+' Zeit: '+ZeitBlock.strzeit );
endif; // UhrZyklus
end;
procedure InitPorts;
begin
// OUT_LED_ERR
DDRH.2 := 1; // Ausgang
PortH.2 := 0; // schalte auf 0
// OUT_LED_RUN
DDRH.3 := 1; // Ausgang
PortH.3 := 0; // schalte auf 0
// OUT_LED_COM
DDRH.4 := 1; // Ausgang
PortH.4 := 0; // schalte auf 0
// OUT_LED_OK
DDRH.5 := 1; // Ausgang
PortH.5 := 0; // schalte auf 0
// IN_RUNSTOP
DDRJ.3 := 0; // Eingang
PortJ.3 := 1; // Pullup EIN
// IN_SOFTRESET
DDRJ.4 := 0; // Eingang
PortJ.4 := 1; // Pullup EIN
// IN_TAST1
DDRD.4 := 0; // Eingang
PortD.4 := 1; // Pullup EIN
//IN_MMCINSERT
DDRB.4 := 0; // Eingang
PortB.4 := 1; // Pullup EIN
end InitPorts;
{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
begin
// Bootvorgang...
InitPorts;
EnableInts;
mDelay(400);
WriteLn(serout, 'DEBUG: Systemboot abgeschlossen....');
mDelay(400); // Warte bis Eingangszustand ok und in Ruhe
// Zustand im RUN ? dann setze System in den Status SysRUN
SysRUN:= IO_Board.RunStop.IBit;
OUT_LED_RUN := not IO_Board.RunStop.IBit; // Schalte RUN LED entsprechend EIN/AUS
// Achtung ab hier LOOP!
loop
ReadInputOnboard; // Lese OnBoard IO's
// RunStop Auswertung
if (IO_Board.RunStop.IBitR or IO_Board.RunStop.IBitF) then // Flanke auswerten und Umschaltung
OUT_LED_RUN := not IO_Board.RunStop.IBit;
SysRUN:= IO_Board.RunStop.IBit;
endif;
// wenn System im RUN Zustand läuft es weiter
if SysRUN then
OKLED; //Status LED
UhrZeit; // RTC Uhrzeit holen
endif; // Ende wenn kein RUN Zustand
endloop; // Zyklus-Ende
end PVS_I2C.
Gruss
Thorsten
ich habe da ein kleines Problem, entweder habe ich hier einen Denkfehler und sehe vor lauter Bäumen den Wald nicht mehr, aber im Moment weiss ich nicht weiter.
Ich habe einen kleinen Dallas 1307 I2C RTC-Chip. der mit TWI_BR100 laufen sollte,
eigentlich hab ich schon mit AVRco den PCA9555 und auch den RTC 8564 Chip am laufen gehabt.
Aber mit den DS1307 beisse ich mir die Zähne aus, ich frage in meinem Programm alle 205.000 Zyklen den DS1307 ab (ich brauche die Zeit ja nicht ms genau), somit spare ich mir Rechenleistung für was wichtigeres.
Dabei ist mir aufgefallen, das aus irgendeinen Grund nur alle 10-15x das I2C Telegramm wirklich an den DS1307 gesendet wird. Das deckt sich auch mit meiner Osci-Anzeige und dem Logic-Analyser.
Die Leitung IDat und ICLK sind mit 10k auf 5v gezogen.
Ich vermute wohl einen Fehler in meiner DEFINE, bis jetzt hatte ich immer nur den SOFT-I2C genutzt, bei diesem Board möchte ich aber den OnBoard I2C nutzen, vieleicht habe ich deswegen einen Denkfehler. Hier mal einen Teil des CODE's, vieleicht hat Jemand von euch einen Tip oder sieht meinen Fehler auf Anhieb:
Code
program PVS_I2C;
{$NOSHADOW}
{ $WG} {global Warnings off}
Device = mega1280, VCC=5;
{ $BOOTRST $0F000} {Reset Jump to $0F000}
Define_Fuses
Override_Fuses;
NoteBook = E;
LockBits0 = [];
FuseBits0 = [];
FuseBits1 = [SPIEN, JTAGEN, OCDEN];
ProgMode = JTAG;
Import SysTick, SerPort, {SwitchPort1,} I2Cport, TickTimer, TWImaster, SysLEDblink, {SPIdriver,} ADCPort {, SPIdriver1};
From System Import LongWord;
Define
ProcClock = 16000000; {Hertz}
SysTick = 10; {msec}
StackSize = $0064, iData;
FrameSize = $0064, iData;
// SPIorder = MSB;
// SPIcpol = 1;
// SPIcpha = 1;
// SPIpresc = 1; // presc = 0..3 -> 4/16/64/128
// SPI_SS = true; // use SS pin as chipselect
// SPImode = 0; // 0, 1, 2, 3
SerPort = 57600, Stop1; {Baud, StopBits|Parity}
RxBuffer = 8, iData;
TxBuffer = 8, iData;
I2Cport = PortD;
I2Cdat = 1;
I2Cclk = 0;
TWIpresc = TWI_BR100;
TickTimer = Timer1;
SysLEDblink = 50;
SysLedPort = @BlinkRam, $00; // byte-var, polarity (*4*)
ADCchans = 8, iData, int2; // = [n], iData; = [m,n], iData;
ADCpresc = 128;
// SPIdriver1 = PortC, 0, 1, 2, 3; // SCK, MOSI, MISO, SS
// SPIorder1 = MSB;
// SPIcpol1 = 1;
// SPIcpha1 = 1;
Implementation
{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
type
TimeBlock = record
ok : boolean;
sekunde : byte;
minute : byte;
stunde : byte;
tag : byte;
wochentag: byte;
monat : byte;
jahr : byte;
strzeit : string[8];
strdatum : string[10];
strtag : string[3];
end;
// IO Handler
//
IOHandler = record
Input : array[0..2] of InputData; // Input
Output : array[0..2] of OutputData; // Output
InLinie : array[1..8] of InputLinie; // Alarmlinie
LinieX : integer; //AktuellerAbfragezähler
end; // Ende Record
// Onboard IO's
//
InputDataBoard = record
RunStop : InputPin;
SoftReset : InputPin;
ServTast : InputPin;
MMCInsert : InputPin;
end; // Ende Record
{--------------------------------------------------------------}
{ Const Declarations }
const
// Wochentage
wDayArr : array[0..6] of string[2] = ('SO', 'MO', 'DI', 'MI', 'DO', 'FR', 'SA');
{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
// Output
OUT_LED_ERR [@PortH, 2 ] : bit;
OUT_LED_RUN [@PortH, 3 ] : bit;
OUT_LED_COM [@PortH, 4 ] : bit;
OUT_LED_OK [@PortH, 5 ] : bit;
// Input
IN_RUNSTOP [@PINJ, 3 ] : bit;
IN_SOFTRESET [@PINJ, 4 ] : bit;
IN_SERVTAST [@PIND, 4 ] : bit;
IN_MMCINSERT [@PINB, 4 ] : bit;
// Standard VAR
sel : byte;
y : integer;
x : integer;
wert : integer;
check : boolean;
Elapsed : boolean;
w : byte;
idx, i : byte;
BLINK : boolean;
ZeitBlock : TimeBlock; // Datum Zeitblock
UhrZyklus : longint;
LinieZyklus : integer; //Abfragezyklus Alarmline
OKZyklus : integer;
COMZyklus : integer;
strBuffer : string[15];
intBuffer : integer;
byteBuffer : Byte;
IO_Reg : IOHandler; // IO Registerhandler
IO_Board : InputDataBoard;
// Sysstatusvariablen
SysRUN : boolean;
{--------------------------------------------------------------}
{ functions }
procedure UhrZeit;
var
buffer : byte;
begin
UhrZyklus:=UhrZyklus+1;
//nur alle 205000mal abfragen
if UhrZyklus >= 205000 then
UhrZyklus:=0;
// Prüfe ob RTC schon überprüft wurde
if not(ZeitBlock.ok) then
ZeitBlock.ok:= TWIstat(DS1307);
if ZeitBlock.ok then
WriteLn(serout, 'Uhr vorhanden.');
TWIout(DS1307, 00); // prepare read register 0
TWIinp(DS1307, ZeitBlock.sekunde);
buffer:= ZeitBlock.sekunde;
if not( buffer.7 ) then // low voltage bit set??
TWIout(DS1307, 00, 00);
TWIout(DS1307, 00, 00); // write to register 0, set run mode
TWIout(DS1307, 01, 00); // write to register 1, no ints
TWIout(DS1307, 02, 00); // write to register 2, reset seconds
TWIout(DS1307, 03, $12); // write to register 3, reset minutes
TWIout(DS1307, 04, $19); // write to register 4, set 18hrs
TWIout(DS1307, 05, $18); // write to register 5, set day 19
TWIout(DS1307, 06, 04); // write to register 6, set thursday
TWIout(DS1307, 07, $06); // write to register 7, set june
TWIout(DS1307, 08, 09); // write to register 8, set year 2003
endif;
endif;
else // Uhr ist vorhanden und läuft
WriteLn(serout, 'Uhr läuft schon ?.');
TWIout(DS1307, 00); // prepare read register 0 = seconds
TWIinp(DS1307, ZeitBlock.sekunde);
ZeitBlock.sekunde:= ZeitBlock.sekunde and $7F;
TWIinp(DS1307, ZeitBlock.minute);
ZeitBlock.minute:= ZeitBlock.minute and $7F;
TWIinp(DS1307, ZeitBlock.stunde);
ZeitBlock.stunde:= ZeitBlock.stunde and $3F;
TWIinp(DS1307, ZeitBlock.wochentag);
ZeitBlock.wochentag:= ZeitBlock.wochentag and $07;
TWIinp(DS1307, ZeitBlock.tag);
ZeitBlock.tag:= ZeitBlock.tag and $3F;
TWIinp(DS1307, ZeitBlock.monat);
ZeitBlock.monat:= ZeitBlock.monat and $1F;
TWIinp(DS1307, ZeitBlock.jahr);
// Erzeuge die Strings
ZeitBlock.strzeit:= ByteToHex(ZeitBlock.stunde)+':'+ByteToHex(ZeitBlock.minute)+':'+ByteToHex(ZeitBlock.sekunde);
ZeitBlock.strdatum:= ByteToHex(ZeitBlock.tag)+'.'+ByteToHex(ZeitBlock.monat)+'.20'+ByteToHex(ZeitBlock.jahr);
ZeitBlock.strtag:= wDayArr[ZeitBlock.wochentag];
endif;
WriteLn(serout, 'DEBUG: Tag: '+ZeitBlock.strtag+' Datum: '+ ZeitBlock.strdatum+' Zeit: '+ZeitBlock.strzeit );
endif; // UhrZyklus
end;
procedure InitPorts;
begin
// OUT_LED_ERR
DDRH.2 := 1; // Ausgang
PortH.2 := 0; // schalte auf 0
// OUT_LED_RUN
DDRH.3 := 1; // Ausgang
PortH.3 := 0; // schalte auf 0
// OUT_LED_COM
DDRH.4 := 1; // Ausgang
PortH.4 := 0; // schalte auf 0
// OUT_LED_OK
DDRH.5 := 1; // Ausgang
PortH.5 := 0; // schalte auf 0
// IN_RUNSTOP
DDRJ.3 := 0; // Eingang
PortJ.3 := 1; // Pullup EIN
// IN_SOFTRESET
DDRJ.4 := 0; // Eingang
PortJ.4 := 1; // Pullup EIN
// IN_TAST1
DDRD.4 := 0; // Eingang
PortD.4 := 1; // Pullup EIN
//IN_MMCINSERT
DDRB.4 := 0; // Eingang
PortB.4 := 1; // Pullup EIN
end InitPorts;
{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
begin
// Bootvorgang...
InitPorts;
EnableInts;
mDelay(400);
WriteLn(serout, 'DEBUG: Systemboot abgeschlossen....');
mDelay(400); // Warte bis Eingangszustand ok und in Ruhe
// Zustand im RUN ? dann setze System in den Status SysRUN
SysRUN:= IO_Board.RunStop.IBit;
OUT_LED_RUN := not IO_Board.RunStop.IBit; // Schalte RUN LED entsprechend EIN/AUS
// Achtung ab hier LOOP!
loop
ReadInputOnboard; // Lese OnBoard IO's
// RunStop Auswertung
if (IO_Board.RunStop.IBitR or IO_Board.RunStop.IBitF) then // Flanke auswerten und Umschaltung
OUT_LED_RUN := not IO_Board.RunStop.IBit;
SysRUN:= IO_Board.RunStop.IBit;
endif;
// wenn System im RUN Zustand läuft es weiter
if SysRUN then
OKLED; //Status LED
UhrZeit; // RTC Uhrzeit holen
endif; // Ende wenn kein RUN Zustand
endloop; // Zyklus-Ende
end PVS_I2C.
Gruss
Thorsten