Operácie

Zbernica i2c: EEPROM Terminál

Zo stránky SensorWiki

Verzia z 23:08, 8. jún 2026, ktorú vytvoril StudentMIPS (diskusia | príspevky) (Pridane Overenie, Co by som urobil inak)
(rozdiel) ← Staršia verzia | Aktuálna úprava (rozdiel) | Novšia verzia → (rozdiel)

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.

Použitý EEPROM čip 24C64WP

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.

Zapojenie EEPROM


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.

Aplikácia.

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é.