一、串口基本介绍

树莓派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,如下图所示。

树莓派串口使用python ttyS0 树莓派串口配置_#include


默认下,serial1是映射到硬件串口的,硬件串口没有引出来给我们使用,板子上的TXD0 RXD0引脚是mini串口的,所以我们先要开启mini串口,具体方法如下:

执行sudo raspi-config命令,打开树莓派配置窗口。依次选择Interface Options -> Serial Port。会出现下面界面:

意思是询问你要不要启用串口登陆树莓派功能。选择。(后面再演示如何使用串口访问登陆树莓派)

树莓派串口使用python ttyS0 树莓派串口配置_#include_02


然后询问你是否打开串口。选择

树莓派串口使用python ttyS0 树莓派串口配置_串口_03


然后选择Finish -> 是重启树莓派

树莓派串口使用python ttyS0 树莓派串口配置_树莓派串口使用python ttyS0_04


树莓派串口使用python ttyS0 树莓派串口配置_树莓派_05


这个时候,在终端中再次输入ls -l /dev命令,可以看到serial0映射到了mini串口上了,mini串口成功开启。

树莓派串口使用python ttyS0 树莓派串口配置_树莓派串口使用python ttyS0_06


即:

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,然后保存。

树莓派串口使用python ttyS0 树莓派串口配置_树莓派_07

蓝牙使用硬件串口,所以我们在 /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 ttyS0 树莓派串口配置_#include_08

下面再给出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()