极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 388|回复: 6

[已解决] Arduino Uno板 同时用SD卡模块与RFID模块 SPI通讯不了

[复制链接]
发表于 2017-8-12 16:14:23 | 显示全部楼层 |阅读模式
本帖最后由 qq576193486 于 2017-8-27 19:25 编辑

SD卡模块与RFID模块不能同时用吗?或者说两个用到了SPI模块的不能同时用吗?

RFID.h 库文件 有一个构造函数
RFID rfid(10,5) 也就是引脚10是CS片选 5是中断信号(不过这个5 我没用到)
RFID的初始化函数是rfid.init()

SD.h 是官方的库
初始化是SD.begin(4) 通常就用4号引脚作为CS片选

SPI是官方的库
初始化是SPI.begin()

我想用RFID读卡 读完卡 把一些东西存到SD卡模块 简言之 就是用到了SD卡模块 RFID模块
两个模块都用到了SPI的东西 就是MOSI MISO SCK(对应引脚 11 12 13) 这三个引脚我用了面包板一起接到了各个模块上

但是呢 两个模块工作都是有些问题
首先感觉就是电源的问题:就算我只用了一个RFID模块(代码就是RFID的例子) 但是如果我把SD模块的正负极一起接到Uno板上
RFID是不能正常工作的。 把SD模块的正极拿掉 就可以正常工作了

其次就是我的代码问题了吧。我不太懂什么SPI通讯 协议的 网上说是要选择片选 同一时刻 只能用一个模块 用的时候 要把相应的CS引脚给高电平或者低电平。
但是这里我也试过高低电平了,但是还是不能用。

请问有没有人试过这两个模块同时用,或者其他的两个都用到了SPI的不同模块,求指教
回复

使用道具 举报

发表于 2017-8-12 21:56:40 | 显示全部楼层
本帖最后由 zjz5717 于 2017-8-12 22:00 编辑

我试过同时用这两个模块,没有什么问题的
而且arduino的供电同时给这两个模块供电也不虚
只有片选为低的模块接受指令
我用的时候就是先RFID低,SD高,初始化RFID
RFID高,SD低,初始化SD
RFID低,SD高,寻卡读卡
RFID高,SD低,写SD数据
因为寻卡命令发送如果发送到SD端口,SD会返回Error导致RFID也无法正常使用
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2017-8-12 22:15:24 | 显示全部楼层
zjz5717 发表于 2017-8-12 21:56
我试过同时用这两个模块,没有什么问题的
而且arduino的供电同时给这两个模块供电也不虚
只有片选为低的 ...

那么可以发下你的代码嘛 大致的 或者详细请教一下你呗
回复 支持 反对

使用道具 举报

发表于 2017-8-13 08:21:13 | 显示全部楼层
qq576193486 发表于 2017-8-12 22:15
那么可以发下你的代码嘛 大致的 或者详细请教一下你呗

我现在在外地。。。源码都放在学校了
不好意思哈
回复 支持 反对

使用道具 举报

发表于 2017-8-15 15:32:55 | 显示全部楼层
片选, 扫噶,GET关键词了。 话说我之前用SPI的方式控制LED矩阵同时使用时钟模块的时候就会跟你一样。后来瞎鼓捣好了也不知道原因

之前不知道片选,我去搜搜。 给你顶一下。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-15 22:31:31 | 显示全部楼层
Stormer 发表于 2017-8-15 15:32
片选, 扫噶,GET关键词了。 话说我之前用SPI的方式控制LED矩阵同时使用时钟模块的时候就会跟你一样。后来 ...

emmmmmmm 找到相关的资料记得回复我哦
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-8-27 19:22:51 | 显示全部楼层
本帖最后由 qq576193486 于 2017-8-27 19:24 编辑

这几天算是解决了。(我在其他的论坛也发过相关的帖子,这个解决方案也会发在那些论坛里,如果各位在其他论坛看到,或者转载都没问题)一开始也想过,既然共用有问题,那么就不让它们共用。那么把两个模块的电源引脚单独用一个引脚去控制。
这个解决方案,应该说很不好。因为两个模块都说是用SPI通讯的,跟电源没关系。
在Google上,倒是看到过类似的情况,
有的说是要在SD模块的MISO(即主机输入,从机输出,模块向板子发送)之间加一个330R的电阻(这个方案我试过,没成功)
有的说是要在SD模块的MISO之间加个二极管,阳极接SD卡模块,阴极接板子(这个还没试过)

那么 我只把我的实现方法介绍给那些,在搞这两个模块一起用的。在弄这两个模块也发现了以前没注意到的

首先是 RFID模块:
我用的是RFID库, 整理者:极客工坊bg1lsy (lsy@sogou.com) 整理时间:2013.05.25
(这个应该蛮多人都在用的,官方有个MRC522的库,应该是基于这个库整理的)
RFID rfid(10,5) (rfid 是个名称 可以改 例 myrfid)
第一个参数 是片选引脚 也就是SDA引脚, (对于SD卡模块 片选引脚是CS引脚 ChipSelect)
然后呢有个初始化函数 rfid.init()
当RFID给电以后 只能运行一次:也就是说
RFID给电后 执行了两次rfid.init() RFID 不工作
RFID断电,重新给电后 没有执行rfid.init() RFID不工作(重新给电后 要延时一小会 再执行初始化函数)


接着是SD卡模块:
这个SD卡官方有库的
SD可以不用声明对象的
初始化函数SD.begin(4) (4就是CS引脚)成功返回true 失败返回false
这个不同于RFID的初始化
如果SD卡模块没问题,第一次执行会返回true 再次执行会返回false,但是SD卡还是能用的,比如读写文件
(我们都可以把SD卡拿下来,再插上去,都不用重启)

还有一点就是,SD卡打开的文件名字不能过长,8+3(文件名别超过8个字母,扩展名别超过3个)
当打开一个不存在的文件时,它会自动以大写字母创建一个文件
----------------------------------------------------------------
我用到了RFID模块,SD模块,舵机(也就是门禁,人比较多,板子存不下了,就加个SD卡)
功能就是RFID读卡号(这里卡号我用的是10进制),去SD卡里的记事本里面一行一行比对,如果有,就舵机动,没有就存到SD卡的一个记事本里面(把没有的存起来,这样添加更简单)
在发一大堆长代码之前,我先把一些函数功能写出来,免得看起来头疼
先写官方的:
File dataFile;//文件类型的,用来准备下一步 SD卡打开的文件
不能同时打开两个文件,也就是说,如果要打开另一个文件之前 要先关闭当前打开的文件 函数是dataFile.close()
dataFile = SD.open("people.txt");//打开文件



dataFile.available();//这个是判断文件是否读取完 常用形式就是while(dataFile.available()) 如果文件没读完 就执行这个循环


dataFile.readStringUntil('\n');//这个就是说读取到指定的字符 我这里就是说读取到换行符结束,返回的是字符串String
我用的形式 就是 String str=dataFile.readStringUntil('\n'); 这样的话 str 就是一行的字符串了
这里还有个文件指针,大概理解就是,记事本里光标的位置
当我执行完一次readStringUntil('\n')后,再次执行的时候,它是从下一行 开始读取的
这个位置向文件写东西的时候 有关 在打开文件的时候 有关


dataFile.println();//这个函数是向文件里写东西的,参数可以是字符串String 整形int 自动加换行符
那么从哪开始写的呢,这就涉及到位置了。那么对于我来说,我是希望向文件写东西的时候 是写到最后面的
这里就涉及到打开文件的方式了


SD卡打开文件:
dataFile = SD.open("people.txt");//这个打开方式 它的位置 是在最开始的(读取的时候 通常采用这种方式)
dataFile = SD.open("people.txt", FILE_WRITE);//这个打开方式 它的位置是在最末尾(写文件的时候 常采用这种)



Servo舵机:
myservo.detach();//使得舵机不加力


String的函数:
str.indexOf('/');//这个函数是在字符串中 找到第一个匹配的字符,返回字符所在位置 即整形
str.substring(0,n);//这个函数是截取字符串,第一个参数0是起始位置,第二个参数n是结束位置,返回一个新的字符串
这两个函数 结合起来用 就是
str = str.substring(0, str.indexOf('/'));
这样的话str就是/前面的字符了。我的意图就是记事本里 /前面保存卡号 /后面保存注释
例如 111111111111/XXX 修改时间:xxxx年xx月xx日

然后是我自己写的函数
void judge() 用来比较卡号的
void openTheDoor() 开门的
void readCard() 读卡号的
void turnOnSD() 这个函数先关闭RFID的电源 再给SD电源
void turnOnRFID() 这个函数先关闭SD的电源 再给RFID电源
  1. //整理者:仰望
  2. //整理时间:2017年8月20日
  3. #include <Servo.h>
  4. #include <SD.h>
  5. #include <SPI.h>
  6. #include <RFID.h>
  7. //---------宏定义 各个引脚------------
  8. //---------RFID-----------------------
  9. #define RFID_SS_PIN 10
  10. #define RFID_RST_PIN 5
  11. #define RFID_POWER_PIN 7//RFID的电源用引脚来控制

  12. //---------SD-------------------------
  13. #define SD_SS_PIN 4
  14. #define SD_POWER_PIN 8

  15. //---------Servo----------------------
  16. #define Servo_PIN 9

  17. //---------两个模块切换的时间间隔 毫秒
  18. #define CHANGE_TIME 10


  19. String num = "";//用字符串 存储当前读到的卡号
  20. int pos = 0;//舵机的角度
  21. bool flag = false;//是否开门


  22. Servo myservo;  //声明舵机对象
  23. RFID rfid(RFID_SS_PIN, RFID_RST_PIN);   //D10--读卡器MOSI引脚、D5--读卡器RST引脚

  24. void turnOnRFID() {
  25.         //关掉SD
  26.         digitalWrite(SD_POWER_PIN, LOW);
  27.         delay(CHANGE_TIME);
  28.         //打开RFID
  29.         digitalWrite(RFID_POWER_PIN, HIGH);//RFID的电源给电
  30.         delay(CHANGE_TIME);//延时一小会 再初始化
  31.         rfid.init();//每次重新上电 都要重新初始化
  32. }
  33. void turnOnSD() {
  34.         //关掉RFID
  35.         digitalWrite(RFID_POWER_PIN, LOW);
  36.         delay(CHANGE_TIME);
  37.         //打开SD
  38.         digitalWrite(SD_POWER_PIN, HIGH);//SD的电源给电
  39.         delay(CHANGE_TIME);
  40.         SD.begin(SD_SS_PIN);
  41. }
  42. void readCard()
  43. {
  44.         //Serial.println("Find the card!");
  45.         //读取卡序列号
  46.         if (rfid.readCardSerial()) {
  47.                 num.concat(rfid.serNum[0]);//拼接字符串
  48.                 num.concat(rfid.serNum[1]);
  49.                 num.concat(rfid.serNum[2]);
  50.                 num.concat(rfid.serNum[3]);
  51.                 num.concat(rfid.serNum[4]);
  52.                 //Serial.println(num);
  53.         }
  54.         //选卡,可返回卡容量(锁定卡片,防止多数读取),去掉本行将连续读卡
  55.         rfid.selectTag(rfid.serNum);
  56. }
  57. void openTheDoor()
  58. {
  59.         myservo.attach(Servo_PIN);
  60.         for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
  61.                                                                                           // in steps of 1 degree
  62.                 myservo.write(180);              // tell servo to go to position in variable 'pos'
  63.                 delay(5);                       // waits 15ms for the servo to reach the position
  64.         }
  65.         delay(3500);
  66.         for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
  67.                 myservo.write(0);              // tell servo to go to position in variable 'pos'
  68.                 delay(5);                       // waits 15ms for the servo to reach the position
  69.         }
  70.         num = "";
  71.         Serial.println(num);
  72.         flag = false;
  73. }
  74. void judge()
  75. {
  76.         String s;//用来保存从文件读取的一行字符串(截止符'/'前面的字符串)
  77.         Serial.println();
  78.         int n;//用来计数的
  79.         File dataFile;
  80.         dataFile = SD.open("teachers.txt");//打开文件
  81.         if (dataFile) {//判断文件是否打开成功
  82.                 n = 1;
  83.                 while (dataFile.available())//判断是否读完了整个文件
  84.                 {
  85.                         s = dataFile.readStringUntil('\n');//读取到换行符 结束(也就是读取一行的字符串)
  86.                                                                                            //substring 截取字符串 第一个参数是起始位置 第二个参数是结束位置
  87.                                                                                            //indexOf 查找一个字符的位置 返回位置
  88.                         s = s.substring(0, s.indexOf('/'));
  89.                         if (s == num) {//判断是否找到了人
  90.                                 flag = true;//找到了人 令flag为真
  91.                                 Serial.print("Welcom Teacher ");
  92.                                 Serial.print("No.");
  93.                                 Serial.print(n);
  94.                                 Serial.print("  CARD:");
  95.                                 Serial.println(s);
  96.                                 return;
  97.                         }
  98.                         n++;//没找到就自增1
  99.                 }
  100.         }
  101.         else {
  102.                 Serial.println("error opening file teachers.txt");
  103.         }
  104. dataFile.close();
  105. delay(10);
  106.         dataFile = SD.open("students.txt");//打开文件
  107.         if (dataFile) {//判断文件是否打开成功
  108.                 n = 1;
  109.                 while (dataFile.available())//判断是否读完了整个文件
  110.                 {
  111.                         s = dataFile.readStringUntil('\n');//读取到换行符 结束(也就是读取一行的字符串)
  112.                                                                                            //substring 截取字符串 第一个参数是起始位置 第二个参数是结束位置
  113.                                                                                            //indexOf 查找一个字符的位置 返回位置
  114.                         s = s.substring(0, s.indexOf('/'));
  115.                         if (s == num) {//判断是否找到了人
  116.                                 flag = true;//找到了人 令flag为真
  117.                                 Serial.print("Welcom Student ");
  118.                                 Serial.print("No.");
  119.                                 Serial.print(n);
  120.                                 Serial.print("  CARD:");
  121.                                 Serial.println(s);
  122.                                 return;
  123.                         }
  124.                         n++;//没找到就自增1
  125.                 }
  126.         }
  127.         else {
  128.                 Serial.println("error opening file students.txt");
  129.         }
  130.         if (!flag)
  131.         {//如果是未注册的 就写到unexist.txt文件里 方便社员自己加入卡
  132.     dataFile.close();
  133.     delay(10);
  134.                 Serial.print("Unregistered CARD: ");
  135.                 Serial.println(num);
  136.                 dataFile = SD.open("unexist.txt", FILE_WRITE);
  137.                 if (dataFile) {
  138.                         dataFile.println(num + "/");
  139.                 }
  140.                 //没打开文件
  141.                 else {
  142.                         Serial.println("error opening file unexist.txt");
  143.                 }
  144.         }
  145. dataFile.close();
  146. delay(10);
  147. }
  148. void setup()
  149. {
  150.         pinMode(RFID_POWER_PIN, OUTPUT);
  151.         pinMode(SD_POWER_PIN, OUTPUT);
  152.         Serial.begin(9600);
  153.         SPI.begin();
  154.         myservo.attach(Servo_PIN);//舵机的初始化
  155.         myservo.write(0);
  156.         delay(100);
  157.         //   member=sizeof(password);
  158.         Serial.println("START!");
  159. digitalWrite(SD_POWER_PIN,HIGH);
  160. if (!SD.begin(SD_SS_PIN)) {
  161.     Serial.println("Card failed, or not present");
  162.     // don't do anything more:
  163.     return;
  164.   }
  165.   Serial.println("card initialized.");
  166.   delay(CHANGE_TIME);
  167.         turnOnRFID();//初始化的时候 先初始化RFID 因为RFID的初始化 必须只执行一次
  168. }

  169. void loop()
  170. {
  171.         //turnOnRFID();//打开RFID
  172.         //找卡
  173.         if (rfid.isCard())
  174.         {
  175.                 readCard();//读卡
  176.                                    //读完卡后 把卡号存到了 String变量num里面 然后在判断之前 打开SD模块
  177.                 turnOnSD();
  178.                 judge();//判断刷入卡号是否登记
  179.                                 //判断完后 SD关电 RFID重新上电 执行一次RFID的初始化函数
  180.                 turnOnRFID();
  181.         }


  182.         if (flag)
  183.         {
  184.                 openTheDoor();//开门
  185.         }
  186.         myservo.detach();//使得舵机不加力
  187.         pinMode(Servo_PIN, OUTPUT);
  188.         digitalWrite(Servo_PIN, LOW);
  189.         delay(90);
  190.         num = "";//清空
  191. }
复制代码


回复 支持 反对

使用道具 举报

高级模式  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2017-10-18 04:30 , Processed in 0.044791 second(s), 7 queries , File On.

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表