IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Arduino软串口通信的实现及softwareserial库应用详解 -> 正文阅读

[嵌入式]Arduino软串口通信的实现及softwareserial库应用详解

????我们都知道Arduino?UNO板的数字IO端口为D0~D13,其中D0、D1还作为串口通信的接收(Rx)、发送(Tx)端口,当Arduino?UNO板外接的串口通信模块超过一个时,怎么办?此外,我们调试程序时经常会用到串口显示语句Serial.print(),如果我们的模块占用了这个串口,就没法用Serial.print()语句来显示我们的测试数据了。Arduino?UNO板解决这个问题的办法,就是用其它的IO端口来模拟串口通信,也就是我们通常称之为软串口(或模拟串口)。

????一般采用微处理器芯片的单板机等,数字IO口的电平信号都是采用TTL电平标准的,即5V为1,0V为0Arduino的数字IO口亦是采用TTL电平标准,它上面的硬件串口(D0、D1)采用的也是TTL标准的串行协议因此我们就可以用其它的IO口来模拟硬件串口,即用软件程序将一个字节(BYTE)拆成8个位(bit),根据bit=1或0,依次按指定的频率用相应的高低电平串行发送,接收端读取到这些高低电平后,再将这些高低电平信号还原成1或0,然后还原成一个字节数据,也就是模拟硬件串口进行通信。

????如果按上述的方法编程,那不是太麻烦了啊!幸好Arduino IDE里已经自带了一个softwareserial.h库,它让我们使用软串口编程与硬串口编程几乎一模一样。我们使用这个库可以将D2~D13的任何2个IO端口定义为软串口的接收(Rx)或发送(Tx)端口。可以创建多个SoftwareSerial对象,但是在给定时刻只能有一个活动。

????下面说下如何在程序中使用softwareserial.h库。

????

????(一)softwareserial.h库提供了一个SoftwareSerial类,当然我们首先要引用一下库,即:

????#include<SoftwareSerial.h>

????

????(二)接着自定义一个软串口SoftwareSerial类的实例对象:

????SoftwareSerial mySerial(rxPin, txPin)

????参数:

????mySerial:用户自定义软串口对象名

????rxPin:软串口接收引脚

????txPin:软串口发送引脚

????返回:

????无

????这里自定义软件串口对象的名,可以随便取,例如你可以取名为SS1或其他的,如果用D10作为接收端口,D11作为发送端口,则程序语句为:

????SoftwareSerial ?SS1(10,11);

????

????(三)接着我们要用begin来设置串行通信的速度(波特率):

????mySerial.begin(speed)

????参数

????speed:所需波特率。支持的波特率为:300、600、1200、2400、4800、9600、14400、19200、28800、31250、38400、57600。

????返回:

????无

????

????(四)接下来我们就可以用available来检测接收缓冲区里是否有已经接收到的数据:

????mySerial.available()

????参数

????无

????返回:

????可读取的字节数

????

????(五)然后就可以用read来读取接收引脚(rxPin上接收到的字符,并且清除掉接收缓冲区中的第一个字节。请注意,一次只能有一个SoftwareSerial对象接收传入的数据(使用listen()函数选择哪个对象)。

????(1)

????mySerial.read()

????参数

????无

????返回:

????如果没有可用的字符,则为-1。

????

????(2)

????也可以用peek来读取接收引脚(rxPin上接收到的字符,但是与read()不同,它不清除掉接收缓冲区中的第一个字节,因此对该函数的后续调用将返回相同的字符。

????mySerial.peek()

????参数

????无

????返回:

????如果没有可用的字符,则为-1。

????

????(六)发送数据的话,可以用print、println、write。

????(1)print是将数据作为ASCII文本发送到串行端口。这个函数可以有多种形式。每个数字都使用ASCII字符打印数字。浮点数也是打印为ASCII数字,默认为两位小数。字节作为单个字符发送。字符和字符串按原样发送。

????mySerial.print(val)

????mySerial.print(val, format)

????参数

????val:要发送的值。允许的数据类型:任何数据类型。

????返回:

????发送的字节数(读取此数字是可选的)。

????

????mySerial.print(val, format)

????可选的第二个参数指定要使用的格式允许值为BIN(二进制)OCT(八进制)DEC(十进制)HEX(十六进制或十六进制)。对于浮点数,此参数指定要使用的小数位数。例如

????

????mySerial.print(78, BIN)给出“1001110”

????

????mySerial.print(78, OCT)给出“116”

????

????mySerial.print(78, DEC)给出“78”

????

????mySerial.print(78, HEX)给出“4E”

????

????mySerial.print(1.23456, 0)给出“1”

????

????mySerial.print(1.23456, 2)给出“1.23”

????

????mySerial.print(1.23456, 4)给出“1.2346”

????

????(2)println也是将数据作为ASCII文本发送到串行端口只是在发送完参数val后,自行再增加发送了回车和换行符。工作原理和println()函数

????

????(3)还有一个发送数据的函数write,write也是发送数据,但它发送的是数值本身。这里我简单的说下与print的区别,当用print发送一个数据时,Arduino发送的并不是数据本身,而是将数据转换成字符,再将对应的ASCII码发送出去,即print是以ASCII码的形式输出数据到串口。而当用write发送一个数据时,Arduino发送的是数值本身。

????mySerial.write(val)

????参数

????发送的数值

????返回:

????发送的字节数(读取此数字是可选的)。

????

????(七)我们前面说到“可以创建多个SoftwareSerial对象,但是在给定时刻只能有一个活动”,那我们怎么转换到指定的软串口呢?SoftwareSerial库提供了2个相关的函数。

????(1)当我们需要启用所选的某个SoftwareSerial对象来进行软串口通信,可以用listen。因为一次只能监听一个SoftwareSerial对象,因此到达其他端口的数据将被丢弃。在调用listen函数期间,将丢弃已接收到的任何数据(除非给定实例已在侦听)。

????mySerial.listen()

????参数:

????无

????返回:

????如果替换另一个则返回true。

????

????(2)还有一个isListening函数,是用来测试某个指定的软串口是否为当前活动的SoftwareSerial对象。

????mySerial.isListening()

????参数:

????无

????返回:

????布尔值

????

????使用Listen和isListening例:

????

????#include <SoftwareSerial.h>

????

????// Set up a new SoftwareSerial object with RX in digital pin 10 and TX in digital pin 11

????SoftwareSerial portOne(10, 11);

????

????// Set up a new SoftwareSerial object with RX in digital pin 8 and TX in digital pin 9

????SoftwareSerial portTwo(8, 9);

????

????void setup() {

????????// Set the baud rate for the Serial object

????????Serial.begin(9600);

????

????????// Set the baud rate for the SerialSoftware objects

????????portOne.begin(9600);

????????portTwo.begin(9600);

????}

????

????void loop() {

????????// Enable SoftwareSerial object to listen

????????portOne.listen();

????????

????????if (portOne.isListening()) {

????????????Serial.println("portOne is listening!");

????????} else {

????????????Serial.println("portOne is not listening!");

????????}

????

????????if (portTwo.isListening()) {

????????????Serial.println("portTwo is listening!");

????????} else {

????????????Serial.println("portTwo is not listening!");

????????}

????}

????

????(八)还有一个overflow函数,是用来检测是否发生软件串行缓冲区溢出。调用此函数将清除溢出标志,这意味着后续调用将返回false,除非在此期间接收并丢弃另一字节的数据。软件串行缓冲区最多可容纳64个字节。

????mySerial.overflow()

????参数:

????无

????返回:

????布尔值

????

????下面我们就用一个实验来印证一下软串口的使用,就还用我上一篇写的《Arduino实现语音实时播报当前温湿度》实验,这次我们在Arduino端不使用硬件串口,使用IO端口D10、D11作为软串口的接收(Rx)和发送(Tx)端口,程序基本不用改,除了在前面添加了引用softwareserial库和建立一个软串口实例(我取名为softSerial),其他就是在原程序里把Serial对象替换成softSerial对象,当然连接线也要改下,原来接D0、D1的线,改接到D10、D11,是不是非常简单?如果没有看过《Arduino实现语音实时播报当前温湿度》的,可以点击这个文章名,直接进入该文查看。接线图还是再放一下:

????

????用软串口的Arduino端的完整程序如下( LU-ASR01端程序完全不用改,就不再放上来了):

/*

???本程序通过DHT11获得当前温湿度,并通过软串口通信与ASR01连接,然后由ASR01播报

???当前温湿度。

???通信报文长度为3字节,报文格式:

???第1字节:命令编号 ??第2、3字节:数据

???本程序的报文用了三个命令:

???发送温度报文:编号:0x23(字节1),字节2温度整数部分,字节3温度2位小数部分

???发送湿度报文:编号:0x24(字节1),字节2湿度整数部分,字节3湿度2位小数部分

???接收请求发送温湿度报文:编号:0x25(字节1),字节2未使用,字节3 ?=1温度,=2湿度

*/

#include "DHT.h"

#include<SoftwareSerial.h>

const int DHTPin = ?12; // 定义DHTPin连接的引脚为D12

const int SRxPin = ?10; // 定义软串口的接收(Receive Rx)引脚为D10

const int STxPin = ?11; // 定义软串口的接收(Transmit Tx)引脚为D11

DHT dht;

SoftwareSerial softSerial(SRxPin,STxPin);

#define MLEN 3 ??//定义报文长度为3

unsigned char Txbyte[MLEN]; ?//串口发送的字符数据,长度为MLEN

unsigned char Rxbyte[MLEN]; ?//串口读取的字符数据,长度为MLEN

float thtmp; //

//初始化

void setup() {

??softSerial.begin(9600); //设置串口波特率9600

??pinMode(DHTPin, INPUT); ?//设置DHTPin ???

??dht.setup(DHTPin); // 设置DHT11数据传输的引脚

}

//发送报文子程序

//参数txb为准备发送的报文数据,n为报文长度

void txmss(unsigned char txb[],int n){

??int i;

??for(i=0;i<n;++i){

????softSerial.write(txb[i]);

????delay(2); ?

??}

}

//接收报文子程序,成功接收返回值为true,否则为false

//参数rxb为返回的报文数据,n为报文长度

bool rxmss(unsigned char rxb[],int n){

int i,dn; ?//dn为超时计数器

??for (i=0; i<n; ++i) {

????dn=0; ?//超时计数变量复位

????while(1){ ??// ?

??????if (dn<=50){ ?//设等待读取一字节的最大时间为50ms,若没有超时则

????????if(softSerial.available() > 0){ //当串口缓冲区有数据

??????????rxb[i]=softSerial.read(); //读取一个字节

??????????break; ?//跳出while(1)循环

????????}

????????else{ ?//若串口缓冲区没有数据,且没有超时,则超时计数器+1

??????????delay(1);

??????????dn+=1; ???//超时计数器+1

????????}

??????}

??????else return false; ?//接收超时则函数rxmss退出,返回false

????}

??}

??return true; ?//正常接收到n个字节,函数rxmss返回true

}

//主程序

void loop() {

??delay(dht.getMinimumSamplingPeriod()); //获取DHT11的最小采样周期

??if (softSerial.available() > 0){ ????//当串口缓冲区有数据

????if (rxmss(Rxbyte,MLEN)){ ???//若成功接收到一个报文(即3字节数据已接收到数组Rxbyte)

??????if(Rxbyte[0]==0x25) { ???//若接收的Rxbyte[0]为0x25则为要求发送温湿度命令

????????if(Rxbyte[2]==1){ //要求发送的是温度

??????????//填写报文

??????????Txbyte[0]=0x23; ?//命令码0x23表示发送温度数据

??????????thtmp=(float) dht.getTemperature(); //从DHT11读取温度

??????????Txbyte[1]=(int) thtmp; //温度的整数部分放在Txbyte[1]

??????????Txbyte[2]=(int) (thtmp-Txbyte[1]*100); ?//温度的2位小数放在Txbyte[2]

??????????txmss(Txbyte,MLEN); ?//发送报文,将温度数据发送给LU-ASR01

????????}

????????if(Rxbyte[2]==2){ //要求发送的是湿度

??????????//填写报文

??????????Txbyte[0]=0x24; ?//命令码0x24表示发送温度数据

??????????thtmp=(float) dht.getHumidity(); //从DHT11读取湿度

??????????Txbyte[1]=(int) thtmp; //湿度的整数部分放在Txbyte[1]

??????????Txbyte[2]=(int) (thtmp-Txbyte[1]*100); ?//湿度的2位小数放在Txbyte[2]

??????????txmss(Txbyte,MLEN); ?//发送报文,将湿度数据发送给LU-ASR01

????????}

??????}

????}

??}

}

????

本人网名为“不赦先生”,发表在CSDN上的文章均为本人原创,且仅在CSDN网站发布,其他网站的转载均未获得过本人的授权。

????

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-09-13 11:33:13  更:2022-09-13 11:33:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:32:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码