unit avr_rtc;
{$mode objfpc}{$H+}
interface
uses
avr_hwi2c_master;
const
RTC_ADDR = $68;
type
Trtc_Time = record
s: Byte;
m: Byte;
h: Byte;
mday: Byte; //Monatstag
wday: Byte; //Wochentag
mon: Byte; //Monat
year: Int16; //Jahr (0..99)
end;
procedure rtc_init;
function rtc_recv(var ATime: Trtc_Time): Boolean;
function rtc_send(ATime: Trtc_Time): Boolean;
implementation
function dec2bcd(ADec: Byte): Byte;
begin
Result := ((ADec div 10 * 16) + (ADec mod 10));
end;
function bcd2dec(ABcd: Byte): Byte;
begin
Result := ((ABcd div 16 * 10) + (ABcd mod 16));
end;
procedure rtc_init;
begin
I2CInit;
end;
function rtc_recv(var ATime: Trtc_Time): Boolean;
var
I: Byte;
Recv: Array [0..6] of Byte;
begin
Result := I2CMasterStart((RTC_ADDR shl 1) or I2C_Write);
If Result = True then
begin
I2CWrite($0);
I2CStop;
Result := I2CMasterStart((RTC_ADDR shl 1) or I2C_Read);
If Result = True then
begin
for I := 0 to 5 do
Recv[I] := I2CRead;
Recv[6] := I2CReadLast;
I2CStop;
ATime.s := Bcd2dec(Recv[0]);
ATime.m := Bcd2dec(Recv[1]);
ATime.h := Bcd2dec(Recv[2]);
ATime.wday := Bcd2dec(Recv[3]);
ATime.mday := Bcd2dec(Recv[4]);
ATime.mon := Bcd2dec(Recv[5] and $1F);
I := (Recv[5] and $80) shr 7;
If I = 1 then
ATime.year := 2000 + bcd2dec(Recv[6]) Else
ATime.year := 1900 + bcd2dec(Recv[6]);
end;
end;
end;
function rtc_send(ATime: Trtc_Time): Boolean;
var
I: Byte;
Send: Array [0..6] of Byte;
begin
Result := I2CMasterStart((RTC_ADDR shl 1) or I2C_Write);
If Result = True then
begin
I2CWrite($0);
Send[0] := Dec2Bcd(ATime.s);
Send[1] := Dec2Bcd(ATime.m);
Send[2] := Dec2Bcd(ATime.h);
Send[3] := Dec2Bcd(ATime.wday);
Send[4] := Dec2Bcd(ATime.mday);
If ATime.year >= 2000 then
begin
I := $80;
Send[6] := ATime.year - 2000;
end Else
begin
I := $0;
Send[6] := ATime.year - 1900;
end;
Send[5] := Dec2Bcd(ATime.mday)+I;
for I := 0 to 6 do
I2CWrite(Send[I]);
I2CStop;
end;
end;
end.
unit avr_hwi2c_master;
{$mode objfpc}{$H+}
interface
uses
avr_const;
procedure I2CInit;
procedure I2CUpdateStatus;
function I2CMasterStart(Addr: Byte): Boolean;
procedure I2CStop;
procedure I2CWrite(u8data: byte);
function I2CRead: byte;
function I2CReadLast: byte;
const
I2C_Write = 0;
I2C_Read = 1;
var
//Status des I2C Bus:
TW_STATUS_MASK: Byte;
TW_STATUS: Byte;
implementation
procedure I2CInit;
const
TWBR_val = byte((CPU_Clock div I2C_Speed) - 16) div 2;
begin
TWSR := 0;
TWBR := byte(TWBR_val);
end;
procedure I2CUpdateStatus;
var
TWSR2: bitpacked array [0..7] of boolean absolute TWSR;
TWSRM: bitpacked array [0..7] of boolean absolute TW_STATUS_MASK;
I: Byte;
begin
TW_STATUS_MASK := 0;
for I := 7 downto 3 do
TWSRM[I] := TWSR2[I];
TW_STATUS := TWSR and TW_STATUS_MASK;
end;
function I2CMasterStart(addr: byte): Boolean;
begin
Result := True;
// Senden/Empfangen einleiten
TWCR := 0;
TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
// Adresse des Endgerätes senden
TWDR := addr;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
end;
{Versuch den Status vom i²c Bus mit zu überprüfen, Unterschied = 0...
function I2CMasterStart(Addr: byte): Boolean;
const
TW_START = $08;
TW_REP_START = $10;
TW_MT_SLA_ACK = $18;
TW_MR_SLA_ACK = $40;
var
TWST: Byte;
begin
Result := False;
// Senden/Empfangen einleiten
TWCR := 0;
TWCR := (1 shl TWINT) or (1 shl TWSTA) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
I2CUpdateStatus;
TWST := TW_STATUS and $F8;
if (TWST = TW_START) or (TWST = TW_REP_START) then
begin
// Adresse des Endgerätes senden
TWDR := addr;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
I2CUpdateStatus;
TWST := TW_STATUS and $F8;
if (TWST <> TW_MT_SLA_ACK) and (TWST <> TW_MR_SLA_ACK) then
Result := True;
end;
end; }
procedure I2CStop;
begin
TWCR := (1 shl TWINT) or (1 shl TWSTO) or (1 shl TWEN);
end;
procedure I2CWrite(u8data: byte);
begin
TWDR := u8data;
TWCR := (1 shl TWINT) or (1 shl TWEN);
while ((TWCR and (1 shl TWINT)) = 0) do begin
end;
end;
// Lesen bis zum vorletzten Zeichen.
function I2CRead: byte;
begin
TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
while (TWCR and (1 shl TWINT)) = 0 do begin
end;
Result := TWDR;
end;
// Letztes Zeichen lesen.
function I2CReadLast: byte;
begin
TWCR := (1 shl TWINT) or (1 shl TWEN);
while (TWCR and (1 shl TWINT)) = 0 do begin
end;
Result := TWDR;
end;
end.
unit avr_const;
{$mode objfpc}{$H+}
interface
const
{
CPU_Clock: Bei Start des Programms einzustellen,
wenn nicht 16MHZ
(16MHZ nur bei Arduino oder mit Externem Kristall).
Flashing Script beachten!
}
//CPU_Clock = 1000000; // 1MHZ Fuses auf 1/8 gesetzt
CPU_Clock = 8000000; // 8MHZ Fuses auf int. Osc. ohne 1/8 gesetzt
//CPU_Clock = 16000000; //16MHZ Fuses auf ext. Osc. (Kristall) gesetzt (z.b. im Arduino Uno)
{
Uart / Serielle Verbindung / Nachrichtenanzeige:
}
uart_Baud = 9600; // Baudrate
uart_Div = CPU_Clock div (16 * uart_Baud) - 1;
i2c_Speed = 400000;
implementation
end.
while (TWCR and (1 shl TWINT)) = 0 do begin
end;
Das TWIRead müsste ich mal im Tutorial anpassen.
function TWIReadACK_Error: byte;
var
err:byte;
begin
err := 0;
TWCR := (1 shl TWINT) or (1 shl TWEN) or (1 shl TWEA);
while ((TWCR and (1 shl TWINT)) = 0) and (err < 255) do begin
Inc(err);
end;
if err = 255 then begin
UARTSendString('I²C-Timeout');
Result := 0;
end else begin
Result := TWDR;
end;
end;
Timm Thaler hat geschrieben:Ich hab mal noch ein paar AVR Tutorials eingeworfen:
http://wiki.freepascal.org/AVR_Embedded_-_Delays
http://wiki.freepascal.org/AVR_Embedded_-_Software_I2C_/_TWI
http://wiki.freepascal.org/AVR_Embedded_-_SPI
Mathias hat geschrieben:Dies kann gar nicht funktionieren, da du DDRx und PORTx verwechselt hast.
Mathias hat geschrieben:Was mich verwundert, das man mit dem Konfiguration-Register Daten ausgeben kann.
Mathias hat geschrieben:Kurz gesagt, High, wird mit den Pullup Widerständen erzeugt ?
Mitglieder in diesem Forum: Google [Bot] und 2 Gäste