Урок 33
Часть 6
SPI. Карта SD. FAT
В предыдущей части занятия мы считали данные с флеш-карты и записали на неё также данные, также мы проверили данные результаты.
А в данной части мы устраним мелкие ошибки, а также вместо цифрового отображения результата действий с картой SD мы напишем код для отображения в более удобочитаемом текстовом виде.
Также мы удалим лишние неиспользуемые функции и фрагменты исходного кода.
Сначала удалим вот эти строки из функции main()
clearlcd();//очистим дисплей
setpos(0,0);
str_lcd("String 1");
setpos(2,1);
str_lcd("String 2");
setpos(4,2);
str_lcd("String 3");
setpos(6,3);
str_lcd("String 4");
_delay_ms(1000);
Также уберём закомментированный буфер в начале главного модуля
//char buffer[512] ="Sel…ия";
Также в функции disk_initialize в файле mmc.c закомментируем код вывода на дисплей и некоторый другой код. Можно, конечно, и удалить, но мало ли кому пригодится.
Поэтому под спойлером приведу полный код функции со всеми комментариями.
DSTATUS disk_initialize (void)
{
BYTE n, cmd, ty, ocr[4];
WORD tmr;
INIT_SPI();
// if ((PINB&_BV(SD_INS))!=0x00) return STA_NOINIT;
#if _WRITE_FUNC
if (MMC_SEL) disk_writep(0, 0); // Finalize write process if it is in progress
#endif
for (n = 100; n; n—) rcv_spi(); // Dummy clocks
ty = 0;
if (send_cmd(CMD0, 0) == 1) { // Enter Idle state
if (send_cmd(CMD8, 0x1AA) == 1) { // SDv2
// setpos(0,3);
// str_lcd("SDv2");
for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); // Get trailing return value of R7 resp
// setpos(8,0);
// sprintf(str,"%02X",ocr[3]);
// str_lcd(str);
// setpos(11,0);
// sprintf(str,"%02X",ocr[2]);
// str_lcd(str);
// setpos(14,0);
// sprintf(str,"%02X",ocr[1]);
// str_lcd(str);
// setpos(17,0);
// sprintf(str,"%02X",ocr[0]);
// str_lcd(str);
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { // The card can work at vdd range of 2.7-3.6V
// setpos(5,3);
// str_lcd("AA01");
for (tmr = 12000; tmr && send_cmd(ACMD41, 1UL << 30); tmr—) ; // Wait for leaving idle state (ACMD41 with HCS bit)
if (tmr && send_cmd(CMD58, 0) == 0) { // Check CCS bit in the OCR
// setpos(10,3);
// str_lcd("CCS");
for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
// setpos(8,1);
// sprintf(str,"%02X",ocr[3]);
// str_lcd(str);
// setpos(11,1);
// sprintf(str,"%02X",ocr[2]);
// str_lcd(str);
// setpos(14,1);
// sprintf(str,"%02X",ocr[1]);
// str_lcd(str);
// setpos(17,1);
// sprintf(str,"%02X",ocr[0]);
// str_lcd(str);
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; // SDv2 (HC or SC)
}
}
} else { // SDv1 or MMCv3
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; // SDv1
} else {
ty = CT_MMC; cmd = CMD1; // MMCv3
}
for (tmr = 25000; tmr && send_cmd(cmd, 0); tmr—) ; // Wait for leaving idle state
if (!tmr || send_cmd(CMD16, 512) != 0) // Set R/W block length to 512
ty = 0;
}
}
CardType = ty;
// sprintf(str,"%d",CardType);
// setpos(0,1);
// str_lcd(str);
release_spi();
return ty ? 0 : STA_NOINIT;
}
А вообще, весь полный код содержится по ссылке "исходный код" внизу страницы.
Также закомментируем код вывода на дисплей в файле pff.c
fmt = check_fs(buf, bsect); /* Check sector 0 as an SFD format */
// sprintf(str,"%d",fmt);
// setpos(4,0);
// str_lcd(str);
Теперь внесём некоторые поправки в главной функции main().
Позиционирование дисплея в верхний левый угол перенесём вот в это место, а также напишем туда строку
setpos(0,0);
str_lcd("Mount SD… ");
res=pf_mount(&fs);
Между вызовом функции монтирования и открытия файла всё удалим, а вместо удалённого вставим вот такой код, в котором мы отчитаемся на дисплее, примонтировался ли у нас раздел, в противном случае собщим об ошибке
res=pf_mount(&fs);
if (res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
res=pf_open("/123.txt"); //Попытка открыть файл 123.txt
Теперь соберём код, прошьём контроллер и посмотрим, как у нас всё отображается
Всё у нас получилось, только конечно информация затем затирается, но это мы всё постепенно поправим.
После задержки вставим следующий подобный код только для открытия файла
_delay_ms(1000);
setpos(0,3);
str_lcd("Open file… ");
res=pf_open("/123.txt"); //Попытка открыть файл 123.txt
Затем между функцией открытия файла и позиционирования указателя в файле удалим весь код и вставим вот такой код, который отчитается об успешном или неуспешном открытии файла и также подготовит следующую строку о попытке установки указателя в определённую позицию в файле
res=pf_open("/123.txt"); //Попытка открыть файл 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,2);
str_lcd("Move pointer… ");
res=pf_lseek(0); //Установим курсор чтения на 0 в 123.txt
Подобные действия проделаем и между вызовом функции установки уазателя и функции чтения байтов из файла
res=pf_lseek(0); //Установим курсор чтения на 0 в 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,3);
str_lcd("Read file… ");
res=pf_read(buffer2,128,&s1);
Теперь мы дошли до такого момента, когда у нас закончились строки на дисплее, а также до того состояния, когда нам нужно будет вывести строку. Отлично, что всё совпало. Поэтому между функцией чтения байтов в буфер и размонтирования раздела мы сначала отчитаемся о результате считывания, подождём побольше, очистим дисплей выведем строку и на следующей строке заготовим информацию о размонтированиии раздела
res=pf_read(buffer2,128,&s1);
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(2000);
clearlcd();//очистим дисплей
setpos(0,0);
str_lcd(buffer2);
_delay_ms(1000);
setpos(0,1);
str_lcd("Unmout SD… ");
res=pf_mount(0x00);//Демонтируем файловую систему карты
Соберём код, пршьём контроллер и посмотрим результат, а то если не проверять, исправлять будет потом трудно
Отлично всё сработало.
Продолжим дальше приблизительно таким же образом и добавим код между всеми функциями до бесконечного цикла. Думаю, что стоит всё это спрятать под спойлер, иначе будет очень длинный текст
res=pf_mount(0x00);//Демонтируем файловую систему карты
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,2);
str_lcd("Mount SD… ");
res=pf_mount(&fs);
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,3);
str_lcd("Open file… ");
res=pf_open("/123.txt"); //Попытка открыть файл 123.txt, чтобы в него записать данные
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(2000);
sprintf(buffer2,"World Hello!");
clearlcd();//очистим дисплей
setpos(0,0);
str_lcd("Write data… ");
res=pf_write(buffer2,strlen(buffer2),&s1);//Запишем текст из buffer2 в файл 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,1);
str_lcd("Finalise… ");
res=pf_write(0,0,&s1);//Финализируем файл 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,2);
str_lcd("Unmout SD… ");
res=pf_mount(0x00);//Демонтируем файловую систему карты
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,3);
str_lcd("Mount SD… ");
res=pf_mount(&fs);
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(2000);
clearlcd();//очистим дисплей
setpos(0,0);
str_lcd("Open file… ");
res=pf_open("/123.txt"); //Попытка открыть файл 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,1);
str_lcd("Move pointer… ");
res=pf_lseek(0); //Установим курсор чтения на 0 в 123.txt
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,2);
str_lcd("Read file… ");
res=pf_read(buffer2,128,&s1);
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
_delay_ms(1000);
setpos(0,3);
str_lcd(buffer2);
_delay_ms(3000);
clearlcd();//очистим дисплей
setpos(0,0);
str_lcd("Unmout SD… ");
res=pf_mount(0x00);//Демонтируем файловую систему карты
if(res==FR_OK) str_lcd("Done");
else str_lcd("Error");
while(1)
Проверим код на практике, собрав его сначала и затем прошив контроллер
Теперь давайте удалим лишние функции, оставим только port_ini() и main().
Также удалим локальную переменную
int main(void)
{
char str[10];
Соберём код и прошьём контроллер.
Предыдущая часть Программирование МК AVR Следующий урок
Техническая документация на Secure Digital
Программатор, модуль SD и дисплей можно приобрести здесь:
Программатор (продавец надёжный) USBASP USBISP 2.0
Смотреть ВИДЕОУРОК (нажмите на картинку)
А где у Вас mmc.c подключается?
В дереве проектов. Файлы c не подключаются с помощью директивы include, поэтому выполняются все.
Вопрос снят. В 7-й студии загрузился нормально.
Ага, я понял, тем не менее ответил, чтоб другие посмотрели.
Не планируете рассказать, как с SD-карты картинки (RAW-файл, например) выводить на экран?
Пытался переделать функцию TFT9341_DrawBitmap из проекта STM, заменив обращения к USB на SD. Почему-то закрашивает весь экран черным. ):
Привет, я не говорю по-русски, и это перевод Google.
Извиняюсь заранее.
Я запускаю эту программу, но текстовый файл не создается.
Если я создам текстовый файл с компьютером и пишу текст в нем, содержимое внутри него читается и даже может быть записано.
Но если карта памяти пуста, этот файл не будет создан.
Я использую микроконтроллер at90can128. И я также использую другое аппаратное соединение spi.
Как вы думаете, в чем проблема?
Благодарю вас!
Привет!
Затрудняюсь ответить.
Что-то не так с доступом к файлу в библиотеке FatFS.
Здравствуйте, а как можно воспроизвести музыку с SD?
или и microSD
В PROTEUSE — не работает !!!