概述
本文实现了基于STM32F107VC的金牛开发板的基于SPI模式的SD卡驱动和FatFS的移植,以及利用minini库对ini配置信息文件进行读取。
因为后面连接网络需要相关配置参数,而且可能随时发生变化,这些参数不可能固定在程序中,所以,我们现在把它放在sd卡中,以便随时更改。
IDE环境为: MDK v5.23
硬件环境:基于STM32F107VC的金牛开发板
一、添加SD卡驱动代码、移植FatFS
为了节省时间,就不造轮子了,直接使用网上共享的spi和sd驱动代码、FatFS源代码。
这部分源代码摘自:
STM32_SD_FATFS_LCD_TOUCH
备用地址:STM32_SD_FATFS_LCD_TOUCH
把这个源代码下来,解压。
把STM32_SD_FATFS_LCD_TOUCH.rarUserSD_CARDsrc 目录下的spi.c、sdcard.c文件和
STM32_SD_FATFS_LCD_TOUCH.rarUserSD_CARDinc 目录下的spi.h、sdcard.h文件都复制到我们工程的BSP目录下,并把spi.c、sdcard.c加入工程的BSP组。
在spi.h中加入:
#include "stm32f10x_spi.h"
然后下载FatFS官方源码:
http://elm-chan.org/fsw/ff/arc/ff13.zip
解压后重命名整个文件夹为FatFS,并把它复制到我们工程的third_party目录下。
在IDE上添加一个组,名字为:third_party/FatFS,添加third_party/FatFS/source目录下的diskio.c、ff.c这两个文件。
其中ff.c是具体fat文件系统的实现,diskio.c是文件系统硬件驱动接口实现。
接下来,把STM32_SD_FATFS_LCD_TOUCH.rarUserfatfs 目录下的diskio.h和diskio.c文件复制到third_party/FatFS/Source下面来,覆盖原同名文件。
这样就直接使用来源于网上的SD卡驱动接口实现了。
然后,把third_party/FatFS/source这个路径添加到IDE的包含路径中。
编译一下可以通过。
移植完了。写个demo测试一下。
首先参考网上的例程,写一个fatfs测试代码,主体放在common.h和common.c中:
common.h
#ifndef _COMMON_H_
#define _COMMON_H_ 1
#include "stm32f10x.h"
#define FI 1
#define DI 2
/* Values magic to the Board keys */
#define NOKEY 0
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4
#define RCC_KEY1 RCC_APB2Periph_GPIOD
#define GPIO_KEY1_PORT GPIOD
#define GPIO_KEY1 GPIO_Pin_3
#define RCC_KEY2 RCC_APB2Periph_GPIOA
#define GPIO_KEY2_PORT GPIOA
#define GPIO_KEY2 GPIO_Pin_8
#define RCC_KEY3 RCC_APB2Periph_GPIOC
#define GPIO_KEY3_PORT GPIOC
#define GPIO_KEY3 GPIO_Pin_13
#define RCC_KEY4 RCC_APB2Periph_GPIOA
#define GPIO_KEY4_PORT GPIOA
#define GPIO_KEY4 GPIO_Pin_0
#define GPIO_KEY_ANTI_TAMP GPIO_KEY3
#define GPIO_KEY_WEAK_UP GPIO_KEY4
uint8_t GetKey(void);
void Sys_Soft_Reset(void);
void get_file_name(uint8_t *file_name,uint8_t length,uint8_t type);
uint8_t check_file_name(uint8_t *file_name,uint8_t length);
void format_disk(void);
void creat_file(void);
void delete_file(void);
void list_file(void);
void get_disk_info(void);
void creat_dir(void);
void edit_file(void);
void read_file(void);
int InitMQTTServerInfo(void);
#endif
common.c
#include "spi.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include "ff.h"
#include "integer.h"
#include "diskio.h"
#include <string.h>
#include "FreeRTOS.h"
#include "serial.h"
//#define _DEBUG
#include "dprintf.h"
/* Handle to the com port used by both tasks. */
static xComPortHandle xPort = NULL;
/* The Rx task will block on the Rx queue for a long period. */
#define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff )
void edit_file(void)
{
FATFS fs;
FIL file;
FRESULT res;
DIR dirs;
FILINFO finfo;
signed char key = 0;
char path[20];
uint32_t index = 0x00;
uint32_t reindex = 0x00;
uint8_t file_buff[512] = {0};
uint32_t files_num = 0;
uint8_t length;
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_opendir(&dirs,"/");
printf("rn------------ÎļþÁбí------------");
if (res == FR_OK)
{
while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0])
{
if (finfo.fattrib & AM_DIR)//Èç¹ûÊÇÎļþ¼Ð
{
continue;
}
else
{
files_num++;
//ÏÔʾÎļþÃû,ÏÔʾÎļþʵ¼Ê´óС ,Îļþʵ¼Ê´óС²ÉÓÃËÄÉáÎåÈë·¨
printf("rn/%12s%7ld KB ", &finfo.fname[0],(finfo.fsize+512)/1024);
}
}
if( files_num == 0 )//ÎÞÎļþ
{
printf("rnÎÞÎļþ!");
}
}
else
{
printf("rn´ò¿ª¸ùĿ¼ʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
printf("rnÊäÈëÒª±à¼ÎļþÈ«Ãû,ÒԻسµ½áÊø...");
get_file_name((uint8_t *)path,length,FI);
res = f_open(&file,path,FA_READ | FA_WRITE);
if (res == FR_OK)
{
printf("rn´ò¿ªÎļþ %s ³É¹¦",path);
printf("rnÏÖÔÚÊÇÎļþ±à¼×´Ì¬,ÇëÊäÈëҪдÈëµÄÊý¾Ý!");
printf("rn°´ESC»òÕßCtrl+C½áÊø±à¼!rn");
while(1)
{
if(xSerialGetChar( xPort, &key, comRX_BLOCK_TIME )== pdFALSE)
{
continue;
}
if ((key == 0x1B) && (index == 0x00))//key ESC
{
printf("rnÊý¾Ý»¹Ã»ÓÐÊäÈë,ÏÖÔÚ´¦ÓÚ±à¼Ä£Ê½...");
continue;
}
else if ((key == 0x1B)) //key ESC
{
printf("rn±£´æÊý¾Ý...");
res = f_write(&file,file_buff,index,&reindex);
if ((res == FR_OK) && (reindex == index))
{
printf("rn±£´æÊý¾Ý³É¹¦!");
f_close(&file);
index = 0x00;
reindex = 0x00;
}
else
{
printf("rn±£´æÊý¾Ýʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
break;
}
else if (key == 0x03) //key Ctrl+C
{
printf("rn½áÊøÎļþ±à¼!");
printf("rn±£´æÊý¾Ý...");
res = f_write(&file,file_buff,index,&reindex);
if ((res == FR_OK) && (reindex == index))
{
printf("rn±£´æÊý¾Ý³É¹¦!");
f_close(&file);
index = 0x00;
reindex = 0x00;
}
else
{
printf("rn±£´æÊý¾Ýʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
break;
}
else if ((key < 0x21) || (key > 0x80))
{
continue;
}
else
{
file_buff[index++] = key;
printf("%c",key);
if (index > 512)
{
index = 0x00;
}
}
}
}
else
{
printf("rn´ò¿ªÎļþʧ°Ü,´íÎó´úÂë: %u",res);
}
}
void read_file(void)
{
FATFS fs;
FIL file;
FRESULT res;
DIR dirs;
FILINFO finfo;
char path[20]={0};
char buffer[512] = {0};
uint32_t i;
uint8_t length;
uint32_t re,files_num = 0;
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_opendir(&dirs,"/");
if (res == FR_OK)
{
//i = strlen(path);
printf("rn-----------ÎļþÁбí-------");
while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0])
{
if (finfo.fattrib & AM_DIR)//Èç¹ûÊÇÎļþ¼Ð
{
continue;
}
else
{
files_num++;
//ÏÔʾÎļþÃû,ÏÔʾÎļþʵ¼Ê´óС
printf("rn/%12s%7ld Byte ", &finfo.fname[0],finfo.fsize);
}
}
if( files_num == 0 )//ÎÞÎļþ
{
printf("rnÎÞÎļþ,Çë·µ»ØÏÈ´´½¨Îļþ!");
return;
}
}
else
{
printf("rn´ò¿ª¸ùĿ¼ʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
printf("rnÊäÈëÎļþÈ«Ãû,ÒԻسµ½áÊø...");
get_file_name((uint8_t *)path,length,FI);
res = f_open(&file,path,FA_READ);
if (res == FR_OK)
{
printf("rnÕýÔÚ´ò¿ªÎļþ,ÒÔÏÂÊÇÎļþÊý¾Ý:rn");
while (1)
{
for(i = 0;i < 512;i++)
{
buffer[i] = 0x00;
}
res = f_read(&file,buffer,512,&re);
printf("%s",buffer);
if (res || re == 0)
{
printf("rnÎļþ¶ÁÈ¡½áÊø,¹Ø±ÕÎļþ!");
f_close(&file);
break;
}
}
}
else
{
printf("rn´ò¿ªÎļþ %s ´íÎó£¡n",path);
}
f_mount(NULL,"",0);
}
void creat_dir(void)
{
FATFS fs;
FRESULT res;
char path[20];
uint8_t length;
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
printf("rnÇëÊäÈëÎļþ¼ÐÃû,»Ø³µÈ·ÈÏ...¸ñʽ 8 + 3...");
get_file_name((uint8_t *)path,length,DI);
res = f_mkdir(path);
if (res == FR_OK)
{
printf("rn´´½¨ÎļþĿ¼³É¹¦!");
}
else
{
printf("rn´´½¨Ä¿Â¼Ê§°Ü...");
printf("rn´íÎó´úÂë: %u",res);
}
f_mount(NULL,"",0);
}
void get_file_name(uint8_t *file_name,uint8_t length,uint8_t type)
{
signed char key;
uint8_t name_leng = 0;
printf("rn");
while (1)
{
if(xSerialGetChar( xPort, &key, comRX_BLOCK_TIME )== pdFALSE)
{
continue;
}
if ((key == 13) && (name_leng == 0))
{
printf("rn");
continue;
}
else if ((key == 0x2F) || (key == 0x5C))
{
printf("%c",key);
continue;
}
else if ((key == 13) && (name_leng > 0))
{
printf("rn");
if (type == FI)
{
if (check_file_name(file_name,name_leng) == 0)
{
break;
}
}
else
{
break;
}
}
else
{
printf("%c",key);
file_name[name_leng] = key;
name_leng++;
if (name_leng > 12)
{
printf("rnÎļþÃû¸ñʽ: 8 + 3£¬Ö»Ö§³Ö8¸ö×Ö·û,3¸öÀ©Õ¹Ãû!");
printf("rnÇëÖØÐÂÊäÈë...");
name_leng = 0;
continue;
}
}
}
}
void format_disk(void)
{
FATFS fs;
uint8_t res;
BYTE work[FF_MAX_SS]; /* Work area (larger is better for processing time) */
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
printf("rnÕýÔÚ¸ñʽ»¯´ÅÅÌ,ÇëÉÔºò...");
res = f_mkfs("", FM_ANY,0,work,sizeof(work));
if (res == FR_OK)
{
printf("rn¸ñʽ»¯³É¹¦...");
}
else
{
printf("rn¸ñʽ»¯Ê§°Ü...");
printf("rn´íÎó´úÂë: %urn",res);
}
f_mount(NULL,"",0);
}
void creat_file(void)
{
FIL file;
FIL *pf = &file;
FATFS fs;
uint8_t res;
uint8_t name[16] = {0};
uint8_t length = 0;
printf("rnÇëÊäÈëÎļþÃû,»Ø³µÈ·ÈÏ...¸ñʽ 8 + 3...");
printf("rnÀý:123.datrn");
get_file_name(name,length,FI);
res = f_mount(&fs,"",0); /* Mount a Logical Drive 0 */
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_open(pf,(TCHAR *)name,FA_READ | FA_WRITE | FA_CREATE_NEW);
if (res == FR_OK)
{
printf("rn´´½¨Îļþ³É¹¦!");
res = f_close(pf);
if (res != FR_OK)
{
printf("rn´´½¨Îļþ³É¹¦,µ«¹Ø±ÕÎļþʱ,ʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
}
else
{
printf("rn´´½¨Îļþʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
f_mount(NULL,"",0);
}
void delete_file(void)
{
FATFS fs;
FRESULT res;
DIR dirs;
FILINFO finfo;
uint8_t name[16] = {0};
uint8_t length = 0;
uint32_t files_num = 0;
res = f_mount(&fs,"",0); /* Mount a Logical Drive 0*/
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_opendir(&dirs,"/"); /* Create a Directroy Object */
if (res == FR_OK)
{
printf("rn-----------ÎļþÁбí-------");
while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0])
{
if (finfo.fattrib & AM_DIR)//Èç¹ûÊÇÎļþ¼Ð
{
continue;
}
else
{
files_num++;
//ÏÔʾÎļþÃû,ÏÔʾÎļþʵ¼Ê´óС ,Îļþʵ¼Ê´óС²ÉÓÃËÄÉáÎåÈë·¨
printf("rn/%12s%7ld KB ", &finfo.fname[0],(finfo.fsize+512)/1024);
}
}
if( files_num == 0 )//ÎÞÎļþ
{
printf("rnÎÞÎļþ,Çë·µ»ØÏÈ´´½¨Îļþ!");
return;
}
}
get_file_name(name,length,FI); /* Get file name */
res = f_unlink((TCHAR *)name); /* Delete a File or Directory */
if (res == FR_OK)
{
printf("rnɾ³ýÎļþ³É¹¦!");
}
else if (res == FR_NO_FILE)
{
printf("rnÕÒ²»µ½Îļþ»òĿ¼!");
}
else if (res == FR_NO_PATH)
{
printf("rnÕÒ²»µ½Â·¾¶!");
}
else
{
printf("rn´íÎó´úÂë: %u",res);
}
f_mount(NULL,"",0);
}
void list_file(void)
{
FATFS fs;
FILINFO finfo;
FRESULT res;
DIR dirs;
int i;
int files_num=0;
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_opendir(&dirs,"/"); /* Create a Directroy Object */
printf("rn------------ÎļþÁбí------------");
if (res == FR_OK)
{
while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0]) /* Read Directory Entry in Sequense*/
{
i = strlen(finfo.fname);
if (finfo.fattrib & AM_DIR)//Èç¹ûÊÇÎļþ¼Ð
{
files_num++;
printf("rn/%s", &finfo.fname[0]);
switch(i)//×÷ÓãºÊä³öÎļþÃû×ó¶ÔÆë
{
case 1:printf(" ");
case 2:printf(" ");
case 3:printf(" ");
case 4:printf(" ");
case 5:printf(" ");
case 6:printf(" ");
case 7:printf(" ");
case 8:printf("%15s"," ");
}
}
else
{
continue;
}
}
}
else
{
printf("rn´ò¿ª¸ùĿ¼ʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
res = f_opendir(&dirs, "/");
if (res == FR_OK)
{
while ((f_readdir(&dirs, &finfo) == FR_OK) && finfo.fname[0])
{
if (finfo.fattrib & AM_DIR)
{
continue;
}
else
{
files_num++;
printf("rn/.%12s%7ld KB ", &finfo.fname[0],(finfo.fsize+512)/1024);
}
}
if( files_num==0 )//ÎÞÎļþ
{
printf("rnÎÞÎļþ!");
}
}
else
{
printf("rn´ò¿ª¸ùĿ¼ʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
f_mount(NULL,"",0);
}
void get_disk_info(void)
{
FATFS fs;
FATFS *fls = &fs;
FRESULT res;
DWORD fre_clust;
res = f_mount(&fs,"",0); /* Mount a Logical Drive 0 */
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return;
}
res = f_getfree("/",&fre_clust,&fls); /* Get Number of Free Clusters */
if (res == FR_OK)
{
/* Print free space in unit of MB (assuming 4096 bytes/sector) */
printf("rn%d KB Total Drive Space.rn"
"%d KB Available Space.rn",
((fls->n_fatent-2)*fls->csize)*4,(fre_clust*fls->csize)*4);
}
else
{
printf("rn»ñµÃ´ÅÅÌÐÅϢʧ°Ü!");
printf("rn´íÎó´úÂë: %u",res);
}
f_mount(NULL,"",0); /*Unmount a Logical Drive 0 */
}
uint8_t check_file_name(uint8_t *file_name,uint8_t length)
{
uint8_t res;
if (length > 13)
{
res = 1;
}
else
{
if (file_name[length - 4] == '.')
{
res = 0;
}
else
{
res = 2;
}
}
return res;
}
void Sys_Soft_Reset(void)
{
SCB->AIRCR =0X05FA0000|(u32)0x04;
}
main.c
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "utils.h"
#define _DEBUG
#include "dprintf.h"
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure IO connected to LD1, LD2, LD3 and LD4 leds *********************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
//??????
void NVIC_Configuration(void)
{
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x20000000 */
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
void RCC_Configuration(void)
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA
|RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
|RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE
|RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO
|RCC_APB2Periph_SPI1, ENABLE );
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_ALL ,ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4
|RCC_APB1Periph_USART3|RCC_APB1Periph_TIM2
, ENABLE );
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
{
/* This function will get called if a task overflows its stack. If the
parameters are corrupt then inspect pxCurrentTCB to find which was the
offending task. */
( void ) pxTask;
printf("ÈÎÎñ£º%s ·¢ÏÖÕ»Òç³ön", pcTaskName);
for( ;; );
}
/*-----------------------------------------------------------*/
void vApplicationTickHook( void )
{
}
static void prvSetupHardware( void )
{
/* Start with the clocks in their expected state. */
RCC_DeInit();
/* Enable HSE (high speed external clock). */
RCC_HSEConfig( RCC_HSE_ON );
/* Wait till HSE is ready. */
while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )
{
}
/* 2 wait states required on the flash. */
*( ( unsigned long * ) 0x40022000 ) = 0x02;
/* HCLK = SYSCLK */
RCC_HCLKConfig( RCC_SYSCLK_Div1 );
/* PCLK2 = HCLK */
RCC_PCLK2Config( RCC_HCLK_Div1 );
/* PCLK1 = HCLK/2 */
RCC_PCLK1Config( RCC_HCLK_Div2 );
/* Enable PLL. */
RCC_PLLCmd( ENABLE );
/* Wait till PLL is ready. */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source. */
RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );
/* Wait till PLL is used as system clock source. */
while( RCC_GetSYSCLKSource() != 0x08 )
{
}
/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );
/* Set the Vector Table base address at 0x08000000 */
NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
/* Configure HCLK clock as SysTick clock source. */
SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );
GPIO_Configuration();
}
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
#define ledFLASH_RATE_BASE ( ( TickType_t ) 333 )
static TaskHandle_t xHandleTaskLED=NULL;
static void vTaskLED(void* pvParameters)
{
TickType_t xFlashRate, xLastFlashTime;
xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( TickType_t ) 2 );
xFlashRate /= portTICK_PERIOD_MS;
xFlashRate /= ( TickType_t ) 2;
xLastFlashTime = xTaskGetTickCount();
while(1)
{
/* Turn on LD1 */
GPIO_SetBits(GPIOD, GPIO_Pin_2);
/* Insert delay */
//vTaskDelay(300);
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
/* Turn off LD1 */
GPIO_ResetBits(GPIOD, GPIO_Pin_2);
/* Insert delay */
//vTaskDelay(300);
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
}
}
#include "serial.h"
#include "integer.h"
#include "diskio.h"
#include "ff.h"
#include "sdcard.h"
#include "common.h"
#include <stdio.h>
#define SYSTEM_INIT_TASK_PRIO ( tskIDLE_PRIORITY )
/* Handle to the com port used by both tasks. */
static xComPortHandle xPort = NULL;
/* The Rx task will block on the Rx queue for a long period. */
#define comRX_BLOCK_TIME ( ( TickType_t ) 0xffff )
static void sd_card_task(void* pvParameters)
{
signed char key = 0;
GPIO_ResetBits(GPIOF, GPIO_Pin_6); //LED1 on
while(1)
{
printf("rn============ ÇëÑ¡Ôñ...===============rnn");
printf("¸ñ ʽ »¯------------------------------- 1rnn");
printf("´´½¨Îļþ------------------------------- 2rnn");
printf("ɾ³ýÎļþ ------------------------------ 3rnn");
printf("ÁбíÎļþ------------------------------- 4rnn");
printf("ÖØÆôϵͳ ------------------------------ 5rnn");
printf("´ÅÅÌÐÅÏ¢------------------------------- 6rnn");
printf("´´½¨Ä¿Â¼------------------------------- 7rnn");
printf("±à¼Îļþ------------------------------- 8rnn");
printf("¶ÁÈ¡Îļþ------------------------------- 9rnn");
printf("========================================rnn");
xSerialGetChar( xPort, &key, comRX_BLOCK_TIME );
if (key == 0x31) //Format FS
{
printf("rn----1----");
format_disk();
}
else if (key == 0x32) //Creat File
{
printf("rn----2----");
creat_file();
}
else if (key == 0x33) //Delete File
{
printf("rn----3----");
delete_file();
}
else if (key == 0x34) //List File
{
printf("rn----4----");
list_file();
}
else if (key == 0x35) //Reset FS
{
printf("rn----5----");
Sys_Soft_Reset();
}
else if (key == 0x36) //Disk info
{
printf("rn----6----");
get_disk_info();
}
else if (key == 0x37) //Creat Dir
{
printf("rn----7----");
creat_dir();
}
else if (key == 0x38) //Edit File
{
printf("rn----8----");
edit_file();
}
else if (key == 0x39) //Read File
{
printf("rn----9----");
read_file();
}
else
{
printf("rn----%c----",key);
printf("rnÖ»½ÓÊÜ1-9ÃüÁÇëÖØÐÂÊäÈë");
}
}
}
int main(void)
{
__set_PRIMASK(1);//½ûֹȫ¾ÖÖжÏ
prvSetupHardware();
FreeRTOS_printf_service_init();
printf("###############################################rn");
printf("## hello! welcome to FreeRTOS v9.0.0 ##rn");
printf("###############################################rn");
printf("rnrn");
SD_Init();
xTaskCreate(vTaskLED,"vTaskLED",ledSTACK_SIZE,NULL,3,&xHandleTaskLED);
xTaskCreate(sd_card_task,"vTaskSDCard",1024,NULL,SYSTEM_INIT_TASK_PRIO,NULL);
vTaskStartScheduler();//Æô¶¯ÈÎÎñµ÷¶ÈÆ÷
}
/******************* (C) COPYRIGHT 2012 WildFire Team *****END OF FILE************/
到此,文件系统已经基本OK,需要说明的是,此次移植没有加上对unicode的支持,因此,也就不支持中文,需要支持中文的读者请参考其他移植文章。
下面写一个ini文件,保存为ipcfg.ini,里面内容:
[server]
ip=10.0.0.105
port=1883
name=
password=
关于server是域名(feild),ip是关键字(key),“=”后面是该关键字参数的值(value)。
关于这部分请自行搜索参考有关文章。
把ipcgf.ini放到SD卡上,进行读取操作。
以下是一些展示:
以上完整源代码:
STM32F107_FreeRTOS_v9.0.0_SDCard-FatFS.rar
二、移植minIni库
本项目使用了minIni库来读取ini文件解析配置参数,版本为minini_12b。
minIni官方网站:
https://www.compuphase.com/minini.htm
minini_12b官方源码地址:
https://www.compuphase.com/software/minini_12b.zip
下载下来,解压到minini_12b文件夹,把minini_12b整个文件夹复制到third_party目录下。
然后,在IED上添加一个组,命名为third_party/minIni,把third_party/minini_12b下的minIni.c文件加入到工程里面。
并把third_party/minini_12b加入到包含路径中。
此时编译会出现两个错误:
..OutputFreeRTOS_v9.0.0.: Error: L6218E: Undefined symbol __aeabi_assert (referred from minini.o).
..OutputFreeRTOS_v9.0.0.: Error: L6218E: Undefined symbol strnicmp (referred from minini.o).
这是链接找不到这两个函数。
所以,minIni.c需要修改。
对于__aeabi_assert,我们需要自定义实现,我们编写一个头文件bsp_assert.h,实现它:
bsp_assert.h:
#undef assert
#ifdef __cplusplus
extern "C" {
#endif
#ifdef NDEBUG
/*
* If not debugging, assert does nothing.
*/
#define assert(x) ((void)0)
#else /* debugging enabled */
/*
* CRTDLL nicely supplies a function which does the actual output and
* call to abort.
*/
extern void _assert(const char *mesg, const char *file, int line);
/*
* Definition of the assert macro.
*/
#define assert(e) ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__))
#endif /* NDEBUG */
#ifdef __cplusplus
}
#endif
并把它放在BSP目录下。
然后把minIni.c中的
#include <assert.h>
换成我们的
#include "bsp_assert.h"
对于strnicmp,我们只需要在#include “bsp_assert.h”下面加一行宏:
#define PORTABLE_STRNICMP
这一部分代码改后如下:
#if defined NDEBUG
#define assert(e)
#else
//#include <assert.h>
#include "bsp_assert.h" //added @2017.09.25
#define PORTABLE_STRNICMP //added @2017.09.25
#endif
接下来,要配置一下FatFS函数接口配置:
把minIni.h中的
#include "minGlue.h"
#include "minGlue-FatFs.h"
此时编译会出错:
..third_partyminini_12bminGlue-FatFs.h(34): error: #144: a value of type "int" cannot be used to initialize an entity of type "char *"
..third_partyminini_12bminGlue-FatFs.h(35): error: #20: identifier "NULL" is undefined
D:Program Files (x86)Keil_v5ARMARMCCBin..includestring.h(209): error: #159: declaration is incompatible with previous "strchr" (declared at line 34 of "..third_partyminini_12bminGlue-FatFs.h")
打开minGlue-FatFs.h文件,在文件顶端加入:
#include <string.h>
修改ini_rename函数,在char *drive定义前面加const:
static int ini_rename(TCHAR *source, const TCHAR *dest)
{
/* Function f_rename() does not allow drive letters in the destination file */
const char *drive = strchr(dest, ':');
drive = (drive == NULL) ? dest : drive + 1;
return (f_rename(source, drive) == FR_OK);
}
F7编译通过了。
下面写一个程序来读取上面ipcfg.ini中的参数。
在common.c中最下面加入以下代码:
#include "minIni.h"
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
const char inifile[] = "ipcfg.ini";
static char MQTTServerIP[16]={0};
static int MQTTServerPort;
static char MQTTServerName[32]={0};
static char MQTTServerPassword[32]={0};
const char * getMQTTServerIP(void)
{
return MQTTServerIP;
}
int getMQTTServerPort(void)
{
return MQTTServerPort;
}
char * getMQTTServerName(void)
{
return MQTTServerName;
}
char * getMQTTServerPassword(void)
{
return MQTTServerPassword;
}
int InitMQTTServerInfo(void)
{
FATFS fs;
FRESULT res;
char str[32+1]={0};
long n;
//int s, k;
//char section[50];
res = f_mount(&fs,"",0);
if (res != FR_OK)
{
printf("rn¹ÒÔØÎļþϵͳʧ°Ü,´íÎó´úÂë: %u",res);
return -1;
}
n = ini_gets("server", "ip", "192.168.1.1", str, sizearray(str), inifile);
printf("nserver ip:[ %s ]n",str);
memcpy(MQTTServerIP,str,n);
n = ini_gets("server", "port", "1883", str, sizearray(str), inifile);
printf("server port:[ %s ]n",str);
MQTTServerPort = atoi(str);
n = ini_gets("server", "name", "", str, sizearray(str), inifile);
printf("server name:[ %s ]n",str);
memcpy(MQTTServerName,str,n);
//dprintf("%sn",MQTTServerName);
if(strcmp(MQTTServerName,"")==0)
{
dprintf("MQttServerName=""n");
}
n = ini_gets("server", "password", "", str, sizearray(str), inifile);
printf("server password:[ %s ]n",str);
memcpy(MQTTServerPassword,str,n);
//dprintf("%sn",MQTTServerPassword);
if(strcmp(MQTTServerPassword,"")==0)
{
dprintf("MQTTServerPassword=""n");
}
f_mount(NULL,"",0);
return 0;
}
在common.h中加入:
extern int InitMQTTServerInfo(void);
extern const char * getMQTTServerIP(void);
extern int getMQTTServerPort(void);
extern char * getMQTTServerName(void);
extern char * getMQTTServerPassword(void);
其中,InitMQTTServerInfo(void)函数读取了ipcfg.ini文件,并把参数解析出来放在缓存中。
剩下的几个函数是从缓存中读取参数出来。
ini_gets(“server”, “ip”, “192.168.1.1”, str, sizearray(str), inifile); 是读取server域中的ip关键字,如果没有该关键字,则设置成默认值(此处为”192.168.1.1”)。
在程序中如果ipcfg.ini文件读取出错则会设置成以下默认值:
ip=192.168.1.1
port=1883
name=""
password=""
在mian函数中的SD_Init(); 下面添加一行:
InitMQTTServerInfo();
然后,编译链接,烧到板子上运行,可以看到:
参数已经读取出来了。
修改一下参数,把sd卡的ipcfg.ini内容改成如下:
[server]
ip=10.0.0.108
port=10000
name=admin
password=123456
上电再试:
oK,完成!
完整源代码:
STM32F107_FreeRTOS_v9.0.0_SDCard-FatFS-ini.rar
下一篇将移植LwIP-1.4.1。
最后
以上就是勤劳斑马为你收集整理的基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(三)SD卡驱动、FatFS等的移植和ini配置文件读取的实现一、添加SD卡驱动代码、移植FatFS二、移植minIni库的全部内容,希望文章能够帮你解决基于FreeRTOS与MQTT的物联网技术应用系列——步进电机控制(三)SD卡驱动、FatFS等的移植和ini配置文件读取的实现一、添加SD卡驱动代码、移植FatFS二、移植minIni库所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复