查看: 789|回复: 14

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

[复制链接]
  • TA的每日心情
    开心
    2019-2-2 22:53
  • 签到天数: 25 天

    [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的每日心情
    郁闷
    2019-2-15 13:51
  • 签到天数: 39 天

    [LV.5]常住居民I

    发表于 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的每日心情
    开心
    2019-2-2 22:53
  • 签到天数: 25 天

    [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的每日心情
    开心
    2019-2-2 22:53
  • 签到天数: 25 天

    [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的每日心情
    开心
    2019-2-2 22:53
  • 签到天数: 25 天

    [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的每日心情
    开心
    2019-2-2 22:53
  • 签到天数: 25 天

    [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只支持写入单字节数据,多字节要自己拼凑了。照理说指针应该是一个双字节的才对,有点晕了。
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    博哥零基础教你玩转ESP8266(十三) ESP8266WiFiGeneric库
    博哥零基础教你玩转ESP826
    帖子导航帖 博哥零基础教你玩转ESP8266(一) 重识ESP8266 博哥零基础教你玩转ESP8266
    求助!WeMos D1 WiFi怎么接0.96寸OLED?(ㄒoㄒ)
    求助!WeMos D1 WiFi怎么
    求助!WeMos D1 WiFi怎么接0.96寸OLED?(ㄒoㄒ) 想用WeMos D1 WiFi接收服务器的数据然
    串口发送16进制指令求助
    串口发送16进制指令求助
    我准备串口发出16进制指令到我的外置设备 代码如下图 我分别监控ARDUINO的tx口和USB口
    一文教你选择Arduino开发板,小白进
    一文教你选择Arduino开发
    笔者在2016年接触了Arduino,跳了万条坑,行了千里弯,到今天也算是Arduino的一
    大神们!1602显示屏上的MQ2浓度示数不是实时监测的何解
    大神们!1602显示屏上的MQ
    本人小白,刚刚接触arduino,长时间的查阅资料后,通过复制修改代码接线实现了DHT11实
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表