一、串口基本介绍
树莓派3/4B的外设一共包含两个串口,一个称之为硬件串口(/dev/ttyAMA0),一个称之为mini串口(/dev/ttyS0)。
硬件串口由硬件实现,有单独的波特率时钟源,性能高、可靠。在树莓派1代2代中 ,引出的串口默认是CPU的那个硬件串口。在树莓派3/4B中,由于板载蓝牙模块,因此这个硬件串口被默认分配给与蓝牙模块通信了。
mini串口性能低,功能也简单,并且没有波特率专用的时钟源而是由CPU内核时钟提供,因此mini串口有个致命的弱点是:波特率受到内核时钟的影响。内核若在智能调整功耗降低主频时,相应的这个mini串口的波特率便受到牵连了,虽然你可以固定内核的时钟频率,但这显然不符合低碳、节能的口号。树莓派3/4B中,把mini串口默认分配给了排针引出的GPIO,即TXD0 RXD0。
二、串口设置
1、启动mini串口
在终端中输入:ls -l /dev
,在默认情况下,只能看到1个串口serial1,如下图所示。
默认下,serial1是映射到硬件串口的,硬件串口没有引出来给我们使用,板子上的TXD0 RXD0引脚是mini串口的,所以我们先要开启mini串口,具体方法如下:
执行sudo raspi-config
命令,打开树莓派配置窗口。依次选择Interface Options -> Serial Port
。会出现下面界面:
意思是询问你要不要启用串口登陆树莓派功能。选择否
。(后面再演示如何使用串口访问登陆树莓派)
然后询问你是否打开串口。选择是
:
然后选择Finish -> 是
重启树莓派
这个时候,在终端中再次输入ls -l /dev
命令,可以看到serial0映射到了mini串口上了,mini串口成功开启。
即:
serial0,GPIO映射的串口,默认是ttyS0,即mini串口。
serial1,板载蓝牙映射的串口,默认是ttyAMA0,即硬件串口。
2、交换映射关系
树莓派引出的串口IO,默认情况下必须得使用性能很低的mini串口(因为serial0映射到了mini串口),而且本文上方已经提到,mini串口随着内核主频的变化,会造成波特率的变化,导致通信的失败,几乎很难使用。
所以我们希望恢复硬件串口与GPIO 14/15(TXD0 RXD0)的映射关系,使得我们能够通过GPIO使用高性能的硬件串口来连接我们的串口设备。
下面是交换串口映射关系的步骤:
在终端输入sudo nano /boot/config.txt
。
在对应的文件末尾加入dtoverlay=pi3-disable-bt
,然后保存。
蓝牙使用硬件串口,所以我们在 /boot/config.txt里面加上
dtoverlay=pi3-disable-bt
,ttyAMA0 得以释放,这时候树莓派也自动交换了ttyAMA0和ttyS0,把serial0 分配给了 ttyAMA0 。
随后,输入 sudo reboot
重启树莓派,使修改生效。
重启后,运行ls -l /dev
命令,可以看到serial0映射到了ttyAMA0,映射关系交换成功。
三、代码测试
通过USB-TTL连接树莓派的TXD/RXD连接到PC,并打开PC端的串口助手,设置波特率为115200。
树莓派上,编写usart.c,代码如下所示(使用了wiringPi库,函数功能请查看我的另一篇博客《树莓派wiringPi库函数》):
#include "stdio.h"
#include "wiringPi.h"
#include "wiringSerial.h"
#include "unistd.h"
#include "string.h"
#include "errno.h"
int main(int argc, char *argv[])
{
int fd;
int err;
int len;
char rd_buf[128] = {0};
if(wiringPiSetup() != 0)
{
printf("wiringPiSetup error\n");
return -1;
}
//初始化并打开串口
fd = serialOpen("/dev/serial0", 115200);
if(fd < 0)
{
printf("serialOpen error, errno = %d\n", errno);
return -2;
}
while(1)
{
len = read(fd, rd_buf, 128);
if(len!=0)
{
printf("receive length:%d ,receive data:%s\n", len, rd_buf);
serialPrintf(fd, "receive OK\n");
memset(rd_buf, 0, strlen(rd_buf));
}
}
serialClose(fd);
return 0;
}
输入以下指令,运行代码,并打开串口调试助手,观察现象:
gcc -o usart usart.c -lwiringPi
./usart
下面再给出python库的代码。
树莓派上,编写usart.py,代码如下所示:
# -*- coding: utf-8 -*
import serial
import time
def main():
while True:
# 获得接收缓冲区字符
count = ser.inWaiting()
if count != 0:
# 读取内容并显示
recv = ser.read(count)
print recv
# 清空接收缓冲区
ser.flushInput()
# 必要的软件延时
time.sleep(0.1)
if __name__ == '__main__':
try:
# 打开串口
ser = serial.Serial('/dev/ttyAMA0', 9600)
if ser.isOpen == False:
ser.open() # 打开串口
ser.write(b"Raspberry pi is ready")
main()
except KeyboardInterrupt:
if ser != None:
ser.close()