注意,本博客适合像我一样的小白,会的不多,但是想快速做些东西,不适合会写驱动的大佬。
本文使用stm32f103c8t6,裸机开发。
/**
* 硬件连接:
* CS -> PB12 连接SD卡CS
* SCK -> PB13 连接SD卡SCK
* MISO -> PB14 连接SD卡MISO
* MOSI -> PB15 连接SD卡MOSI
* 注意:
* 有的SD卡是带有AMS1117的,其VCC要接在5V上,
* STM32在只有jinl供电时5V是不会输出的,要用USB给STM32供电!!!
* 有的SD卡不支持SPI模式,我尝试后发现SNMSUNG的SD卡不支持,但是KINGSTON的可以
*/
【免费】stm32f103c8t6SD卡驱动(Fatfs)_103C8T6的FAFS文件系统资源-优快云文库
一、SD卡驱动
(一)copy源码,移植
我在优快云上找到了一位大佬用HAL库和fatfs实现stm32f103c8t6对micro SD卡读写的驱动。于是借(抄)鉴(袭)之。
1.编写SPI初始化函数(CubeIDE编辑生成的初始化代码好像在main.c和xxx_msp.c,比较散乱,于是直接上手写)
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //开启SPI2的时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB12引脚初始化为推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB13和PB15引脚初始化为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB14引脚初始化为上拉输入
/*SPI初始化*/
SPI_InitTypeDef SPI_InitStructure; //定义结构体变量
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //模式,选择为SPI主模式
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //方向,选择2线全双工
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据宽度,选择为8位
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //先行位,选择高位先行
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; //波特率分频,选择128分频
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI极性,选择低极性
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI相位,选择第一个时钟边沿采样,极性和相位决定选择SPI模式0
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS,选择由软件控制
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多项式,暂时用不到,给默认值7
SPI_Init(SPI2, &SPI_InitStructure); //将结构体变量交给SPI_Init,配置SPI1
SPI_Cmd(SPI2, ENABLE); //使能SPI2,开始运行
/*设置默认电平*/
SD_CS(1); //SS默认高电平
从原子哥的讲解来看,我们还需要更改SPI的速度,(也就是SPI_baudratePrescaler)可是 标准库当中并没有给出,我们只好操作寄存器,编写该函数(我比较菜,直接从原子哥的fatfs的SPI源码中copying过来)
SPI速度设置函数如下
/**
* @brief 设置SPI2的速度为低速
*/
void sd_spi_speed_low(void)
{
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler_256; //����SPI2�ٶ�
SPI_Cmd(SPI2,ENABLE);
}
/**
* @brief 设置SPI2的速度为高速
*/
void sd_spi_speed_high(void)
{
SPI2->CR1&=0XFFC7;
SPI2->CR1|=SPI_BaudRatePrescaler_2; //����SPI2�ٶ�
SPI_Cmd(SPI2,ENABLE);
}
之后出现了一些灵异事件!
main.c中有一个读写文件的示例函数:
void WritetoSD(char SD_FileName[], uint8_t write_buff[],uint8_t bufSize)
// {
// FATFS fs;
// FIL file;
// uint8_t res=0;
// UINT Bw;
// res = SD_init(); //SD卡初始化
// if(res == 1)
// {
// UsartPrintf(USART_DEBUG,"SD卡初始化失败! \r\n");
// OLED_ShowString(1,1,"failed!");
// }
// else
// {
// UsartPrintf(USART_DEBUG,"SD卡初始化成功! \r\n");
// OLED_ShowString(1,1,"init successed!");
// }
// res=f_mount(&fs,"0:",1); //挂载
// // if(test_sd == 0) //用于测试格式化
// if(res == FR_NO_FILESYSTEM) //没有文件系统,格式化
// {
// // test_sd =1; //用于测试格式化
// UsartPrintf(USART_DEBUG,"没有文件系统! \r\n");
// OLED_ShowString(2,1,"no file system!");
// res = f_mkfs("", 0, 0); //格式化sd卡
// if(res == FR_OK)
// {
// UsartPrintf(USART_DEBUG,"格式化成功! \r\n");
// OLED_ShowString(1,1,"geshihua sed!");
// res = f_mount(NULL,"0:",1); //格式化后先取消挂载
// res = f_mount(&fs,"0:",1); //重新挂载
// if(res == FR_OK)
// {
// UsartPrintf(USART_DEBUG,"SD卡已经成功挂载,可以进进行文件写入测试!\r\n");
// OLED_ShowString(3,1,"can test");
// }
// }
// else
// {
// UsartPrintf(USART_DEBUG,"格式化失败! \r\n");
// OLED_ShowString(1,1,"geshihua fad!");
//