Каталог статей

Главная » Статьи » Мои статьи

Программа для PIC-микроконтроллера и карты памяти MMC с FAT16

Поиск и чтение файла (даже если он состоит из нескольких фрагментов).

Здесь представлен пример программы, который находит файл на отформатированной под FAT16 карте памяти MMC 64Мб.

Наша предыдущая программа могла обращаться к любому участку памяти MMC карты. Для того чтобы найти файл на отформатированном носителе, нужны: позиция начала файла, и, если файл состоит из множества фрагментов, нужно знать позицию каждого фрагмента. Для этого программа должна находить начальные сектора файловой структуры FAT, а также перебирать байты данных и находить нужные.

Следующие функции выполняют вышеперечисленные действия:

Имя функцииВходВыходОписание
void Byte_Read(void)AX, AL, BytNByteLesСчитывает 2 байта из определённой позиции в секторе и сохраняет их в переменную ByteLes. Старший (H) и младший (L) байты адреса сектора указываются в AX,AL, позиция - в переменной BytN (0..512)
void Find(const char *word)String, VerzByteLesИщет 11-байтовую строку - имя файла + расширение (8+3). Сохраняет в переменную ByteLes номер первого кластера файла. Перед вызовом функции необходимо записать начальный адрес области каталога файлов в переменную Verz.
void Read(char H, uns16 L)H, L-Считывает данные с сектора и отправляет их в компьютер. Перед вызовом нужно указать адрес сектора.

Пошаговое описание программы:

ШагОписание
1Инициализация последовательного интерфейса
2Инициализация SPI-интерфейса и MMC карты
32-х байтовое значение в нулевом секторе, позиция 1C6h - это начало записи MBR1 (Master Boot Recorder - главная загрузочная запись). Таблица раздела (1BEh) 1C6h-1BEh=8 - на этом месте в записи раздела находится значение смещения между сектором MBR и первым сектором раздела.
4В AL передаётся 2-х байтовое значение, теперь AL содержит начальный адрес загрузочной записи раздела.
52-х байтовое значение, прочитанное из сектора = начальный адрес загрузочной записи раздела (смещение Eh). Это количество зарезервированных секторов.
6Начальный адрес загрузочной записи раздела суммируется с количеством зарезервированных секторов и сохраняется в переменную "FAT" - это начальный адрес таблицы FAT.
72-х байтовое значение, прочитанное из сектора = начальный адрес загрузочной записи раздела (смещение 16h) Это количество секторов на FAT. Так как у нас есть 2 таблицы FAT, полученное значение умножаем на 2, чтобы узнать общее количество секторов, занимаемых FAT.
8Расчёт начального адреса записей каталога: начальный адрес FAT-таблицы складывают с количествомвом секторов, которые заняты FAT. Результат сохраняется в переменной "Verz".
9Далее рассчитывается количество секторов, которые резервируются для записей корневого каталога. Для этого используется формула:
(количество записей каталога) * 32 / 512.
Из нескольких источников я узнал, что количество записей каталога всегда резервируется для 512 записей. Итак, количество секторов, которые резервируются для записей корневого каталога: 512*32/512=32
10Рассчитывается адрес первого сектора области данных (Cluster 0 - нулевой кластер). Начальный адрес записей каталога суммируется с количествомвом секторов записей каталога (32). Результат записывается в переменную "Dat". Таким образом находятся все начальные сектора структуры FAT и записываются в переменные "FAT", "Verz", "Dat".
11Запускается подпрограмма Suche("TEST TXT"). Она ищет первый кластер файла Test.txt. Имя файла всегда должно быть 8 символов в длину. Если оно короче, оно дополняется пробелами. Точка между именем файла и расширением в записи каталога не отображается. Искомая строка должна содержать 11 ПРОПИСНЫХ символов. Найденный номер первого кластера записывается в переменную "ByteLes".
12Здесь начинается цикл, который закончится, когда номер кластера примет значение 0XFFFF. Это означает, что файл не имеет следующих кластеров (конец файла). В цикле выполняется следующее:
13При первом прохождении переменная "Cluster" получает номер первого кластера файла. При следующих прохождениях переменная "Cluster" получает из "ByteLes" номер следующего кластера, который устанавливается в конце цикла.
14Номер кластера корректируется, так как две первых позиции в FAT зарезервированы, а в области данных данные начинаются с кластера 0. Таким образом, настоящий номер кластера = номер кластера - 2.
15Настоящий номер кластера передаётся в переменную "AL".
16Рассчитывается абсолютный физический адрес сектора:
Для этого номер кластера нужно умножить на 2 (так как 1 кластер = 2 сектора). Это происходит сдвигом позиции влево, а именно через флаг переноса. Если при этом происходит переполнение "AL" (если файл на MMC находится в области > 32 Мбайт), перенос попадает в "AH".
17Полученный номер сектора складывается с адресом первого сектора области данных (кластер 0). Суммирование происходит в режиме ассемблера, так как результат – это 24-битное число, а компилятор cc5x может работать только с 16-битными числами.
Таким образом мы получаем абсолютный физический адрес сектора в "AH", "AL", где AH – 8-битная переменная, содержит старшую часть адреса сектора, а AL – 16-битная переменная, содержит младшую часть адреса сектора.
18Функцией Lesen(AH,AL) читаем из первого сектора кластера файла.
19Физический адрес сектора увеличиваем на 1 с соблюдением переноса в "AH"
20Функцией Lesen(AH,AL) читаем из второго сектора кластера файла.
21Из таблицы FAT считываем следующий номер кластера:
Рассчитывается сектор, в котором находится запись FAT. Номер кластера делится на 100h (256), так как в секторе 200h (512) байтов, а размер записи FAT составляет 2 байта (в секторе умещается 100h (256) записей). Результат сохраняется во временную переменную.
22В AL содержится фактический адрес сектора искомой записи FAT, который складывается из начального адреса FAT и рассчитанного значения во временной переменной.
23Чтобы получить номер записи FAT в вычисленном секторе, мы должны вычесть из номера кластера количество записей FAT в предыдущих секторах. Так как размер записи FAT составляет 2 байта, то позиция байта = (номер записи FAT в вычисленном секторе)*2.
24Теперь, когда у нас есть адрес сектора и позиция в секторе, с помощью функции Byte_lessen мы можем считать запись FAT.
25Теперь "ByteLes" содержит номер следующего кластера файла. Программа продолжается с шага 12.

Ниже приведён код программы на СИ (компилятор CC5x):

// Чтение файла из 64 Мб MMC-памяти под FAT16
// Последовательный интерфейс (9600,n,8,1) на 20MHz
// Компилятор CC5x

#include 
#pragma config |= 0b.11.111101.11.00.10
#pragma bit CS @ PORTC.2 // Выход для выбора микросхемы CS

uns16 AL, BytN,ByteLes,Claster,FAT,Verz,Dat; // Объявляем переменные
char AH ;

#pragma origin 100

//******************************************************************************
void InitUSART()
{
 BRGH=1;
 SPBRG=129; // (9600 бод при входной тактовой частоте 20 МГц)
 SPEN = 1; // Set_Serial_Pins;
 SYNC = 0; // Set_Async_Mode;
 TX9 = 0; // Set_8bit_Tx;
 RX9 = 0; // Set_8bit_Rx;
 CREN = 1; // Enable_Rx;
 TXEN = 1; // Enable_Tx;
 RCIE=0; // Отключить прерывание Rx
}

//**************************************************************************
void SerString(const char *str) //Передача последовательной строки
{
 char ps;
 ps = *str; // Запомнить указатель на начало строки в ps
 while(ps>0) // Проверка, не достигнут ли конец строки
 {
 str++; // Увеличение указателя для доступа к следующем символу
 if (ps== 0) break; // Проверка, не достигнут ли конец строки
 while(!TXIF); // Проверка, пуст ли регистр TXREG
 TXREG =ps ; // Передача байта данных
 ps = *str; // Запомнить содержимое указателя в ps
 }
}

//*****************************************************************************
char SPI(char d) // Передача по интерфейсу SPI
{
 SSPBUF=d;
 while (!BF); // Ожидание, пока идёт передача
 return SSPBUF; // Одновременный приём
}

//******************************************************************************
char Command(char befF,uns16 AdrH,uns16 AdrL,char befH )
{ // Передача команды в MMC
 char a;
 for (a=0;a<9;a++)
 {
 Carry=0;
 AdrL = rl(AdrL);
 AdrH = rl(AdrH);
 }
 SPI(0xFF);
 SPI(befF);
 SPI(AdrH.high8);
 SPI(AdrH.low8);
 SPI(AdrL.high8);
 SPI(AdrL.low8);
 SPI(befH);
 SPI(0xFF);
 return SPI(0xFF); // Возвращаем ответ на команду
}

//****************************************************************************
bit MMC_Init()
{
 SMP=0; // Вход действителен в середине синхроимпульса
 CKE=0; // CKE=1; // Фронт передачи (Fordere Flanke) (передний)
 CKP=1; // CKP=0; // Низкий уровень – пассивное состояние
 SSPM0=1;
 SSPEN=1; // Включить SPI
 CS=1; // Отключить MMC
 char i; // Переменная
 for(i=0; i < 10; i++)SPI(0xFF);
 CS=0;
 if (Command(0x40,0,0,0x95) !=1)goto Fehler ;
 st:
 if (Command(0x41,0,0,0xFF) !=0) goto st ;
 return 1;
 Fehler:
 return 0;
}

//***********************************************************************************
void Byte_lesen (void)
{
 bit zw;
 char a;
 int16 i;
 zw=0;
 Command(0x51,AH,AL,0xFF);
 while(SPI(0xFF) != 0xFE); // Ожидание 0xFE – начала каждой передачи данных
 for(i=0; i < 512; i++)
 {
 a=SPI(0xFF);
 if (zw)
 {
 ByteLes.high8=a;
 zw=0;
 }
 if (i==BytN)
 {
 ByteLes.low8=a;
 zw=1;
 }

 }
 SPI(0xFF); // В конце 2 незначимых байта
 SPI(0xFF);
}

//******************************************************************************
void Suche(const char *wort)
{
 uns16 i,L,N;
 bit gef;
 char a,m,b;
 gef=0;
 m=0;
 N=Verz+32; // Конец области каталога
 for (L=Verz;Lwhile(SPI(0xFF) != 0xFE);
 for(i=0; i < 512; i++)
 {
 a=SPI(0xFF) ;
 b=wort[m];
 if(a==b)
 {
 m++;
 if(!wort[m])
 {
 SerString("Gefunden ");
 m=0;
 BytN=i;
 AL=L;
 AH=0;
 gef=1;
 }
 goto fu;
 }

 m=0;
 fu:
 }
 SPI(0xFF); // В конце 2 незначимых байта
 SPI(0xFF);
 if(gef) goto raus;
 }
 raus:
 SerString("Beendet ");
 BytN+=16;
 Byte_lesen();
}

//*******************************************************************************
void Lesen(char H,uns16 L)
{
 uns16 i;

 // 512-байтное чтение
 if (Command(0x51,H,L,0xFF) !=0) SerString("Lese_resp_Fehler"); // "Ошибка"
 while(SPI(0xFF) != 0xFE); // Ожидание 0xFE – начала каждой передачи данных
 for(i=0; i < 512; i++)
 {
 while(!TXIF); // Проверка, пуст ли регистр TXREG
 TXREG =SPI(0xFF); // Передача байта данных
 }
 SPI(0xFF); // В конце 2 незначимых байта
 SPI(0xFF);
}

//*********************************************************************************

void main(void)
{
 uns16 temp;
 INTCON=0; // Отключить прерывания
 ADCON1=0x6; // Все выходы PortA - цифровые
 TRISC=0b.1101.0011; // sck rc3-0, sdo rc5-0, CS rc2-0.
 TRISB=0b.0000.0010; // RB2>TX, RB1<RX
 InitUSART(); // 1 шаг. Инициализация последовательной передачи данных
 //SerString("Ich bin ON "); // Стартовое сообщение
 MMC_Init(); // 2 шаг

 // Определение начала каждой области
 AL=0; // 3 шаг
 AH=0;
 BytN=0x1C6;
 Byte_lesen();
 AL=ByteLes; // 4 шаг
 BytN=0xE; // 5 шаг
 Byte_lesen();
 FAT=ByteLes+AL; // 6 шаг
 BytN=0x16; // 7 шаг
 Byte_lesen();
 ByteLes=ByteLes*2;
 Verz=FAT+ByteLes; // 8 шаг
 Dat=Verz+32; // 9, 10 шаги


 Suche("TEST TXT"); // 11 шаг

 while(ByteLes != 0xFFFF) // 12, 25 шаги
 {
 Claster=ByteLes; // 13 шаг
 Claster=Claster-2; // 14 шаг
 AL=Claster; // 15 шаг
 Carry=0; // 16 шаг Здесь учитываются границы переменной (флаг переноса)
 AL = rl(AL); // Умножение на 2 с переносом
 AH = rl(AH);

 #asm // 17 шаг
 MOVF Dat+1,W
 ADDWF AL+1,1
 MOVF Dat,W
 ADDWF AL,1
 BTFSS 0x03,Carry
 GOTO keinCarry
 BCF 0x03,Carry
 INCF AL+1,1
 BTFSC 0x03,Carry
 INCF AH,1
 keinCarry:
 #endasm

 Lesen(AH,AL); // 18 шаг Первый блок кластеров
 Carry=0; // 19 шаг
 AL++;
 if(Carry)AH++; // Здесь учитываются границы переменной (флаг переноса)
 Lesen(AH,AL); // 20 шаг Второй блок кластеров

 AL=FAT; // 21 шаг следующий кластер
 temp=ByteLes/0x100;
 AL=AL+temp; // 22 шаг
 temp=temp*0x100; // 23 шаг
 BytN=ByteLes-temp;
 BytN=BytN*2;
 Byte_lesen(); // 24 шаг

 }



© PIClist-RUS (piclist.ru), 2007 г.

Категория: Мои статьи | Добавил: MAS (26.11.2012)
Просмотров: 845 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Категории раздела
Мои статьи [51]
Справочные данные [165]
Справочные данные
Наш опрос
Оцените мой сайт
Всего ответов: 30
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Баннер
$$
Друзья сайта
  • Спортсменам
  • Огородникам СЮД(А
  • Строим вместе
  • Мир развлечений
  • Кто хочет похудеть
  • Здоровье у нас одно
  • Юмор
  • Кулинарные рецепты
  • Картинки_Заставки_Демотивоторы
  • Семья
  • Кто на мальчишник
  • Металлообработка
  • Кто на девишник
  • Блоки питания
  • Смерть соседям
  • Радиомедведь
  • Кибермедведь
  • Радиосайт
  • Деревообработка
  • Поиск