Zbernica i2c: EEPROM Terminál: Rozdiel medzi revíziami
Zo stránky SensorWiki
Opis pripojenia EEPROM |
Pridane Overenie, Co by som urobil inak |
||
| (2 medziľahlé úpravy od rovnakého používateľa nie sú zobrazené.) | |||
| Riadok 24: | Riadok 24: | ||
Pre správne zapojenie datalinie SDA a SCL musia máť Pull-Up rezistory pripojené na napájacie napätie. | Pre správne zapojenie datalinie SDA a SCL musia máť Pull-Up rezistory pripojené na napájacie napätie. | ||
Piny výberu adresy pripojíme na GND a tak dostaneme adresu zariadenia 000. | Piny výberu adresy pripojíme na GND a tak dostaneme adresu zariadenia 000. | ||
Pin WriteControl pripojíme na GND aby neblokoval nám zápis dát. | |||
[[Obrázok:I2c_schematic.png|400px|thumb|center|Zapojenie EEPROM]] | [[Obrázok:I2c_schematic.png|400px|thumb|center|Zapojenie EEPROM]] | ||
| Riadok 30: | Riadok 31: | ||
=== Algoritmus a program === | === Algoritmus a program === | ||
Script sa skláda z viacerých časti: | |||
Výber rozmeru EEPROM pamäte. Použité EEPROM vyrobca ponúka v dvoch variáciach 32Kib a 64 Kib. Mikroprocessor nevie si zistiť tento rozmer bez prepisania pamäte, teda to mu musí povedať používateľ. Reťazec načítany z scanf sa začne porovnávať, či jeho prvý symbol sa zhoduje s možnosťami vyberu alebo nie. | |||
<tabs> | <tabs> | ||
<tab name=" | <tab name="Vyber rozmeru EEPROM"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
while(!isOptionChosen) { | |||
{ | printf("\nChoose your EEPROM size:\n1) 32Kibit (4KiByte)\n2) 64Kibit (8KiByte)\nOption:"); | ||
clearInput(); | |||
scanf("%s", uartInput); | |||
if(uartInput[0] == '1') { | |||
isEepromLarge = 0; | |||
isOptionChosen = 1; | |||
} else if(uartInput[0] == '2') { | |||
isEepromLarge = 1; | |||
isOptionChosen = 1; | |||
} else { | |||
printf("\nNot a valid answer.\n"); | |||
isOptionChosen = 0; | |||
} | |||
} | |||
</syntaxhighlight ></tab> | |||
</tabs> | |||
Hlavný interface programu funguje podobne, ale je spravený cez switch case namiesto if else. Ako je vidieť, rozmery EEPROM sú dinamické a menia sa on-the-go posunutím čisla o jeden bit isEepromLarge, ktorý sme zadavali predtým. Čítanie a zápis riadkov sú oddelnými funkciami aby sa nemisiel kód písať viackrat. Na ošetrenie situácii ked sa očakáva číslo, ale uživateľ zadá iné symboly, používa sa čistenie bufferu. | |||
<tabs> | |||
<tab name="Hlavny interface"><syntaxhighlight lang="c++" style="background: LightYellow;"> | |||
while(!exitChosen){ | |||
printf("\nChoose an option:\n1)Read a line\n2)Write a line\n3)Read all\n4)Exit\nOption:"); | |||
clearInput(); | |||
scanf("%s", uartInput); | |||
printf("\n"); | |||
switch (uartInput[0]) { | |||
case '1': | |||
lineAddress = 0; | |||
while(1 > lineAddress || lineAddress > (128 << isEepromLarge)) { | |||
printf("\nChoose a line to read [1-%d]:", (128 << isEepromLarge)); | |||
scanf("%d", &lineAddress); | |||
while (getchar() != '\n' && !feof(stdin)); | |||
if (1 > lineAddress || lineAddress > (128 << isEepromLarge)) { | |||
printf("\nNot a valid answer.\n"); | |||
while (getchar() != '\n' && !feof(stdin)); | |||
} | |||
} | |||
printf("\n"); | |||
readLine(); | |||
break; | |||
case '2': | |||
lineAddress = 0; | |||
while(1 > lineAddress || lineAddress > (128 << isEepromLarge)) { | |||
printf("\nChoose a line to write [1-%d]:", (128 << isEepromLarge)); | |||
scanf("%d", &lineAddress); | |||
if (1 > lineAddress || lineAddress > (128 << isEepromLarge)) { | |||
printf("\nNot a valid answer.\n"); | |||
while (getchar() != '\n' && !feof(stdin)); | |||
} | |||
} | |||
printf("\nEnter text (max 32 characters):\n"); | |||
clearInput(); | |||
while (getchar() != '\n' && !feof(stdin)); | |||
scanf("%32[^\n]", uartInput); | |||
writeLine(); | |||
break; | |||
case '3': | |||
for(i = 1; i <= (128 << isEepromLarge); i++) { | |||
lineAddress = i; | |||
readLine(); | |||
} | |||
break; | |||
case '4': | |||
exitChosen = 1; | |||
printf("\nGoodbye!\n"); | |||
break; | |||
default: | |||
printf("\nNot a valid answer.\n\n"); | |||
while (getchar() != '\n' && !feof(stdin)); | |||
break; | |||
} | |||
} | } | ||
</syntaxhighlight ></tab> | |||
</tabs> | |||
Funkcie čítania a zápisu prepočitávajú user-friendly čislo riadku na reálnu adresu pamäte. Jedným príkazom vieme poslať na I2C linku iba 8 bitov, ale adresa je 16 bitová, teda musíme rozdeliť ju na dva príkazy. Na urychlenie processu čítania dát, môžeme čítať viac bajtov za sebou ak počet je menší 32, na konci musíme poslať Nak príkaz. | |||
<tabs> | |||
<tab name="Funkcie citania a zapisu"><syntaxhighlight lang="c++" style="background: LightYellow;"> | |||
void readLine(void) { | |||
uint16_t memAddr = (lineAddress - 1) * 32; | |||
i2c_start_wait( (EEPROM_ADDR << 1) | I2C_WRITE); | |||
i2c_write(memAddr >> 8); | |||
i2c_write(memAddr & 0b11111111); | |||
i2c_rep_start( (EEPROM_ADDR << 1) | I2C_READ ); | |||
for(k = 0; k < 32; k++) { | |||
if(k < 31) | |||
uartInput[k] = i2c_readAck(); | |||
else | |||
uartInput[k] = i2c_readNak(); | |||
} | |||
i2c_stop(); | |||
uartInput[32] = '\0'; | |||
printf("Line %3d: [%32s]\n", lineAddress, uartInput); | |||
} | } | ||
< | void writeLine(void) { | ||
uint16_t memAddr = (lineAddress - 1) * 32; | |||
i2c_start_wait((EEPROM_ADDR << 1) | I2C_WRITE); | |||
i2c_write(memAddr >> 8); | |||
i2c_write(memAddr & 0b11111111); | |||
for(k = 0; k < 32; k++) { | |||
if(uartInput[k] == '\0') break; | |||
i2c_write(uartInput[k]); | |||
} | |||
i2c_stop(); | |||
printf("Line %3d written successfully!\n", lineAddress); | |||
} | |||
</syntaxhighlight ></tab> | </syntaxhighlight ></tab> | ||
</tabs> | </tabs> | ||
Zdrojový kód: [[Médiá:EgorBukhtiiarov2026.zip|zdrojaky.zip]] | |||
Zdrojový kód: [[Médiá: | |||
=== Overenie === | === Overenie === | ||
Pripojil som EEPROM k mikroprocessoru pomocou uvedených schém. Na zariadení fizicky nič sa nemení, teda do videa prikládam len prácu s UART terminálom. | |||
[[Súbor: | [[Súbor:Arduino-24C64WP-nometa.png|400px|thumb|center|Aplikácia.]] | ||
'''Video:''' | '''Video:''' | ||
<center><youtube> | <center><youtube>SDEE0DPeq-A </youtube></center> | ||
== Čo by som urobil inak == | == Čo by som urobil inak == | ||
Rád by som sa dozvediel ako sa majú robiť podobné ConsoleUI lebo vidím, že môj kód je viac if-else, než niečo čo by málo štrukturu. Ešte by som chiel nájsť lepší spôsob práci s user-input hodnotami, teraz to vyzerá chaotické. | |||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] | ||
Aktuálna revízia z 23:08, 8. jún 2026
Záverečný projekt predmetu MIPS / LS2026 - Egor Bukhtiiarov
Zadanie
Cieľom projektu je napisanie kodu, ktorý umožní čítanie a zápis textovych reťazcov z I2C EEPROM pomocou príkazov, posielaných cez UART.

Literatúra:
Pripojenie EEPROM
Použitý EEPROM ako aj iné I2C zariadenia sa pripájaju k mikrokontrolleru len dvoma vodičmi SDA pre data a SCK pre synchronizáciu časovania. Väčšina I2C sariadení majú možnosť zmeny adresy zariadenia, čo umožňujé aj použitý EEPROM.
Pre správne zapojenie datalinie SDA a SCL musia máť Pull-Up rezistory pripojené na napájacie napätie. Piny výberu adresy pripojíme na GND a tak dostaneme adresu zariadenia 000. Pin WriteControl pripojíme na GND aby neblokoval nám zápis dát.

Algoritmus a program
Script sa skláda z viacerých časti:
Výber rozmeru EEPROM pamäte. Použité EEPROM vyrobca ponúka v dvoch variáciach 32Kib a 64 Kib. Mikroprocessor nevie si zistiť tento rozmer bez prepisania pamäte, teda to mu musí povedať používateľ. Reťazec načítany z scanf sa začne porovnávať, či jeho prvý symbol sa zhoduje s možnosťami vyberu alebo nie.
while(!isOptionChosen) {
printf("\nChoose your EEPROM size:\n1) 32Kibit (4KiByte)\n2) 64Kibit (8KiByte)\nOption:");
clearInput();
scanf("%s", uartInput);
if(uartInput[0] == '1') {
isEepromLarge = 0;
isOptionChosen = 1;
} else if(uartInput[0] == '2') {
isEepromLarge = 1;
isOptionChosen = 1;
} else {
printf("\nNot a valid answer.\n");
isOptionChosen = 0;
}
}
Hlavný interface programu funguje podobne, ale je spravený cez switch case namiesto if else. Ako je vidieť, rozmery EEPROM sú dinamické a menia sa on-the-go posunutím čisla o jeden bit isEepromLarge, ktorý sme zadavali predtým. Čítanie a zápis riadkov sú oddelnými funkciami aby sa nemisiel kód písať viackrat. Na ošetrenie situácii ked sa očakáva číslo, ale uživateľ zadá iné symboly, používa sa čistenie bufferu.
while(!exitChosen){
printf("\nChoose an option:\n1)Read a line\n2)Write a line\n3)Read all\n4)Exit\nOption:");
clearInput();
scanf("%s", uartInput);
printf("\n");
switch (uartInput[0]) {
case '1':
lineAddress = 0;
while(1 > lineAddress || lineAddress > (128 << isEepromLarge)) {
printf("\nChoose a line to read [1-%d]:", (128 << isEepromLarge));
scanf("%d", &lineAddress);
while (getchar() != '\n' && !feof(stdin));
if (1 > lineAddress || lineAddress > (128 << isEepromLarge)) {
printf("\nNot a valid answer.\n");
while (getchar() != '\n' && !feof(stdin));
}
}
printf("\n");
readLine();
break;
case '2':
lineAddress = 0;
while(1 > lineAddress || lineAddress > (128 << isEepromLarge)) {
printf("\nChoose a line to write [1-%d]:", (128 << isEepromLarge));
scanf("%d", &lineAddress);
if (1 > lineAddress || lineAddress > (128 << isEepromLarge)) {
printf("\nNot a valid answer.\n");
while (getchar() != '\n' && !feof(stdin));
}
}
printf("\nEnter text (max 32 characters):\n");
clearInput();
while (getchar() != '\n' && !feof(stdin));
scanf("%32[^\n]", uartInput);
writeLine();
break;
case '3':
for(i = 1; i <= (128 << isEepromLarge); i++) {
lineAddress = i;
readLine();
}
break;
case '4':
exitChosen = 1;
printf("\nGoodbye!\n");
break;
default:
printf("\nNot a valid answer.\n\n");
while (getchar() != '\n' && !feof(stdin));
break;
}
}
Funkcie čítania a zápisu prepočitávajú user-friendly čislo riadku na reálnu adresu pamäte. Jedným príkazom vieme poslať na I2C linku iba 8 bitov, ale adresa je 16 bitová, teda musíme rozdeliť ju na dva príkazy. Na urychlenie processu čítania dát, môžeme čítať viac bajtov za sebou ak počet je menší 32, na konci musíme poslať Nak príkaz.
void readLine(void) {
uint16_t memAddr = (lineAddress - 1) * 32;
i2c_start_wait( (EEPROM_ADDR << 1) | I2C_WRITE);
i2c_write(memAddr >> 8);
i2c_write(memAddr & 0b11111111);
i2c_rep_start( (EEPROM_ADDR << 1) | I2C_READ );
for(k = 0; k < 32; k++) {
if(k < 31)
uartInput[k] = i2c_readAck();
else
uartInput[k] = i2c_readNak();
}
i2c_stop();
uartInput[32] = '\0';
printf("Line %3d: [%32s]\n", lineAddress, uartInput);
}
void writeLine(void) {
uint16_t memAddr = (lineAddress - 1) * 32;
i2c_start_wait((EEPROM_ADDR << 1) | I2C_WRITE);
i2c_write(memAddr >> 8);
i2c_write(memAddr & 0b11111111);
for(k = 0; k < 32; k++) {
if(uartInput[k] == '\0') break;
i2c_write(uartInput[k]);
}
i2c_stop();
printf("Line %3d written successfully!\n", lineAddress);
}
Zdrojový kód: zdrojaky.zip
Overenie
Pripojil som EEPROM k mikroprocessoru pomocou uvedených schém. Na zariadení fizicky nič sa nemení, teda do videa prikládam len prácu s UART terminálom.

Video:
Čo by som urobil inak
Rád by som sa dozvediel ako sa majú robiť podobné ConsoleUI lebo vidím, že môj kód je viac if-else, než niečo čo by málo štrukturu. Ešte by som chiel nájsť lepší spôsob práci s user-input hodnotami, teraz to vyzerá chaotické.

