This is an old revision of the document!


SD Card Buddy

Sergiu Moga 332CB

Introducere

SD Card Buddy este un proiect Arduino care are ca scop expunerea unui shell prin care un utilizator poate interactiona cu sistemul de fisiere de pe un SD Card. Ideea proiectului este de a avea ceva micut si la indemana cu care poti modifica continutul de pe un SD Card, ceea ce il poate face util in anumite cazuri.

Descriere generală

Folosind o placuta compatibila Arduino, prin comunicare SPI cu 2 sclavi (un display si un modul de SD Card) o sa expun printr-un display un shell interactiv cu care utilizatorul poate naviga/citi/scrie intr-un sistem de fisiere de pe SD Card. Pentru interactionare se va folosi o tastatura improvizata (15-16 butoane legate la acelasi pin prin rezistente diferite pentru a le putea distinge cu ajutorul analogRead).

Hardware Design

Componente:

  • Placuta compatibila Arduino UNO
  • display cu interfatare SPI
  • modul de SD Card cu interfatare SPI
  • 15-16 push-buttons
  • niste fire + cablaj testare

Schematic:

Software Design

Software utilizat:

  • Arduino IDE
  • draw.io
  • Eagle

Biblioteci utilizate:

  • ESP8266WebServer pentru a putea obtine functionalitatea de Server Web pe ESP8266
  • SoftwareSerial pentru a putea realiza usor comunicarea intre cele doua placute compatibile Arduino
  • SPI si SD pentru a putea realiza comunicarea cu cardul microSD

Structuri de date utilizate:

  • o matrice kbd_buttons care contine asocierea litere ↔ butoane tastatura
  • un array kbd_button_index care retine indecsii din matricea kbd_buttons corespunzatoare valorii citite prin analogRead
  • second_half este folosit ca index al primei dimensiuni a matricii ca sa poata fi accesata a doua jumatate a tastaturii (ca un Caps Lock)
int second_half = 0;
// ranges = {{1000, 1050}, {950, 1000}, {850, 900}, {450, 550}, {50, 150}}
int kbd_button_index[] = {4, 4, -1, -1, 3, 3, -1, -1, 2, 1, 0};
char kbd_buttons[2][4][5] = { { {'A', 'B', 'C', 'D', 'E'},
                                {'F', 'G', 'H', 'I'},
                                {'J', 'K', 'L', 'M'},
                                {' ', '0', '\n'}  },
                                { {'N', 'O', 'P', 'Q', 'R'},
                                  {'S', 'T', 'U', 'V'},
                                  {'W', 'X', 'Y', 'Z'},
                                  {'/', '0', '\n'}  } };
  • un buffer care retine comanda de interpretat si unul pentru a retine output-ul ce trebuie afisat pe serverul web
  • indecsii pentru a retine pozitia in cele doua buffere
char cmd[50];
char output[150];
int cmd_index, output_index;

Functii/Algoritmi: Setup:

  • ESP8266: incepe seriala intre Uno si ESP8266, realizeaza conexiunea Wi-Fi, incepe server-ul HTTP
void setupServer()
{
  server.on("/", htmlIndex);
 
  server.begin();
}
 
void htmlIndex()
{
  int replyCode = 200;
 
  String contentType = "text/html";
 
  memcpy(markdown + sizeof(head) - 1, message, sizeof(message));
 
  server.send(replyCode, contentType, markdown);
}
 
void connectToWiFi()
{
  WiFi.mode(WIFI_STA);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED)
    delay(500);
}
 
void setup()
{
  mySerial.begin(4800);
 
  delay(1000);
 
  connectToWiFi();
 
  setupServer();
}
  • Uno: Incepe seriala intre Uno si ESP8266 si conexiunea cu modulul SDCard. Daca conexiunea din urma esueaza, agata executia
void setup() {
  mySerial.begin(4800);
 
  if (!SD.begin(10)) {
    while (1);
  }
}

Loop:

  • ESP8266: citeste din conexiunea seriala si asteapta ca clientul sa faca un HTTP Request. Cand clientul face un request, se va executa htmlIndex
void htmlIndex()
{
  int replyCode = 200;
 
  String contentType = "text/html";
 
  memcpy(markdown + sizeof(head) - 1, message, sizeof(message));
 
  server.send(replyCode, contentType, markdown);
}
 
void loop()
{
  mySerial.readBytes(message, sizeof(message));
 
  server.handleClient();
}
  • Uno: parcurge pinii ADC si decide ce cheie a fost apasata si stocheaz-o in buffer-ul de comenzi. Daca s-a apasat Enter, inseamna ca se doreste executia de comenzi si functia cmd_exec este apelata. Aceasta functie executa operatia de I/O dorita cu SD Card-ul. De exemplu, daca se doreste afisarea continutului SD Card-ului, parcurge recursiv continutul directoarelor apeland functia list
void list(File dir, int level) {  
  int len;
  while (true) {
    File entry =  dir.openNextFile();
 
    if (!entry) {
      return;
    }
 
    for (uint8_t i = 0; i < level; i++) {
      output[output_index++] = '-';
      output[output_index++] = '-';
    }
 
    len = strlen(entry.name());
    memcpy(output + output_index, entry.name(), len);
    output_index += len;
 
    output[output_index++] = '<';
    output[output_index++] = 'b';
    output[output_index++] = 'r';
    output[output_index++] = '>';
 
    if (entry.isDirectory()) {
      output[output_index++] = '<';
      output[output_index++] = 'b';
      output[output_index++] = 'r';
      output[output_index++] = '>';
 
      list(entry, level + 1);
 
    }
 
    entry.close();
  }
}
 
void cmd_exec() {
  char *p = strtok(cmd, " ");
  File file, dir;
  int offset, bytes_count;
 
  if (p) {
    if (*p == 'L') {
      p = strtok(NULL, " ");
 
      dir = SD.open(p);
 
      list(dir, 0);
 
      output[output_index] = 0;
      mySerial.write(output, sizeof(output));
      output_index = 0;
 
      return;
 
    } else if (*p == 'R') { // read
      p = strtok(NULL, " ");
      if (!SD.exists(p)) {
        memcpy(output + output_index, "No such file or directory!", sizeof("No such file or directory!"));
        output_index += sizeof("No such file or directory!");
 
        output[output_index] = 0;
        mySerial.write(output, sizeof(output));
        output_index = 0;
 
        return;
      }
 
      Serial.println(p);
      file = SD.open(p, FILE_READ);
 
      char c = 0;
      c = file.read();
      while (c != -1) {
        output[output_index++] = c;
        c = file.read();
      }
 
      file.close();
 
      output[output_index] = 0;
      mySerial.write(output, sizeof(output));
      output_index = 0;
 
      return;
 
    } else if (*p == 'W') { // write
      p = strtok(NULL, " ");
 
      Serial.println(p);
      file = SD.open(p, FILE_WRITE);
 
      p = strtok(NULL, " ");
 
      Serial.println(p);
      file.write(p, strlen(p));
 
      file.close();
 
      return;
 
    } else {
      Serial.println("lool");
      memcpy(output + output_index, "No such command!\n", sizeof("No such command!<br>"));
      output_index += sizeof("No such command!<br>");
 
      output[output_index] = 0;
      mySerial.write(output, sizeof(output));
      output_index = 0;
 
      return;
    }
  }
}
 
void loop() {
  char c;
 
  A0_value = analogRead(A0);
  if (A0_value > THRESHOLD) {
    c = kbd_buttons[second_half][0][kbd_button_index[A0_value / 100]];
 
    cmd[cmd_index++] = c;
 
    output[output_index++] = c;
    output[output_index] = 0;
    mySerial.write(output, sizeof(output));
  }
 
  A1_value = analogRead(A1);
  if (A1_value > THRESHOLD) {
    c = kbd_buttons[second_half][1][kbd_button_index[A1_value / 100]];
 
    cmd[cmd_index++] = c;
 
    output[output_index++] = c;
    output[output_index] = 0;
    mySerial.write(output, sizeof(output));
  }
 
  A2_value = analogRead(A2);
  if (A2_value > THRESHOLD) {
    c = kbd_buttons[second_half][2][kbd_button_index[A2_value / 100]];
 
    cmd[cmd_index++] = c;
 
    output[output_index++] = c;
    output[output_index] = 0;
    mySerial.write(output, sizeof(output));
  }
 
  A3_value = analogRead(A3);
  if (A3_value > THRESHOLD) {
    c = kbd_buttons[second_half][3][kbd_button_index[A3_value / 100]];
 
    switch (c) {
    case '/':
    case ' ':
      cmd[cmd_index++] = c;
 
      output[output_index++] = c;
      output[output_index] = 0;
      mySerial.write(output, sizeof(output));
 
      break;
 
    case '\n':
      output[output_index++] = '<';
      output[output_index++] = 'b';
      output[output_index++] = 'r';
      output[output_index++] = '>';
      output[output_index] = 0;
 
      cmd_exec();
      memset(cmd, 0, sizeof(cmd));
      cmd_index = 0;
      output_index = 0;
      memset(output, 0, sizeof(output));
 
      break;
 
    case '0':
      second_half ^= 1;
 
      analogWrite(9, second_half);
 
      break;
    }
  }
 
  delay(150);
}

Rezultate Obţinute

Care au fost rezultatele obţinute în urma realizării proiectului vostru.

Concluzii

Download

O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).

Fişierele se încarcă pe wiki folosind facilitatea Add Images or other files. Namespace-ul în care se încarcă fişierele este de tipul :pm:prj20??:c? sau :pm:prj20??:c?:nume_student (dacă este cazul). Exemplu: Dumitru Alin, 331CC → :pm:prj2009:cc:dumitru_alin.

Jurnal

Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.

Bibliografie/Resurse

Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe Resurse Software şi Resurse Hardware.

Export to PDF

pm/prj2022/cristip/sdcardbuddy.1654033338.txt.gz · Last modified: 2022/06/01 00:42 by sergiu.moga
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0