Zbernica i2c: EEPROM Terminál: Rozdiel medzi revíziami
Zo stránky SensorWiki
Opis WriteProtect |
Pridany algorytmus a program |
||
| Riadok 31: | 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 (1) | 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 === | ||
| Riadok 73: | Riadok 178: | ||
'''Video:''' | '''Video:''' | ||
<center><youtube> | <center><youtube>SDEE0DPeq-A </youtube></center> | ||
== Čo by som urobil inak == | == Čo by som urobil inak == | ||
Verzia z 22:51, 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
Ako ste overili funkciu, napríklad... Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku hotového zariadenia.

Video:
Čo by som urobil inak
Zamyslite sa spätne nad problémom, ktorý ste riešili a napíšte, čo sa vám nepodarilo a nabudúce by ste spravili inak.
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.

