概述
单工:
是指数据传输仅能沿一个方向,不能实现反向传输。
半双工:
是指数据传输可以沿两个方向,但不能同时进行传输。
全双工:
是指数据可以同时进行双向传输。
void setup() { // put your setup code here, to run once: Serial.begin(9600);}void loop() { // put your main code here, to run repeatedly: char s[]="I am Arduino A";//每隔1s发送一次字符数组s Serial.print(s); delay(1000);}
再在Arduino B里烧录以下代码:
String a=""; //定义字符串,接收数据void setup() { // put your setup code here, to run once: Serial.begin(9600);}void loop() { while(Serial.available())//当发现缓存中有数据时,将数据送至字符数组a中 { a+=char(Serial.read()); delay(3); } if (a.length() > 0){ Serial.println(a) a = "" }}
这样就A就通过UART向B发送了“
I am Arduino A”消息,B接收到以后输出。当然你可以修改A的代码实现双向数据传输,这里我们就点到即止了。UART是最常见的通信协议之一,它可以实现全双工传输,但它的传输速度比较慢,而且只能支持一对一的设备。
I2C协议I2C是Philips公司在1980年代发明的一种协议,全称是Inter-Integrated Circuit。I2C最常被应用于模块或者传感器之间的通信,因为I2C基于二根传输线,同步通信的半双工协议,而且协议也非常简单可靠。
I2C使用两根传输线实现一个主设备与多个从设备,甚至是多个主设备与对应从设备之间的通信。
这两根通讯线一根为控制时钟线,称之为SCL,用于同步设备间的数据传输时钟;
另一根为数据线,称之为SDA,用于携带数据。理论上,一条I2C总线上能支持挂载128台设备。
Arduino UNO的I2C引脚是A4(SDA), A5(SDL)。Arduino对I2C协议也进行了库封装:
https://www.arduino.cc/en/Reference/Wire
下面我们还是用两块Arduino来实践一下如何利用I2C协议来传输数据。如图连接好两块Arduino:
一台我们作为主设备(Master),烧录以下代码:
#include void setup() { Serial.begin(9600); /* begin serial comm. */ Wire.begin(); /* join i2c bus as master */ Serial.println("I am I2C Master");}void loop() { Wire.beginTransmission(8); /* begin with device address 8 */ Wire.write("Hello Slave"); /* sends hello string */ Wire.endTransmission(); /* stop transmitting */ Wire.requestFrom(8, 9); /* request & read data of size 9 from slave */ while(Wire.available()){ char c = Wire.read();/* read data received from slave */ Serial.print(c); } Serial.println(); delay(1000);}
另一块作为从设备(Slave),烧录以下代码:
#include void setup() { Wire.begin(8); /* join i2c bus with address 8 */ Wire.onReceive(receiveEvent); /* register receive event */ Wire.onRequest(requestEvent); /* register request event */ Serial.begin(9600); /* start serial comm. */ Serial.println("I am I2C Slave");}void loop() { delay(100);}// function that executes whenever data is received from mastervoid receiveEvent(int howMany) { while (0 char c = Wire.read(); /* receive byte as a character */ Serial.print(c); /* print the character */ } Serial.println(); /* to newline */}// function that executes whenever data is requested from mastervoid requestEvent() { Wire.write("Hi Master"); /*send string on request */}
这样,我们就实现了主从设备的双向传输。打开主机Arduino的串口监视器我们可以看见如下的输出:
从机Arduino的串口输出:
I2C虽然只需要两根线,就能支持多主机多从机的数据传输,但由于只有一根用于数据传输,它通过在“接收”和“传输”两种状态之间但切换实现了双向传输,但牺牲了不少传输速率。I2C还有典型的开漏问题,总线需要加上拉电阻。
SPI协议
最后,我们来看一下SPI协议。SPI全称Serial Peripheral Interface(串行外设接口),由摩托罗拉公司提出的一种同步串行数据传输协议。SPI类似I2C也是同步通信的协议,但是全双工,支持数据的同时输出和输入。这两个特征使SPI的传输速率比UART和I2C都高,这对于像SD卡、或者屏幕等数据型模块来说,是非常具有优势的。
SPI支持一主多从的模式,但SPI也是三种协议中需要线最多的协议,一共需要4条信号线:
但Arduino UNO默认的SPI引脚分别为D13(SCK), D12(MISO), D11(MOSI), D10(SS),其中SS是从机选择引脚,没有强制要求,你也可以选其他的引脚。
同样,我们来实践一下用SPI实现数据传输。
如图连接好两块Arduino UNO。还是一块作为主机(Master), 另一块作为从机(Slave)。Arduino对SPI协议也做了类封装:
https://www.arduino.cc/en/reference/SPI
主机烧录以下代码:
#include void setup (void){ Serial.begin(115200); digitalWrite(SS, HIGH); SPI.begin (); SPI.setClockDivider(SPI_CLOCK_DIV8);}void loop (void){ char c; // enable Slave Select digitalWrite(SS, LOW); // SS is pin 10 // send test string for (const char * p = "Hello, world!n" ; c = *p; p++) { SPI.transfer (c); Serial.print(c); } // disable Slave Select digitalWrite(SS, HIGH); delay (1000);}
从机烧录:
#include char buf [100];volatile byte pos;volatile boolean process_it; void setup (void){ Serial.begin (115200); // debugging // turn on SPI in slave mode SPCR |= bit (SPE); // have to send on master in, *slave out* pinMode(MISO, OUTPUT); // get ready for an interrupt pos = 0; // buffer empty process_it = false; // now turn on interrupts SPI.attachInterrupt();} // end of setup // SPI interrupt routineISR (SPI_STC_vect){ byte c = SPDR; // grab byte from SPI Data Register // add to buffer if room if (pos < sizeof buf) { buf [pos++] = c; // example: newline means time to process buffer if (c == 'n') process_it = true; } // end of room available} // end of interrupt routine SPI_STC_vect // main loop - wait for flag set in interrupt routinevoid loop (void){ if (process_it) { buf [pos] = 0; Serial.println(buf); pos = 0; process_it = false; } // end of flag set } // end of loop
这样从机就能接受到主机发过来的消息了。
总结
今天,我们粗略地介绍了一下Arduino数据通信中最常用的三种协议:UART、I2C和SPI。
协议 | 通信方式 | 通信方向 | 信号线 | 传输速率 | 主从模式 |
UART | 异步 | 全双工 | 2线 RX、TX | 最低 | 一对一 |
I2C | 同步 | 半双工 | 2线 SDA、SCL,以地址选择从机 | 低 | 多主机 多从机 |
SPI | 同步 | 全双工 | 4线 MOSI、MISO、SCLK、CS(或SS),以CS选择从机 | 高 | 一主多从 |
它们各自都有自己的优缺点和适用的场景,并没有绝对的好坏,这也是这三种协议经久不衰的原因。只有了解并掌握它们,我们才能在具体的应用场景里选择最合适的协议。当然在嵌入式世界里,还有其他很多协议,小编以后再介绍吧。如果对这三种协议的底层感兴趣的朋友,也可以自己再去深入了解。
感谢您的耐心阅读,欢迎关注、点赞并转发。
Arduino电子书和视频教程获取方式
也想要一份我们套件附送的Arduino电子书和各种视频教程么?
扫描下方二维码加关注后,回复“福利”
戳阅读原文,购买Arduino入门学习套件
最后
以上就是可靠宝马为你收集整理的arduino串口监视器显示nan_Arduino常用的三种通信协议UART, I2C和SPI的全部内容,希望文章能够帮你解决arduino串口监视器显示nan_Arduino常用的三种通信协议UART, I2C和SPI所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复