实验环境树莓派 3B 开发板
2018-06-27-raspbian-stretch 树莓派操作系统
使用 Windows 10 通过网线连接远程登陆访问方式控制树莓派
实验目的
为了将树莓派构建成一个智能家居的数据中心,我们需要在树莓派上连接 ZigBee 无线通信模块,实现与传感器的一对多通信。
由于 ZigBee 使用的是串口通信方式,所以我们需要打开树莓派的串口功能。由于 3 代的树莓派板载集成了很多以串口作为通信接口的模块,如蓝牙模块、低速 WiFi 模块、GPS 模块、GPRS 模块等。由于板载了蓝牙模块,而这个蓝牙模块占用了我们板子上的硬件串口,所以使得我们的 3 代树莓派在串口的设置上较为麻烦。
3代树莓派串口存在的主要问题
树莓派从大的方向来说一共出了3代,每一代的CPU外设基本相同,但内核不同,外设里面一共包含两个串口,一个称之为硬件串口(/dev/ttyAMA0),一个称之为mini串口(/dev/ttyS0)。硬件串口由硬件实现,有单独的波特率时钟源,性能高、可靠,mini串口性能低,功能也简单,并且没有波特率专用的时钟源而是由CPU内核时钟提供,因此mini串口有个致命的弱点是:波特率受到内核时钟的影响。内核若在智能调整功耗降低主频时,相应的这个mini串口的波特率便受到牵连了,虽然你可以固定内核的时钟频率,但这显然不符合低碳、节能的口号。在所有的树莓派板卡中都通过排针将一个串口引出来了,目前除了树莓派3代以外 ,引出的串口默认是CPU的那个硬件串口。而在树莓派3代中,由于板载蓝牙模块,因此这个硬件串口被默认分配给与蓝牙模块通信了,而把那个mini串口默认分配给了排针引出的GPIO Tx Rx,下图是树莓派3的接口图:
其中红框中就是引出的串口IO,如果我们需要通过UART外接模块,默认情况下必须得使用性能很低的mini串口了,而且随着内核主频的变化,还会造成波特率的变化导致通信的失败,几乎很难使用。所以我们希望恢复硬件串口与GPIO 14/15的映射关系,使得我们能够通过GPIO使用高性能的硬件串口来连接我们的串口设备。
确保串口功能已经激活
在进行串口模式的修改之前,我们想要确保串口的功能已经激活,在 /boot/config.txt 文件中进行查看,是否存在如下语句:
没有的话,就手动在最后一行添加:
enable_uart=1
重启设备,生效。
查看串口别名和硬件串口与mini串口交换的解决方案
树莓派可以配置文件来修改设备树,我的理解是可以通过配置文件来修改管脚的映射关系,这在许多Cortex-M3内核的单片机中也很常见,可以将同一个串口映射到不同的管脚上,以方便PCB的布线。
为了在树莓派3中通过GPIO使用高性能的硬件串口,我们必须将分配给蓝牙使用的硬件串口与分配给IO排针的mini串口进行对换,这必然会使得蓝牙模块的功能受到影响,但还好,蓝牙并不是必须的。
在树莓派系统的 /boot/overlays/ 目录下,提供了一个 pi3-miniuart-bt.dtbo文件。其文件作用可以在当前目录下的 README 文件中进行查看:
README文件中说明了这个文件的功能是将树莓派3的蓝牙切换到mini串口(ttyS0),并且恢复硬件串口(ttyAMA0)到GPIO 14&15脚中。并且给出了载入的方法。
首先在树莓派命令终端中通过命令查看树莓派3当前的串口映射关系:
ls -l /dev
红色框中体现的应该是一种映射关系,此处暂时没有做深究,简单理解 serial0 就是GPIO映射的串口,此时GPIO映射的串口是默认的 /dev/ttyS0这个mini串口。
禁用串口的控制台功能
前面的步骤已经交换了硬件串口与mini串口的映射关系,但现在想使用树莓派外接串口模块进行通信还不行,因为树莓派IO引出的串口默认是用来做控制台使用的,它的初衷是为了在没有网络接口时,通过串口对树莓派进行相关的配置。因此需要禁用这个默认功能,使得串口为我们自由使用。
在树莓派命令窗口中分别通过如下两个命令停止和禁用串口的控制台功能:
sudo systemctl stop [email protected]
sudo systemctl disable [email protected]
然后通过下列指令编辑 cmdline.txt 文件:
sudo vim /boot/cmdline.txt
然后看到里面类似如下的内容:
然后,我们把红色方框框起来的那部分删除即可,得到如下结果:
重启设备,生效。
将树莓派的硬件串口与mini串口默认映射对换
使用下面这条指令编辑 /boot/config.txt 文件
sudo vim /boot/config.txt
根据之前在 README 文件中得到指示内容在该文件中增加一行代码:
dtoverlay=pi3-miniuart-bt
然后保存文件,重启树莓派使之生效。
再通过 ls -l /dev 命令查看修改后的映射关系:
此时,ttyAMA0串口可以正常用于串口通信,ttyS0则无法被用于串口通信,蓝牙功能失效。
编写一个简单的串口程序
wiringPi 实际上不只提供了基本的IO口的读写函数,还提供了串口操作库函数,引用 "wiringSerial.h" 即可使用,仍然使用前面的工程,参考 wiringpi的串口例程 ,写了如下代码:
#include #include #include #include #include #include
char UartBuff[100];
int main(void)
{
int fd;
if ((fd = serialOpen("/dev/ttyAMA0", 115200)) < 0)
{
fprintf(stderr, "Unable to open serial device: %s\n", strerror(errno));
return 1 ;
}
serialPuts(fd, "uart send test, just by launcher\n");
while(1)
{
UartBuff[0] = serialGetchar(fd);
if (UartBuff[0] > 0)
{
putchar(UartBuff[0]);
serialPutchar(fd,UartBuff[0]);
}
}
return 0;
}
使用 USB 转 TTL 串口模块,USB 端接电脑,TTL 端接树莓派的 IO 口,实物连接图如下:
运行在树莓派上编写完成的串口接收和发送程序,我们在 Windows 电脑端的串口调试助手接收到如下数据:
接着,从串口助手发送“hello world!”给树莓派,树莓派接收到如下数据,并打印出来:
串口助手也同时接收到如下信息:
至此,证明我们的树莓派串口设置成功。
最后,再给出一份使用 Python2 写的串口通信代码,提供给大家参考,毕竟使用 Python 再树莓派上进行数据处理的人相对会比较多一些:
import serial
import time
ser = serial.Serial("/dev/ttyAMA0", 115200)
def main():
while True:
recv = get_recv()
if recv != None:
print recv
ser.write(recv[0] + "\n")
time.sleep(0.1)
def get_recv():
cout = ser.inWaiting()
if cout != 0:
line = ser.read(cout)
recv = str.split(line)
ser.reset_input_buffer()
return recv
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
if ser != None:
ser.close()
参考资料: