Guten Tag, ich habe hier ein Buch in dem es bei einem Beispiel Code um den IC2 bus geht. Und dort wurde die Taktfrequenz nach folgender Rechnung festgelegt I²C CLK Frequency = 100kHz, CLK = 8000000/(16 + 2*(0x50)*1) Jetzt ist es aber so das ich 16Mhz nutzen möchte, Und die 0x50 werden ja in diesem Register gesetzt.: TWBR = 0x50; // Set the TWI clock-frequency in bit rate register jetzt wollte ich die obige Rechnung erst einmal eben mit 8000000 nachrechnen um dann später das mit 16000000 zu machen. ich habe festgestellt das ich es nicht schaffe das mit den 0x50 zu berechnen, könnte mir das bitte jemand erklären, wie ich das richtig rechnen kann ?
Michael H. schrieb: > Jetzt ist es aber so das ich 16Mhz nutzen möchte, Das ist abhängig vom Controller, den du nicht genannt hast. Und die Berechnung der Taktrate steht im Datenblatt des verwendeten Controllers. Du brauchst nur dort nachsehen.
> ich habe festgestellt das ich es nicht schaffe das mit den > 0x50 zu berechnen Ich verstehe deine Frage nicht. Was hindert dich daran, in der Formel die 8MHz durch 16MHz zu ersetzen?
Entschuldigung das habe ich vergessen das ist ein Atmega88PA ich habe auch ins Datenblatt geschaut. Da steht das das TWBR Praktisch der Teiler ist. Heisst das dann, ich kann mit den 8bit einen Teiler von 1-256 einstellen ? und mit dem 0x50 wurde hier ein Teiler von 144 eingestellt oder wie ?
Hallo, im DB http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf steht: 22.5 Overview of the TWI Module unter 22.5.2 Bit Rate Generator Unit This unit controls the period of SCL when operating in a Master mode. The SCL period is controlled by settings in the TWI Bit Rate Register (TWBR) and the Prescaler bits in the TWI Status Register (TWSR). Slave operation does not depend on Bit Rate or Prescaler settings, but the CPU clock frequency in the Slave must be at least 16 times higher than the SCL frequency. Note that slaves may prolong the SCL low period, thereby reducing the average TWI bus clock period. [Formel] SCL frequency = F_CPU / (16 +2(TWBR) *PrescalerValue) [/Formel] TWBR = Value of the TWI Bit Rate Register PrescalerValue = Value of the prescaler, see Table 22-7 on page 241. Schaut man dann nach unter "22.9.1 TWBR – TWI Bit Rate Register", findet man: *Bits 7...0* !! TWI Bit Rate RegisterTWBR selects the division factor for the bit rate generator. The bit rate generator is a frequency divider which generates the SCL clock frequency in the Master modes.
Wenn der Prescaler 1 ist, dann haben wir SCL frequency = F_CPU / (16 +2(TWBR)) Umgestellt ergibt das: ((F_CPU / SCL frequency) - 16) / 2 = TWBR Wir setzen ein: ((8000000 Hz/ 100000 Hz) - 16) / 2 = 32 Du musst also TWBR=32 einstellen, um auf 100kHz zu kommen. Zur Kontrolle: 8000000 Hz / (16 +2(32)) = 100000 Hz Was käme denn bei 0x50 (=80 dezimal) heraus?: 8000000 Hz / (16 +2(80)) = 45455 Hz 16000000 Hz / (16 +2(80)) = 90909 Hz Bringt dich das weiter?
Michael H. schrieb: > I²C CLK Frequency = 100kHz, CLK = 8000000/(16 + 2*(0x50)*1) Wenn ich 8000000/(16 + 2*(0x50)*1) rechne komme ich aber auf 8000000 / (16 + 2 * 80) = 45455 Hz Stefanus war schneller :-)
:
Bearbeitet durch User
Falls du auf 400kHz hoch gehen willst, beachte dabei dass TWBR mindestesn den Wert 10 haben muss. Die 400kHz wirst du mit einem 8MHz Quarz also nicht erreichen können.
Danke hilft mir schon etwas weiter, jetzt zeige ich euch hier mal den Code, den ich allerdings nicht für den LM75 verwenden will sondern, wenn ich es geschafft habe den Takt richtig zu bestimmen, will ich eigentlich nur die Funktionen nutzen um dann auf einen MCP4735 einen Wert ins Register schreiben, So steht der Code in meinem Buch. Und aus der while schleife habe ich halt schon einiges entfernt aber das tut ja hier nichts zur sache, ich will ja nur den richtigen Takt für 16 Mhz einstellen
1 | * LM75_Tempsensor.c |
2 | * Temperaturmessung (5x pro Sekunde) und Ausgabe der Temperatur als Binärwert am PORTD |
3 | * Eine negative Temperatur wird zusätzlich durch eine LED an PB0 angezeigt |
4 | * CPU: ATmega88 |
5 | * FCPU: 8MHz |
6 | * I²C CLK Frequency = 100kHz, CLK = 8000000/(16 + 2*(0x50)*1) |
7 | */
|
8 | #include <avr/io.h> |
9 | #include <util/delay.h> |
10 | |
11 | /*** Statusregister codes and other defines ***/
|
12 | #define START 0x08 // A START condition has been transmitted
|
13 | #define R_START 0x10 // A REPEATED START condition has been transmitted
|
14 | #define SLA_W 0xC0 // Slave Address & Write 1100 0000
|
15 | #define SLA_R 0xC1 // Slave Address & Read 1100 0001
|
16 | #define MT_SLA_ACK 0x18 // Master Transmit SLA+W has been transmitted & ACK has been received
|
17 | #define MR_SLA_ACK 0x40 // Master Receive SLA + R has been transmitted & ACK has been received
|
18 | #define MT_DATA_ACK 0x28 // Master Transmit Data byte has been transmitted & ACK has been received
|
19 | #define MR_DATA_NACK 0x58 // Master Receive Data byte has been transmitted & NACK has been returned
|
20 | #define BIT_RATE 0x50 // Set value for the bit rate register TWBR
|
21 | #define POINTER_ADDRESS 0x00 // LM75 pointer address for temperature register/ Registerwert
|
22 | void ERROR(void); // Prototyping of function "ERROR" |
23 | |
24 | /*** Function to send a START Condition ***/
|
25 | void TWI_START(void) |
26 | {
|
27 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); |
28 | // Wait for TWINT Flag set. This indicates that the START condition has been transmitted
|
29 | while (!(TWCR & (1<<TWINT))); |
30 | // Check value of TWI statusregister. Mask prescaler bits. If status different from START go to ERROR if ((TWSR & 0xF8) != START)
|
31 | ERROR(); |
32 | }
|
33 | |
34 | /*** Function to send the Slave Address with ACK in Master Transmit Mode ***/
|
35 | void TWI_MT_SLA_ACK(void) |
36 | {
|
37 | // Load SLA_W into TWDR Register
|
38 | TWDR = SLA_W; |
39 | // Clear TWINT bit in TWCR to start transmission of address
|
40 | TWCR = (1<<TWINT) | (1<<TWEN); |
41 | // Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received.
|
42 | while (!(TWCR & (1<<TWINT))); |
43 | // Check value of TWI status register. Mask prescaler bits. If status different from MT_SLA_ACK go to ERROR
|
44 | if ((TWSR & 0xF8) != MT_SLA_ACK) |
45 | ERROR(); |
46 | }
|
47 | |
48 | /*** Function to send 8Bit of data with ACK in Master Transmit Mode **/
|
49 | void TWI_MT_DATA_ACK(void) |
50 | {
|
51 | // Load DATA into TWDR register
|
52 | TWDR = POINTER_ADDRESS; |
53 | // Clear TWINT bit in TWCR to start transmission of data
|
54 | TWCR = (1<<TWINT) | (1<<TWEN); |
55 | // Wait for TWINT flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received.
|
56 | while (!(TWCR & (1<<TWINT))); |
57 | // Check value of TWI status register. Mask prescaler bits. If status different from MT_DATA_ACK go to ERROR
|
58 | if ((TWSR & 0xF8) != MT_DATA_ACK) |
59 | ERROR(); |
60 | }
|
61 | |
62 | /*** Function to send a REPEATED START condition **/
|
63 | void TWI_R_START(void) |
64 | {
|
65 | // Send a START condition
|
66 | TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); |
67 | // Wait for TWINT Flag set. This indicates that the START condition has been transmitted
|
68 | while (!(TWCR & (1<<TWINT))); |
69 | // Check value of TWI statusregister. Mask prescaler bits. If status different from R_START go to ER-ROR
|
70 | if ((TWSR & 0xF8) != R_START) |
71 | ERROR(); |
72 | }
|
73 | |
74 | /*** Function to send the Slave Address in Master Receive Mode with Acknowledge **/
|
75 | void TWI_MR_SLA_ACK(void) |
76 | {
|
77 | // Load SLA_R into TWDR Register
|
78 | TWDR = SLA_R; |
79 | // Clear TWINT bit in TWCR to start transmission of address
|
80 | TWCR = (1<<TWINT) | (1<<TWEN); |
81 | // Wait for TWINT Flag set. This indicates that the SLA+W has been transmitted, and ACK/NACK has been received.
|
82 | while (!(TWCR & (1<<TWINT))); |
83 | // Check value of TWI status register. Mask prescaler bits. If status different from MR_SLA_ACK go to ERROR
|
84 | if ((TWSR & 0xF8) != MR_SLA_ACK) |
85 | ERROR(); |
86 | }
|
87 | |
88 | /*** Function to read one Databyte in Master Receive Mode with NACK ***/
|
89 | uint8_t TWI_READ_DATABYTE_NACK(void) |
90 | {
|
91 | // Read one data byte
|
92 | TWCR = (1<<TWINT)| (1<<TWEN); |
93 | // Wait for TWINT flag set. This indicates that the DATA has been transmitted, and ACK/NACK has been received.
|
94 | while (!(TWCR & (1<<TWINT))); |
95 | // Check value of TWI status register. Mask prescaler bits. If status different from MR_DATA_NACK go to ERROR
|
96 | if ((TWSR & 0xF8) != MR_DATA_NACK) |
97 | ERROR(); |
98 | return TWDR; // Return the value of data register |
99 | }
|
100 | |
101 | /*** function to send a STOP condition ***/
|
102 | void TWI_STOP(void) |
103 | {
|
104 | TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // Transmit STOP condition |
105 | }
|
106 | |
107 | /*** function to show a bus error ***/
|
108 | void ERROR(void) |
109 | {
|
110 | PORTB |= (1<<PB1); // ERROR LED ON |
111 | }
|
112 | |
113 | uint8_t LSByte, MSByte; |
114 | uint16_t data_16bit, temperature, high_byte, low_byte; |
115 | |
116 | int main(void) |
117 | {
|
118 | DDRD = 0xFF; // PORTD = output |
119 | DDRC = 0x3F; // PC0 ... PC5 = output |
120 | DDRB = 0x03; // PB0 and PB1 = output |
121 | TWBR = BIT_RATE; // Set the TWI clock-frequency in bit rate register |
122 | while(1) |
123 | {
|
124 | TWI_START(); // Send START condition |
125 | TWI_MT_SLA_ACK(); // Master Transmit Slave Address with ACK |
126 | TWI_MT_DATA_ACK(); // Master Transmit Data with ACK |
127 | TWI_STOP(); // Send STOP condition |
128 | |
129 | |
130 | _delay_ms(200); // wait 200ms for new readout |
131 | }
|
132 | }
|
Da fehlt ein Zeilenumbruch vor dem "if": > // Check value of TWI statusregister. Mask prescaler bits. If status > different from START go to ERROR if ((TWSR & 0xF8) != START) > ERROR();
Hi >Falls du auf 400kHz hoch gehen willst, beachte dabei dass TWBR >mindestesn den Wert 10 haben muss. Diese Einschränkung kenne ich von alter AT90S... . Bei aktuellen AVRs finde ich diese Einschränkung nicht mehr. MfG Spess
Michael H. schrieb: > das ist ein Atmega88PA spess53 schrieb: > Diese Einschränkung kenne ich von alter AT90S... . Bei aktuellen AVRs > finde ich diese Einschränkung nicht mehr. Datenblatt Kapitel 19.5.2: "Note: ...TWBR should be 10 or higher if the TWI operates in master mode. If TWBR is lower than 10, the master may produce an incorrect output on SDA and SCL for the reminder of the byte. "
Hi
>Datenblatt Kapitel 19.5.2:
Welches Datenblatt? Bei dem Kapitel stoße ich bei den ATMega88 immer auf
SPI.
MfG Spess
Beitrag #5751970 wurde von einem Moderator gelöscht.
Stefanus F. schrieb: > Da fehlt ein Zeilenumbruch vor dem "if": > >> // Check value of TWI statusregister. Mask prescaler bits. If status >> different from START go to ERROR if ((TWSR & 0xF8) != START) >> ERROR(); Ja, das ist wohl dem Geschuldet das ich es hier rein kopiert habe. mir geht es eigentlich hautsächlich Darum das ich diesen Code für meine 16Mhz konfiguriere, und da blicke ich nicht durch, da ich für die Berechnung den Prescaler CLKPR den ich ja setzen soll niergends in dem Code finden kann. ich weiß aber das dieser so mit 8Mhz ohne Probleme funktioniert.
spess53 schrieb: >>Datenblatt Kapitel 19.5.2: > Welches Datenblatt? http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9365-Automotive-Microcontrollers-ATmega88-ATmega168_Datasheet.pdf
Moin, die section zum CLKPR findest du unter "System Clock and Clock Options" im Datasheet gruß (:
Wenn du den Parameter nicht im Code findest musst du ihn wohl einbauen?!
"The CKDIV8 fuse(!) determines the initial value of the CLKPS bits. If CKDIV8 is unprogrammed, the CLKPS bits will be reset to “0000”. If CKDIV8 is programmed, CLKPS bits are reset to “0011”, giving a division factor of 8 at start up"
ja, das ist klar, aber ich verstehe es ja erst einmal nicht, warum es genau so wie oben mit 8Mhz funktioniert und, wenn ich 16 Mhz benützen will muss ich ja etwas anderes machen, ich kann das auch noch öfters lesen ich check es nicht. ich könnte ja auch einfach den internen oszilator auf 8Mhz einstellen, aber dann bin ich immer noch nicht schlauer, wie der Mensch zu diesem Code bzw. aus diesem Coder diese Berechnung aufgestellt hat. I²C CLK Frequency = 100kHz, CLK = 8000000/(16 + 2*(0x50)*1) den irgendwo muss ja der prescaler *1 herkommen. ja ich weiß im clkpr, aber das muss ja dann schon irgendwo mit 1 gesetzt sein. das sehe ich nicht. Und F_CPU8000000UL wird ja auch nicht definiert und stimmt aber dann troztdem die Zeiten mit 8Mhz alles überein
Hi
>http://ww1.microchip.com/downloads/..
Gibt es die ATMeg88 Automobile überhaupt noch?
Der TO hat einen ATMega88PA. Und dort steht der Passus definitiv nicht
mehr drin.
MfG Spess
Stefanus F. schrieb: > spess53 schrieb: >>>Datenblatt Kapitel 19.5.2: >> Welches Datenblatt? > > http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9365-Automotive-Microcontrollers-ATmega88-ATmega168_Datasheet.pdf Das ist definitiv neu. In älteren Datenblättern findet sich das nicht. Die erste Frage ist: alter Bug (spät entdeckt) oder neues Silizium mit einem neuen Bug? Die zweite Frage: was muss man sich unter "the master may produce an incorrect output on SDA and SCL for the reminder of the byte" vorstellen? Was für ein Byte? Welchen Remainder eines Bytes könnte es geben? Was genau meint "incorrect"? In den Errata steht dazu absolut garnix. Das ist doch Bullshit. Ich würde mal darauf tippen, dass hier ein Inder was an der falschen Stelle in die Doku eingepflegt hat, vor allem deshalb, weil mir in der Realität auch keinerlei diesbezügliche Probleme begegnet sind...
c-hater schrieb: > Das ist definitiv neu. Naja, von 2016. Offensichtlich habe ich das falsche Datenblatt erwischt, das "P" fehlt.
Hi >Ich würde mal darauf tippen, dass hier ein Inder was an der falschen >Stelle in die Doku eingepflegt hat, vor allem deshalb, weil mir in der >Realität auch keinerlei diesbezügliche Probleme begegnet sind... Sehe ich auch so. Lt.meinen ATMEL-CDs ist beim ATMega88 dieser Absatz irgendwann zwischen Oktober 2005 und April 2006 aus dem Datenblatt verschwunden. Das Datenblatt vom ATMega88 Automotive von 2016 ist die Revision A, die seit 02/2009 unverändert ist. Wahrscheinlich war das schon damals falsch. MfG Spess
Hallo ! Der Quelltext kommt mir bekannt vor, als wenn er auch dem dicken "AVR Programmierung in C" Buch ist. Da ich da auch so einiges aus dem Buch durchprobiert habe, aber auch keine 8MHz Tacktfrequenz habe/hatte, habe ich mich an diesem Codebeispiel orientiert und etwas umgeschrieben dann:
1 | definieren im Quelltextkopf : |
2 | ......
|
3 | #define F_CPU 16000000UL // 16MHz Q-frequenz
|
4 | #define SCL_CLOCK 100000UL // 100kHz TWI Clock
|
5 | ......
|
6 | *
|
7 | *
|
8 | *
|
9 | void i2c_init() |
10 | {
|
11 | /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
|
12 | |
13 | TWSR = 0; /* no prescaler */ |
14 | TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */ |
15 | |
16 | }/* i2c_init */ |
Das Ausrechnen ob TWBR > 10 ist überlass ich mal dem Anwender... ;) Ich hoffe ich konnt ein wenig helfen.. Gerhard Nachtrag : den Prescaler stellt man an den beiden Bit TWPS1 TWPS0 im TWSTATUS-Register "TWSR" ein ..Im Datenblatt nachlesen...
:
Bearbeitet durch User
Gerhard H. schrieb: > Ich hoffe ich konnt ein wenig helfen. Nö .... damit bringst du nur diejenigen durcheinander die den Prescaler verwenden wollen oder müssen. Aber Hauptsache du hast eine Ladung ASCII hier abgeladen, das macht frei! Gerhard H. schrieb: > Nachtrag : den Prescaler stellt man an den beiden Bit TWPS1 TWPS0 im > TWSTATUS-Register "TWSR" ein ..Im Datenblatt nachlesen... Gut dass du das geschrieben hast denn bisher hat das keiner gewusst, und sonst müsste man das mühselig im Datenblatt nachlesen ... aber vielleicht stehts auch gar nicht drin.
Nun HababaBene, dann hast Du ja wenigstens des Rätsels Lösung hier völlig dar gelegt. Gruss Gerhard
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.