查看: 374|回复: 14

[未解决] SD卡存储数组数据(非字符或字符串)

[复制链接]
  • TA的每日心情
    郁闷
    2018-12-15 20:26
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    发表于 2018-12-4 13:52 | 显示全部楼层 |阅读模式
    Arduino怎么使用数组存储一组数组数据(非ASCII码字符),我看书上有用file.writez(buf , len)可以实现,但是实际编译确编译不过去。(报错:no matching function for call to 'write(int, unsigned int)')file:///C:/Users/YUMU/Documents/Tencent%20Files/1109943828/Image/Group/WKX%7D_%N3WPVL_OI2YKHO)64.jpg
    哪位高手知道怎么样可以在SD卡存储数组文件,和读取数组文件。
    麻烦大家了
  • TA的每日心情
    奋斗
    2018-12-16 14:04
  • 签到天数: 22 天

    [LV.4]偶尔看看III

    发表于 2018-12-7 15:40 | 显示全部楼层
    本帖最后由 t3486784401 于 2018-12-7 15:47 编辑

    来来来 C 语言复习起来!

    首先 File.write 可以写入你想要的任何长度、任何内容,前提是你对 C 指针语法有了解,不使用错。
    我在我的 SD 模块上写了一段,输出四个文件,下面一一解释之。
    由于我的 Arduino 和 SD 模块之间挂了一片 16V8 做总线地址解析,因而繁杂的底层已经略去,仅显示 SD 操作。

    kittenblock中小学创客名师推荐的图形化编程软件

    // Write to Files
    File fo;
    
    char str1[]= "Hey guy!";
    fo= SD.open("1_ASCTXT.TXT", FILE_WRITE);
    fo.println(str1);           // println(char*)
    fo.println(str1[0]);        // println(char)
    fo.write(str1, 3);          // write(char*, int)
    fo.close();
    
    uint8_t buf2[]= {0x01, 0x03, 0x05, 0x07};
    fo= SD.open("2_RAWU08.DAT", FILE_WRITE);
    fo.write(buf2, 1);
    fo.write(buf2, 3);
    fo.close();
    
    uint16_t buf3[]= {0x1234, 0xABCD, 0x9876, 0xFEDC};
    fo= SD.open("3_RAWU16.DAT", FILE_WRITE);
    fo.write((uint8_t*)buf3, 2);        // Warning: LE format
    fo.write((uint8_t*)&buf3[2], 4);    // Warning: LE format
    fo.close();
    
    uint32_t c;
    fo= SD.open("4_RAWU32.DAT", FILE_WRITE);
    for(c=0; c<20; c++)
    {
        fo.write((uint8_t*)&c, 4);      // Warning: LE-Format
    }
    fo.close();
    
    float fv= 3.14159;
    fo= SD.open("5_RAWF32.DAT", FILE_WRITE);
    fo.print(fv);                       // print(float)
    fo.write((uint8_t*)&fv, sizeof(fv));// Warning: IEEE-Format
    fo.close();



    输出结果总计五个文件,这里使用 WinHex 打开查看。

    0-Files.png

    直接 char[] 数组输出:
    File#1-Exp.png


    u8数组输出:
    File#2-Exp.png


    u16数组输出(含指定起始地址):
    File#3-Exp.png


    u32循环输出:
    File#4-Exp.png


    float输出(含文本形、IEEE形):
    File#5-Exp.png


    可以输出任意类型,只需在 write 当中做一次强制指针类型转换,强制把地址转换为 (uint8_t*) 类型即可
    当然前提是你真的了解内存里存的是什么,如果像 float 那样输出了 IEEE 格式就不好玩了。

    话说这个 write 接口设计的也不好,第一个指针参数应该设计成 void* 型,这样默认就可以转换了。
    以下内容摘自 Windows 标准编程 MFC 当中的参考手册,class CFile 当中的 write 接口原型:

    virtual void Write( const void* lpBuf,UINT nCount );

    这个原型下,任意地址都可以往 Write 里传,默认都会转换好。

    还有一个就是大小端对齐的问题(LE/BE),直观说就是 0x1234 中的 34h 字节存在前(低地址)或后(高地址)的问题。
    AVR 使用小端对齐(LE),34h 存储在低地址,直接 write 的话就会看到上边 WinHex 看到的 34 12 数据。
    当然这个是相对的,如果你用 read 接口读取这个文件,34 12 数据会被正确翻译回 0x1234。

    ------------------------------------------------------------------------------------------

    以上,说的如有问题大家多指教



    点评

    谢谢!看来还需要好好研读一下C基础。  发表于 2018-12-12 18:02
  • TA的每日心情
    奋斗
    2018-12-6 11:03
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    发表于 2018-12-5 08:51 | 显示全部楼层

    回帖奖励 +30 金币

    你把代码贴出来看看...
  • TA的每日心情
    郁闷
    2018-12-15 20:26
  • 签到天数: 17 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-12-5 12:17 | 显示全部楼层
    代码是:#include <SPI.h>
    #include <SD.h>
    File myFile;
    unsigned int i, s[68];
    void setup()
    {
    Serial.begin(9600);
    }
    void loop()
    {
      for(int j=0;j<30;j++)
      {
      myFile = SD.open("A" , FILE_WRITE);         //写入方式打开文件A
      if (myFile)                                     //如果文件打开正常,请写下来:
       {
         i++;              //i循环30次(1,2,3...)
         myFile.write(30,i ); //写入数组i(i=1,2,3...)
         Serial.print(myFile.read());
       }
      }
      myFile.close();   //关闭文件  
    }

  • TA的每日心情
    郁闷
    2018-12-15 20:26
  • 签到天数: 17 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-12-5 12:18 | 显示全部楼层
    lxw1997 发表于 2018-12-5 08:51
    你把代码贴出来看看...

    #include <SPI.h>
    #include <SD.h>
    File myFile;
    unsigned int i, s[68];
    void setup()
    {
    Serial.begin(9600);
    }
    void loop()
    {
      for(int j=0;j<30;j++)
      {
      myFile = SD.open("A" , FILE_WRITE);         //写入方式打开文件A
      if (myFile)                                     //如果文件打开正常,请写下来:
       {
         i++;              //i循环30次(1,2,3...)
         myFile.write(30,i ); //写入数组i(i=1,2,3...)
         Serial.print(myFile.read());
       }
      }
      myFile.close();   //关闭文件  
    }
  • TA的每日心情
    奋斗
    2018-12-6 11:03
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    发表于 2018-12-5 12:38 | 显示全部楼层
    YUMU2018 发表于 2018-12-5 12:18
    #include
    #include
    File myFile;
    myFile.write(30,i ); //写入数组i(i=1,2,3...)
    这一行不对吧,write需要两个参数:const uint8_t *buf, size_t size
    一个是写入缓冲区的首址(*buf),一个是字节大小(size=1代表数据为1个字节)
  • TA的每日心情
    郁闷
    2018-12-15 20:26
  • 签到天数: 17 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-12-5 13:18 | 显示全部楼层
    lxw1997 发表于 2018-12-5 12:38
    这一行不对吧,write需要两个参数:const uint8_t *buf, size_t size
    一个是写入缓冲区的首址(*buf), ...

    软件刚入门,还是看不太明白。麻烦在我的基础上写个例子或者给个供新手看的例子可以吗?
  • TA的每日心情
    奋斗
    2018-12-6 11:03
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    发表于 2018-12-5 18:39 | 显示全部楼层
    本帖最后由 lxw1997 于 2018-12-5 19:01 编辑
    YUMU2018 发表于 2018-12-5 13:18
    软件刚入门,还是看不太明白。麻烦在我的基础上写个例子或者给个供新手看的例子可以吗? ...

    kittenblock中小学创客名师推荐的图形化编程软件

    /*
      SD card read/write
    
      This example shows how to read and write data to and from an SD card file
      The circuit:
       SD card attached to SPI bus as follows:
     ** MOSI - pin 11
     ** MISO - pin 12
     ** CLK - pin 13
     ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
    
      created   Nov 2010
      by David A. Mellis
      modified 9 Apr 2012
      by Tom Igoe
    
      This example code is in the public domain.
    
    */
    
    #include <SPI.h>
    #include <SD.h>
    
    File myFile;
    uint8_t i=0;
    uint8_t j;
    void setup() {
      // Open serial communications and wait for port to open:
      Serial.begin(9600);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
      }
    
      Serial.print("Initializing SD card...");
    
      if (!SD.begin(4)) {
        Serial.println("initialization failed!");
        while (1);
      }
      Serial.println("initialization done.");
    
      // open the file. note that only one file can be open at a time,
      // so you have to close this one before opening another.
      myFile = SD.open("A", FILE_WRITE);    //写入方式打开文件A
      if (myFile) {
        for (j = 0; j < 30; j++)
        {
          if (myFile)         //如果文件打开正常,请写下来:
          {
            i++;              //i递增30次(1,2,3...)
            myFile.write(&i,1); //写入数组i(i=1,2,3...),注意这个地方i前加&
            Serial.print("write:");
            Serial.println(i,DEC);
          }
        }
        myFile.close();   //关闭文件
        Serial.println("done.");
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening test.txt");
      }
    
      // re-open the file for reading:
      myFile = SD.open("A");
      if (myFile) {
        Serial.println("");
        Serial.println("now reading...:");
    
        // read from the file until there's nothing else in it:
        while (myFile.available()) {
          j = myFile.read();  //读出刚才写入的i值,并打印
          Serial.println(j,DEC);
        }
        // close the file:
        myFile.close();
      } else {
        // if the file didn't open, print an error:
        Serial.println("error opening file");
      }
    }
    
    void loop() {
      // nothing happens after setup
    }
    
  • TA的每日心情
    郁闷
    2018-12-15 20:26
  • 签到天数: 17 天

    [LV.4]偶尔看看III

     楼主| 发表于 2018-12-5 23:53 | 显示全部楼层
    lxw1997 发表于 2018-12-5 18:39
    [mw_shl_code=arduino,true]/*
      SD card read/write

    非常感谢您的回答!
    但还是有问题,使用myFile.write(&i,1);只能输出8位,最大255的数(本质上属于一个ASCII字符)。   请问怎么可以输出两字节或更大的数呢 (一旦使用uint16_t i;就报错)。
    另外使用uint8_t i;    myFile.write(&i,1);跟直接使用myFile.write(data);是不是没区别呢?

    麻烦您了!万分感激!
  • TA的每日心情
    奋斗
    2018-12-6 11:03
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    发表于 2018-12-6 07:55 | 显示全部楼层
    YUMU2018 发表于 2018-12-5 23:53
    非常感谢您的回答!
    但还是有问题,使用myFile.write(&i,1);只能输出8位,最大255的数(本质上属于一个AS ...

    之前有说过,write需要两个参数:第一个是变量的地址,第二个是变量的长度(以字节计)。所以你用uint16_t定义变量i,那么第二个参数就不能用1,得改成2 。
    第二个参数也可以使用表达式sizeof(i),自动返回i所占的内存字节数。
  • TA的每日心情
    奋斗
    2018-12-6 11:03
  • 签到天数: 29 天

    [LV.4]偶尔看看III

    发表于 2018-12-6 10:38 | 显示全部楼层
    本帖最后由 lxw1997 于 2018-12-6 11:14 编辑

    又看了源码一下,write(const uint8_t *buf, size_t size)的第一个参数是一个单字节的指针。看来write只支持写入单字节数据,多字节要自己拼凑了。照理说指针应该是一个双字节的才对,有点晕了。
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    KittenBot杯第六届开源硬件开发大赛启动啦
    KittenBot杯第六届开源硬
    大赛简介: 第六届开源硬件开发大赛由Arduino中文社区发起 由KittenBot冠名赞助
    DIY一个超炫酷“锹甲”机器人——Arduino Nrf24L01遥控机械臂
    DIY一个超炫酷“锹甲”机
    大家好,初来乍到,这是我最近DIY的作品,欢迎小伙伴们拍砖! 由于某些原因我把介绍都
    闲来无事,用语音控制器做个语音灯
    闲来无事,用语音控制器做
    手上刚刚好有个微雪的 LD3320语音控制板,闲来没事干,就想着做一个语音灯,让晚上
    Arduino 时钟
    Arduino 时钟
    arduino 时钟 模块:DHT11、DS1302、蜂鸣器、Arduino nano、按键 功能:时钟日期显
    呼吸灯实验
    呼吸灯实验
    本文节选自《Arduino程序设计基础》 之前的章节已经介绍了多种方法控制LED,但单是开
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表