1. 程式人生 > >淺嘗樹莓派3之串列埠配置

淺嘗樹莓派3之串列埠配置

引言

本文轉載自:  http://etrd.org/2017/01/29/%E6%A0%91%E8%8E%93%E6%B4%BE3%E7%A1%AC%E4%BB%B6%E4%B8%B2%E5%8F%A3%E7%9A%84%E4%BD%BF%E7%94%A8%E5%8F%8A%E7%BC%96%E7%A8%8B/ 主要為了記錄下來下次再配置時的方便。

通常學習一塊新的硬體平臺,大家第一個工程便是流水燈,實際上這屬於IO口的基本控制,這與上篇文章VS使用wiringPi庫控制樹莓派的GPIO是異曲同工的,接下來便應該是開始使用其通訊介面,而通訊接口裡面最簡單的又屬串列埠(uart),雖然簡單但目前仍然有很多模組是以串列埠作為通訊介面的,如一些藍芽模組、低速wifi模組、GPS模組、GPRS模組等。樹莓派3代與之前的樹莓派相比除了CPU效能上的提升外,還有一個顯著的特色便是板載集成了WIFI及藍芽,正是由於整合的這個藍芽模組,又使得樹莓派3代的串列埠使用相比於之前版本有了些麻煩,本文的目的便是解決這些麻煩並編寫驗證了一個簡單的串列埠程式碼。

樹莓派3代串列埠的麻煩

樹莓派從大的方向來說一共出了3代,每一代的CPU外設基本相同,但核心不同,外設裡面一共包含兩個串列埠,一個稱之為硬體串列埠(/dev/ttyAMA0),一個稱之為mini串列埠(/dev/ttyS0)。硬體串列埠由硬體實現,有單獨的波特率時鐘源,效能高、可靠,mini串列埠效能低,功能也簡單,並且沒有波特率專用的時鐘源而是由CPU核心時鐘提供,因此mini串列埠有個致命的弱點是:波特率受到核心時鐘的影響。核心若在智慧調整功耗降低主頻時,相應的這個mini串列埠的波特率便受到牽連了,雖然你可以固定核心的時鐘頻率,但這顯然不符合低碳、節能的口號。在所有的樹莓派板卡中都通過排針將一個串列埠引出來了,目前除了樹莓派3代以外 ,引出的串列埠預設是CPU的那個硬體串列埠。而在樹莓派3代中,由於板載藍芽模組,因此這個硬體串列埠被預設分配給與藍芽模組通訊了,而把那個mini串列埠預設分配給了排針引出的GPIO Tx Rx,下圖是樹莓派3的介面圖

QQ截圖20170129145844

其中紅框中就是引出的串列埠IO,如果我們需要通過UART外接模組,預設情況下必須得使用效能很低的mini串列埠了,而且隨著核心主頻的變化,還會造成波特率的變化導致通訊的失敗,幾乎很難使用。所以我們希望恢復硬體串列埠與GPIO 14/15的對映關係,使得我們能夠通過GPIO使用高效能的硬體串列埠來連線我們的串列埠裝置。

將樹莓派3的硬體串列埠與mini串列埠預設對映對換

樹莓派可以配置檔案來修改裝置樹,我的理解是可以通過配置檔案來修改管腳的對映關係,這在許多Cortex-M3核心的微控制器中也很常見,可以將同一個串列埠對映到不同的管腳上,以方便PCB的佈線。

為了在樹莓派3中通過GPIO使用高效能的硬體串列埠,我們必須將分配給藍芽使用的硬體串列埠與分配給IO排針的mini串列埠進行對換,這必然會使得藍芽模組的功能受到影響,但還好,藍芽並不是必須的。

在樹莓派系統中

1
/boot/overlays/

目錄下,提供了一個pi3-miniuart-bt-overlay.dtb的檔案,這個檔案的作用可以通過該目錄下的README檔案檢視

如果沒有pi3-miniuart-bt-overlay.dtb這個檔案,點選 http://ukonline2000.com/wp-content/uploads/2016/03/ 下載

QQ截圖20170129153256

QQ截圖20170129153541

README檔案中說明了這個檔案的功能是將樹莓派3的藍芽切換到mini串列埠(ttyS0),並且恢復硬體串列埠(ttyAMA0)到GPIO 14&15腳中。並且給出了載入的方法。

首先在樹莓派命令終端中通過命令檢視樹莓派3當前的串列埠對映關係

1
ls -l /dev

QQ截圖20170129151839

紅色框中體現的應該是一種對映關係,此處暫時沒有做深究,簡單理解 serial0 就是GPIO對映的串列埠,此時GPIO對映的串列埠是預設的/dev/ttyS0這個mini串列埠。

使用下面這條指令編輯 /boot/config.txt 檔案

1
sudo nano /boot/config.txt

在該檔案中增加一行程式碼

1
dtoverlay=pi3-miniuart-bt

然後儲存檔案,重啟樹莓派使之生效。

再通過 ls -l /dev 命令檢視修改後的對映關係

QQ截圖20170129154121

對比修改前的關係,可以看出serial0和serial1 與 ttyAMA0和ttyS0的對映關係對換完成了,也就是ttyAMA0對映到了引出的GPIO Tx Rx上。

禁用串列埠的控制檯功能

前面的步驟已經交換了硬體串列埠與mini串列埠的對映關係,但現在想使用樹莓派外接串列埠模組進行通訊還不行,因為樹莓派IO引出的串列埠預設是用來做控制檯使用的,它的初衷是為了在沒有網路介面時,通過串列埠對樹莓派進行相關的配置。因此需要禁用這個預設功能,使得串列埠為我們自由使用。

在樹莓派命令視窗中分別通過如下兩個命令停止和禁用串列埠的控制檯功能

1
2
sudo systemctl stop [email protected]
sudo systemctl disable [email protected]

由於我們前面已經交換了串列埠的對映關係,因此這裡注意是ttyAMA0。

然後通過下列指令編輯cmdline.txt檔案

1
sudo nano /boot/cmdline.txt

然後看到裡面類似如下的內容

1
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

把console=serial0,115200刪掉 console=serial0,115200 ,剩下的內容類似如下

1
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

然後重新啟動樹莓派,使修改生效

編寫一個簡單的串列埠程式

wiringpi實際上不只提供了基本的IO口的讀寫函式,還提供了串列埠操作庫函式,引用”wiringserial.h”即可使用,仍然使用前面的工程,參考wiringpi的串列埠例程,寫了如下程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <errno.h>
#include <string.h>
#include <wiringpi.h>
#include <wiringserial.h>

int main(int argc, char *argv[])
{
	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");

	for (;;)
	{
		if (serialDataAvail(fd) > 0)
		{
			putchar(serialGetchar(fd));	
		}

	}
	return 0;
}

使用USB轉TTL串列埠模組,USB端接電腦,TTL端接樹莓派的IO口,實物連線圖如下:

QQ截圖20170129165518

1
serialPuts(fd, "uart send test, just by launcher");

該語句是實現樹莓派發送一串字串給Windows電腦端的串列埠除錯助手

1
2
3
4
if (serialDataAvail(fd) > 0)
{
	putchar(serialGetchar(fd));	
}

這幾行程式碼是實現將Windows電腦端串列埠除錯助手發過來的資訊進行接收,並顯示在除錯輸出資訊上。

實測結果:

QQ截圖20170129142637

這是Windows串列埠除錯助手上接收的資訊,以及等待發送的資訊。

QQ截圖20170129162448

這是除錯時,樹莓派串列埠接收到資訊時的輸出

小結

樹莓派3代不同於以往的樹莓派舊版,CPU的高效能硬體串列埠預設分配給了藍芽使用,GPIO 14&15預設分配的是效能較差的mini串列埠,在無需使用板載藍芽的情況下,可以通過配置檔案修改樹莓派的裝置樹,使得高效能硬體串列埠重新恢復對映到IO排針介面中。同時要想通過GPIO 14&15外接串列埠通訊模組還需要關掉串列埠的預設控制檯功能。本文在參考已有文獻資料的情況下試圖闡述清楚了樹莓派中兩個串列埠的關係,並最後給出了一個簡單的示例程式碼實現了串列埠的程式設計使用。

限於水平,難免有理解或者認識的錯誤之處,有任何問題,請讓我知道。

參考文獻