add arduino sources

master
Peter Babič 4 years ago
parent e555d1e3cf
commit 0ebe9c4fd7
  1. 546
      arduino-sources/Bakalarka.cpp
  2. 88
      arduino-sources/Bakalarka.h
  3. 202
      arduino-sources/DS1302/DS1302.cpp
  4. 1388
      arduino-sources/MFRC522/MFRC522.cpp
  5. 329
      arduino-sources/MFRC522/MFRC522.h
  6. 334
      arduino-sources/PCD8544/PCD8544.cpp
  7. 78
      arduino-sources/PCD8544/PCD8544.h
  8. 24
      arduino-sources/Release/DS1302/subdir.mk
  9. 24
      arduino-sources/Release/MFRC522/subdir.mk
  10. 24
      arduino-sources/Release/PCD8544/subdir.mk
  11. 27
      arduino-sources/Release/SD/subdir.mk
  12. 30
      arduino-sources/Release/SD/utility/subdir.mk
  13. 27
      arduino-sources/Release/SDFAT16/subdir.mk
  14. 24
      arduino-sources/Release/SPI/subdir.mk
  15. 24
      arduino-sources/Release/SerialCommand/subdir.mk
  16. 27
      arduino-sources/Release/subdir.mk
  17. 38
      arduino-sources/SDFAT16/Fat16Config.h
  18. 208
      arduino-sources/SDFAT16/Fat16mainpage.h
  19. 418
      arduino-sources/SDFAT16/FatStructs.h
  20. 277
      arduino-sources/SDFAT16/SdCard.cpp
  21. 192
      arduino-sources/SDFAT16/SdCard.h
  22. 117
      arduino-sources/SDFAT16/SdInfo.h
  23. 66
      arduino-sources/SPI/SPI.cpp
  24. 70
      arduino-sources/SPI/SPI.h
  25. 94
      arduino-sources/SerialCommand/SerialCommand.h
  26. 118
      arduino-sources/prescaler.h
  27. 148
      arduino-sources/rotary.cpp
  28. 37
      arduino-sources/rotary.h

@ -0,0 +1,546 @@
#include "Bakalarka.h"
#include "prescaler.h"
#include <stdio.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
//#include <avr/wdt.h>
#include "rotary.h"
Rotary encoder = Rotary(ENC_A, ENC_B);
#include "DS1302/DS1302.h"
DS1302 rtc(DS_RST, DS_IO, DS_SCK);
#include "SPI/SPI.h"
#include "MFRC522/MFRC522.h"
MFRC522 mfrc522(RFID_SS, RFID_RST);
#include "PCD8544/PCD8544.h"
PCD8544 lcd(LCD_DC, LCD_RST, LCD_SS);
#include <Fat16.h>
#include <Fat16util.h>
// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))
SdCard card;
Fat16 file;
#include "SerialCommand/SerialCommand.h"
SerialCommand SCmd;
volatile uint32_t lastDebounce;
volatile int8_t currentMenuItem = 0;
volatile boolean button = false, cursor = false, reading = false;
uint16_t lastRefresh;
static uint8_t storageIndex EEMEM;
Menu storage = {"Storage", list, 0};
Menu add_storage = {"New file", addStorage, 0};
Menu date_time = {"Date/time", frontPage, 0};
Menu exit_menu = {"Exit", frontPage, 0};
//Menu s1 = {"s1", list, 0};
//Menu s2 = {"s2", list, 0};
//Menu s3 = {"s3", list, 0};
//Menu s4 = {"s4", list, 0};
Menu mainMenu = { "", NULL, 4, { &storage, &add_storage, &date_time, &exit_menu} };
// bitmaps
const byte icon_usb[20] PROGMEM = {
0x08, 0x1C, 0x3E, 0x3E, 0x1C, 0x08, 0x0C, 0x0E, 0x0A, 0x1A,
0x3B, 0x6B, 0x4B, 0xE8, 0xE8, 0xE8, 0x08, 0x3E, 0x1C, 0x08
};
const byte icon_battery_100[21] PROGMEM = {
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81,
0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xFF, 0x3C, 0x3C
};
const byte icon_battery_75[21] PROGMEM = {
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81,
0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C
};
const byte icon_battery_50[21] PROGMEM = {
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0xBD, 0xBD, 0xBD, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C
};
const byte icon_battery_25[21] PROGMEM = {
0xFF, 0x81, 0xBD, 0xBD, 0xBD, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x3C, 0x3C
};
const byte icon_arrow[6] PROGMEM = {
0x00, 0xFE, 0x7C, 0x38, 0x10, 0x00
};
void setup(void) {
// There is 16HMz crystal used, halve it to reliable 8MHz@3V3
setClockPrescaler(CLOCK_PRESCALER_2);
// The fastest reliable baud rate is 38400
Serial.begin(38400);
lcd.begin();
lcd.clear();
// Rotary interrupt pin change enable
PCICR |= (1 << PCIE1);
PCMSK1 |= (1 << PCINT8) | (1 << PCINT9);
// RFID host interrupt request
attachInterrupt(0, RFIDInterrupt, FALLING);
// Encoder button interrupt handle
attachInterrupt(1, debounceInterrupt, FALLING);
// Encoder button pull-up
pinMode(BTN, INPUT_PULLUP);
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 card
if (!card.init(0, SD_SS))
error("card.init failed!");
if (!Fat16::init(&card))
error("Fat16::init failed!");
pinMode(SPKR, OUTPUT);
pinMode(VBAT_ADC_EN, OUTPUT);
// wdt_enable(WDTO_8S);
frontPage();
SCmd.addCommand("ls", ls);
SCmd.addCommand("touch", touch);
SCmd.addCommand("rm", rm);
// SCmd.addCommand("HELLO", SayHello); // Echos the string argument back
// SCmd.addCommand("P", process_command); // Converts two arguments to integers and echos them back
SCmd.addDefaultHandler(unrecognized); // Handler for command that isn't matched (says "What?")
sei();
}
void loop(void) {
// wdt_reset();
// tone(SPKR, 1000, 100);
// topBar();
SCmd.readSerial();
if (millis() - lastRefresh > 1000) {
frontPage();
lastRefresh = millis();
}
if (button) {
button = false;
navigateMenu(&mainMenu);
return;
// uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]);
// if (currentMenuItem >= menuLenght)
// currentMenuItem = 0;
// else if (currentMenuItem < 0)
// currentMenuItem = menuLenght - 1;
// lcd.setCursor(0, 0);
// uint8_t i = 0, offset = 0;
// if (currentMenuItem >= PCD8544_LINES)
// offset = currentMenuItem - PCD8544_LINES + 1;
// for (i = offset; i < menuLenght && i < PCD8544_LINES + offset; i++) {
// if (i == (uint8_t)currentMenuItem)
// lcd.bitmap(icon_arrow, 1, 6);
// else
// lcd.print(' ');
// lcd.print(menuItems[i]);
// lcd.clearRestOfLine();
// }
}
// delay(1000);
// lcd.clear();
// topBar();
// delay(1000);
// if (Serial.available()) {
// Fat16::ls(LS_DATE | LS_SIZE);
// while(Serial.available())
// Serial.read();
// }
if (reading && mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
// // Look for new cards
// if ( ! mfrc522.PICC_IsNewCardPresent())
// return;
//
//
// // Select one of the cards
// if ( ! mfrc522.PICC_ReadCardSerial())
// return;
tone(SPKR, 5500, 70);
delay(1500);
reading = false;
if (file.open(eeprom_read_byte(&storageIndex), O_APPEND | O_WRITE)) {
Time t = rtc.time();
char buf[21];
snprintf(buf, sizeof buf, "%04d-%02d-%02d %02d:%02d:%02d;", t.yr, t.mon, t.day, t.hr, t.min, t.sec);
file.print(buf);
for (byte i = 0; i < mfrc522.uid.size; i++) {
file.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
file.print(mfrc522.uid.uidByte[i], HEX);
}
file.println(";");
file.close();
}
// lcd.setCursor(0, 1);
// for (byte i = 0; i < mfrc522.uid.size; i++) {
// lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
// lcd.print(mfrc522.uid.uidByte[i], HEX);
// }
// lcd.clearRestOfLine();
//// Dump debug info about the card. PICC_HaltA() is automatically called.
// mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
}
delay(100);
}
ISR(PCINT1_vect) {
cursor = encoder.process();
if (cursor == DIR_CW)
currentMenuItem++;
else if (cursor == DIR_CCW)
currentMenuItem--;
}
void debounceInterrupt(void) {
if ((long) (micros() - lastDebounce) >= (long)DEBOUNCE * 1000) {
button = true;
lastDebounce = micros();
}
}
void RFIDInterrupt(void) {
if (!reading)
reading = true;
}
void error_P(const char* str) {
lcd.setCursor(1, 4);
lcd.print(PSTR("ERROR"));
PgmPrint("error: ");
SerialPrintln_P(str);
if (card.errorCode) {
PgmPrint("SD error: ");
Serial.println(card.errorCode, HEX);
}
while (1)
;
}
void navigateMenu(Menu *menu) {
if (menu->numSubmenus == 0) {
/* Execute the command */
lcd.clear();
menu->command();
return;
}
/* This is a menu, not a command, so show the menu and get the user's choice */
displayMenu(menu);
if (button) {
button = false;
menu = menu->submenu[currentMenuItem];
}
// menu = get_user_selection(menu);
navigateMenu(menu);
}
void displayMenu(Menu *menu) {
// uint8_t menuLenght = sizeof(menuItems) / sizeof(menuItems[0]);
if (currentMenuItem >= menu->numSubmenus)
currentMenuItem = 0;
else if (currentMenuItem < 0)
currentMenuItem = menu->numSubmenus - 1;
lcd.setCursor(0, 0);
uint8_t i = 0, offset = 0;
if (currentMenuItem >= PCD8544_LINES)
offset = currentMenuItem - PCD8544_LINES + 1;
for (i = offset; i < PCD8544_LINES + offset; i++) {
// clear rest of the menu screen if there are less items than LCD lines
if (i >= menu->numSubmenus) {
lcd.print(' ');
lcd.clearRestOfLine();
continue;
}
if (i == (uint8_t)currentMenuItem)
lcd.bitmap(icon_arrow, 1, 6);
else
lcd.print(' ');
lcd.print(menu->submenu[i]->title);
lcd.clearRestOfLine();
}
}
void list(void) {
cursor = DIR_CW;
while (!button) {
if (cursor) {
lcd.setCursor(0, 0);
dir_t d;
uint16_t i = 0;
boolean found = false;
uint8_t offset = 0;
if (currentMenuItem >= PCD8544_LINES)
offset = currentMenuItem - PCD8544_LINES + 1;
for (i = offset; Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID); i++) {
// if we are over the display, just seek the last file index
if (i >= (uint16_t)(PCD8544_LINES + offset))
continue;
if (i == (uint16_t) currentMenuItem) {
lcd.bitmap(icon_arrow, 1, 6);
found = true;
}
else
lcd.print(' ');
lcd.print(i);
lcd.print(':');
printDirName(d);
}
Serial.print("a: ");
if (!found) {
Serial.print("NOTfound, ");
if (cursor == DIR_CW) {
currentMenuItem++;
Serial.print("++");
} else if (cursor == DIR_CCW) {
currentMenuItem--;
Serial.print("--");
}
}
else
// this means that the screen will be refreshed
cursor = false;
if (currentMenuItem < 0) {
currentMenuItem = i - 1;
cursor = DIR_CCW;
Serial.print("i-1");
}
if ((uint16_t) currentMenuItem > i - 1) {
currentMenuItem = 0;
Serial.print("0");
cursor = DIR_CW;
}
Serial.print("; cmi: ");
Serial.print(currentMenuItem);
Serial.print(", li: ");
Serial.print(i);
Serial.print(", cursor: ");
Serial.print(cursor);
Serial.print(", button: ");
Serial.println(button);
}
}
Serial.println("Saved");
// save index of a file to store into to the EEPROM memory
eeprom_write_byte(&storageIndex, currentMenuItem);
button = false;
lcd.clear();
frontPage();
}
void addStorage(void) {
// file.writeError = false;
char buf[14];
for (unsigned short int i = 1; ; i++) {
snprintf(buf, sizeof buf, "file%d.csv", i);
if (file.open(buf, O_CREAT | O_WRITE | O_EXCL))
break;
}
file.close();
frontPage();
// snprintf(buf, sizeof buf, "FILE%d.CSV", 1);
}
void frontPage(void) {
// lcd.clear();
lcd.setCursor(0, 0);
// tone(SPKR, 5000, 50);
// USB plugged in
if (analogRead(STAT) < 512) {
lcd.bitmap(icon_usb, 1, 20);
}
// battery
else {
digitalWrite(VBAT_ADC_EN, LOW);
uint8_t vbat = (analogRead(VBAT_ADC) - 523) / 5;
if (vbat < 25)
lcd.bitmap(icon_battery_25, 1, 21);
else if (vbat < 50)
lcd.bitmap(icon_battery_50, 1, 21);
else if (vbat < 75)
lcd.bitmap(icon_battery_75, 1, 21);
else
lcd.bitmap(icon_battery_100, 1, 21);
digitalWrite(VBAT_ADC_EN, HIGH);
}
// Get the current time and date from the chip.
Time t = rtc.time();
char buf[24];
lcd.setCursor(9, 0);
snprintf(buf, sizeof(buf), "%02d:%02d", t.hr, t.min);
lcd.print(buf);
uint16_t i = eeprom_read_byte(&storageIndex);
dir_t d;
if (Fat16::readDir(&d, &i, DIR_ATT_VOLUME_ID)) {
lcd.setCursor(0, 2);
lcd.println("Saving to: ");
printDirName(d);
}
}
void printDirName(const dir_t& dir) {
uint8_t w = 0;
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')
continue;
if (i == 8) {
lcd.print('.');
w++;
}
lcd.print((char) dir.name[i]);
w++;
}
lcd.clearRestOfLine();
}
//
//void SayHello() {
// char *arg;
// arg = SCmd.next(); // Get the next argument from the SerialCommand object buffer
// if (arg != NULL) // As long as it existed, take it
// {
// Serial.print("Hello ");
// Serial.println(arg);
// } else {
// Serial.println("Hello, whoever you are");
// }
//}
//
//void process_command() {
// int aNumber;
// char *arg;
//
// Serial.println("We're in process_command");
// arg = SCmd.next();
// if (arg != NULL) {
// aNumber = atoi(arg); // Converts a char string to an integer
// Serial.print("First argument was: ");
// Serial.println(aNumber);
// } else {
// Serial.println("No arguments");
// }
//
// arg = SCmd.next();
// if (arg != NULL) {
// aNumber = atol(arg);
// Serial.print("Second argument was: ");
// Serial.println(aNumber);
// } else {
// Serial.println("No second argument");
// }
//
//}
void ls() {
Fat16::ls();
}
void touch() {
char *arg, fileName[14];
arg = SCmd.next();
snprintf(fileName, sizeof fileName, "%s.csv", arg);
PgmPrint("File '");
Serial.print(fileName);
if (!file.open(fileName, O_CREAT | O_WRITE))
PgmPrintln("' could not be created.");
else
PgmPrintln("' was created successfully");
}
void rm() {
char *arg, fileName[14];
arg = SCmd.next();
snprintf(fileName, sizeof fileName, "%s.csv", arg);
PgmPrint("File '");
Serial.print(fileName);
if (file.open(fileName, O_WRITE) && file.remove())
PgmPrintln("' was removed successfully");
else
PgmPrintln("' could not be removed.");
}
void mv() {
char *arg;
}
// This gets set as the default handler, and gets called when no other command matches.
void unrecognized() {
PgmPrintln("Unrecognized command. Possibilities are: ");
PgmPrintln("ls\t\t\t- display files");
PgmPrintln("touch FILE\t\t- create file FILE.csv");
Serial.println();
}

@ -0,0 +1,88 @@
// Only modify this file to include
// - function definitions (prototypes)
// - include files
// - extern variable definitions
// In the appropriate section
#ifndef Bakalarka_H_
#define Bakalarka_H_
#include "Arduino.h"
//add your includes for the project Bakalarka here
#include "PCD8544/PCD8544.h"
#include <Fat16.h>
//end of add your includes here
#ifdef __cplusplus
extern "C" {
#endif
void loop();
void setup();
#ifdef __cplusplus
} // extern "C"
#endif
//add your function definitions for the project Bakalarka here
// pins on ATmega328
#define RFID_IRQ 2
#define BTN 3
#define RFID_RST 4
#define DS_SCK 5
#define DS_IO 6
#define DS_RST 7
#define LCD_SS 8
#define SD_SS 9
#define RFID_SS 10
#define ENC_A A0
#define ENC_B A1
#define LCD_DC A2
#define LCD_RST A3
#define SPKR A4
#define VBAT_ADC_EN A5
#define VBAT_ADC A6
#define STAT A7
// config
#define DEBOUNCE 200
// function macros
//#define error(s) error_P(PSTR(s)) // store error strings in flash to save RAM
#define MAX_SUBMENUS 4
typedef struct menu {
const char title[PCD8544_COLS];
void (*command)();
uint8_t numSubmenus;
struct menu *submenu[MAX_SUBMENUS];
} Menu;
// prototypes
void debounceInterrupt(void);
void RFIDInterrupt(void);
void error_P(const char* str);
void frontPage(void);
void list(void);
void navigateMenu(Menu *menu);
void displayMenu(Menu *menu);
void addStorage(void);
void printDirName(const dir_t& dir);
//void SayHello(void);
//void process_command(void);
void ls(void);
void touch(void);
void rm(void);
void unrecognized(void);
//Do not add code below this line
#endif /* Bakalarka_H_ */

@ -0,0 +1,202 @@
#include "Arduino.h"
#include "DS1302.h"
Time::Time(const uint16_t yr, const uint8_t mon, const uint8_t date,
const uint8_t hr, const uint8_t min, const uint8_t sec,
const Day day) {
this->yr = yr;
this->mon = mon;
this->date = date;
this->hr = hr;
this->min = min;
this->sec = sec;
this->day = day;
}
DS1302::DS1302(const uint8_t ce_pin, const uint8_t io_pin,
const uint8_t sclk_pin) {
ce_pin_ = ce_pin;
io_pin_ = io_pin;
sclk_pin_ = sclk_pin;
pinMode(ce_pin, OUTPUT);
pinMode(sclk_pin, OUTPUT);
}
void DS1302::writeOut(const uint8_t value) {
pinMode(io_pin_, OUTPUT);
shiftOut(io_pin_, sclk_pin_, LSBFIRST, value);
}
uint8_t DS1302::readIn() {
uint8_t input_value = 0;
uint8_t bit = 0;
pinMode(io_pin_, INPUT);
for (int i = 0; i < 8; ++i) {
bit = digitalRead(io_pin_);
input_value |= (bit << i);
digitalWrite(sclk_pin_, HIGH);
delayMicroseconds(1);
digitalWrite(sclk_pin_, LOW);
}
return input_value;
}
uint8_t DS1302::registerBcdToDec(const Register reg, const uint8_t high_bit) {
const uint8_t mask = (1 << (high_bit + 1)) - 1;
uint8_t val = readRegister(reg);
val &= mask;
val = (val & 15) + 10 * ((val & (15 << 4)) >> 4);
return val;
}
uint8_t DS1302::registerBcdToDec(const Register reg) {
return registerBcdToDec(reg, 7);
}
void DS1302::registerDecToBcd(const Register reg, uint8_t value,
const uint8_t high_bit) {
const uint8_t mask = (1 << (high_bit + 1)) - 1;
uint8_t regv = readRegister(reg);
// Convert value to bcd in place.
uint8_t tvalue = value / 10;
value = value % 10;
value |= (tvalue << 4);
// Replace high bits of value if needed.
value &= mask;
value |= (regv &= ~mask);
writeRegister(reg, value);
}
void DS1302::registerDecToBcd(const Register reg, const uint8_t value) {
registerDecToBcd(reg, value, 7);
}
uint8_t DS1302::readRegister(const Register reg) {
uint8_t cmd_byte = 129; // 1000 0001
uint8_t reg_value;
cmd_byte |= (reg << 1);
digitalWrite(sclk_pin_, LOW);
digitalWrite(ce_pin_, HIGH);
writeOut(cmd_byte);
reg_value = readIn();
digitalWrite(ce_pin_, LOW);
return reg_value;
}
void DS1302::writeRegister(const Register reg, const uint8_t value) {
uint8_t cmd_byte = (128 | (reg << 1));
digitalWrite(sclk_pin_, LOW);
digitalWrite(ce_pin_, HIGH);
writeOut(cmd_byte);
writeOut(value);
digitalWrite(ce_pin_, LOW);
}
void DS1302::writeProtect(const bool enable) {
writeRegister(kWriteProtectReg, (enable << 7));
}
void DS1302::halt(const bool enable) {
uint8_t sec = readRegister(kSecondReg);
sec &= ~(1 << 7);
sec |= (enable << 7);
writeRegister(kSecondReg, sec);
}
uint8_t DS1302::seconds() {
return registerBcdToDec(kSecondReg, 6);
}
uint8_t DS1302::minutes() {
return registerBcdToDec(kMinuteReg);
}
uint8_t DS1302::hour() {
uint8_t hr = readRegister(kHourReg);
uint8_t adj;
if (hr & 128) // 12-hour mode
adj = 12 * ((hr & 32) >> 5);
else // 24-hour mode
adj = 10 * ((hr & (32 + 16)) >> 4);
hr = (hr & 15) + adj;
return hr;
}
uint8_t DS1302::date() {
return registerBcdToDec(kDateReg, 5);
}
uint8_t DS1302::month() {
return registerBcdToDec(kMonthReg, 4);
}
Time::Day DS1302::day() {
return static_cast<Time::Day>(registerBcdToDec(kDayReg, 2));
}
uint16_t DS1302::year() {
return 2000 + registerBcdToDec(kYearReg);
}
Time DS1302::time() {
return Time(year(), month(), date(),
hour(), minutes(), seconds(),
day());
}
void DS1302::seconds(const uint8_t sec) {
registerDecToBcd(kSecondReg, sec, 6);
}
void DS1302::minutes(const uint8_t min) {
registerDecToBcd(kMinuteReg, min, 6);
}
void DS1302::hour(const uint8_t hr) {
writeRegister(kHourReg, 0); // set 24-hour mode
registerDecToBcd(kHourReg, hr, 5);
}
void DS1302::date(const uint8_t date) {
registerDecToBcd(kDateReg, date, 5);
}
void DS1302::month(const uint8_t mon) {
registerDecToBcd(kMonthReg, mon, 4);
}
void DS1302::day(const Time::Day day) {
registerDecToBcd(kDayReg, static_cast<int>(day), 2);
}
void DS1302::year(uint16_t yr) {
yr -= 2000;
registerDecToBcd(kYearReg, yr);
}
void DS1302::time(const Time t) {
seconds(t.sec);
minutes(t.min);
hour(t.hr);
date(t.date);
month(t.mon);
day(t.day);
year(t.yr);
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,329 @@
/**
* MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT.
* Based on code Dr.Leong ( WWW.B2CQSHOP.COM )
* Created by Miguel Balboa (circuitito.com), Jan, 2012.
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.)
* Released into the public domain.
*
* Please read this file for an overview and then MFRC522.cpp for comments on the specific functions.
* Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board.
*
* There are three hardware components involved:
* 1) The micro controller: An Arduino
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
* 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
*
* The microcontroller and card reader uses SPI for communication.
* The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf
*
* The card reader and the tags communicate using a 13.56MHz electromagnetic field.
* The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision".
* A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
* Details are found in chapter 6, Type A Initialization and anticollision.
*
* If only the PICC UID is wanted, the above documents has all the needed information.
* To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected.
* The MIFARE Classic chips and protocol is described in the datasheets:
* 1K: http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
* 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.pdf
* Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf
* The MIFARE Ultralight chip and protocol is described in the datasheets:
* Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
* Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf
*
* MIFARE Classic 1K (MF1S503x):
* Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes.
* The blocks are numbered 0-63.
* Block 3 in each sector is the Sector Trailer. See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7:
* Bytes 0-5: Key A
* Bytes 6-8: Access Bits
* Bytes 9: User data
* Bytes 10-15: Key B (or user data)
* Block 0 is read only manufacturer data.
* To access a block, an authentication using a key from the block's sector must be performed first.
* Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11).
* All keys are set to FFFFFFFFFFFFh at chip delivery.
* Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked.
* To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns.
* MIFARE Classic 4K (MF1S703x):
* Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes.
* The blocks are numbered 0-255.
* The last block in each sector is the Sector Trailer like above.
* MIFARE Classic Mini (MF1 IC S20):
* Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes.
* The blocks are numbered 0-19.
* The last block in each sector is the Sector Trailer like above.
*
* MIFARE Ultralight (MF0ICU1):
* Has 16 pages of 4 bytes = 64 bytes.
* Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
* Pages 4-15 are read/write unless blocked by the lock bytes in page 2.
* MIFARE Ultralight C (MF0ICU2):
* Has 48 pages of 4 bytes = 64 bytes.
* Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
* Pages 4-39 are read/write unless blocked by the lock bytes in page 2.
* Page 40 Lock bytes
* Page 41 16 bit one way counter
* Pages 42-43 Authentication configuration
* Pages 44-47 Authentication key
*/
#ifndef MFRC522_h
#define MFRC522_h
#include <Arduino.h>
#include "../SPI/SPI.h"
class MFRC522 {
public:
// MFRC522 registers. Described in chapter 9 of the datasheet.
// When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3)
enum PCD_Register {
// Page 0: Command and status
// 0x00 // reserved for future use
CommandReg = 0x01 << 1, // starts and stops command execution
ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits
DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits
ComIrqReg = 0x04 << 1, // interrupt request bits
DivIrqReg = 0x05 << 1, // interrupt request bits
ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed
Status1Reg = 0x07 << 1, // communication status bits
Status2Reg = 0x08 << 1, // receiver and transmitter status bits
FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer
FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer
WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning
ControlReg = 0x0C << 1, // miscellaneous control registers
BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames
CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface
// 0x0F // reserved for future use
// Page 1:Command
// 0x10 // reserved for future use
ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving
TxModeReg = 0x12 << 1, // defines transmission data rate and framing
RxModeReg = 0x13 << 1, // defines reception data rate and framing
TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2
TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation
TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver
RxSelReg = 0x17 << 1, // selects internal receiver settings
RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder
DemodReg = 0x19 << 1, // defines demodulator settings
// 0x1A // reserved for future use
// 0x1B // reserved for future use
MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters
MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters
// 0x1E // reserved for future use
SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface
// Page 2: Configuration
// 0x20 // reserved for future use
CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation
CRCResultRegL = 0x22 << 1,
// 0x23 // reserved for future use
ModWidthReg = 0x24 << 1, // controls the ModWidth setting?
// 0x25 // reserved for future use
RFCfgReg = 0x26 << 1, // configures the receiver gain
GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation
ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation
TModeReg = 0x2A << 1, // defines settings for the internal timer
TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value
TReloadRegL = 0x2D << 1,
TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value
TCounterValueRegL = 0x2F << 1,
// Page 3:Test Registers
// 0x30 // reserved for future use
TestSel1Reg = 0x31 << 1, // general test signal configuration
TestSel2Reg = 0x32 << 1, // general test signal configuration
TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7
TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus
TestBusReg = 0x35 << 1, // shows the status of the internal test bus
AutoTestReg = 0x36 << 1, // controls the digital self test
VersionReg = 0x37 << 1, // shows the software version
AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2
TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1
TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2
TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels
// 0x3C // reserved for production tests
// 0x3D // reserved for production tests
// 0x3E // reserved for production tests
// 0x3F // reserved for production tests
};
// MFRC522 comands. Described in chapter 10 of the datasheet.
enum PCD_Command {
PCD_Idle = 0x00, // no action, cancels current command execution
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
PCD_Receive = 0x08, // activates the receiver circuits
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
PCD_SoftReset = 0x0F // resets the MFRC522
};
// Commands sent to the PICC.
enum PICC_Command {
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision.
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 1
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
// The read/write commands can also be used for MIFARE Ultralight.
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
};
// MIFARE constants that does not fit anywhere else
enum MIFARE_Misc {
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
};
// PICC types we can detect. Remember to update PICC_GetTypeName() if you add more.
enum PICC_Type {
PICC_TYPE_UNKNOWN = 0,
PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4
PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC)
PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes
PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB
PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB
PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C
PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus
PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete.
};
// Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more.
enum StatusCode {
STATUS_OK = 1, // Success
STATUS_ERROR = 2, // Error in communication
STATUS_COLLISION = 3, // Collission detected
STATUS_TIMEOUT = 4, // Timeout in communication.
STATUS_NO_ROOM = 5, // A buffer is not big enough.
STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-)
STATUS_INVALID = 7, // Invalid argument.
STATUS_CRC_WRONG = 8, // The CRC_A does not match
STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK.
};
// A struct used for passing the UID of a PICC.
typedef struct {
byte size; // Number of bytes in the UID. 4, 7 or 10.
byte uidByte[10];
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;
// A struct used for passing a MIFARE Crypto1 key
typedef struct {
byte keyByte[MF_KEY_SIZE];
} MIFARE_Key;
// Member variables
Uid uid; // Used by PICC_ReadCardSerial().
// Size of the MFRC522 FIFO
static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
/////////////////////////////////////////////////////////////////////////////////////
MFRC522(byte chipSelectPin, byte resetPowerDownPin);
void setSPIConfig();
/////////////////////////////////////////////////////////////////////////////////////
// Basic interface functions for communicating with the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_WriteRegister(byte reg, byte value);
void PCD_WriteRegister(byte reg, byte count, byte *values);
byte PCD_ReadRegister(byte reg);
void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0);
void setBitMask(unsigned char reg, unsigned char mask);
void PCD_SetRegisterBitMask(byte reg, byte mask);
void PCD_ClearRegisterBitMask(byte reg, byte mask);
byte PCD_CalculateCRC(byte *data, byte length, byte *result);
/////////////////////////////////////////////////////////////////////////////////////
// Functions for manipulating the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_Init();
void PCD_Reset();
void PCD_AntennaOn();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
byte PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
byte PICC_RequestA(byte *bufferATQA, byte *bufferSize);
byte PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
byte PICC_REQA_or_WUPA( byte command, byte *bufferATQA, byte *bufferSize);
byte PICC_Select(Uid *uid, byte validBits = 0);
byte PICC_HaltA();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid);
void PCD_StopCrypto1();
byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
byte MIFARE_Decrement(byte blockAddr, long delta);
byte MIFARE_Increment(byte blockAddr, long delta);
byte MIFARE_Restore(byte blockAddr);
byte MIFARE_Transfer(byte blockAddr);
byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
/////////////////////////////////////////////////////////////////////////////////////
// Support functions
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_MIFARE_Transceive( byte *sendData, byte sendLen, bool acceptTimeout = false);
const char *GetStatusCodeName(byte code);
byte PICC_GetType(byte sak);
const char *PICC_GetTypeName(byte type);
void PICC_DumpToSerial(Uid *uid);
void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
void PICC_DumpMifareUltralightToSerial();
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
bool PICC_IsNewCardPresent();
bool PICC_ReadCardSerial();
/////////////////////////////////////////////////////////////////////////////////////
// User functions
/////////////////////////////////////////////////////////////////////////////////////
// void MFRC522::UID_to_lcd(Uid *uid);
private:
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low)
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data);
};
#endif

@ -0,0 +1,334 @@
#include <stdint.h>
#include "PCD8544.h"
#include <pins_arduino.h>
#include <avr/pgmspace.h>
// LCD commands, Table 1, page 14
#define PCD8544_FUNCTION_SET (1<<5)
#define PCD8544_FUNCTION_PD (1<<2)
#define PCD8544_FUNCTION_V (1<<1)
#define PCD8544_FUNCTION_H (1<<0)
// Normal instructions, H = 0
#define PCD8544_DISPLAY_CONTROL (1<<3)
#define PCD8544_DISPLAY_CONTROL_D (1<<2)
#define PCD8544_DISPLAY_CONTROL_E (1<<0)
#define PCD8544_DISPLAY_CONTROL_BLANK 0
#define PCD8544_DISPLAY_CONTROL_NORMAL_MODE PCD8544_DISPLAY_CONTROL_D
#define PCD8544_DISPLAY_CONTROL_ALL_ON PCD8544_DISPLAY_CONTROL_E
#define PCD8544_DISPLAY_CONTROL_INVERSE (PCD8544_DISPLAY_CONTROL_D|PCD8544_DISPLAY_CONTROL_E)
#define PCD8544_SET_Y_ADDRESS (1<<6)
#define PCD8544_Y_ADRESS_MASK 0b111
#define PCD8544_SET_X_ADDRESS (1<<7)
#define PCD8544_X_ADRESS_MASK 0b01111111
// Extended instructions. H = 1
#define PCD8544_TEMP_CONTROL (1<<2)
#define PCD8544_TEMP_TC1 (1<<1)
#define PCD8544_TEMP_TC0 (1<<0)
#define PCD8544_BIAS (1<<4)
#define PCD8544_BIAS_BS2 (1<<2)
#define PCD8544_BIAS_BS1 (1<<1)
#define PCD8544_BIAS_BS0 (1<<0)
#define PCD8544_VOP (1<<7)
const unsigned char PROGMEM small_num[][4] = {
{0x0e,0x15,0x0e,0x00}, // 48, zero
{0x12,0x1f,0x10,0x00}, // 49, one
{0x12,0x19,0x16,0x00}, // 50, two
{0x11,0x15,0x0b,0x00}, // 51, three
{0x07,0x04,0x1f,0x00}, // 52, four
{0x17,0x15,0x09,0x00}, // 53, five
{0x0e,0x15,0x09,0x00}, // 54, six
{0x19,0x05,0x03,0x00}, // 55, seven
{0x1a,0x15,0x0b,0x00}, // 56, eight
{0x12,0x15,0x0e,0x00}, // 57, nine
{0x00,0x10,0x00,0x00}, // 46, period
};
const unsigned char PROGMEM font6x8 [][5] = {
{0x00,0x00,0x00,0x00,0x00,}, // ' ' 32
{0x00,0x00,0x5F,0x00,0x00,}, // '!' 33
{0x00,0x07,0x00,0x07,0x00,}, // '"' 34
{0x14,0x7F,0x14,0x7F,0x14,}, // '#' 35
{0x24,0x2A,0x7F,0x2A,0x12,}, // '$' 36
{0x23,0x13,0x08,0x64,0x62,}, // '%' 37
{0x36,0x49,0x55,0x22,0x50,}, // '&' 38
{0x00,0x05,0x03,0x00,0x00,}, // ''' 39
{0x00,0x1C,0x22,0x41,0x00,}, // '(' 40
{0x00,0x41,0x22,0x1C,0x00,}, // ')' 41
{0x14,0x08,0x3E,0x08,0x14,}, // '*' 42
{0x08,0x08,0x3E,0x08,0x08,}, // '+' 43
{0x00,0x50,0x30,0x00,0x00,}, // ',' 44
{0x08,0x08,0x08,0x08,0x08,}, // '-' 45
{0x00,0x60,0x60,0x00,0x00,}, // '.' 46
{0x20,0x10,0x08,0x04,0x02,}, // '/' 47
{0x3E,0x51,0x49,0x45,0x3E,}, // '0' 48
{0x00,0x42,0x7F,0x40,0x00,}, // '1' 49
{0x42,0x61,0x51,0x49,0x46,}, // '2' 50
{0x21,0x41,0x45,0x4B,0x31,}, // '3' 51
{0x18,0x14,0x12,0x7F,0x10,}, // '4' 52
{0x27,0x45,0x45,0x45,0x39,}, // '5' 53
{0x3C,0x4A,0x49,0x49,0x30,}, // '6' 54
{0x03,0x01,0x71,0x09,0x07,}, // '7' 55
{0x36,0x49,0x49,0x49,0x36,}, // '8' 56
{0x06,0x49,0x49,0x29,0x16,}, // '9' 57
{0x00,0x36,0x36,0x00,0x00,}, // ':' 58
{0x00,0x56,0x36,0x00,0x00,}, // ';' 59
{0x08,0x14,0x22,0x41,0x00,}, // '<' 60
{0x14,0x14,0x14,0x14,0x14,}, // '=' 61
{0x00,0x41,0x22,0x14,0x08,}, // '>' 62
{0x02,0x01,0x51,0x09,0x06,}, // '?' 63
{0x32,0x49,0x79,0x41,0x3E,}, // '@' 64
{0x7E,0x11,0x11,0x11,0x7E,}, // 'A' 65
{0x7F,0x49,0x49,0x49,0x36,}, // 'B' 66
{0x3E,0x41,0x41,0x41,0x22,}, // 'C' 67
{0x7F,0x41,0x41,0x22,0x1C,}, // 'D' 68
{0x7F,0x49,0x49,0x49,0x41,}, // 'E' 69
{0x7F,0x09,0x09,0x01,0x01,}, // 'F' 70
{0x3E,0x41,0x49,0x49,0x3A,}, // 'G' 71
{0x7F,0x08,0x08,0x08,0x7F,}, // 'H' 72
{0x00,0x41,0x7F,0x41,0x00,}, // 'I' 73
{0x20,0x41,0x41,0x3F,0x01,}, // 'J' 74
{0x7F,0x08,0x14,0x22,0x41,}, // 'K' 75
{0x7F,0x40,0x40,0x40,0x40,}, // 'L' 76
{0x7F,0x02,0x0C,0x02,0x7F,}, // 'M' 77
{0x7F,0x04,0x08,0x10,0x7F,}, // 'N' 78
{0x3E,0x41,0x41,0x41,0x3E,}, // 'O' 79
{0x7F,0x09,0x09,0x09,0x06,}, // 'P' 80
{0x3E,0x41,0x51,0x21,0x5E,}, // 'Q' 81
{0x7F,0x09,0x19,0x29,0x46,}, // 'R' 82
{0x26,0x49,0x49,0x49,0x32,}, // 'S' 83
{0x01,0x01,0x7F,0x01,0x01,}, // 'T' 84
{0x3F,0x40,0x40,0x40,0x3F,}, // 'U' 85
{0x1F,0x20,0x40,0x20,0x1F,}, // 'V' 86
{0x3F,0x40,0x38,0x40,0x3F,}, // 'W' 87
{0x63,0x14,0x08,0x14,0x63,}, // 'X' 88
{0x07,0x08,0x70,0x08,0x07,}, // 'Y' 89
{0x61,0x51,0x49,0x45,0x43,}, // 'Z' 90
{0x00,0x7F,0x41,0x41,0x00,}, // '[' 91
{0x02,0x04,0x08,0x10,0x20,}, // '\' 92
{0x00,0x41,0x41,0x7F,0x00,}, // ']' 93
{0x04,0x02,0x01,0x02,0x04,}, // '^' 94
{0x40,0x40,0x40,0x40,0x40,}, // '_' 95
{0x00,0x01,0x02,0x04,0x00,}, // '`' 96
{0x20,0x54,0x54,0x54,0x78,}, // 'a' 97
{0x7F,0x48,0x44,0x44,0x38,}, // 'b' 98
{0x38,0x44,0x44,0x44,0x20,}, // 'c' 99
{0x38,0x44,0x44,0x48,0x3F,}, // 'd' 100
{0x38,0x54,0x54,0x54,0x18,}, // 'e' 101
{0x08,0x7E,0x09,0x01,0x02,}, // 'f' 102
{0x0C,0x52,0x52,0x52,0x3E,}, // 'g' 103
{0x7F,0x08,0x04,0x04,0x78,}, // 'h' 104
{0x00,0x44,0x7D,0x40,0x00,}, // 'i' 105
{0x20,0x40,0x45,0x3C,0x00,}, // 'j' 106
{0x7F,0x10,0x28,0x44,0x00,}, // 'k' 107
{0x00,0x41,0x7F,0x40,0x00,}, // 'l' 108
{0x7C,0x04,0x18,0x04,0x78,}, // 'm' 109
{0x7C,0x08,0x04,0x04,0x78,}, // 'n' 110
{0x38,0x44,0x44,0x44,0x38,}, // 'o' 111
{0x7C,0x14,0x14,0x14,0x08,}, // 'p' 112
{0x08,0x14,0x14,0x18,0x7C,}, // 'q' 113
{0x7C,0x08,0x04,0x04,0x08,}, // 'r' 114
{0x48,0x54,0x54,0x54,0x20,}, // 's' 115
{0x04,0x3F,0x44,0x40,0x20,}, // 't' 116
{0x3C,0x40,0x40,0x20,0x7C,}, // 'u' 117
{0x1C,0x20,0x40,0x20,0x1C,}, // 'v' 118
{0x3C,0x40,0x30,0x40,0x3C,}, // 'w' 119
{0x44,0x28,0x10,0x28,0x44,}, // 'x' 120
{0x0C,0x50,0x50,0x50,0x3C,}, // 'y' 121
{0x44,0x64,0x54,0x4C,0x44,}, // 'z' 122
{0x00,0x08,0x36,0x41,0x00,}, // '{' 123
{0x00,0x00,0x7F,0x00,0x00,}, // '|' 124
{0x00,0x41,0x36,0x08,0x00,}, // '}' 125
{0x10,0x08,0x08,0x10,0x08,}, // '~' 126
{0x08,0x1C,0x2A,0x08,0x08,} // <- 127
};
PCD8544::PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t hardware_spi)
{
dc = dc_pin;
cs = cs_pin;
reset = reset_pin;
hardware_spi_num = hardware_spi;
if (hardware_spi_num > 2)
hardware_spi_num = 2;
#ifndef MAPLE
sdin = MOSI;
sclk = SCK;
#else
sdin = 11; // Change to maple names
sclk = 13;
if (hardware_spi_num == 2) {
sdin = 32;
sclk = 34;
}
#endif
}
PCD8544::PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t sdin_pin, uint8_t sclk_pin)
{
dc = dc_pin;
cs = cs_pin;
reset = reset_pin;
sdin = sdin_pin;
sclk = sclk_pin;
hardware_spi_num = 0;
}
void PCD8544::begin(void)
{
pinMode(cs, OUTPUT);
pinMode(reset, OUTPUT);
pinMode(dc, OUTPUT);
pinMode(sdin, OUTPUT);
pinMode(sclk, OUTPUT);
if (hardware_spi_num > 0) {
pinMode(SS, OUTPUT); // To ensure master mode
SPCR |= (1<<SPE) | (1<<MSTR);
}
digitalWrite(reset, LOW);
delay(1);
digitalWrite(reset, HIGH);
// Extenden instructions and !powerdown
// and horizontal adressing (autoincrement of x-adress)
command(PCD8544_FUNCTION_SET | PCD8544_FUNCTION_H);
// Set Vop to 0x3F
command(PCD8544_VOP | 0xBF);
// Vlcd temp. coeff. 0
command(PCD8544_TEMP_CONTROL);
// Bias system 4, 1:48
command(PCD8544_BIAS | PCD8544_BIAS_BS1 | PCD8544_BIAS_BS0);
// Set H = 0 for normal instructions
command(PCD8544_FUNCTION_SET);
// Normal mode
command(PCD8544_DISPLAY_CONTROL | PCD8544_DISPLAY_CONTROL_NORMAL_MODE);
}
void PCD8544::clear(void)
{
int i;
for (i = 0; i < PCD8544_WIDTH*PCD8544_LINES; i++)
data(0);
}
WRITE_RESULT PCD8544::write(uint8_t ch)
{
uint8_t i;
if (ch == '\r')
gotoRc(current_row, 0);
if (ch == '\n')
gotoRc(current_row+1, current_column);
if (ch >= ' ' && ch <= 127) {
for (i = 0; i < 5; i++)
data(pgm_read_byte(&font6x8[ch-' '][i]) <<1);
data(0);
}
WRITE_RETURN;
}
//void PCD8544::toggle_invert(void) {
// invert_line = !invert_line;
//}
void PCD8544::data(uint8_t data) {
// if (invert_line)
// send(1, ~data);
// else
send(1, data);
}
void PCD8544::command(uint8_t data)
{
send(0, data);
}
void PCD8544::send(uint8_t data_or_command, uint8_t data)
{
digitalWrite(dc, data_or_command);
digitalWrite(cs, LOW);
if (hardware_spi_num == 0) {
shiftOut(sdin, sclk, MSBFIRST, data);
} else {
SPDR = data;
while(!(SPSR & (1<<SPIF))) ;
}
digitalWrite(cs, HIGH);
if(data_or_command)
inc_row_column();
}
void PCD8544::setCursor(uint8_t column, uint8_t row)
{
gotoRc(row, 6*column);
}
void PCD8544::gotoRc(uint8_t row, uint8_t column)
{
if (row >= PCD8544_LINES)
row %= PCD8544_LINES;
if (column >= PCD8544_WIDTH)
row %= PCD8544_WIDTH;
command(PCD8544_SET_X_ADDRESS | column);
command(PCD8544_SET_Y_ADDRESS | row);
current_row = row;
current_column = column;
}
void PCD8544::inc_row_column(void)
{
if (++current_column >= PCD8544_WIDTH) {
current_column = 0;
if (++current_row >= PCD8544_LINES)
current_row = 0;
}
// invert_line = false;
}
void PCD8544::smallNum(uint8_t num, uint8_t shift)
{
uint8_t i;
for (i = 0; i < 4; i++)
data(pgm_read_byte(&small_num[num][i])<<shift);
}
void PCD8544::clearRestOfLine(void)
{
while (current_column != 0)
data(0);
}
void PCD8544::bitmap(const byte bdata[], uint8_t rows, uint8_t columns)
{
uint8_t row, column, i;
uint8_t toprow = current_row;
uint8_t startcolumn = current_column;
for (row = 0, i = 0; row < rows; row++) {
gotoRc(row+toprow, startcolumn);
for (column = 0; column < columns; column++) {
data(pgm_read_byte(&bdata[i++]));
}
}
}

@ -0,0 +1,78 @@
#ifndef PCD8544_H
#define PCD8544_H
#include <stdint.h>
#include <Print.h>
#include <Arduino.h> // Arduino 1.0
#define WRITE_RESULT size_t
#define WRITE_RETURN return 1;
//#ifndef __AVR-GCC__
//#define MAPLE 1
//
//#ifndef SPI_NUM
//#define SPI_NUM 1
//#endif
//#endif
class PCD8544 : public Print {
public:
// Constructor for harware SPI
PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t hardware_spi = 1);
// Constructor for software SPI.
PCD8544(uint8_t dc_pin, uint8_t reset_pin, uint8_t cs_pin, uint8_t sdin_pin, uint8_t sclk_pin);
// Call this first
void begin(void);
// Clear lcd without changing location
void clear(void);
// Change current position to (character) column and row
void setCursor(uint8_t column, uint8_t row);
// Change current location to 0 <= row <= 5,
// 0 <= pixel_column <= 83
void gotoRc(uint8_t row, uint8_t pixel_column);
// Send data to lcd. Will draw data as one pixel wide, 8 pixel high.
// LSB up.
void data(uint8_t data);
// Small numbers. 0<= num <=9 for number and num = 10 for decimal
// point. Optional parameter shift will move the numbers up/down.
// shift shold be 0,1,2,3 for the digit to be visible.
void smallNum(uint8_t num, uint8_t shift = 1);
void clearRestOfLine(void);
void bitmap(const byte *data, uint8_t rows, uint8_t columns);
// void toggle_invert(void);
private:
void send(uint8_t dc, uint8_t data);
void command(uint8_t data);
virtual WRITE_RESULT write(uint8_t ch);
void inc_row_column(void);
uint8_t dc;
uint8_t cs;
uint8_t reset;
uint8_t hardware_spi_num;
uint8_t sdin;
uint8_t sclk;
uint8_t current_row, current_column;
uint8_t invert_line;
};
#define PCD8544_LINES 6
#define PCD8544_COLS 14
#define PCD8544_WIDTH 84
#define PCD8544_HEIGHT 48
#endif

@ -0,0 +1,24 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../DS1302/DS1302.cpp
OBJS += \
./DS1302/DS1302.o
CPP_DEPS += \
./DS1302/DS1302.d
# Each subdirectory must supply rules for building sources it contributes
DS1302/%.o: ../DS1302/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,24 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../MFRC522/MFRC522.cpp
OBJS += \
./MFRC522/MFRC522.o
CPP_DEPS += \
./MFRC522/MFRC522.d
# Each subdirectory must supply rules for building sources it contributes
MFRC522/%.o: ../MFRC522/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,24 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../PCD8544/PCD8544.cpp
OBJS += \
./PCD8544/PCD8544.o
CPP_DEPS += \
./PCD8544/PCD8544.d
# Each subdirectory must supply rules for building sources it contributes
PCD8544/%.o: ../PCD8544/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,27 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../SD/File.cpp \
../SD/SD.cpp
OBJS += \
./SD/File.o \
./SD/SD.o
CPP_DEPS += \
./SD/File.d \
./SD/SD.d
# Each subdirectory must supply rules for building sources it contributes
SD/%.o: ../SD/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/usr/share/arduino/hardware/arduino/cores/arduino" -I"/home/delmadord/dev/arduino/Bakalarka/SD/utility" -I"/usr/share/arduino/hardware/arduino/variants/standard" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO=1:105+dfsg2-1 -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,30 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../SD/utility/Sd2Card.cpp \
../SD/utility/SdFile.cpp \
../SD/utility/SdVolume.cpp
OBJS += \
./SD/utility/Sd2Card.o \
./SD/utility/SdFile.o \
./SD/utility/SdVolume.o
CPP_DEPS += \
./SD/utility/Sd2Card.d \
./SD/utility/SdFile.d \
./SD/utility/SdVolume.d
# Each subdirectory must supply rules for building sources it contributes
SD/utility/%.o: ../SD/utility/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/usr/share/arduino/hardware/arduino/cores/arduino" -I"/home/delmadord/dev/arduino/Bakalarka/SD/utility" -I"/usr/share/arduino/hardware/arduino/variants/standard" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO=1:105+dfsg2-1 -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -mmcu=atmega328p -DF_CPU=16000000UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,27 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../SDFAT16/Fat16.cpp \
../SDFAT16/SdCard.cpp
OBJS += \
./SDFAT16/Fat16.o \
./SDFAT16/SdCard.o
CPP_DEPS += \
./SDFAT16/Fat16.d \
./SDFAT16/SdCard.d
# Each subdirectory must supply rules for building sources it contributes
SDFAT16/%.o: ../SDFAT16/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,24 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../SPI/SPI.cpp
OBJS += \
./SPI/SPI.o
CPP_DEPS += \
./SPI/SPI.d
# Each subdirectory must supply rules for building sources it contributes
SPI/%.o: ../SPI/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,24 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../SerialCommand/SerialCommand.cpp
OBJS += \
./SerialCommand/SerialCommand.o
CPP_DEPS += \
./SerialCommand/SerialCommand.d
# Each subdirectory must supply rules for building sources it contributes
SerialCommand/%.o: ../SerialCommand/%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,27 @@
################################################################################
# Automatically-generated file. Do not edit!
################################################################################
# Add inputs and outputs from these tool invocations to the build variables
CPP_SRCS += \
../Bakalarka.cpp \
../rotary.cpp
OBJS += \
./Bakalarka.o \
./rotary.o
CPP_DEPS += \
./Bakalarka.d \
./rotary.d
# Each subdirectory must supply rules for building sources it contributes
%.o: ../%.cpp
@echo 'Building file: $<'
@echo 'Invoking: AVR C++ Compiler'
avr-g++ -I"/home/delmadord/dev/arduino" -I"/home/delmadord/dev/arduino/Bakalarka" -D__IN_ECLIPSE__=1 -DUSB_VID= -DUSB_PID= -DARDUINO= -Wall -Os -ffunction-sections -fdata-sections -fno-exceptions -g -DF_CPU=0UL -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -c -o "$@" -x c++ "$<"
@echo 'Finished building: $<'
@echo ' '

@ -0,0 +1,38 @@
/* Arduino FAT16 Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino FAT16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
* \file
* Configuration file
*/
#ifndef Fat16Config_h
#define Fat16Config_h
/**
* Allow use of deprecated functions if non-zero
*/
#define ALLOW_DEPRECATED_FUNCTIONS 1
/**
* SdCard::writeBlock will protect block zero if set non-zero
*/
#define SD_PROTECT_BLOCK_ZERO 1
/**
* Set non-zero to allow access to Fat16 internals by cardInfo debug sketch
*/
#define FAT16_DEBUG_SUPPORT 1
#endif // Fat16Config_h

@ -0,0 +1,208 @@
/* Arduino FAT16 Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino FAT16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
/**
\mainpage Arduino Fat16 Library
<CENTER>Copyright &copy; 2008 by William Greiman
</CENTER>
\section Intro Introduction
The Arduino Fat16 Library is a minimal implementation of the FAT16 file system
on standard SD flash memory cards. Fat16 supports read, write, file
creation, deletion, and truncation.
The Fat16 class only supports access to files in the root directory and only
supports short 8.3 names. Directory time and date fields for creation
and modification can be maintained by providing a date/time callback
function \link Fat16::dateTimeCallback() dateTimeCallback()\endlink
or calling \link Fat16::timestamp() timestamp()\endlink.
Fat16 was designed to use the Arduino Print class which
allows files to be written with \link Print::print() print() \endlink and
\link Print::println() println()\endlink.
\section comment Bugs and Comments
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
\section SDcard SD Cards
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
most consumer devices use the 4-bit parallel SD protocol. A card that
functions well on A PC or Mac may not work well on the Arduino.
Most cards have good SPI read performance but cards vary widely in SPI
write performance. Write performance is limited by how efficiently the
card manages internal erase/remapping operations. The Arduino cannot
optimize writes to reduce erase operations because of its limit RAM.
SanDisk cards generally have good write performance. They seem to have
more internal RAM buffering than other cards and therefore can limit
the number of flash erase operations that the Arduino forces due to its
limited RAM.
Some Dane-Elec cards have a write speed that is only 20% as fast as
a good SanDisk card.
\section Hardware Hardware Configuration
Fat16 was developed using an <A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
<A HREF = "http://ladyada.net/make/gpsshield/modules.html"> GPS Shield</A>.
The hardware interface to the SD card should not use a resistor based level
shifter. SdCard::init() sets the SPI bus frequency to 8 MHz which results in
signal rise times that are too slow for the edge detectors in many newer SD card
controllers when resistor voltage dividers are used.
The 5 to 3.3 V level shifter for 5 V arduinos should be IC based like the
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
74LCX245.
If you are using a resistor based level shifter and are having problems try
setting the SPI bus frequency to 4 MHz. This can be done by using
card.init(true) to initialize the SD card.
\section Fat16Class Fat16 Usage
The class Fat16 is a minimal implementation of FAT16 on standard SD cards.
High Capacity SD cards, SDHC, are not supported. It should work on all
standard cards from 8MB to 2GB formatted with a FAT16 file system.
\note
The Arduino Print class uses character
at a time writes so it was necessary to use a \link Fat16::sync() sync() \endlink
function to control when data is written to the SD card.
\par
An application which writes to a file using \link Print::print() print()\endlink,
\link Print::println() println() \endlink
or \link Fat16::write write() \endlink must call \link Fat16::sync() sync() \endlink
at the appropriate time to force data and directory information to be written
to the SD Card. Data and directory information are also written to the SD card
when \link Fat16::close() close() \endlink is called.
\par
Applications must use care calling \link Fat16::sync() sync() \endlink
since 2048 bytes of I/O is required to update file and
directory information. This includes writing the current data block, reading
the block that contains the directory entry for update, writing the directory
block back and reading back the current data block.
Fat16 only supports access to files in the root directory and only supports
short 8.3 names.
It is possible to open a file with two or more instances of Fat16. A file may
be corrupted if data is written to the file by more than one instance of Fat16.
Short names are limited to 8 characters followed by an optional period (.)
and extension of up to 3 characters. The characters may be any combination
of letters and digits. The following special characters are also allowed:
$ % ' - _ @ ~ ` ! ( ) { } ^ # &
Short names are always converted to upper case and their original case
value is lost.
Fat16 uses a slightly restricted form of short names.
Only printable ASCII characters are supported. No characters with code point
values greater than 127 are allowed. Space is not allowed even though space
was allowed in the API of early versions of DOS.
Fat16 has been optimized for The Arduino ATmega168. Minimizing RAM use is the
highest priority goal followed by flash use and finally performance.
Most SD cards only support 512 byte block write operations so a 512 byte
cache buffer is used by Fat16. This is the main use of RAM. A small
amount of RAM is used to store key volume and file information.
Flash memory usage can be controlled by selecting options in Fat16Config.h.
\section HowTo How to format SD Cards as FAT16 Volumes
Microsoft operating systems support removable media formatted with a
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
in block zero.
Microsoft operating systems expect MBR formatted removable media
to have only one partition. The first partition should be used.
Microsoft operating systems do not support partitioning SD flash cards.
If you erase an SD card with a program like KillDisk, Most versions of
Windows will format the card as a super floppy.
The best way to restore an SD card's MBR is to use SDFormatter
which can be downloaded from:
http://www.sdcard.org/consumers/formatter/
SDFormatter does not have an option for FAT type so it may format
small cards as FAT12.
After the MBR is restored by SDFormatter you may need to reformat small
cards that have been formatted FAT12 to force the volume type to be FAT16.
The FAT type, FAT12, FAT16, or FAT32, is determined by the count
of clusters on the volume and nothing else.
Microsoft published the following code for determining FAT type:
\code
if (CountOfClusters < 4085) {
// Volume is FAT12
}
else if (CountOfClusters < 65525) {
// Volume is FAT16
}
else {
// Volume is FAT32
}
\endcode
If you format a FAT volume with an OS utility , choose a cluster size that
will result in:
4084 < CountOfClusters && CountOfClusters < 65525
The volume will then be FAT16.
If you are formatting an SD card on OS X or Linux, be sure to use the first
partition. Format this partition with a cluster count in above range.
\section References References
The Arduino site:
http://www.arduino.cc/
For more information about FAT file systems see:
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
For information about using SD cards as SPI devices see:
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
The ATmega328 datasheet:
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
*/

@ -0,0 +1,418 @@
/* Arduino Fat16 Library
* Copyright (C) 2009 by William Greiman
*
* This file is part of the Arduino Fat16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef FatStructs_h
#define FatStructs_h
/**
* \file
* FAT file structures
*/
/*
* mostly from Microsoft document fatgen103.doc
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
*/
//------------------------------------------------------------------------------
/** Value for byte 510 of boot block or MBR */
uint8_t const BOOTSIG0 = 0X55;
/** Value for byte 511 of boot block or MBR */
uint8_t const BOOTSIG1 = 0XAA;
//------------------------------------------------------------------------------
/**
* \struct partitionTable
* \brief MBR partition table entry
*
* A partition table entry for a MBR formatted storage device.
* The MBR partition table has four entries.
*/
struct partitionTable {
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t beginHead;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned beginSector : 6;
/** High bits cylinder for first block in partition. */
unsigned beginCylinderHigh : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t beginCylinderLow;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t endHead;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned endSector : 6;
/** High bits of end cylinder */
unsigned endCylinderHigh : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t endCylinderLow;
/** Logical block address of the first block in the partition. */
uint32_t firstSector;
/** Length of the partition, in blocks. */
uint32_t totalSectors;
};
/** Type name for partitionTable */
typedef struct partitionTable part_t;
//------------------------------------------------------------------------------
/**
* \struct masterBootRecord
*
* \brief Master Boot Record
*
* The first block of a storage device that is formatted with a MBR.
*/
struct masterBootRecord {
/** Code Area for master boot program. */
uint8_t codeArea[440];
/** Optional WindowsNT disk signature. May contain more boot code. */
uint32_t diskSignature;
/** Usually zero but may be more boot code. */
uint16_t usuallyZero;
/** Partition tables. */
part_t part[4];
/** First MBR signature byte. Must be 0X55 */
uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1;
};
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
/**
* \struct biosParmBlock
*
* \brief BIOS parameter block
*
* The BIOS parameter block describes the physical layout of a FAT volume.
*/
struct biosParmBlock {
/**
* Count of bytes per sector. This value may take on only the
* following values: 512, 1024, 2048 or 4096
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128.
*/
uint8_t sectorsPerCluster;
/**
* Number of sectors before the first FAT.
* This value must not be zero.
*/
uint16_t reservedSectorCount;
/** The count of FAT data structures on the volume. This field should
* always contain the value 2 for any FAT volume of any type.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrtack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
};
/** Type name for biosParmBlock */
typedef struct biosParmBlock bpb_t;
//------------------------------------------------------------------------------
/**
* \struct fat32BootSector
*
* \brief Boot sector for a FAT16 or FAT32 volume.
*
*/
struct fat32BootSector {
/** X86 jmp to boot program */
uint8_t jmpToBootCode[3];
/** informational only - don't depend on it */
char oemName[8];
/** BIOS Parameter Block */
bpb_t bpb;
/** for int0x13 use value 0X80 for hard drive */
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/** usually generated by combining date and time */
uint32_t volumeSerialNumber;
/** should match volume label in root dir */
char volumeLabel[11];
/** informational only - don't depend on it */
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
};
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT16 end of chain value used by Microsoft. */
uint16_t const FAT16EOC = 0XFFFF;
/** Minimum value for FAT16 EOC. Use to test for EOC. */
uint16_t const FAT16EOC_MIN = 0XFFF8;
/** FAT32 end of chain value used by Microsoft. */
uint32_t const FAT32EOC = 0X0FFFFFFF;
/** Minimum value for FAT32 EOC. Use to test for EOC. */
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
/** Mask a for FAT32 entry. Entries are 28 bits. */
uint32_t const FAT32MASK = 0X0FFFFFFF;
/** Type name for fat32BootSector */
typedef struct fat32BootSector fbs_t;
//------------------------------------------------------------------------------
/**
* \struct directoryEntry
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
/**
* Short 8.3 name.
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reservedNT;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creationTimeTenths;
/** Time file was created. */
uint16_t creationTime;
/** Date file was created. */
uint16_t creationDate;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t lastAccessDate;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t firstClusterHigh;
/** Time of last write. File creation is considered a write. */
uint16_t lastWriteTime;
/** Date of last write. File creation is considered a write. */
uint16_t lastWriteDate;
/** Low word of this entry's first cluster number. */
uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
};
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
/** escape for name[0] = 0XE5 */
uint8_t const DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
uint8_t const DIR_NAME_DELETED = 0XE5;
/** name[0] value for entry that is free and no allocated entries follow */
uint8_t const DIR_NAME_FREE = 0X00;
/** file is read-only */
uint8_t const DIR_ATT_READ_ONLY = 0X01;
/** File should hidden in directory listings */
uint8_t const DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
uint8_t const DIR_ATT_SYSTEM = 0X04;
/** Directory entry contains the volume label */
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
/** Entry is for a directory */
uint8_t const DIR_ATT_DIRECTORY = 0X10;
/** Old DOS archive bit for backup support */
uint8_t const DIR_ATT_ARCHIVE = 0X20;
/** Test value for long name entry. Test is
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
/** Test mask for long name entry */
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
/** Directory entry is part of a long name */
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
}
/** Mask for file/subdirectory tests */
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
/** Directory entry is for a file */
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
}
/** Directory entry is for a subdirectory */
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
}
/** Directory entry is for a file or subdirectory */
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
#endif // FatStructs_h

@ -0,0 +1,277 @@
/* Arduino FAT16 Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino FAT16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <avr/pgmspace.h>
#include <Arduino.h>
#include <Fat16Config.h>
#include <SdCard.h>
//------------------------------------------------------------------------------
// r1 status values
uint8_t const R1_READY_STATE = 0;
uint8_t const R1_IDLE_STATE = 1;
// start data token for read or write
uint8_t const DATA_START_BLOCK = 0XFE;
// data response tokens for write block
uint8_t const DATA_RES_MASK = 0X1F;
uint8_t const DATA_RES_ACCEPTED = 0X05;
uint8_t const DATA_RES_CRC_ERROR = 0X0B;
uint8_t const DATA_RES_WRITE_ERROR = 0X0D;
//
// stop compiler from inlining where speed optimization is not required
#define STATIC_NOINLINE static __attribute__((noinline))
//------------------------------------------------------------------------------
// SPI static functions
//
// clock byte in
STATIC_NOINLINE uint8_t spiRec(void) {
SPDR = 0xff;
while (!(SPSR & (1 << SPIF)));
return SPDR;
}
// clock byte out
STATIC_NOINLINE void spiSend(uint8_t b) {
SPDR = b;
while (!(SPSR & (1 << SPIF)));
}
//------------------------------------------------------------------------------
// wait for card to go not busy
// return false if timeout
static uint8_t waitForToken(uint8_t token, uint16_t timeoutMillis) {
uint16_t t0 = millis();
while (spiRec() != token) {
if (((uint16_t)millis() - t0) > timeoutMillis) return false;
}
return true;
}
//------------------------------------------------------------------------------
uint8_t SdCard::cardCommand(uint8_t cmd, uint32_t arg) {
uint8_t r1;
// select card
chipSelectLow();
// wait if busy
waitForToken(0XFF, SD_COMMAND_TIMEOUT);
// send command
spiSend(cmd | 0x40);
// send argument
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
// send CRC - must send valid CRC for CMD0
spiSend(cmd == CMD0 ? 0x95 : 0XFF);
// wait for not busy
for (uint8_t retry = 0; (0X80 & (r1 = spiRec())) && retry != 0XFF; retry++);
return r1;
}
//------------------------------------------------------------------------------
uint8_t SdCard::cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
//==============================================================================
// SdCard member functions
//------------------------------------------------------------------------------
/**
* Determine the size of a standard SD flash memory card
* \return The number of 512 byte data blocks in the card
*/
uint32_t SdCard::cardSize(void) {
uint16_t c_size;
csd_t csd;
if (!readReg(CMD9, &csd)) return 0;
uint8_t read_bl_len = csd.read_bl_len;
c_size = (csd.c_size_high << 10) | (csd.c_size_mid << 2) | csd.c_size_low;
uint8_t c_size_mult = (csd.c_size_mult_high << 1) | csd.c_size_mult_low;
return (uint32_t)(c_size+1) << (c_size_mult + read_bl_len - 7);
}
//------------------------------------------------------------------------------
void SdCard::chipSelectHigh(void) {
digitalWrite(chipSelectPin_, HIGH);
// make sure MISO goes high impedance
spiSend(0XFF);
}
//------------------------------------------------------------------------------
void SdCard::chipSelectLow(void) {
// Enable SPI, Master, clock rate F_CPU/4
SPCR = (1 << SPE) | (1 << MSTR);
// Doubled Clock Frequency to F_CPU/2 unless speed_ is nonzero
if (!speed_) SPSR |= (1 << SPI2X);
digitalWrite(chipSelectPin_, LOW);
}
//------------------------------------------------------------------------------
void SdCard::error(uint8_t code, uint8_t data) {
errorData = data;
error(code);
}
//------------------------------------------------------------------------------
void SdCard::error(uint8_t code) {
errorCode = code;
chipSelectHigh();
}
//------------------------------------------------------------------------------
/**
* Initialize a SD flash memory card.
*
* \param[in] speed Set SPI Frequency to F_CPU/2 if speed = 0 or F_CPU/4
* if speed = 1.
* \param[in] chipSelectPin SD chip select pin number.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*
*/
uint8_t SdCard::init(uint8_t speed, uint8_t chipSelectPin) {
if (speed > 1) {
error(SD_ERROR_SPI_SPEED);
return false;
}
speed_ = speed;
chipSelectPin_ = chipSelectPin;
errorCode = 0;
uint8_t r;
// 16-bit init start time allows over a minute
uint16_t t0 = (uint16_t)millis();
pinMode(chipSelectPin_, OUTPUT);
digitalWrite(chipSelectPin_, HIGH);
pinMode(SPI_MISO_PIN, INPUT);
pinMode(SPI_SS_PIN, OUTPUT);
pinMode(SPI_MOSI_PIN, OUTPUT);
pinMode(SPI_SCK_PIN, OUTPUT);
// Enable SPI, Master, clock rate F_CPU/128
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
digitalWrite(chipSelectPin_, LOW);
// command to go idle in SPI mode
while ((r = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_ERROR_CMD0, r);
return false;
}
}
// start initialization and wait for completed initialization
while ((r = cardAcmd(ACMD41, 0)) != R1_READY_STATE) {
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
error(SD_ERROR_ACMD41, r);
return false;
}
}
chipSelectHigh();
return true;
}
//------------------------------------------------------------------------------
/**
* Reads a 512 byte block from a storage device.
*
* \param[in] blockNumber Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
if (cardCommand(CMD17, blockNumber << 9)) {
error(SD_ERROR_CMD17);
return false;
}
return readTransfer(dst, 512);
}
//------------------------------------------------------------------------------
uint8_t SdCard::readReg(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
chipSelectHigh();
return false;
}
return readTransfer(dst, 16);
}
//------------------------------------------------------------------------------
uint8_t SdCard::readTransfer(uint8_t* dst, uint16_t count) {
// wait for start of data
if (!waitForToken(DATA_START_BLOCK, SD_READ_TIMEOUT)) {
error(SD_ERROR_READ_TIMEOUT);
}
// start first spi transfer
SPDR = 0XFF;
for (uint16_t i = 0; i < count; i++) {
while (!(SPSR & (1 << SPIF)));
dst[i] = SPDR;
SPDR = 0XFF;
}
// wait for first CRC byte
while (!(SPSR & (1 << SPIF)));
spiRec(); // second CRC byte
chipSelectHigh();
return true;
}
//------------------------------------------------------------------------------
/**
* Writes a 512 byte block to a storage device.
*
* \param[in] blockNumber Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
uint8_t SdCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
uint32_t address = blockNumber << 9;
#if SD_PROTECT_BLOCK_ZERO
// don't allow write to first block
if (address == 0) {
error(SD_ERROR_BLOCK_ZERO_WRITE);
return false;
}
#endif // SD_PROTECT_BLOCK_ZERO
if (cardCommand(CMD24, address)) {
error(SD_ERROR_CMD24);
return false;
}
// optimize write loop
SPDR = DATA_START_BLOCK;
for (uint16_t i = 0; i < 512; i++) {
while (!(SPSR & (1 << SPIF)));
SPDR = src[i];
}
while (!(SPSR & (1 << SPIF))); // wait for last data byte
spiSend(0xFF); // dummy crc
spiSend(0xFF); // dummy crc
// get write response
uint8_t r1 = spiRec();
if ((r1 & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_ERROR_WRITE_RESPONSE, r1);
return false;
}
// wait for card to complete write programming
if (!waitForToken(0XFF, SD_WRITE_TIMEOUT)) {
error(SD_ERROR_WRITE_TIMEOUT);
}
chipSelectHigh();
return true;
}

@ -0,0 +1,192 @@
/* Arduino FAT16 Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino FAT16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdCard_h
#define SdCard_h
/**
* \file
* SdCard class
*/
#include <SdInfo.h>
//------------------------------------------------------------------------------
// Warning only SD_CHIP_SELECT_PIN, the SD card select pin, may be redefined.
// define hardware SPI pins
#if defined(__AVR_ATmega168__)\
||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos
/** Slave Select pin */
uint8_t const SPI_SS_PIN = 10;
/** Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = 11;
/** Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = 12;
/** Serial Clock */
uint8_t const SPI_SCK_PIN = 13;
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega1280__)\
|| defined(__AVR_ATmega2560__)
// pins for Arduino Mega
uint8_t const SPI_SS_PIN = 53;
uint8_t const SPI_MOSI_PIN = 51;
uint8_t const SPI_MISO_PIN = 50;
uint8_t const SPI_SCK_PIN = 52;
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega644P__)\
|| defined(__AVR_ATmega644__)\
|| defined(__AVR_ATmega1284P__)
// pins for Sanguino
uint8_t const SPI_SS_PIN = 4;
uint8_t const SPI_MOSI_PIN = 5;
uint8_t const SPI_MISO_PIN = 6;
uint8_t const SPI_SCK_PIN = 7;
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega32U4__)
// pins for Teensy 2.0
uint8_t const SPI_SS_PIN = 0;
uint8_t const SPI_MOSI_PIN = 2;
uint8_t const SPI_MISO_PIN = 3;
uint8_t const SPI_SCK_PIN = 1;
//------------------------------------------------------------------------------
#elif defined(__AVR_AT90USB646__)\
|| defined(__AVR_AT90USB1286__)
// pins for Teensy++ 1.0 & 2.0
uint8_t const SPI_SS_PIN = 20;
uint8_t const SPI_MOSI_PIN = 22;
uint8_t const SPI_MISO_PIN = 23;
uint8_t const SPI_SCK_PIN = 21;
//------------------------------------------------------------------------------
#else // SPI pins
#error unknown CPU
#endif // SPI pins
//------------------------------------------------------------------------------
/**
* SD Chip Select pin
*
* Warning if this pin is redefined the hardware SS pin will be enabled
* as an output by init(). An avr processor will not function as an SPI
* master unless SS is set to output mode.
*
* For example to set SD_CHIP_SELECT_PIN to 8 for the SparkFun microSD shield:
* uint8_t const SD_CHIP_SELECT_PIN = 8;
*
* The default chip select pin for the SD card is SS.
*/
uint8_t const SD_CHIP_SELECT_PIN = SPI_SS_PIN;
//------------------------------------------------------------------------------
/** command timeout ms */
uint16_t const SD_COMMAND_TIMEOUT = 300;
/** init timeout ms */
uint16_t const SD_INIT_TIMEOUT = 2000;
/** read timeout ms */
uint16_t const SD_READ_TIMEOUT = 300;
/** write timeout ms */
uint16_t const SD_WRITE_TIMEOUT = 600;
//------------------------------------------------------------------------------
// error codes
/** Card did not go into SPI mode */
uint8_t const SD_ERROR_CMD0 = 1;
/** Card did not go ready */
uint8_t const SD_ERROR_ACMD41 = 2;
/** Write command not accepted */
uint8_t const SD_ERROR_CMD24 = 3;
/** Read command not accepted */
uint8_t const SD_ERROR_CMD17 = 4;
/** timeout waiting for read data */
uint8_t const SD_ERROR_READ_TIMEOUT = 5;
/** write error occurred */
uint8_t const SD_ERROR_WRITE_RESPONSE = 6;
/** timeout waiting for write status */
uint8_t const SD_ERROR_WRITE_TIMEOUT = 7;
/** attempt to write block zero */
uint8_t const SD_ERROR_BLOCK_ZERO_WRITE = 8;
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_ERROR_WRITE_PROGRAMMING = 9;
/** invalid SPI speed in init() call */
uint8_t const SD_ERROR_SPI_SPEED = 10;
//------------------------------------------------------------------------------
// SD command codes
/** SEND OPERATING CONDITIONS */
uint8_t const ACMD41 = 0X29;
/** GO_IDLE_STATE - init card in spi mode if CS low */
uint8_t const CMD0 = 0X00;
/** SEND_CSD - Card Specific Data */
uint8_t const CMD9 = 0X09;
/** SEND_CID - Card IDentification */
uint8_t const CMD10 = 0X0A;
/** SEND_STATUS - read the card status register */
uint8_t const CMD13 = 0X0D;
/** READ_BLOCK */
uint8_t const CMD17 = 0X11;
/** WRITE_BLOCK */
uint8_t const CMD24 = 0X18;
/** APP_CMD - escape for application specific command */
uint8_t const CMD55 = 0X37;
//------------------------------------------------------------------------------
/**
* \class SdCard
* \brief Hardware access class for SD flash cards
*
* Supports raw access to a standard SD flash memory card.
*
*/
class SdCard {
public:
/** Code for a SD error. See SdCard.h for definitions. */
uint8_t errorCode;
/** Data that may be helpful in determining the cause of an error */
uint8_t errorData;
uint32_t cardSize(void);
/**
* Initialize an SD flash memory card with default clock rate and chip
* select pin. See SdCard::init(uint8_t sckRateID, uint8_t chipSelectPin).
*/
uint8_t init(void) {
return init(0, SD_CHIP_SELECT_PIN);
}
/**
* Initialize an SD flash memory card with the selected SPI clock rate
* and the default SD chip select pin.
* See SdCard::init(uint8_t slow, uint8_t chipSelectPin).
*/
uint8_t init(uint8_t speed) {
return init(speed, SD_CHIP_SELECT_PIN);
}
uint8_t init(uint8_t speed, uint8_t chipselectPin);
uint8_t readBlock(uint32_t block, uint8_t* dst);
/** Read the CID register which contains info about the card.
* This includes Manufacturer ID, OEM ID, product name, version,
* serial number, and manufacturing date. */
uint8_t readCID(cid_t* cid) {
return readReg(CMD10, cid);
}
uint8_t writeBlock(uint32_t block, const uint8_t* src);
private:
uint8_t cardAcmd(uint8_t cmd, uint32_t arg);
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
uint8_t chipSelectPin_;
uint8_t speed_;
void chipSelectHigh(void);
void chipSelectLow(void);
void error(uint8_t code, uint8_t data);
void error(uint8_t code);
uint8_t readReg(uint8_t cmd, void* buf);
uint8_t readTransfer(uint8_t* dst, uint16_t count);
};
#endif // SdCard_h

@ -0,0 +1,117 @@
/* Arduino FAT16 Library
* Copyright (C) 2008 by William Greiman
*
* This file is part of the Arduino FAT16 Library
*
* This Library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with the Arduino Fat16 Library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef SdInfo_h
#define SdInfo_h
#include <stdint.h>
// Based on the document:
//
// SD Specifications
// Part 1
// Physical Layer
// Simplified Specification
// Version 2.00
// September 25, 2006
//
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
//
// Card IDentification (CID) register
typedef struct CID {
// byte 0
uint8_t mid; // Manufacturer ID
// byte 1-2
char oid[2]; // OEM/Application ID
// byte 3-7
char pnm[5]; // Product name
// byte 8
unsigned prv_m : 4; // Product revision n.m
unsigned prv_n : 4;
// byte 9-12
uint32_t psn; // Product serial number
// byte 13
unsigned mdt_year_high : 4; // Manufacturing date
unsigned reserved : 4;
// byte 14
unsigned mdt_month : 4;
unsigned mdt_year_low :4;
// byte 15
unsigned always1 : 1;
unsigned crc : 7;
}cid_t;
// Card-Specific Data register
typedef struct CSD {
// byte 0
unsigned reserved1 : 6;
unsigned csd_ver : 2;
// byte 1
uint8_t taac;
// byte 2
uint8_t nsac;
// byte 3
uint8_t tran_speed;
// byte 4
uint8_t ccc_high;
// byte 5
unsigned read_bl_len : 4;
unsigned ccc_low : 4;
// byte 6
unsigned c_size_high : 2;
unsigned reserved2 : 2;
unsigned dsr_imp : 1;
unsigned read_blk_misalign :1;
unsigned write_blk_misalign : 1;
unsigned read_bl_partial : 1;
// byte 7
uint8_t c_size_mid;
// byte 8
unsigned vdd_r_curr_max : 3;
unsigned vdd_r_curr_min : 3;
unsigned c_size_low :2;
// byte 9
unsigned c_size_mult_high : 2;
unsigned vdd_w_cur_max : 3;
unsigned vdd_w_curr_min : 3;
// byte 10
unsigned sector_size_high : 6;
unsigned erase_blk_en : 1;
unsigned c_size_mult_low : 1;
// byte 11
unsigned wp_grp_size : 7;
unsigned sector_size_low : 1;
// byte 12
unsigned write_bl_len_high : 2;
unsigned r2w_factor : 3;
unsigned reserved3 : 2;
unsigned wp_grp_enable : 1;
// byte 13
unsigned reserved4 : 5;
unsigned write_partial : 1;
unsigned write_bl_len_low : 2;
// byte 14
unsigned reserved5: 2;
unsigned file_format : 2;
unsigned tmp_write_protect : 1;
unsigned perm_write_protect : 1;
unsigned copy : 1;
unsigned file_format_grp : 1;
// byte 15
unsigned always1 : 1;
unsigned crc : 7;
}csd_t;
#endif // SdInfo_h

@ -0,0 +1,66 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#include "pins_arduino.h"
#include "SPI.h"
SPIClass SPI;
void SPIClass::begin() {
// Set SS to high so a connected chip will be "deselected" by default
digitalWrite(SS, HIGH);
// When the SS pin is set as OUTPUT, it can be used as
// a general purpose output port (it doesn't influence
// SPI operations).
pinMode(SS, OUTPUT);
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
// automatically switches to Slave, so the data direction of
// the SS pin MUST be kept as OUTPUT.
SPCR |= _BV(MSTR);
SPCR |= _BV(SPE);
// Set direction register for SCK and MOSI pin.
// MISO pin automatically overrides to INPUT.
// By doing this AFTER enabling SPI, we avoid accidentally
// clocking in a single bit since the lines go directly
// from "input" to SPI control.
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
}
void SPIClass::end() {
SPCR &= ~_BV(SPE);
}
void SPIClass::setBitOrder(uint8_t bitOrder)
{
if(bitOrder == LSBFIRST) {
SPCR |= _BV(DORD);
} else {
SPCR &= ~(_BV(DORD));
}
}
void SPIClass::setDataMode(uint8_t mode)
{
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
}
void SPIClass::setClockDivider(uint8_t rate)
{
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
}

@ -0,0 +1,70 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#ifndef _SPI_H_INCLUDED
#define _SPI_H_INCLUDED
#include <stdio.h>
#include <Arduino.h>
#include <avr/pgmspace.h>
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
//#define SPI_CLOCK_DIV64 0x07
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define SPI_MODE2 0x08
#define SPI_MODE3 0x0C
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
class SPIClass {
public:
inline static byte transfer(byte _data);
// SPI Configuration methods
inline static void attachInterrupt();
inline static void detachInterrupt(); // Default
static void begin(); // Default
static void end();
static void setBitOrder(uint8_t);
static void setDataMode(uint8_t);
static void setClockDivider(uint8_t);
};
extern SPIClass SPI;
byte SPIClass::transfer(byte _data) {
SPDR = _data;
while (!(SPSR & _BV(SPIF)))
;
return SPDR;
}
void SPIClass::attachInterrupt() {
SPCR |= _BV(SPIE);
}
void SPIClass::detachInterrupt() {
SPCR &= ~_BV(SPIE);
}
#endif

@ -0,0 +1,94 @@
/*******************************************************************************
SerialCommand - An Arduino library to tokenize and parse commands received over
a serial port.
Copyright (C) 2011-2013 Steven Cogswell <steven.cogswell@gmail.com>
http://awtfy.com
Version 20131021A.
Version History:
May 11 2011 - Initial version
May 13 2011 - Prevent overwriting bounds of SerialCommandCallback[] array in addCommand()
defaultHandler() for non-matching commands
Mar 2012 - Some const char * changes to make compiler happier about deprecated warnings.
Arduino 1.0 compatibility (Arduino.h header)
Oct 2013 - SerialCommand object can be created using a SoftwareSerial object, for SoftwareSerial
support. Requires #include <SoftwareSerial.h> in your sketch even if you don't use
a SoftwareSerial port in the project. sigh. See Example Sketch for usage.
Oct 2013 - Conditional compilation for the SoftwareSerial support, in case you really, really
hate it and want it removed.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
#ifndef SerialCommand_h
#define SerialCommand_h
#include "Arduino.h"
// If you want to use SerialCommand with the hardware serial port only, and want to disable
// SoftwareSerial support, and thus don't have to use "#include <SoftwareSerial.h>" in your
// sketches, then uncomment this define for SERIALCOMMAND_HARDWAREONLY, and comment out the
// corresponding #undef line.
//
// You don't have to use SoftwareSerial features if this is not defined, you can still only use
// the Hardware serial port, just that this way lets you get out of having to include
// the SoftwareSerial.h header.
#define SERIALCOMMAND_HARDWAREONLY 1
//#undef SERIALCOMMAND_HARDWAREONLY
#include <string.h>
#define SERIALCOMMANDBUFFER 16
#define MAXSERIALCOMMANDS 10
#define MAXDELIMETER 2
#define SERIALCOMMANDDEBUG 1
#undef SERIALCOMMANDDEBUG // Comment this out to run the library in debug mode (verbose messages)
class SerialCommand
{
public:
SerialCommand(); // Constructor
void clearBuffer(); // Sets the command buffer to all '\0' (nulls)
char *next(); // returns pointer to next token found in command buffer (for getting arguments to commands)
void readSerial(); // Main entry point.
void addCommand(const char *, void(*)()); // Add commands to processing dictionary
void addDefaultHandler(void (*function)()); // A handler to call when no valid command received.
private:
char inChar; // A character read from the serial stream
char buffer[SERIALCOMMANDBUFFER]; // Buffer of stored characters while waiting for terminator character
int bufPos; // Current position in the buffer
char delim[MAXDELIMETER]; // null-terminated list of character to be used as delimeters for tokenizing (default " ")
char term; // Character that signals end of command (default '\r')
char *token; // Returned token from the command buffer as returned by strtok_r
char *last; // State variable used by strtok_r during processing
typedef struct _callback {
char command[SERIALCOMMANDBUFFER];
void (*function)();
} SerialCommandCallback; // Data structure to hold Command/Handler function key-value pairs
int numCommand;
SerialCommandCallback CommandList[MAXSERIALCOMMANDS]; // Actual definition for command/handler array
void (*defaultHandler)(); // Pointer to the default handler function
int usingSoftwareSerial; // Used as boolean to see if we're using SoftwareSerial object or not
};
#endif //SerialCommand_h

@ -0,0 +1,118 @@
/*
* prescaler.h
*
* Provides useful tools to manage the clock prescaler and issues
* related to time and delays. Allows to easily set the prescaler
* and get access to its value. Also provides alternative functions
* to the millis() and delay() functions.
*
* (c) 2008 Sofian Audry | info(@)sofianaudry(.)com
* http://sofianaudry.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PRESCALER_INC
#define PRESCALER_INC
#include "Arduino.h"
/**
* Prescaler division
*/
#define CLOCK_PRESCALER_1 (0x0)
#define CLOCK_PRESCALER_2 (0x1)
#define CLOCK_PRESCALER_4 (0x2)
#define CLOCK_PRESCALER_8 (0x3)
#define CLOCK_PRESCALER_16 (0x4)
#define CLOCK_PRESCALER_32 (0x5)
#define CLOCK_PRESCALER_64 (0x6)
#define CLOCK_PRESCALER_128 (0x7)
#define CLOCK_PRESCALER_256 (0x8)
// Initialize global variable.
static uint8_t __clock_prescaler = (CLKPR & (_BV(CLKPS0) | _BV(CLKPS1) | _BV(CLKPS2) | _BV(CLKPS3)));
inline void setClockPrescaler(uint8_t clockPrescaler) {
if (clockPrescaler <= CLOCK_PRESCALER_256) {
// Disable interrupts.
uint8_t oldSREG = SREG;
cli();
// Enable change.
CLKPR = _BV(CLKPCE); // write the CLKPCE bit to one and all the other to zero
// Change clock division.
CLKPR = clockPrescaler; // write the CLKPS0..3 bits while writing the CLKPE bit to zero
// Copy for fast access.
__clock_prescaler = clockPrescaler;
// Recopy interrupt register.
SREG = oldSREG;
}
}
inline uint8_t getClockPrescaler() {
return (__clock_prescaler);
}
inline uint16_t getClockDivisionFactor() {
return ((uint16_t)(1 << __clock_prescaler));
}
/**
* Time in milliseconds.
*
* NOTE: This is the equivalent of the millis() function but it readjusts it according
* to the current clock division. As such, be careful of how you make use of it, in
* particular remember it will be wrong if the clock division factor is changed during the
* course of computation. Remember that you can reset the overflow counter by calling the
* init() function from wiring.h.
*/
inline unsigned long trueMillis()
{
return millis() * getClockDivisionFactor();
}
inline unsigned long trueMicros() {
return micros() * getClockDivisionFactor();
}
// Waits for #ms# milliseconds.
// NOTE: Please see comment above.
inline void trueDelay(unsigned long ms)
{
unsigned long start = trueMillis();
while (trueMillis() - start < ms);
}
/**
* Rescales given delay time according to division factor. Should be called before a call
* to delay(). Insures compatibility with function using delay().
* Example use:
* delay( rescaleDelay(1000) ); // equivalent to wait(1000)
*/
inline unsigned long rescaleDuration(unsigned long d) {
return (d / getClockDivisionFactor());
}
/**
* Rescales given time (in milliseconds or microseconds) according to division factor. Should
* be called
*/
inline unsigned long rescaleTime(unsigned long t) {
return (t * getClockDivisionFactor());
}
#endif

@ -0,0 +1,148 @@
/* Rotary encoder handler for arduino. v1.1
*
* Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
* Contact: bb@cactii.net
*
* A typical mechanical rotary encoder emits a two bit gray code
* on 3 output pins. Every step in the output (often accompanied
* by a physical 'click') generates a specific sequence of output
* codes on the pins.
*
* There are 3 pins used for the rotary encoding - one common and
* two 'bit' pins.
*
* The following is the typical sequence of code on the output when
* moving from one step to the next:
*
* Position Bit1 Bit2
* ----------------------
* Step1 0 0
* 1/4 1 0
* 1/2 1 1
* 3/4 0 1
* Step2 0 0
*
* From this table, we can see that when moving from one 'click' to
* the next, there are 4 changes in the output code.
*
* - From an initial 0 - 0, Bit1 goes high, Bit0 stays low.
* - Then both bits are high, halfway through the step.
* - Then Bit1 goes low, but Bit2 stays high.
* - Finally at the end of the step, both bits return to 0.
*
* Detecting the direction is easy - the table simply goes in the other
* direction (read up instead of down).
*
* To decode this, we use a simple state machine. Every time the output
* code changes, it follows state, until finally a full steps worth of
* code is received (in the correct order). At the final 0-0, it returns
* a value indicating a step in one direction or the other.
*
* It's also possible to use 'half-step' mode. This just emits an event
* at both the 0-0 and 1-1 positions. This might be useful for some
* encoders where you want to detect all positions.
*
* If an invalid state happens (for example we go from '0-1' straight
* to '1-0'), the state machine resets to the start until 0-0 and the
* next valid codes occur.
*
* The biggest advantage of using a state machine over other algorithms
* is that this has inherent debounce built in. Other algorithms emit spurious
* output with switch bounce, but this one will simply flip between
* sub-states until the bounce settles, then continue along the state
* machine.
* A side effect of debounce is that fast rotations can cause steps to
* be skipped. By not requiring debounce, fast rotations can be accurately
* measured.
* Another advantage is the ability to properly handle bad state, such
* as due to EMI, etc.
* It is also a lot simpler than others - a static state table and less
* than 10 lines of logic.
*/
#include "Arduino.h"
#include "rotary.h"
/*
* The below state table has, for each state (row), the new state
* to set based on the next encoder output. From left to right in,
* the table, the encoder outputs are 00, 01, 10, 11, and the value
* in that position is the new state to set.
*/
#define R_START 0x0
#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
// R_START (00)
{R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START},
// R_CCW_BEGIN
{R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START},
// R_CW_BEGIN
{R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START},
// R_START_M (11)
{R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START},
// R_CW_BEGIN_M
{R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW},
// R_CCW_BEGIN_M
{R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW},
};
#else
// Use the full-step state table (emits a code at 00 only)
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6
const unsigned char ttable[7][4] = {
// R_START
{R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START},
// R_CW_FINAL
{R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW},
// R_CW_BEGIN
{R_CW_NEXT, R_CW_BEGIN, R_START, R_START},
// R_CW_NEXT
{R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START},
// R_CCW_BEGIN
{R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START},
// R_CCW_FINAL
{R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW},
// R_CCW_NEXT
{R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif
/*
* Constructor. Each arg is the pin number for each encoder contact.
*/
Rotary::Rotary(char _pin1, char _pin2) {
// Assign variables.
pin1 = _pin1;
pin2 = _pin2;
// Set pins to input.
pinMode(pin1, INPUT);
pinMode(pin2, INPUT);
#ifdef ENABLE_PULLUPS
digitalWrite(pin1, HIGH);
digitalWrite(pin2, HIGH);
#endif
// Initialise state.
state = R_START;
}
unsigned char Rotary::process() {
// Grab state of input pins.
unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
// Determine new state from the pins and state table.
state = ttable[state & 0xf][pinstate];
// Return emit bits, ie the generated event.
return state & 0x30;
}

@ -0,0 +1,37 @@
/*
* Rotary encoder library for Arduino.
*/
#ifndef rotary_h
#define rotary_h
#include "Arduino.h"
// Enable this to emit codes twice per step.
//#define HALF_STEP
// Enable weak pullups
#define ENABLE_PULLUPS
// Values returned by 'process'
// No complete step yet.
#define DIR_NONE 0x0
// Clockwise step.
#define DIR_CW 0x10
// Anti-clockwise step.
#define DIR_CCW 0x20
class Rotary
{
public:
Rotary(char, char);
// Process pin(s)
unsigned char process();
private:
unsigned char state;
unsigned char pin1;
unsigned char pin2;
};
#endif
Loading…
Cancel
Save