В предыдущей части урока мы настроили проект и создали функцию обработки состояний программы.
Добавим ещё один глобальный массив для отправки строк в USART для последующего отображения их в терминальной программе в ПК
1 2 |
char fn[30] = {0}; char str_usart[512] = {0}; |
В функции App_File_Operations добавим строковый массив для хранения имени файла
1 2 3 |
void App_File_Operations(char* fname) { char fnm[15]; |
Скопируем имя файла в строковый массив, добавив префикс раздела
1 2 |
char fnm[15]; sprintf(fnm,"0:%s",fname); |
Попытаемся открыть файл. В случае неудачи выведем соответствующее сообщение в терминальную программу, в случаи удачи — другое сообщение, а затем закроем файл
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sprintf(fnm,"0:%s",fname); //read and write if (f_open(&MyFile, (const TCHAR*)fnm, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) { sprintf(str_usart,"Cannot Open %s file for write.n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } else { sprintf(str_usart,"INFO : %s opened for writen",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); f_close(&MyFile); } |
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе, соответственно, заблаговременно её запустив и соединив с соответствующим портом.
Если всё пройдёт нормально, то получим следующий результат
Добавим глобальную переменную для результата выполнения файловых операций (глобальная надёжнее)
1 2 |
FATFS *fs; FRESULT res; |
Также добавим инициализированный глобальный текстовый массив
1 2 |
__IO MSC_APP_State state; uint8_t wtext[] = "USB Host Library : Mass Storage Example"; |
Вернёмся в функцию App_File_Operations и добавим пару локальных переменных
1 2 |
char fnm[15]; uint16_t bytesread, bytesWritten; |
Попробуем что-нибудь записать в открытый файл и также, в случае неудачи выведем соответствующее сообщение в терминальную программу, в случаи удачи — другое сообщение
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sprintf(str_usart,"INFO : %s opened for writen",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&bytesWritten); if ((bytesWritten == 0) || (res != FR_OK)) { sprintf(str_usart,"Cannot Write on the %s file n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } else { sprintf(str_usart,"INFO : Text written on the %s file n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } |
Соберём код, прошьём контроллер и посмотрим сначала результат в терминальной программе
Затем извлечём из разъёма кабеля FLASH-накопитель и поместим его в USB-порт ПК. Наш файл на месте
Откроем файл и убедимся, что содержимое файла также соответствует заданному в программе
Отлично!
Теперь попробуем программными средствами прочитать содержимое файла.
Сначала откроем файл для чтения, сначала заново скопировав имя файла в локальный массив, иначе путь почему-то теряется. Также не забываем перед открытием закрыть файл
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
sprintf(str_usart,"INFO : Text written on the %s file n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); f_close(&MyFile); sprintf(fnm,"0:%s",fname); if (f_open(&MyFile, (const TCHAR*)fnm, FA_READ) != FR_OK) { sprintf(str_usart,"Cannot Open %s file for read.n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } else { sprintf(str_usart,"INFO : %s opened for read, size: %lun",fnm+2,MyFile.obj.objsize); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } |
Добавим глобальный строковый массив для хранения прочитанного содержимого файла
1 2 |
__IO MSC_APP_State state; uint8_t rtext[200]; |
Вернёмся в функцию App_File_Operations и попытаемся прочитать содержимое нашего файла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
sprintf(str_usart,"INFO : %s opened for read, size: %lun",fnm+2,MyFile.obj.objsize); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); res = f_read(&MyFile, rtext, sizeof(rtext), (void *)&bytesread); if ((bytesread == 0) || (res != FR_OK)) // EOF or Error { sprintf(str_usart,"Cannot Read from the %s file n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } else { HAL_UART_Transmit(&huart1,rtext,bytesread,0x1000); sprintf(str_usart,"nn"); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); } |
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Отлично! Теперь попробуем поработать с длинными именами, а также с длинными файлами (по содержимому).
Для этого скопируем на наш FLASH-накопитель ещё два файла — один с коротким именем, но с большим содержимым, а другой — также с большим содержимым, но ещё и с длинным именем
Вернёмся в наш код и закомментируем пока работу с файлом USBHost.txt
/*
//read and write
if (f_open(&MyFile, (const TCHAR*)fnm, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
...
f_close(&MyFile);
}
*/
Объявим несколько глобальных неоптимизируемых переменных
1 2 3 |
uint8_t rtext[200]; __IO uint16_t i=0, i1=0; __IO uint32_t f_size = 0, ind=0; |
Выше функции App_File_Operations добавим ещё одну функцию для чтения файлов с длинным содержимым
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//-------------------------------------------------------------- FRESULT ReadLongFile(void) { uint16_t bytesread; f_size = MyFile.obj.objsize; sprintf(str1,"fsize: %lurn",(unsigned long)f_size); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); ind=0; do { if(f_size<512) { i1=f_size; } else { i1=512; } f_size-=i1; f_lseek(&MyFile,ind); f_read(&MyFile,sect,i1,(UINT *)&bytesread); for(i=0;i<bytesread;i++) { HAL_UART_Transmit(&huart1,sect+i,1,0x1000); } ind+=i1; } while(f_size>0); HAL_UART_Transmit(&huart1,(uint8_t*)"rn",2,0x1000); return FR_OK; } //-------------------------------------------------------------- |
В функции App_File_Operations попытаемся открыть файл с длинным содержимым, но с коротким именем
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
*/ //read long file if(f_open(&MyFile,"0:F74x.txt",FA_READ)!=FR_OK) { sprintf(str_usart,"Cannot Open %s file for write.n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); Error_Handler(); } else { sprintf(str_usart,"fname: %srn","F74x.txt"); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); ReadLongFile(); f_close(&MyFile); } |
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Файл полностью считался.
Теперь попробуем аналогично прочитать файл с длинным именем.
Сначала закомментируем код чтения предыдущего файла
/*
//read long file
...
f_close(&MyFile);
}
*/
Теперь считаем содержимое файла
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
*/ //read longname file if(f_open(&MyFile,"0:stm32f746 Reference Manual.txt",FA_READ)!=FR_OK) { sprintf(str_usart,"Cannot Open %s file for write.n",fnm+2); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); Error_Handler(); } else { sprintf(str_usart,"fname: %srn","stm32f746 Reference Manual.txt"); HAL_UART_Transmit(&huart1,(uint8_t*)str_usart,strlen(str_usart),0x1000); ReadLongFile(); f_close(&MyFile); } |
Как мы видим, благодаря определённым изменениям в обновлённой библиотеке FATFS нам теперь не нужно проводить дополнительные мероприятия по организации дополнительного буфера для чтения файлов с длинными именами.
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Файл также полностью прочитан.
Теперь аналогично закомментируем участок кода, связанный с чтением данного файла.
Отключим FLASH-накопитель, подключим его к ПК и скопируем на него ещё несколько файлов и папок с файлами (также и с длинными именами, но не с кириллицей в именах и расширениях, так как кириллица — это вообще отдельная и нелёгкая тема)
Вернёмся в код и добавим в функцию App_File_Operations несколько локальных переменных
1 2 3 4 5 |
uint16_t bytesread, bytesWritten; FILINFO fileInfo; DIR dir; DWORD fre_clust, fre_sect, tot_sect; uint8_t result; |
В самом низу тела функции попробуем вывести некоторую полезную информацию о нашем FLASH-накопителе, в том числе и его файловую структуру (только корневую)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
*/ HAL_UART_Transmit(&huart1,(uint8_t*)"rn",2,0x1000); result = f_opendir(&dir, "/"); if (result == FR_OK) { while(1) { result = f_readdir(&dir, &fileInfo); if (result==FR_OK && fileInfo.fname[0]) { HAL_UART_Transmit(&huart1,(uint8_t*)fileInfo.fname,strlen((char*)fileInfo.fname),0x1000); if(fileInfo.fattrib&AM_DIR) { HAL_UART_Transmit(&huart1,(uint8_t*)" [DIR]",7,0x1000); } } else break; HAL_UART_Transmit(&huart1,(uint8_t*)"rn",2,0x1000); } f_closedir(&dir); } f_getfree("/", &fre_clust, &fs); sprintf(str1,"fre_clust: %lurn",fre_clust); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); sprintf(str1,"n_fatent: %lurn",fs->n_fatent - 2); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); sprintf(str1,"fs_ssize: %drn",fs->ssize); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); sprintf(str1,"fs_csize: %drn",fs->csize); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); sprintf(str1,"csize: %drn",fs->ssize * fs->csize); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); tot_sect = (fs->n_fatent - 2) * fs->csize; sprintf(str1,"tot_sect: %lurn",tot_sect); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); fre_sect = fre_clust * fs->csize; sprintf(str1,"fre_sect: %lurn",fre_sect); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); sprintf(str1, "%lu KB total drive space.rn%lu KB available.rn", fre_sect/2, tot_sect/2); HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000); |
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Вся самая важная информация о файловой системе на нашем накопителе, а также и его корневая файловая структура видна. Можно, конечно также вывести информацию о содержимом каждой папки, и подпапки, но это мы оставим на будущее.
Если вы заметили, мы обеспечили ещё то, что при извлечении нашего накопителя файловая система будет отмонтирована, а при помещении накопителя в гнездо USB OTG-кабеля будет примонтирована. И не только примонтирована, а ещё и то, что мы обеспечили при этом старт нашего приложения.
Давайте это проверим.
Извлечём наш накопитель и увидим, что на дисплее слово Start превратилось в Stop
В терминальной программе мы также увидим отчёт об извлечении накопителя
Повторно вставим FLASH-Drive в гнездо и увидим, что надпись на дисплее опять превратилась в Start
Заглянем в окно терминальной программы. Наш процесс отработал, вся информация о накопителе выведена
Таким образом, мы можем извлечь один накопитель и вставить на его место другой и получить информацию уже с него, причём не только получить информацию, а полноправно с ним работать и на запись и на чтение. Только, самое главное, мы не должны забывать о том, что извлекать накопитель мы должны только тогда, когда все файлы и каталоги на нём будут закрыты. В нашем приложении это обеспечено.
Итак, в данном занятии мы научились пользоваться аппаратной поддержкой шины USB HS, а именно классом USB HOST MSC, а также закрепили на практике данные знания при работе с реальным USB FLASH-накопителем с использованием библиотеки FATFS.
Всем спасибо за внимание!
Предыдущая часть Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь 32F746G-DISCOVERY
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий