class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_CardInfoTypeDef pCardInfo = {0};          // SD卡信息结构体
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_GetCardInfo(&hsd, &pCardInfo);            // 获取 SD 卡的信息
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line">2、读数据
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_ReadBlocks(&hsd, aOldData, 7, 2, 3000); // SD卡的句柄、数据、块地址、块数量、超时ms
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line">3、写数据
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_WriteBlocks(&hsd, aTestData, 7, 2, 3000) // SD卡的句柄、数据、块地址、块数量、超时ms
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line">
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line">4、擦除数据
  • class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="12"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_Erase(&hsd, 7, 8) // SD卡的句柄、块起始地址、块结束地址
  • class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    本篇通过DMA读写,将使用以下两个读写函数:

    (和基础读写的函数名称近似,只是多了后辍"_DMA")

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line">4、读取数据_通过DMA
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_ReadBlocks_DMA(&hsd, aOldData, 7, 2); // 读取SD卡指定块的数据; 参数:SD句柄、数据地址、块起始地址、需要读取的块数量;
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">
    4. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line">5、写入数据_通过DMA
    5. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line">HAL_SD_WriteBlocks_DMA(&hsd, aTestData, 7, 2); // 向指定块写入数据; 参数:SD句柄、数据地址、块起始地址、需要写入的块数量;
    6. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line">
    class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    注意机制的不同:

    4、中断回调函数

    通过DMA读、写后,有两种方式可以知道读写操作是否完成:

    1. 通过HAL_SD_GetState(&hsd)获取状态;
    2. 通过它俩的中断回调函数。本篇将使用中断回调函数的方式,这样操作性更好;

    中断回调函数需要自行手写,可以写在 it.c 或 main.c底部 ,它俩分别是:

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line">1、DMA TX 传输完成 中断回调函数
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line">
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
    4. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line">{
    5. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line"> printf("写入完成\r\n");
    6. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line">}
    7. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line">
    8. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line">2、DMA RX 传输完成 中断回调函数
    9. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line">void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
    10. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line">{
    11. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line"> printf("读取完成\r\n");
    12. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="12"> class="hljs-ln-code"> class="hljs-ln-line">}
    class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    5、具体读写操作示例

    首先说明一点,本示例示范如何通过DMA读写,而示范代码中的状态判断,只是提供一个思路,这种写法是不高效的,需按自身方案作出适合的修改。

    第一步:新建两个变量,作为DMA读写完成的标志。

    在main()的上方,新建两个变量,作为读写结束的标志:

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line">volatile uint8_t myFlagSDReadReady = 0; // 读取传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line">volatile uint8_t myFlagSDWriteReady = 0; // 写入传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">
    class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    技巧:

    这里用了volatile关键字修饰变量。

    因为示范代码中有几段 while (myFlagSDReadReady == 0) 这样的空循环判断变量状态变化。

    而CubeMX生成的工程,默认编译优化等级是3。编译时会把这一段中的变量误判为是不变的,编译运行后,就会导致循环体“卡死”。

    使用 volatile 修饰,是告诉编译器不要优化它,每次循环时都必须从内存中读一次这变量的真实值。

    编写完成后,位置如下图:

    第二步:在main() 下方,即/* USER CODE BEGIN 4 */下面,编写需要的两个中断回调函数:

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line">/*DMA Tx传输完成中断回调函数*/
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line">void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line">{
    4. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDWriteReady = 1; // 写入传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    5. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line">}
    6. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line">
    7. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line">/*DMA Rx传输完成中断回调函数*/
    8. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line">void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
    9. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line">{
    10. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDReadReady = 1; // 读取传输完成标志; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    11. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line">}
    class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    编写完成后,位置如下图:

    第三步:在 main()函数内,/* USER CODE BEGIN 2 */ 注释下方,编写读写代码:

    有点点长,建议直接复制。

    其实,有效的读写只是简单的几行而已,这里写了一堆,只是为了展示。

    代码里已附详细注释,整体流程是:

    1. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="1"> class="hljs-ln-code"> class="hljs-ln-line"> /***************** SD卡读写通信测试 *****************/
    2. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="2"> class="hljs-ln-code"> class="hljs-ln-line"> /* 1、获取卡信息,打印到串口助手 */
    3. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="3"> class="hljs-ln-code"> class="hljs-ln-line"> /* 2、读测试:读出测试位置原数据,保存在 aOldData[] */
    4. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="4"> class="hljs-ln-code"> class="hljs-ln-line"> /* 3、写测试:在测试的块上,写入指定数据 */
    5. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="5"> class="hljs-ln-code"> class="hljs-ln-line"> /* 读出刚才写入的块数据,打印到串口助手观察 */
    6. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="6"> class="hljs-ln-code"> class="hljs-ln-line"> /* 4、擦除测试:擦除指定块上的数据 */
    7. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="7"> class="hljs-ln-code"> class="hljs-ln-line"> /* 读出刚才擦除块的数据,打印到串口助手观察 */
    8. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="8"> class="hljs-ln-code"> class="hljs-ln-line"> /* 5、写回原数据到指定位置 */
    9. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="9"> class="hljs-ln-code"> class="hljs-ln-line"> /* 读出刚才写入的块数据,打印到串口助手观察 */
    10. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="10"> class="hljs-ln-code"> class="hljs-ln-line">
    11. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="11"> class="hljs-ln-code"> class="hljs-ln-line"> #define SD_TEST_SIZE 1024 // 测试数据的字节数,刚好是2个块大小:2x512
    12. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="12"> class="hljs-ln-code"> class="hljs-ln-line"> static uint8_t aOldData[SD_TEST_SIZE] = {0}; // 用于存放旧数据,先读出来,测试完了,再把旧数据写回去
    13. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="13"> class="hljs-ln-code"> class="hljs-ln-line"> static uint8_t aTestData[SD_TEST_SIZE] = {0}; // 临时缓存,用来存放测试数据
    14. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="14"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_CardInfoTypeDef pCardInfo = {0}; // SD卡信息结构体
    15. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="15"> class="hljs-ln-code"> class="hljs-ln-line">
    16. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="16"> class="hljs-ln-code"> class="hljs-ln-line"> uint8_t status = HAL_SD_GetCardState(&hsd); // SD卡状态标志值
    17. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="17"> class="hljs-ln-code"> class="hljs-ln-line"> if (status == HAL_SD_CARD_TRANSFER)
    18. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="18"> class="hljs-ln-code"> class="hljs-ln-line"> {
    19. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="19"> class="hljs-ln-code"> class="hljs-ln-line"> /* 1、获取卡信息,打印到串口助手 */
    20. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="20"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_GetCardInfo(&hsd, &pCardInfo); // 获取 SD 卡的信息
    21. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="21"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r1、获取SD卡信息 ... \r\n");
    22. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="22"> class="hljs-ln-code"> class="hljs-ln-line"> printf("卡类型:%d \r\n", pCardInfo.CardType); // 类型返回:0-SDSC、1-SDHC/SDXC、3-SECURED
    23. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="23"> class="hljs-ln-code"> class="hljs-ln-line"> printf("卡版本:%d \r\n", pCardInfo.CardVersion); // 版本返回:0-CARD_V1、1-CARD_V2
    24. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="24"> class="hljs-ln-code"> class="hljs-ln-line"> printf("块数量:%d \r\n", pCardInfo.BlockNbr); // 可用的块数量
    25. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="25"> class="hljs-ln-code"> class="hljs-ln-line"> printf("块大小:%d \r\n", pCardInfo.BlockSize); // 每个块的大小; 单位:字节
    26. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="26"> class="hljs-ln-code"> class="hljs-ln-line"> printf("卡容量:%lluG \r\n", ((unsigned long long)pCardInfo.BlockSize * pCardInfo.BlockNbr) / 1024 / 1024 / 1024); // 计算卡的容量
    27. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="27"> class="hljs-ln-code"> class="hljs-ln-line">
    28. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="28"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_Delay(1000); // 重要:稍作延时再开始读写测试; 避免有些仿真器烧录期间的多次复位,短暂运行了程序,导致下列读写数据不完整。
    29. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="29"> class="hljs-ln-code"> class="hljs-ln-line">
    30. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="30"> class="hljs-ln-code"> class="hljs-ln-line"> /* 2、读测试:读出测试位置原数据,保存在 aOldData[] */
    31. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="31"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r2、读取测试块的原数据 ... \r\n");
    32. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="32"> class="hljs-ln-code"> class="hljs-ln-line"> memset(aOldData, 0, SD_TEST_SIZE); // 清0数组的数据
    33. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="33"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDReadReady = 0; // 读取传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个变量赋值1.
    34. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="34"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_ReadBlocks_DMA(&hsd, aOldData, 7, 2); // 读取SD卡指定块的数据; 参数:SD句柄、数据地址、块起始地址、需要读取的块数量;
    35. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="35"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDReadReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    36. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="36"> class="hljs-ln-code"> class="hljs-ln-line"> for (uint32_t i = 0; i < SD_TEST_SIZE; i++) // 打印 原始数据
    37. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="37"> class="hljs-ln-code"> class="hljs-ln-line"> printf("%X ", aOldData[i]);
    38. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="38"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r\n");
    39. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="39"> class="hljs-ln-code"> class="hljs-ln-line">
    40. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="40"> class="hljs-ln-code"> class="hljs-ln-line"> /* 3-1、写测试:在测试的块上写入数据 */
    41. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="41"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r3、SD卡 写入测试 ...\r\n");
    42. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="42"> class="hljs-ln-code"> class="hljs-ln-line"> memset(aTestData, 0x8, SD_TEST_SIZE); // 整个数组填充指定值,作为测试写入的数据
    43. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="43"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDWriteReady = 0; // 写入传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个变量赋值1.
    44. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="44"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_WriteBlocks_DMA(&hsd, aTestData, 7, 2); // 向指定块写入数据; 参数:SD句柄、数据地址、块起始地址、需要写入的块数量;
    45. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="45"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDWriteReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    46. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="46"> class="hljs-ln-code"> class="hljs-ln-line"> printf("对指定块写入结束! \r写入的数据是:\n");
    47. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="47"> class="hljs-ln-code"> class="hljs-ln-line"> for (uint32_t i = 0; i < SD_TEST_SIZE; i++) // 打印 写入的数据
    48. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="48"> class="hljs-ln-code"> class="hljs-ln-line"> printf("%X ", aTestData[i]);
    49. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="49"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r\n");
    50. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="50"> class="hljs-ln-code"> class="hljs-ln-line"> /* 3-2、读出现在块内的数据 */
    51. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="51"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r现在块内的数据是:\r\n");
    52. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="52"> class="hljs-ln-code"> class="hljs-ln-line"> memset(aTestData, 0, SD_TEST_SIZE); // 清0数组的数据
    53. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="53"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDReadReady = 0; // 读取传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个变量赋值1.
    54. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="54"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_ReadBlocks_DMA(&hsd, aTestData, 7, 2); // 读SD卡数据块; 参数:SD句柄、数据地址、块起始地址、读的块数量;
    55. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="55"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDReadReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    56. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="56"> class="hljs-ln-code"> class="hljs-ln-line"> for (uint32_t i = 0; i < SD_TEST_SIZE; i++) // 打印 写入后块内现在数据
    57. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="57"> class="hljs-ln-code"> class="hljs-ln-line"> printf("%X ", aTestData[i]);
    58. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="58"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r\n");
    59. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="59"> class="hljs-ln-code"> class="hljs-ln-line">
    60. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="60"> class="hljs-ln-code"> class="hljs-ln-line"> /* 4-1、擦除测试:擦除指定块上的数据 */
    61. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="61"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r4、擦除块测试 ...\r\n");
    62. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="62"> class="hljs-ln-code"> class="hljs-ln-line"> if (HAL_SD_Erase(&hsd, 7, 8) == HAL_OK) // 擦除SD卡上的数据; 参数:SD结构体、块的起始地址、块的结束地址
    63. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="63"> class="hljs-ln-code"> class="hljs-ln-line"> {
    64. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="64"> class="hljs-ln-code"> class="hljs-ln-line"> while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER); // 等待卡的读写操作结束
    65. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="65"> class="hljs-ln-code"> class="hljs-ln-line"> printf("擦除 成功! \r\n");
    66. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="66"> class="hljs-ln-code"> class="hljs-ln-line"> }
    67. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="67"> class="hljs-ln-code"> class="hljs-ln-line"> else
    68. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="68"> class="hljs-ln-code"> class="hljs-ln-line"> {
    69. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="69"> class="hljs-ln-code"> class="hljs-ln-line"> printf("擦除 失败! \r\n");
    70. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="70"> class="hljs-ln-code"> class="hljs-ln-line"> }
    71. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="71"> class="hljs-ln-code"> class="hljs-ln-line"> /* 4-2、读取,擦除后指定块上的数据 */
    72. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="72"> class="hljs-ln-code"> class="hljs-ln-line"> printf("擦除后,现在块内的数据是:\r\n");
    73. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="73"> class="hljs-ln-code"> class="hljs-ln-line"> memset(aTestData, 0, SD_TEST_SIZE); // 清0数组的数据
    74. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="74"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDReadReady = 0; // 读取传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个值赋值1.
    75. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="75"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_ReadBlocks_DMA(&hsd, aTestData, 7, 2); // 读SD卡数据块; 参数:SD句柄、数据地址、块起始地址、读的块数量;
    76. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="76"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDReadReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    77. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="77"> class="hljs-ln-code"> class="hljs-ln-line"> for (uint32_t i = 0; i < SD_TEST_SIZE; i++) // 打印 块内现在的数据
    78. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="78"> class="hljs-ln-code"> class="hljs-ln-line"> printf("%X ", aTestData[i]);
    79. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="79"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r\n");
    80. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="80"> class="hljs-ln-code"> class="hljs-ln-line">
    81. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="81"> class="hljs-ln-code"> class="hljs-ln-line"> /* 5-1、写回测试块上的原始数据 */
    82. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="82"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r5、写回原数据 ...\r\n");
    83. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="83"> class="hljs-ln-code"> class="hljs-ln-line"> //memset(aOldData, 0, SD_TEST_SIZE); // 这行是备用的,为了测试后写入特定数据
    84. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="84"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDWriteReady = 0; // 写入传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个变量赋值1.
    85. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="85"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_WriteBlocks_DMA(&hsd, aOldData, 7, 2); // 向指定块写入数据; 参数:SD句柄、数据地址、块起始地址、需要写入的块数量;
    86. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="86"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDWriteReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    87. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="87"> class="hljs-ln-code"> class="hljs-ln-line"> printf("写入结束! \n");
    88. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="88"> class="hljs-ln-code"> class="hljs-ln-line"> /* 5-2、读取现在块内的数据 */
    89. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="89"> class="hljs-ln-code"> class="hljs-ln-line"> printf("现在块内的数据是: \r\n");
    90. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="90"> class="hljs-ln-code"> class="hljs-ln-line"> memset(aTestData, 0, SD_TEST_SIZE); // 清0数组的数据
    91. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="91"> class="hljs-ln-code"> class="hljs-ln-line"> myFlagSDReadReady = 0; // 读取传输完成标志。当DMA传输结束后,在DMA中断回调函数里(已写在main.c底部), 把这个值赋值1.
    92. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="92"> class="hljs-ln-code"> class="hljs-ln-line"> HAL_SD_ReadBlocks_DMA(&hsd, aTestData, 7, 2); // 读SD卡数据块; 参数:SD句柄、数据地址、块起始地址、读的块数量;
    93. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="93"> class="hljs-ln-code"> class="hljs-ln-line"> while (myFlagSDReadReady == 0); // 等待传输完成; 重要:CubeMX生成的Keil工程,编译优化等级默认是3,如果变量没有标记为易变的(volatile),编译器可能会认为其值在循环中不会改变,从而导致优化后的代码无法正确检测到变量值的变化,特别是在空循环体中。
    94. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="94"> class="hljs-ln-code"> class="hljs-ln-line"> for (uint32_t i = 0; i < SD_TEST_SIZE; i++) // 打印 块内现在的数据
    95. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="95"> class="hljs-ln-code"> class="hljs-ln-line"> printf("%X ", aTestData[i]);
    96. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="96"> class="hljs-ln-code"> class="hljs-ln-line"> printf("\r\n\r\n");
    97. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="97"> class="hljs-ln-code"> class="hljs-ln-line">
    98. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="98"> class="hljs-ln-code"> class="hljs-ln-line"> printf("SD卡 读写测试结束!\r\n");
    99. class="hljs-ln-numbers"> class="hljs-ln-line hljs-ln-n" data-line-number="99"> class="hljs-ln-code"> class="hljs-ln-line"> }
    class="hide-preCode-box"> class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)">

    编写完成后,位置如下图:

    至此,代码编写完成,可以编译、烧录了。


    四、实验效果

    程序运行后,串口助手输出如下:

    如有错漏 ,望指正~~~!

    data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/qq_49053936/article/details/145304596","extend1":"pc","ab":"new"}">>
    注:本文转载自blog.csdn.net的【 STM32开发 】的文章"https://blog.csdn.net/qq_49053936/article/details/145304596"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
    复制链接

    评论记录:

    未查询到任何数据!