了解通过usb串口与电脑的通信;了解字符与字符串数据类型;利用项目了解通过电脑上的串口通信的方式,
项目功能:控制Arduino的第13脚的led。将依据用户输入“1”或“0”,点亮或关闭位于第13脚的LED。
名称 | 数量 | 规格 |
---|---|---|
Arduino uno控制板 | 1 | R3 |
无
无
电脑把文字信息分成字符(character)和字符串(string)
控制字符 | ASCII编码 | 程序写法 | 说明 |
---|---|---|---|
NULL | 0 | \0 | 没有数据 |
CR(Carriage Return) | 13 | \r | 回车 |
LF(Line Feed或New Line) | 10 | \n | 换行 |
Tab | 09 | \t | 定位键 |
Backspace | 08 | \b | 退位键 |
BEL | 07 | \a | 铃声 |
语句格式
switch(运算式){
case 值1:
语句组;
break;
case 值2:
语句组2;
break;
……
default:
}
说明:
void loop() {
if (Serial.available() ) {
val = Serial.read();
switch (val) {
case '0':
digitalWrite(LED, LOW);
break;
case '1':
digitalWrite( LED, HIGH);
break;
}
}
}
我们可以通过串口联机来观察程序内部的运行情况
Arduino内建处理串口联机的Serial扩展库
设置数据传输频率
Serial.begin(9600)
从串口输出数据
Serial.print("hello ");
Serial.print(“World.”);
Serial.print("Hello\t");
Serial.print("world.");
Serial.print("\n");
Serial.println("Hello\tWorld.");
Serial.println("bye");
• 实验说明: 通过串口来观察某个变量的数值。
• 实验程序:
void setup(){
Serial.begin(9600);
Serial.print("hello ");
Serial.print("World.");
Serial.print("Hello\t");
Serial.print("world.");
Serial.print("\n");
Serial.println("Hello\tWorld.");
Serial.println("bye");
}
void loop(){
}
const byte ledPin = 13;
void setup(){
Serial.begin(9600);
Serial.println("hello,");
Serial.print("\tLED pin is: ");
Serial.print(ledPin);
Serial.print("\nBye");
}
void loop(){
}
char str[] = "hello ";
const byte ledPin = 13;
void setup(){
Serial.begin(9600);
Serial.println(str);
Serial.print("\tLED pin is: ");
Serial.print(ledPin);
Serial.print("\nBye");
}
void loop(){
}
Arduino 在微控制器的内存中划分出缓存区(buffer,可暂存64字节的串行数据),用于来自串口的输入数据
#if (RAMEND < 1000) //若可用的内存(RAM)少于此值
#define SERIAL_BUFFER_SIZE 16 //串行缓存区大小设置成16字节
#else
#define SERIAL_BUFFER_SIZE 64
#endif
代码:
const byte LED = 13;
char val;
void setup(){
pinMode(LED,OUTPUT); // 将LED引脚设置为输出
Serial.begin(9600); //启动串口,并设置传输速率为9600bps
Serial.print("Welcome to Arduino!"); //提示:联机成功。
}
void loop(){
if (Serial.available()) { //available()函数返回大于等于0的数
val = Serial.read();
if (val == '1') { // 接收到的数据类型为字符。
digitalWrite(LED, HIGH);
Serial.print("LED ON");
} else if (val == '0') {
digitalWrite(LED, LOW);
Serial.print("LED OFF");
}
}
}
修改上面的代码,可以提醒输入的数值不是0或1,同时显示打开和关闭LED的次数
Ps:在电脑键盘按下数字‘1’,是字符‘1’,实际数据值是49,因此:val == 'a’与val == 49两种写法相同。
决定是否在输出字符串后面加上“换行”字符。
• 没有行结束符:不在数据后面加上“回车”或“换行
• NL(new line):在数据后面加上“换行”
• CR(carriage return):加上“回车”
• NL与CR:加上“回车”与“换行”
例如,若选择NL,那么当送出‘1’时,实际发送的数据是“1\n”,也就是ASCII编码49和10两个字符。
字符串用于存储文本。它们可用在LCD或Arduino IDE串口监视器窗口中显示文本。字符串也可用于存储用户输入。例如,用户在连接到Arduino的键盘上键入的字符。
在Arduino编程中有两种类型的字符串:
字符数组,与C编程中使用的字符串相同。
字符串是一个特殊的数组,在字符串的末尾有一个额外的元素,其值总是为0(零)。这被称为“空终止字符串”。
void setup() {
char my_str[6]; // an array big enough for a 5 character string
Serial.begin(9600);
my_str[0] = 'H'; // the string consists of 5 characters
my_str[1] = 'e';
my_str[2] = 'l';
my_str[3] = 'l';
my_str[4] = 'o';
my_str[5] = 0; // 6th array element is a null terminator
Serial.println(my_str);
}
void loop() {
}
以下示例显示了字符串由什么组成。一个具有可打印字符的字符数组和0作为数组的最后一个元素,表示这是字符串结束的位置。通过使用 Serial.println()并传递字符串的名称,可以将字符串打印到Arduino IDE串口监视器窗口。
同样的例子可以用更方便的方式编写,如下所示:
示例
void setup() {
char my_str[] = "Hello";
Serial.begin(9600);
Serial.println(my_str);
}
void loop() {
}
在这个草图中,编译器计算字符串数组的大小,并自动使用空值0终止字符串。一个长度为六个元素长,由五个字符后跟一个零组成的数组,其创建方式与上一个草图完全相同。
3. 操作字符串数组
我们可以在草图中更改字符串数组,如下图所示。
例子
void setup() {
char like[] = "I like coffee and cake"; // create a string
Serial.begin(9600);
// (1) print the string
Serial.println(like);
// (2) delete part of the string
like[13] = 0;
Serial.println(like);
// (3) substitute a word into the string
like[13] = ' '; // replace the null terminator with a space
like[18] = 't'; // insert the new word
like[19] = 'e';
like[20] = 'a';
like[21] = 0; // terminate the string
Serial.println(like);
}
void loop() {
}
结果
I like coffee and cake
I like coffee
I like coffee and tea
以上草图按以下方式工作。
(1)创建和打印字符串 在上面给出的草图中,创建了一个新的字符串,然后打印出来显示在串口监视器窗口中。
(2)缩短字符串 通过用空终止0替换字符串中的第14个字符来缩短字符串。这是从0开始计算的字符串数组中的13号元素。
打印字符串时,所有字符都打印到新的空终止0。其他字符不消失;它们仍然存在于内存中,并且字符串数组仍然是相同的大小。唯一的区别是任何使用字符串的函数只能看到第一个空终止符前的字符串。
(3)更改字符串中的单词 最后,草图用“tea”代替“cake”一词。它首先必须用空格替换空终止符,如[13],以便将字符串恢复为原来的格式。
新字符用单词“tea”覆盖单词“cake”的“cak”。这是通过覆盖单个字符来完成的。“cake”的“e”被替换为新的空终止字符。结果是字符串实际上终止于两个空字符,即字符串末尾的原始字符,以及替换“cake”中的“e”的新字符。这在打印新字符串时没有区别,因为打印字符串的函数在遇到第一个空终止字符时将停止打印字符串字符。
4. 操作字符串数组的函数
上一个草图通过访问字符串中的单个字符,以手动方式操作字符串。为了更方便操作字符串数组,你可以编写自己的函数来执行,也可以使用 C语言库中的一些字符串函数。
下面显示了操作字符串数组的列表函数。
下一个草图使用了一些C字符串函数。
例子
void setup() {
char str[] = "This is my string"; // create a string
char out_str[40]; // output from string functions placed here
int num; // general purpose integer
Serial.begin(9600);
// (1) print the string
Serial.println(str);
// (2) get the length of the string (excludes null terminator)
num = strlen(str);
Serial.print("String length is: ");
Serial.println(num);
// (3) get the length of the array (includes null terminator)
num = sizeof(str); // sizeof() is not a C string function
Serial.print("Size of the array: ");
Serial.println(num);
// (4) copy a string
strcpy(out_str, str);
Serial.println(out_str);
// (5) add a string to the end of a string (append)
strcat(out_str, " sketch.");
Serial.println(out_str);
num = strlen(out_str);
Serial.print("String length is: ");
Serial.println(num);
num = sizeof(out_str);
Serial.print("Size of the array out_str[]: ");
Serial.println(num);
}
void loop() {
}
结果 This is my string
String length is: 17
Size of the array: 18
This is my string
This is my string sketch.
String length is: 25
Size of the array out_str[]: 40
以上草图按以下方式工作。
(1)打印字符串 最新创建的字符串将打印到串口监视器窗口,如之前的草图所完成的。
(2)获取字符串的长度 strlen()函数用于获取字符串的长度。字符串的长度仅对于可打印字符,不包括空终止符。
该字符串包含17个字符,因此我们在串口监视器窗口中看到17个字符。
(3)获取数组的长度 运算符sizeof()用于获取包含字符串的数组的长度。长度包括空终止符,因此长度比字符串的长度多1。
sizeof()看起来像一个函数,但技术上是一个运算符。它不是C字符串库的一部分,但在草图中用于显示数组大小和字符串大小(或字符串长度)之间的差异。
(4)复制字符串 strcpy()函数用于将str[]字符串复制到out_num[]数组。strcpy()函数将传递给它的第二个字符串复制到第一个字符串中。现在,字符串的副本存在于out_num[]数组中,但只占用了数组的18个元素,因此在数组中仍然有22个空闲的char元素。这些空闲元素在内存中的字符串的后面可以找到。
将字符串复制到数组中,以便我们在数组中有一些额外的空间用于草图的下一部分,即在字符串的末尾添加一个字符串。
(5)将字符串附加到字符串(连接) 草图将一个字符串加到另一个字符串,这称为串联。这是使用strcat()函数完成的。strcat()函数将传递给它的第二个字符串放到传递给它的第一个字符串的末尾。
串联后,打印字符串的长度以显示新的字符串长度。然后打印数组的长度,以显示在40个元素长的数组中有一个25个字符长度的字符串。
请记住,25个字符长度的字符串实际上占用了数组的26个字符,因为还有空终止0。
5. 数组边界
使用字符串和数组时,在字符串或数组的边界内工作是非常重要的。在示例草图中,创建了一个长度为40个字符的数组,以分配可用于操作字符串的内存。
如果数组太小,而我们尝试复制比数组大的字符串,那么字符串将复制到超出数组的末尾。超出数组末尾的内存可能包含草图中使用的其他重要数据,然而它们将被字符串覆盖。如果超出字符串末尾的内存超出范围,则可能会导致草图崩溃或导致意外行为。
已经定义了数百个通信协议来实现这种数据交换。每个协议可以分为两类:并行或串行。
通过输入/输出端口在Arduino和外设之间进行并行连接是短距离(最多几米)的理想解决方案。然而,在其他情况下,当需要在两个设备之间建立较长距离的通信时,不可能使用并行连接。并行接口同时传输多个位。它们通常需要数据总线 - 通过八条,十六条或更多的线路进行传输。数据以1和0的巨大波形传输。
并行通信的优点和缺点 并行通信肯定有其优势。它比串行更快,更直接,相对容易实施。然而,它需要许多的输入/输出(I / O)端口和线路。如果你曾经把一个项目从一个基本的Arduino Uno移动到一个Mega,你就知道微处理器上的I/O线是很宝贵的,而且很少。因此,我们更喜欢串行通信,牺牲针脚空间的潜在速度。
今天,大多数Arduino板都是用几种不同的串行通信系统作为标准设备。
使用哪个系统取决于以下因素:
串行通信可以进一步分类为:
很容易找出设备是否同步。如果给所有连接的设备提供相同的时钟,则它们是同步的。如果没有时钟线,它是异步的。
例如,UART(通用异步收发器)模块是异步的。
异步串行协议有一些内置的规则。这些规则只是有助于确保可靠且无误的数据传输的机制。这些避免外部时钟信号的机制是:
同步位
同步位是与每个数据包传输的两个或三个特殊位。它们是起始位和停止位。正如它们的名称,这些位分别标记数据包的开始和结束。
起始位始终只有一个,但停止位的数量可以配置为一个或两个(尽管通常保持为1)。
起始位始终由从1到0的空闲数据线指示,而停止位将通过将线保持在1处而转换回空闲状态。
数据位
每个分组中的数据量可以设置为5到9位的任意大小。当然,标准数据大小是基本8位字节,但其他大小有它们的用途。7位数据包的效率可能比8位高,特别是如果你只是传输7位ASCII字符。
奇偶校验位
用户可以选择是否应该有奇偶校验位,如果是,则奇偶校验应该是奇数还是偶数。如果数据位中的1的数目是偶数,则奇偶校验位为0。奇数的奇偶校验正好相反。
波特率
术语波特率用于表示每秒传输的位数[bps]。注意,它指的是位,而不是字节。协议通常要求每个字节与几个控制位一起传输。这意味着串行数据流中的一个字节可以包括11位。例如,如果波特率为300bps,则每秒可以传输最大37字节和最小27字节。
Arduino UART
以下代码将使Arduino在启动时发送hello world。
void setup() {
Serial.begin(9600); //set up serial library baud rate to 9600
Serial.println("hello world"); //print hello world
}
void loop() {
}
将Arduino草图上传到Arduino后,打开Arduino IDE右上角的串口监视器搜索Search。
在串口监视器的顶部框中键入任意内容,然后按发送键或键盘上的enter键。这将发送一系列字节到Arduino。
以下代码返回它接收到的任何东西作为输入。
以下代码将使Arduino根据提供的输入传送输出。
void setup() {
Serial.begin(9600); //set up serial library baud rate to 9600
}
void loop() {
if(Serial.available()) //if number of bytes (characters) available for reading from {
serial port
Serial.print("I received:"); //print I received
Serial.write(Serial.read()); //send what you read
}
}
请注意,Serial.print 和 Serial.println 将发回实际的ASCII代码,而 Serial.write 将返回实际的文本。请参阅ASCII代码了解更多信息。
• Serial.print(val)
• Serial.print(val, format)
参数:
• val: 要发送的数据(任何数据类型)
• format: 指定数字的基数(用于整型数)或者小数的位数(用于浮点数)。允许的值为:BIN (binary二进制), OCT (octal八进制), DEC (decimal十进制), HEX (hexadecimal十六进制)。对于浮点数,该参数指定小数点的位数。
返回值:
size_t (long): print()返回发送的字节数(可丢弃该返回值)。
说明