Forum: Mikrocontroller und Digitale Elektronik I2C-, USART-, EEPROM-Test für ein Feedback


von Marie L. (lendl)


Lesenswert?

Hallo Kolleg:innen,

ich habe mit ein wenig Halbwissen, einigen Tutorials, Google-Suche und 
meiner Bascom-Programmier-Erfahrung schon mal ein paar Grundbausteine 
für mein nächstes (und erstes) C-Projekt zusammengebastelt.
Das Projekt soll Sensordaten via I2C einlesen, diese Daten manipulieren, 
über serielle Verbindungen zum PC und einem Nextion-Display ausgeben, 
Befehle und Werte über diese seriellen Verbindungen empfangen und auch 
einige Parameter im EEPROM abspeichern, usw...

Mit Bascom habe ähnliche Projekte schon realisiert, aber C ist eine neue 
Welt für mich. Zugegeben - da ist noch viel Unverständnis dabei, aber 
meine Neugier war einfach zu groß und mein C-Kurs ist noch lange nicht 
soweit und man lernt doch eh am besten bei der Arbeit am Projekt...

Langer Rede kurzer Sinn, das Wetter ist schlecht und vielleicht hat ja 
jemand Lust sich diesen ersten Code mal anzuschauen und mir ein Feedback 
zu geben, was gut ist und was ich anders/besser machen könnte.

Tausend Dank vorab!
1
/*
2
 * Test für I2C, USART, EEPROM
3
 */ 
4
5
#define F_CPU 2E6
6
#include <avr/io.h>
7
#include <util/delay.h>
8
#include <stdio.h>
9
#include <avr/eeprom.h>
10
#include <avr/interrupt.h>
11
12
/*wird bei Code::Blocks benötigt, bei Geany nicht
13
 * erzeugt dort einen [-Wimplicit-function-declaration] Fehler
14
void init_twi(void);
15
void init_serial_1(void);
16
void init_serial_2(void);
17
void sendChar_1(char c);
18
void sendChar_2(char c);
19
void sendString_1(char *text);
20
void sendString_2(char *text);
21
*/
22
23
/* Byte */
24
uint8_t eeFooByte EEMEM = 13;
25
/* Wort */
26
uint16_t eeFooWord EEMEM = 12345;
27
/* float */
28
float eeFooFloat EEMEM;
29
30
31
int main(void)
32
{
33
  // Initialisierungen
34
  init_serial_1();
35
  init_serial_2();
36
  init_twi();
37
  
38
  // Interrupt für Data-In
39
  PMIC.CTRL = PMIC_LOLVLEN_bm;
40
  sei();
41
  volatile char data_in;
42
43
  // Testdaten ins EEPROM schreiben
44
  eeprom_write_byte (&eeFooByte, 123);
45
  eeprom_write_float (&eeFooFloat, 1.23456);
46
  
47
    
48
    while (1) 
49
    {      
50
    _delay_ms(1000);
51
    
52
    // Variablendeklaration für die I2C Kommunikation
53
    uint8_t DataLow;
54
    uint8_t DataHigh;
55
    uint16_t DataResult;
56
    char str[32];
57
    
58
    /* I2C-Schreiben (Adresse 1111000) wird noch nicht benötigt,
59
     * Funktion muss noch beim DAC geprüft werden
60
    TWIE.MASTER.ADDR = 0x78 << 0x01;
61
    */
62
    
63
    //  I2C-Lesen (Adresse 1111000)    
64
    TWIE.MASTER.ADDR = (0x78 << 0x01) | 0x01; 
65
    
66
    // Alle Datenbytes bis auf das letzte empfangen
67
    while(!(TWIE.MASTER.STATUS & TWI_MASTER_RIF_bm));
68
    DataLow = TWIE.MASTER.DATA;
69
    TWIE.MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc;
70
        
71
    // Empfangen des letzten Datenbytes
72
    while(!(TWIE.MASTER.STATUS & TWI_MASTER_RIF_bm));
73
    DataHigh = TWIE.MASTER.DATA;
74
    
75
    // Senden der Stop-Kondition
76
    TWIE.MASTER.CTRLC = TWI_MASTER_ACKACT_bm | TWI_MASTER_CMD_STOP_gc;    
77
    
78
    // Zusammenbauen der I2C Daten zum Messwert und Ausgabe am Terminal
79
    DataResult = DataLow * 256 + DataHigh;
80
    sprintf(str, "____Messwert: %d", DataResult);
81
    sendString_1(str);  
82
83
    // Ausgabe des Messwerts am Nextion Display
84
    sendString_2("t1.txt=\"");
85
    sprintf(str, "%d", DataResult);  
86
    sendString_2(str);
87
    sendString_2("\"");
88
    sendChar_2(0xFF);  
89
    sendChar_2(0xFF);
90
    sendChar_2(0xFF);
91
    // Keep Alive Meldung an Nextion Display senden
92
    sendString_2("home.vakal.val=1");
93
    sendChar_2(0xFF);  
94
    sendChar_2(0xFF);
95
    sendChar_2(0xFF);
96
    
97
    // EEPROM lesen und Daten ausgeben
98
    uint8_t myByte = eeprom_read_byte (&eeFooByte);
99
    sprintf(str, "Byte auslesen: %d", myByte);
100
    sendString_1(str);    
101
    uint16_t myWord = eeprom_read_word (&eeFooWord);
102
    sprintf(str, "Word auslesen: %d", myWord);
103
    sendString_1(str);
104
    float myFloat = eeprom_read_float(&eeFooFloat);
105
    sprintf(str, "Float auslesen: %f", myFloat); //funktioniert nicht. Kommt nur ein ?
106
    sendString_1(str);
107
108
    // EEPROM schreiben --> funktioniert
109
    //eeprom_write_word (&eeFooWord, DataResult);
110
        
111
    }
112
}
113
114
void init_twi()
115
{
116
  TWIE.MASTER.BAUD = 0x05;
117
  TWIE.MASTER.CTRLA = TWI_MASTER_ENABLE_bm;
118
  TWIE.MASTER.STATUS |= TWI_MASTER_BUSSTATE_IDLE_gc;
119
}
120
121
void init_serial_1()
122
{
123
  // Baudrate 19200
124
  USARTE0.BAUDCTRLA = 0xB0 & 0xFF;
125
  USARTE0.BAUDCTRLB = ((0xB0 & 0xF00) >> 0x08);
126
  USARTE0.BAUDCTRLB |= ((-5 & 0x0F) << 0x04);
127
  /* Baudrate 9600
128
  USARTE0.BAUDCTRLA = 0x181 & 0xFF;
129
  USARTE0.BAUDCTRLB = ((0x181 & 0xF00) >> 0x08);
130
  USARTE0.BAUDCTRLB |= ((-5 & 0x0F) << 0x04);
131
  */
132
  USARTE0.CTRLA = USART_RXCINTLVL_LO_gc;
133
  USARTE0.STATUS |= USART_RXCIF_bm;
134
  USARTE0.CTRLB = USART_TXEN_bm | USART_RXEN_bm;
135
  USARTE0.CTRLC = USART_CHSIZE_8BIT_gc;
136
  USARTE0.CTRLC &= ~(USART_PMODE0_bm | USART_PMODE1_bm | USART_SBMODE_bm);
137
  PORTE.DIR = 0x08;
138
}
139
140
void sendChar_1(char c)
141
{
142
    while( !(USARTE0_STATUS & USART_DREIF_bm) );
143
    USARTE0_DATA = c;     
144
}
145
 
146
void sendString_1(char *text)
147
{
148
    while(*text)
149
    {
150
        sendChar_1(*text++);
151
    }
152
    //noch CR und LF anhängen
153
  while (!(USARTE0.STATUS & USART_DREIF_bm));
154
  USARTE0.DATA = 0x0D;
155
  while (!(USARTE0.STATUS & USART_DREIF_bm));
156
  USARTE0.DATA = 0x0A;
157
}
158
 
159
void init_serial_2()
160
{
161
  // Baudrate 9600
162
  USARTC0.BAUDCTRLA = 0x181 & 0xFF;
163
  USARTC0.BAUDCTRLB = ((0x181 & 0xF00) >> 0x08);
164
  USARTC0.BAUDCTRLB |= ((-5 & 0x0F) << 0x04);
165
  USARTC0.CTRLA = USART_RXCINTLVL_LO_gc;
166
  USARTC0.STATUS |= USART_RXCIF_bm;
167
  USARTC0.CTRLB = USART_TXEN_bm | USART_RXEN_bm;
168
  USARTC0.CTRLC = USART_CHSIZE_8BIT_gc;
169
  USARTC0.CTRLC &= ~(USART_PMODE0_bm | USART_PMODE1_bm | USART_SBMODE_bm);
170
  PORTC.DIR = 0x08;
171
}
172
173
void sendChar_2(char c)
174
{
175
    while( !(USARTC0_STATUS & USART_DREIF_bm) );
176
    USARTC0_DATA = c;     
177
}
178
 
179
void sendString_2(char *text)
180
{
181
    while(*text)
182
    {
183
        sendChar_2(*text++);
184
    }
185
    //noch CR und LF anhängen
186
    /*
187
  while (!(USARTC0.STATUS & USART_DREIF_bm));
188
  USARTC0.DATA = 0x0D;
189
  while (!(USARTC0.STATUS & USART_DREIF_bm));
190
  USARTC0.DATA = 0x0A;
191
  */
192
}
193
194
ISR(USARTE0_RXC_vect) // Interrupt vom Terminal
195
{
196
    char data_in = USARTE0_DATA;
197
  sendChar_1(data_in);  
198
}
199
ISR(USARTC0_RXC_vect) // Interrupt vom Nextion Display
200
{
201
    char data_in = USARTC0_DATA;
202
    sendChar_1(data_in);
203
}

von da und dort (Gast)


Lesenswert?

Marie L. schrieb:
> und mir ein Feedback
> zu geben, was gut ist und was ich anders/besser machen könnte.

Zu allererst lernst du bitte die Hinweise zum Posten zu lesen,
zu verinnerlichen und zu beachten.

Im Speziellen jetzt hier:
----------------------------------------------
Wichtige Regeln - erst lesen, dann posten!
............
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
----------------------------------------------

Will heissen dass eine Source die länger als etwa ein Bildschirm
ist in einen Anhang als *.c Datei gepostet gehört.

Nachdem du schon seit 28.04.2010 hier angemeldet bist, also mehr
als 10 Jahre, solltest du das eigentlich wissen. Ist sozusagen
Bestandteil der Netiquette.

von Stefan F. (Gast)


Lesenswert?

Deine Strings "fressen" eine Menge RAM. Du kannst sie stattdessen im 
FLash Speicher lassen und von dort aus verwenden. Siehe

https://www.nongnu.org/avr-libc/user-manual/pgmspace.html
https://www.nongnu.org/avr-libc/user-manual/pgmspace_8h.html

von Thomas W. (Gast)


Lesenswert?

Moin, -

besorge Dir ein kleines C-Buch zu den Grundlagen.

> #define F_CPU 2E6

ich weiss nicht, ob der Float so eine gute Idee ist und der Compiler das 
richtig bekommt.

> /*wird bei Code::Blocks benötigt, bei Geany nicht
>  * erzeugt dort einen [-Wimplicit-function-declaration] Fehler
> void init_twi(void);

Das sind keine Fehlermeldungen sondern Warnungen des Compilers. Es 
kompiliert irgendwas (nicht unbedingt was Du Dir gedacht hast). Du hast 
implizite Funktionen deklariert (--> C-Buch). Beim Compileraufruf sind 
die Warnungen einstellbar, aber:

"Thou shalt run lint frequently and study its pronouncements with care, 
for verily its perception and judgement oft exceed thine."


>   eeprom_write_byte (&eeFooByte, 123);

eeprom_write_byte koennte auch scheitern. Sicherlich hat das einen 
Return-Wert. Auswerten!

>     float myFloat = eeprom_read_float(&eeFooFloat);
>     sprintf(str, "Float auslesen: %f", myFloat); //funktioniert nicht.
> Kommt nur ein ?

Du hast nur eine eingeschraenkte fprintf-Library. Bei Mikrocontroller 
versuche immer, float-Ausgabe zu vermeiden.

Gruesse

Th.

von Stefan F. (Gast)


Lesenswert?

Thomas W. schrieb:
> besorge Dir ein kleines C-Buch zu den Grundlagen.
>> #define F_CPU 2E6
> ich weiss nicht, ob der Float so eine gute Idee ist und der Compiler das
> richtig bekommt.

Das ist schon in Ordnung

Thomas W. schrieb:
> Du hast nur eine eingeschraenkte fprintf-Library. Bei Mikrocontroller
> versuche immer, float-Ausgabe zu vermeiden.

Float Unterstützung bekommen man mit den folgenden Optionen:
1
# Enable floating-point support in printf
2
# LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
3
4
# Enable floating-point support in scanf
5
# LDFLAGS += -Wl,-u,vscanf -lscanf_flt
(so steht das in meinem Makefile)

von Thomas W. (Gast)


Lesenswert?

Moin, -

Stefan ⛄ F. schrieb:
> Thomas W. schrieb:

> Float Unterstützung bekommen man mit den folgenden Optionen:
>
1
> # Enable floating-point support in printf
2
> # LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
3
> 
4
> # Enable floating-point support in scanf
5
> # LDFLAGS += -Wl,-u,vscanf -lscanf_flt
6
>
> (so steht das in meinem Makefile)

Ja, hast Du Dir den Footprint fuer das bischen Float angeguckt? OK, bei 
einem 32bitter mit richtig Speicher, aber bei einem acht-bitter muesste 
ich schon in bitterer Not sein um die Library zu nutzen (or don't care).

Einfache Nachkomma-Formatierung (z.B. 123.45) geht auch viel einfacher.
(z.B.
https://github.com/eepj/SHT2x_for_STM32_HAL/blob/master/sht2x_for_stm32_hal.c
)

Gruesse

Th.

Edith zeigt auf github.com/eepj/sht2x_for_stm32_hal

von Stefan F. (Gast)


Lesenswert?

Thomas W. schrieb:
> Ja, hast Du Dir den Footprint fuer das bischen Float angeguckt?

ich nutze es nur, wenn ich einen guten Grund dazu habe.

von Marie L. (lendl)


Lesenswert?

Erst mal vielen Dank für die vielen Rückmeldungen!

da und dort schrieb:
> Wichtige Regeln - erst lesen, dann posten!
> ............
> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Mea Culpa - hätte ich mir auch denken können...
Ich gelobe Besserung!

Stefan ⛄ F. schrieb:
> Deine Strings "fressen" eine Menge RAM. Du kannst sie stattdessen
> im
> FLash Speicher lassen und von dort aus verwenden.

Hab ich mir angeschaut, aber leider nicht verstanden. Ich denke, dass 
ich bei vielen Themen einfach noch nicht soweit bin. Das ist ein guter 
Übergang zum nächsten Thema:

Thomas W. schrieb:
> besorge Dir ein kleines C-Buch zu den Grundlagen.

Ich mache gerade einen Udemy-Kurs, bin aber noch relativ am Anfang. Ist 
sehr trocken und am Projekt "rumspielen" macht einfach mehr Spass. Ich 
weiss, dass das die falsche Vorgehensweise ist, aber manchmal kann man 
halt nicht aus seiner Haut :-)

Thomas W. schrieb:
>>   eeprom_write_byte (&eeFooByte, 123);
>
> eeprom_write_byte koennte auch scheitern. Sicherlich hat das einen
> Return-Wert. Auswerten!

Das ist natürlich die Folge der Übereifers. Ich habe nicht versanden wie 
ich das auswerten kann. Vielleicht magst Du mir das ja noch erklären.

Stefan ⛄ F. schrieb:
> Float Unterstützung bekommen man mit den folgenden Optionen:# Enable
> floating-point support in printf
> # LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
> # Enable floating-point support in scanf
> # LDFLAGS += -Wl,-u,vscanf -lscanf_flt
> (so steht das in meinem Makefile)

Super, vielen Dank!!! Du hast mir sehr geholfen. Jetzt funktionieren die 
Floats!

Zur Erklärung, ich werde ca. 15 bis 30 Floats brauchen, weil ich da 
Kalibrierwerte abspeichern muss.

Ich danke Euch allen für die Unterstützung!

von Falk B. (falk)


Lesenswert?

Marie L. schrieb:
> Zur Erklärung, ich werde ca. 15 bis 30 Floats brauchen, weil ich da
> Kalibrierwerte abspeichern muss.

Vielleicht, vielleicht auch nicht. Man sollte auch mal eine Minute an 
das Thema Festkommaarithmetik verschwenden. Die reicht in vielen 
Fällen.

von Stefan F. (Gast)


Lesenswert?

Marie L. schrieb:
>> Deine Strings "fressen" eine Menge RAM. Du kannst sie stattdessen
>> im FLash Speicher lassen und von dort aus verwenden.

> Hab ich mir angeschaut, aber leider nicht verstanden. Ich denke, dass
> ich bei vielen Themen einfach noch nicht soweit bin.

Kurz gesagt, änderst du

> puts("Es war einmal ein langer String...");

in

> puts_p(PSTR("Es war einmal ein langer String..."));

Dann wird der String beim Programmstart nicht ins RAM kopiert, sondern 
direkt aus dem Flash verwendet. Der Zugriff darauf ist ein bisschen 
langsamer.

Oder:

> char geschichte[] PROGMEM = "Es war einmal ein langer String...";
> puts_p(geschichte);

Die ganzen xxx_p() Funktionen sind dafür vorbereitet, direkt aus dem 
Flash zu lesen.

von Thomas W. (Gast)


Lesenswert?

Moin, -

please disregard my comment: in <avr/eeprom.h> ist wie folgt definiert:
1
void eeprom_write_byte   (   
2
        uint8_t *      __p,
3
        uint8_t        __value 
4
    )

d.h. eine Fehlermeldung gibt es nicht. Wenn es einen Fehler gibt (d.h. 
out of bound, Eeprom nicht bereit) bekommst Du das nicht mit (-> per 
Hand programmieren: Schreiben, Lesen, vergleichen)

Gruesse

Th.

von Thomas W. (Gast)


Lesenswert?

Moin, -

noch eine kleine Bemerkung: Flash kann man ca. 10000x beschreiben, 
eeprom ca. 100000x. Hoert sich sehr viel an, wenn Du aber auf die Idee 
kommst, jede Minute Messdaten in den Eeprom zu schreiben, hast Du die 
theoretische Lebenserwartung nach 70 Tagen erreicht.

Gruesse

Th.

von Marie L. (lendl)


Lesenswert?

Falk B. schrieb:
> Vielleicht, vielleicht auch nicht. Man sollte auch mal eine Minute an
> das Thema Festkommaarithmetik verschwenden. Die reicht in vielen
> Fällen.

Ja, das ist in der Tat sehr interessant, das werde ich mir mal genauer 
anschauen. Danke!

Stefan ⛄ F. schrieb:
> Dann wird der String beim Programmstart nicht ins RAM kopiert, sondern
> direkt aus dem Flash verwendet. Der Zugriff darauf ist ein bisschen
> langsamer.

Geschwindigkeit spielt bei den Messungen keine große Rolle, ich werde es 
mal testen, ob ich damit zurecht komme. Danke!

Thomas W. schrieb:
> d.h. eine Fehlermeldung gibt es nicht. Wenn es einen Fehler gibt (d.h.
> out of bound, Eeprom nicht bereit) bekommst Du das nicht mit (-> per
> Hand programmieren: Schreiben, Lesen, vergleichen)

Die Kalibrierwerte müssen nach der Kalibrierung wieder ausgegeben werden 
(zur Kontrolle und Dokumentation). Also wird es sowieso eine Funktion 
geben (müssen), die alle Kalibrierwerte ausliest. Mal schauen ob ich das 
gleich kombinieren kann... Danke!

Thomas W. schrieb:
> noch eine kleine Bemerkung: Flash kann man ca. 10000x beschreiben,
> eeprom ca. 100000x. Hoert sich sehr viel an, wenn Du aber auf die Idee
> kommst, jede Minute Messdaten in den Eeprom zu schreiben, hast Du die
> theoretische Lebenserwartung nach 70 Tagen erreicht.

Ich kann dich beruhigen, es werden nur Kalibrierwerte und keine 
Messwerte ins Eeprom geschrieben. Also maximal 30 Werte und das ca. 
einmal im Jahr. Ansonsten kommen eventuell noch "Zustände" ins Eeprom, 
z.B. der Messbereich, damit man beim Einschalten wieder die gleichen 
Einstellungen hat.

Euch allen nochmal vielen Dank für die freundliche Unterstützung!
Ich werde bestimmt noch die ein oder andere doofe Frage stellen. Der 
Umstieg von Bascom auf C ist nämlich nicht ohne.
Bis bald...

Beitrag #6704419 wurde von einem Moderator gelöscht.
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.