arduino 使用多个SPI设备 how to running multiple SPI device on arduino

how to running PN532 and W5100 on same board

最近研究arduino开发板,尝试将NFC板(PN532)和网络扩展板(w5100)组合在一起,碰到个问题,这两块板子都是通过SPI总线和arduino通信,同时占用pin10,11,12,13三个口,其中10是片选信号SS。这两个设备始终无法同时工作,出现很多莫名其妙的问题。

154149rr5dubo9wbj9wlrw

比如我编译IDE自带的webserver程序,设置了ip地址为192.168.1.15,启动以后,ping 192.168.1.15可以通,但在串口接收到 ip地址为192.139.1.15,甚至是192.192.192.192,或者其他乱七八糟的地址。在PC上访问http://192.168.1.15无法打开。拔除NFC扩展板,web访问正常。然后开始漫长google之路。

参考链接

http://arduino.cc/en/Main/ArduinoEthernetShield

1.首先确认两个设备不能使用同一个SS pin,将nfc的nss针插到其他pin(貌似1,2,4,不能使用,4是SD卡的片选),我选择5,然后在arduino的setup里面增加

pinMode(5,OUTPUT);

digitalWrite(5,HIGH);

测试同时连接NFC和网络,只初始化网卡,webserver正常;如果同时初始化网卡和NFC,依旧无法访问webserver

参考链接

http://www.circuitsathome.com/mcu/running-multiple-slave-devices-on-arduino-spi-bus

2.继续google,发现两个设备的setBitOrder似乎不同,PN532是LSBFIRST,而网络是WSBFIRST,

找到原因后就简单了,只需要启动不同设备的时候,不仅仅设置SS,还要重新设置SPI的参数。

找到PN532.cpp的begin(),大约在43行,将

pn532_SPI.setDataMode(SPI_MODE0);
pn532_SPI.setBitOrder(LSBFIRST);
/*Set the SPI frequency to be one sixteenth of the
frequency of the system clock*/
pn532_SPI.setClockDivider(SPI_CLOCK_DIV16);

注释掉,然后在自己的程序里面分别写上

void enablePN() {
digitalWrite(ETH_SS, HIGH);
digitalWrite(NFC_SS, LOW);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(LSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV16);
delay(10);
}

void enableETH() {
digitalWrite(ETH_SS, LOW);
digitalWrite(NFC_SS, HIGH);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPCR & SPI_MODE_MASK);
SPCR &= ~(_BV(DORD));
SPI.setClockDivider( SPCR & SPI_CLOCK_MASK);
delay(10);
}

需要网卡的时候enableETH,需要NFC的时候启用enablePN,完美解决。

 

 

完整测试代码如下:

/* Web Server
* A simple web server that shows the value of the analog input pins.
*/

 

#include <SPI.h>
#include <Ethernet.h>
#include <PN532.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

byte ip[] = { 192, 168, 1, 15 };

EthernetServer server(80);
#define NFC_DEMO_DEBUG 1
#define PN532_CS 5
PN532 nfc(PN532_CS);

void initNFC()
{
#ifdef NFC_DEMO_DEBUG
Serial.println(“Begin start NFC!”);
#endif
nfc.begin();

uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
#ifdef NFC_DEMO_DEBUG
Serial.print(“Didn’t find PN53x board”);
#endif
//while (1); // halt
return;
// skip NFC, continue other step without NFC
}
#ifdef NFC_DEMO_DEBUG
// Got ok data, print it out!
Serial.print(“Found chip PN5”);
Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print(“Firmware ver. “);
Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print(‘.’);
Serial.println((versiondata>>8) & 0xFF, DEC);
Serial.print(“Supports “);
Serial.println(versiondata & 0xFF, HEX);
#endif
// configure board to read RFID tags and cards
nfc.SAMConfig();
}
void NFCReading()
{
uint32_t id;
// look for MiFare type cards
id = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A);

if (id != 0) {
#ifdef NFC_DEMO_DEBUG
Serial.print(“Read card #”);
Serial.println(id);
#endif
}
}
void WebPrint(EthernetClient client)
{

if (client) {
// an http request ends with a blank line
boolean current_line_is_blank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// if we’ve gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so we can send a reply
if (c == ‘\n’ && current_line_is_blank) {
// send a standard http response header
client.println(“HTTP/1.1 200 OK”);
client.println(“Content-Type: text/html”);
client.println();

// output the value of each analog input pin
client.print(“welcome to tinyos”);
client.println(“<br />”);
client.print(“//*************************************”);
client.println(“<br />”);
client.print(“www.tinyos.net.cn”);
client.println(“<br />”);
client.print(“//*************************************”);
client.println(“<br />”);
for (int i = 0; i < 6; i++) {
client.print(“analog input “);
client.print(i);
client.print(” is “);
client.print(analogRead(i));
client.println(“<br />”);
}
break;
}
if (c == ‘\n’) {
// we’re starting a new line
current_line_is_blank = true;
} else if (c != ‘\r’) {
// we’ve gotten a character on the current line
current_line_is_blank = false;
}
}
}
client.stop();
}
}
#define ETH_SS 10
#define NFC_SS 5
void enablePN() {
digitalWrite(ETH_SS, HIGH);
digitalWrite(NFC_SS, LOW);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(LSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV16);
delay(10);
}

void enableETH() {
digitalWrite(ETH_SS, LOW);
digitalWrite(NFC_SS, HIGH);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPCR & SPI_MODE_MASK);
SPCR &= ~(_BV(DORD));
SPI.setClockDivider( SPCR & SPI_CLOCK_MASK);
delay(10);
}
void setup()
{
Serial.begin(9600);
pinMode(10, OUTPUT);
pinMode(5, OUTPUT);
pinMode(4, OUTPUT);
enableETH();
Ethernet.begin(mac, ip);
server.begin();
Serial.print(“server is at “);
Serial.println(Ethernet.localIP());
enablePN();
initNFC();
//digitalWrite(5,HIGH);
//digitalWrite(10,LOW);
}

void loop()
{
// pinMode(4,HIGH);
//digitalWrite(5,HIGH);
//digitalWrite(10,LOW);
enableETH();
EthernetClient client = server.available();
WebPrint(client);
enablePN();
//delay(100);
//digitalWrite(5,HIGH);
//digitalWrite(10,LOW);
NFCReading();
//delay(100);
}

 

后记:通过这种方式实现了网络、NFC、SD卡读写的协同工作。

Raspberry Pi 使用NFC模块读取标签

使用网上的教程,链接 http://www.geek-workshop.com/thread-10042-1-1.html 。

原文包含SPI和I2C总线两种方式,因为我不想插上一大把线,所以只用了I2C接口,所以内容有删节。

libnfc是首个遵循GNU(自由工程项目)通用公共许可证针对所有人都完全免费的低级别NFC软件开发包和编程应用程序接口。它提供了完整的透明度且免费供大家使用。该库目前支持调制ISO / IEC14443 A和B,FeliCa,Jewel/Topaz标签及数据交换协议(P2P)作为目标和启动程序。想了解更多关于libnfc的信息,可参考http://nfc-tools.org/ITEAD PN532 NFC模块配有双排引脚,可直接通过排线连接到树莓派,然后树莓派将驱动模块进行非接触式近场通信操作,如读写13.56M IC卡。

154149rr5dubo9wbj9wlrw

以下教程,演示如何在树莓派上使用libnfc通过SPI总线来驱动ITEAD PN532 模块。

1, 硬件链接

Itead PN532 Module是使用四条线连接,如下图

154152srjo5ttbbbza07bt

按照上图的连接方式,Itead PN532 模块是通过SPI总线与树莓派连接的,所以需要把NFC模块的工作模式设置为I2C模式,如下图:
即 :  SET0–>H   SET1–>L

154150t0vova0ahg3ta0u8

2,安装依赖的软件包
sudo apt-get update
sudo apt-get install libusb-dev libpcsclite-dev

3,下载并解压缩libnfc源码包
cd ~
wget http://dl.bintray.com/nfc-tools/sources/libnfc-1.7.1.tar.bz2
tar -xf libnfc-1.7.1.tar.bz2

4,编译与安装
cd libnfc-1.7.1
./configure –prefix=/usr –sysconfdir=/etc
make
sudo make install

5, 修改配置文件
cd /etc
sudo mkdir nfc
sudo nano /etc/nfc/libnfc.conf

将如下内容复制到/etc/nfc/libnfc.conf文件中:

# Allow device auto-detection (default: true)
# Note: if this auto-detection is disabled, user has to set manually a device
# configuration using file or environment variable
allow_autoscan = true

# Allow intrusive auto-detection (default: false)
# Warning: intrusive auto-detection can seriously disturb other devices
# This option is not recommended, user should prefer to add manually his device.
allow_intrusive_scan = false

# Set log level (default: error)
# Valid log levels are (in order of verbosity): 0 (none), 1 (error), 2 (info), 3 (debug)
# Note: if you compiled with –enable-debug option, the default log level is “debug”
log_level = 1

# Manually set default device (no default)
# To set a default device, you must set both name and connstring for your device
# Note: if autoscan is enabled, default device will be the first device available in device list.
device.name = “Itead_PN532_SPI”
device.connstring = “pn532_i2c:/dev/i2c-1”

6,树莓派系统默认是将SPI模块的驱动关闭的,我们需要将其打开;

sudo nano /etc/modprobe.d/raspi-blacklist.conf

树莓派开启I2C总线,将/etc/modprobe.d/raspi-blacklist.conf中“blacklist i2c-bcm2708”变为“#blacklist i2c-bcm2708”
在/etc/modules末尾添加一行 “i2c-dev”

154152dpob3559dxp2xkp5

刷卡测试,运行效果如图:

154152sifdbr1fadiqz5ib

———————————————————————————————–
参考资料附录&相关链接:
A1. libnfc配置方法:http://nfc-tools.org/index.php?title=Libnfc:configuration
A2. libnfc安装教程:http://nfc-tools.org/index.php?title=Libnfc
A3. libnfc用户API:http://nfc-tools.org/index.php?title=Libnfc:API
A4. libnfc主页:http://nfc-tools.org/index.php?title=Main_Page
A5. libnfc学习例程:ibnfc:Examples” target=”_blank”>http://nfc-tools.org/index.php?title=Categoryibnfc:Examples
A6. Iteadstudio PN532 Module 网址 http://imall.iteadstudio.com/im130625002.html

A7. Disable R-Pi/RASPBIAN serial console for using UART0 http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/freeing-uart-on-the-pi
————————————————————————————————-
教程到此结束,谢谢大家!有问题请留言或微博@ITEAD创易工作室

以上为引用原文并修改了部分内容和顺序。当时测试时没有修改跳线,始终无法读到数据,后来查到PN532说明书,才知道要修改set0->H,set1->L(文中已添加),数据才读取成功。

 

规划:Pi读取NFC刷卡记录,然后传到网上,并通过微信、短信、微博通知。

场景:父母想知道孩子已经到达某处,可以通过这种方式获得通知。

后续文章会贴出后台部分。