一、SD卡协议原理

1、SD卡简介

SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备,由于它体积小、数据传输速度快、可热插拔等优良的特性,被广泛地于便携式装置上使用,例如数码相机、平板电脑和多媒体播放器等。

SD存储卡(Secure Digital Memory Card)是一种基于半导体快闪存储器的新一代高速存储设备。SD存储卡的技术是从MMC卡(MultiMedia Card格式上发展而来,在兼容SD存储卡基础上发展了SDIO(SD Input/ Output)卡,此兼容性包括机械,电子,电力,信号和软件,通常将SD、SDIO卡俗称SD存储卡。 [2]

SD卡具有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性,它被广泛地应用于便携式装置上,例如数码相机、平板电脑和多媒体播放器等。 [2]

SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,所以有着广泛的应用领域。音乐、电影等多媒体文件都可以方便地保存到SD卡中。目前市场上SD卡的品牌很多诸如:SANDISK、Kingmax、Panasonic和Kingston。 [2]

SD卡作为一种新型的存储设备,具有以下特点: [2]

●高存储容量,最常用的容量:8GB、16GB、32GB、128GB、256GB等。

●内置加密技术,适应基于SDMI协议的著作版权保护功能。

●高速数据传送;最大读写速率为100MB/s。

●体积轻小,便于携带,具有很强的抗冲击能力。

2、原理内部结构

3、SD卡操作模式

SD卡一般都支持 SDIO 和 SPI 这两种接口。
其中SD卡模式的信号线有:CLK、CMD、DAT0-DAT3,6根线。
SPI模式的信号线有:CS、CLK、MISO(DATAOUT)、MOSI(DATAIN),4根线。
SD卡的命令格式:命令CMD0就是0,CMD16就是16,以此类推。
SD卡的命令总共有12类,下表为几个比较重要的命令:
命令    参数    回应    描述
CMD0(0X00)    NONE    R1    复位SD卡
CMD8(0X08)    VHS+Check Pattern    R7    发送接口状态命令
CMD9(0X09)    NONE    R1    读取卡特定数据寄存器
CMD10(0X0A)    NONE    R1    读取卡标志数据寄存器
CMD16(0X10)    块大小    R1    设置块大小(字节数)
CMD17(0X11)    地址    R1    读取一个块的数据
CMD24(0X18)    地址    R1    写入一个块的数据
CMD41(0X29)    NONE    R3    发送给主机容量支持信息和激活卡初始化过程
CMD55(0X37)    NONE    R1    告诉SD卡,下一个是特定应用命令
CMD58(0X3A)    NONE    R3    读取OCR寄存器

二、实验操作

1、实验器材:SD模块及SD卡,STM32f103c8t6,杜邦线若干,电源线一根

2、硬件连接:

stm32 SD卡模块
PA4 SDCS
PA5 SCK
PA7 MOSI
PA6 MISO
VCC VCC
GND

GND

3、HAL库配置(stm32CubeMX)

设置RCC,SYS,在以往博客都有,不在此陈述。

4、完整代码分析

完整代码链接:https://pan.baidu.com/s/1V-u1Mt1gUFCc70Jw8v6PtA
提取码:1234

主函数:

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration---------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_FATFS_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */HAL_UART_Receive_IT(&huart1,&aRxBuffer1,1);   //enable uart   printf(" main \r\n");Get_SDCard_Capacity();   //得到使用内存并选择格式化/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){WritetoSD(WriteBuffer,sizeof(WriteBuffer));      HAL_Delay(500);WriteBuffer[0] = WriteBuffer[0] +10;WriteBuffer[1] = WriteBuffer[1] +10;write_cnt ++;while(write_cnt > 10){ printf(" while \r\n");HAL_Delay(500);}        /* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

写入函数

void WritetoSD(BYTE write_buff[],uint8_t bufSize)
{FATFS fs;FIL file;uint8_t res=0;UINT Bw;  res = SD_init();       //SD卡初始化if(res == 1){printf("SD卡初始化失败! \r\n");      }else{printf("SD卡初始化成功! \r\n");        }res=f_mount(&fs,"0:",1);        //挂载
//  if(test_sd == 0)      //用于测试格式化if(res == FR_NO_FILESYSTEM)      //没有文件系统,格式化{
//      test_sd =1;                //用于测试格式化printf("没有文件系统! \r\n");      res = f_mkfs("", 0, 0);      //格式化sd卡if(res == FR_OK){printf("格式化成功! \r\n");     res = f_mount(NULL,"0:",1);      //格式化后先取消挂载res = f_mount(&fs,"0:",1);            //重新挂载  if(res == FR_OK){printf("SD卡已经成功挂载,可以进进行文件写入测试!\r\n");}  }else{printf("格式化失败! \r\n");      }}else if(res == FR_OK){printf("挂载成功! \r\n");       }else{printf("挂载失败! \r\n");}  res = f_open(&file,SD_FileName,FA_OPEN_ALWAYS |FA_WRITE);if((res & FR_DENIED) == FR_DENIED){printf("卡存储已满,写入失败!\r\n");      }f_lseek(&file, f_size(&file));//确保写词写入不会覆盖之前的数据if(res == FR_OK){printf("打开成功/创建文件成功! \r\n");        res = f_write(&file,write_buff,bufSize,&Bw);       //写数据到SD卡if(res == FR_OK){printf("文件写入成功! \r\n");            }else{printf("文件写入失败! \r\n");}     }else{printf("打开文件失败!\r\n");} f_close(&file);                     //关闭文件      f_mount(NULL,"0:",1);      //取消挂载
}

 实验注意事项:一定要接5V电源,杜邦线最好短一点的。

初始化成功(其中很多辛酸泪)

读出数据

在这里更改写入内容

三、Ubuntu下堆、栈、全局、局部等变量的分配地址

主要代码:

#include <stdio.h>
#include <stdlib.h>
//定义全局变量
int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;
void output(int a)
{printf("hello");printf("%d",a);printf("\n");
}int main( )
{   //定义局部变量int a=2;static int inits_local_c=2, uninits_local_c;int init_local_d = 1;output(a);char *p;char str[10] = "lmy";//定义常量字符串char *var1 = "1234567890";char *var2 = "qwertyuiop";//动态分配int *p1=malloc(4);int *p2=malloc(4);//释放free(p1);free(p2);printf("栈区-变量地址\n");printf("                a:%p\n", &a);printf("                init_local_d:%p\n", &init_local_d);printf("                p:%p\n", &p);printf("              str:%p\n", str);printf("\n堆区-动态申请地址\n");printf("                   %p\n", p1);printf("                   %p\n", p2);printf("\n全局区-全局变量和静态变量\n");printf("\n.bss段\n");printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);printf("\n.data段\n");printf("全局外部有初值 init_global_a:%p\n", &init_global_a);printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);printf("\n文字常量区\n");printf("文字常量地址     :%p\n",var1);printf("文字常量地址     :%p\n",var2);printf("\n代码区\n");printf("程序区地址       :%p\n",&main);printf("函数地址         :%p\n",&output);return 0;
}

输入一下命令:并且在创建的文件下

sudo nano text.cgcc text.c -o text./text

可以发现,Ubuntu在栈区和堆区的地址值都是从上到下增长的。

四、stm32下的C程序中堆、栈、全局、局部等变量的分配地址

1、内存分配

分区    特点
栈区(stack)    由编译器自动分配释放,存放函数的参数值,局部变量的值等。
堆区(heap)    一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收 。
全局区(静态区)(static)    全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。当程序结束后,变量由系统释放 。
文字常量区    存放常量字符串。当程序结束后,常量字符串由系统释放 。
程序代码区    存放函数体的二进制代码。
存储顺序(由上到下)
栈区
堆区
全局区
常量区
代码区
2、全局变量与局部变量

全局变量:
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件。
局部变量:
定义在函数体内部的变量,作用域仅限于函数体内部。离开函数体就会无效,再调用就是出错。
区别如下:
全局变量    局部变量
定义在方法外    定义在方法内
整个类都能用    只能在方法中使用
不赋值也会有默认值    不赋值就没有默认值
位于堆内存    位于栈内存

直接用以前的串口通信改写

main.c

#include "usart.h"
#include <stdio.h>
#include <stdlib.h>int init_global_a = 1;
int uninit_global_a;
static int inits_global_b = 2;
static int uninits_global_b;void output(int a)
{printf("hello");printf("%d",a);printf("\n");
}int main(void)
{   uart_init(115200);  while(1){//定义局部变量int a=2;static int inits_local_c=2, uninits_local_c;int init_local_d = 1;char *p;char str[10] = "zls";//定义常量字符串char *var1 = "1234567890";char *var2 = "qwertyuiop";//动态分配int *p1=malloc(4);int *p2=malloc(4);output(a);//释放free(p1);free(p2);printf("栈区-变量地址\n");printf("                a:%p\n", &a);printf("                init_local_d:%p\n", &init_local_d);printf("                p:%p\n", &p);printf("              str:%p\n", str);printf("\n堆区-动态申请地址\n");printf("                   %p\n", p1);printf("                   %p\n", p2);printf("\n全局区-全局变量和静态变量\n");printf("\n.bss段\n");printf("全局外部无初值 uninit_global_a:%p\n", &uninit_global_a);printf("静态外部无初值 uninits_global_b:%p\n", &uninits_global_b);printf("静态内部无初值 uninits_local_c:%p\n", &uninits_local_c);printf("\n.data段\n");printf("全局外部有初值 init_global_a:%p\n", &init_global_a);printf("静态外部有初值 inits_global_b:%p\n", &inits_global_b);printf("静态内部有初值 inits_local_c:%p\n", &inits_local_c);printf("\n文字常量区\n");printf("文字常量地址     :%p\n",var1);printf("文字常量地址     :%p\n",var2);printf("\n代码区\n");printf("程序区地址       :%p\n",&main);printf("函数地址         :%p\n",&output);return 0;}
}

STM32 在栈区和堆区的地址值从上往下是变小的,与Ubuntu下刚好相反。

五、总结

在此次实验中学会了SD卡的写入,以及堆栈等概念。

六、参考

基于ubuntu,树莓派和stm32的C程序的内存分配问题_Harriet的博客-CSDN博客

【IoT】STM32 内存分配详解_简一商业-CSDN博客_stm32内存分配

基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM - 学以解忧的个人空间 - OSCHINA - 中文开源技术交流社区

STM32 KEIL下的堆栈设置

STM32 KEIL下的堆栈设置_nancy的专栏-CSDN博客_stm32设置堆栈

STM32对SD卡数据读取和在Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址的对比分析相关推荐

  1. 运用STM32对SD卡数据读取

    文章目录 一.利用Altium Designer 18绘制原理图 1 Altium Designer 18的安装 1.1 下载和破解 1.2 添加元件库 2 stm32最小系统的电路原理图 3 STM ...

  2. SD卡数据读取Altium Designer下载

    目录 一.SD卡数据读取 1.SD卡简介 2.代码实现 1.所用软件及硬件 2.SD卡实物连线 3.运行 二.Altium Designer下载及原理图绘制 1.Altium Designer软件安装 ...

  3. 【嵌入式】Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址

    Ubuntu.stm32下的C程序中堆.栈.全局.局部等变量的分配地址 一.总体介绍 1.栈区(stack) 2.堆区(heap) 3.全局区(静态区) (1).bss段 (2).data段 4.常量 ...

  4. Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的重温

    一.C程序的内存分配 1.栈区(stack) 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) 一般由程序员分配释放,若程序员不释放,程序 ...

  5. 【小陈睡不醒SD卡数据读取以及Altium Designer绘制stm32最小系统原理图及stm32+SD卡绘制】

    一SD卡介绍 1.SD卡 SD存储卡(Secure Digital Memory Card)是一种基于半导体快闪存储器的新一代高速存储设备.SD存储卡的技术是从MMC卡(MultiMedia Card ...

  6. Ubuntu、stm32下的C程序中堆、栈、全局、局部等变量的分配地址

    目录 一.C程序中的一些变量及内存分配 1.全局变量 2.局部变量 3.内存分配 4.内存段 5.内存管理 二.在Ubuntu和Keil中显示变量地址分配 1.Ubuntu中运行 代码撰写 运行结果 ...

  7. Ubuntu、stm32下的C程序各变量的分配地址分析

    文章目录 一.C程序的内存分配 1. 栈区(stack) 2. 堆区(heap) 3. 全局区(静态区) 3.1 .bss段 3.2 .data段 4. 常量区 5. 代码区 二. 栈区.堆区等区存放 ...

  8. STM32单片机基础19——使用SDMMC接口读写SD卡数据

    本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件SDMMC外设读取SD卡数据. 1. 准备工作 硬件准备 开发板 首先需要准备一个开发板,这里我准备的是STM32L4 ...

  9. STM32挂载SD卡基于Fatfs文件系统读取文件信息

    STM32挂载SD卡基于Fatfs文件系统读取文件信息

最新文章

  1. new com.mysql.jdbc.Driver()为什么Driver会创建两次
  2. 005_Ajax get请求获取XML响应
  3. 内存不足导致mysql关闭,CentOS6.5增加swap分区
  4. 关于流控器件和压控器件
  5. bash: pcre-config: 未找到命令..._Docker 常用操作命令
  6. html5 职工入职后台管理系统_ChemCMS是一款基于GO+PHP+MYSQL+HTML5构建的化学内容管理系统
  7. 安卓开发第一个小程序HelloWorld
  8. P1010 幂次方 P1022 计算器的改良
  9. oracle+执行变量语句,ORACLE sql 语句的执行过程(SQL性能调整)
  10. DeepFake技术--win7下faceswap环境配置(一)(二)(三)
  11. 涉密计算机清退登记表,涉密载体登记表.doc
  12. matlab选址问题——分级选址定容
  13. mydisktest测试软件,MyDiskTest
  14. 网站浏览器可以打开,在微信中打不开,排查问题的过程
  15. 6.2 不一致数据的转换
  16. 【外挂逆向】《某涯明月刀》BUFF及技能预判
  17. ACM中的数学问题合集
  18. golang导入私有仓库报错:“server response: not found:xxx: invalid version: git ls-remote -q origin in xxx“
  19. Factorials
  20. 1-7 德州扑克(c++)

热门文章

  1. php页面漏洞分析及相关问题解决
  2. 中秋写了个狼吃羊的智力游戏
  3. 如何停止/重启/启动Redis服务
  4. 弹弹堂为什么我早上登陆显示加载服务器列表失败fail,弹弹堂加载服务器列表失败...
  5. 黑马程序员pink老师前端入门教程,零基础必看的JavaScript基础语法视频教程(BOM)
  6. 教你一招通过注册表一键开启/禁用USB端口
  7. 鸿联九五26周年,追梦不止,犇赴未来
  8. Centos 配置服务器
  9. 字 掉落 炫酷 网站_有哪些鲜为人知,但是很有意思的网站?
  10. 深度学习--前馈神经网络、反馈神经网络