使用樹莓派 3B+ 測試 gpio,配置硬件串口,測試串口通信
1、GPIO擴展口定義、DB9接口定義
這裏的板子上40pin引腳有3中編碼方式:
1、Board編碼:對應實際的物理插槽
2、BCM編碼:基本和GPIO的名字對應
2、wiringPi編碼:wiringPi庫使用的引腳編碼方式
DB9公頭接口定義
在進行串口通信,兩個設備間進行雙向通信時,兩個設備的RXD、TXD要交錯連接。
2、串口設置
樹莓派包含兩個串口
1.硬件串口(/dev/ttyAMA0),硬件串口由硬件實現,有單獨的波特率時鐘源,性能高,可靠。一般優先選擇這個使用。
2.mini串口(/dev/ttyS0),mini串口時鐘源是由CPU內核時鐘提供,波特率受到內核時鐘的影響,不穩定。
想要通過樹莓派的GPIO引腳進行穩定的串口通信,需要修改串口的映射關係。
serial0是GPIO引腳對應的串口,serial1是藍牙對應的串口。使用ls -l /dev/serial*
查看當前的映射關係:
可以看到這裏是,藍牙串口serial1使用硬件串口ttyAMA0。
2.1 開啓GPIO串口功能,並使用硬件串口
使用sudo raspi-config
進入圖形界面
選擇菜單 Interfacing Options -> P6 Serial,
第一個選項(would you like a login shell to be accessible over serial?)選擇NO,
第二個選項(would you like the serial port hardware to be enabled?)選擇 YES
保存後重啓,查看映射關係
比之前多了一個gpio的串口serial0,並且使用的ttyS0。這裏已經是開啓了GPIO串口功能,但是使用的cpu實現的軟件串口。
如果想使用穩定可靠的硬件串口,就要將樹莓派3b+的硬件串口與mini串口默認映射對換(先禁用藍牙 sudo systemctl disable hciuart
)。
在/boot/config.txt文件末尾添加一行代碼 dtoverlay=pi3-miniuart-bt
保存後重啓再查看設備對用關係,發現已經調換成功。
2.2 禁用串口的控制檯功能
前面步驟已經交換了硬件串口與mini串口的映射關係,但是,現在還不能使用樹莓派串口模塊與電腦進行通信,因爲,樹莓派gpio口引出串口默認是用來做控制檯使用的,即是爲了用串口控制樹莓派,而不是通信。所以我們要禁用此默認設置。
首先執行命令如下:
sudo systemctl stop [email protected]
sudo systemctl disable [email protected]
然後執行命令行修改文件:
sudo nano /boot/cmdline.txt
並刪除語句console=serial0,115200
(沒有的話就不需要此步驟)
2.3 測試驗證串口通信功能
這裏使用三種方式進行測試驗證, c語言下使用wiringPi庫, python語言下使用serial包,最後命令行使用minicom工具。
先安裝以上開發工具
sudo apt-get install wiringpi
sudo apt-get install python-serial
sudo apt-get install minicom
將usb轉ttl模塊引腳的GND、TX、RX分別與樹莓派的GND、RX、TX連接;電腦端啓用串口調試助手,波特率設置一致。
2.3.1 c語言實現
編寫test.c測試代碼,
#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main()
{
int fd;
if(wiringPiSetup()<0) {
return 1;
}
//if((fd=serialOpen("/dev/ttyS0",115200))<0) { // gpio 使用mini串口
if((fd=serialOpen("/dev/ttyAMA0",115200))<0) { // gpio 使用硬件串口
return 1;
}
printf("serial test output ...\n");
serialPrintf(fd,"1234567890abcdef");
serialClose(fd);
return 0;
}
編譯 gcc test.c -o test -lwiringPi
,運行 sudo ./test
2.3.2 python實現
# -*- coding: utf-8 -*
import serial
import time
ser = serial.Serial("/dev/ttyAMA0",115200)
if not ser.isOpen():
print("open failed")
else:
print("open success: ")
print(ser)
try:
while True:
count = ser.inWaiting()
if count > 0:
recv = ser.read(count)
print("recv: " + recv)
ser.write(recv)
sleep(0.05)
except KeyboardInterrupt:
if ser != None:
ser.close()
運行python代碼,並在串口調試助手中發送字符串,樹莓派收到數據後打印、在回發給串口助手,截圖如下。
2.3.3 minicom命令函實現
使用minicom -b 115200 -D /dev/ttyAMA0
進入串口調試界面,這裏將一直等待接收,直到用戶手動退出。退出時ctrl+A,再按鍵X退出。
minicom調試界面默認是不顯示用戶輸入,使用cttl+A,再按E即可開啓(會捕獲換行)。
串口助手和minicom界面的交互如下:
串口助手發送“1234567890abcdef”,
minicom發送"\n”,“1”,"\n",“3”,“4”,"\n"
串口助手發送“1234567890abcdef”,
界面截圖如下:
2.4 wiringPi庫c語言完整串口通信代碼
使用wiringPI庫進行發送和持續接收的示例代碼,如下
#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int running = 1;
void sig_handle(int sig)
{
if(sig == SIGINT) running = 0;
}
int main()
{
signal(SIGINT, sig_handle);
int fd;
if(wiringPiSetup() < 0){
printf("wiringPi setup failed.\n");
return 1;
}
int baudrate = 115200;
//if((fd = serialOpen("/dev/ttyS0", baudrate)) < 0){
if((fd = serialOpen("/dev/ttyAMA0",baudrate)) < 0){
printf("serial open failed.\n");
return 1;
}
printf("serial test output ...\n");
serialPrintf(fd, "0123456789abcdef"); //發送
while(running)
{
int sz = serialDataAvail(fd); // 等待介紹的數據個數
if(sz > 0)
{
printf("size %d, ", sz);
char *buff =(char*)malloc(sz);
printf("recv: ");
for(int i = 0; i < sz; i++){
int c = serialGetchar(fd); //接收一個字符
//if(c != -1)
buff[i] = c;
}
printf("%s\n", buff);
free(buff);
serialPrintf(fd, buff);//回顯
}
else{
usleep(50000); // 必要的延時50ms
}
}
serialClose(fd);
printf("close serial.\n");
return 0;
}
tip:延時的作用:1、匹配串口讀寫速度,使得下一次讀時,設備已經完成寫操作; 2、減小資源佔用;
若不延時,CPU佔用高,並且最多一次讀取一個字符。
3、GPIO 編程
這裏演示BCM_gpio 22輸出控制,串接一個220歐姆、led燈珠到GND,進行亮、滅燈控制。
這裏涉及引腳連線、編程中確定口線,需要熟悉引腳編碼。先以gpio命令行工具說明編碼、並進行測試,再使用python、c語言實現。
3.1 gpio命令行
使用gpio -v
查看版本
使用gpio readall
查看引腳編碼
這裏我們選擇的名稱爲"BCM_GPIO.22",對應的是BCM編碼"22",wPi編碼"3",而實際的物理插槽BOARD編碼是"15"。 因此實際接線應該使用插槽編碼爲15的口線。
gpio工具使用的是BCM編碼。設置BCM_GPIO.22口爲輸出模式, 寫”1”燈亮,寫”0”燈滅。
gpio -g mode 22 out
gpio -g write 22 1
gpio -g write 22 0
3.2 Python 庫 RPi.GPIO編程
這裏的操作結果同上,使用RPi.GPIO庫。若無該庫,先進行安裝 sudo pip install RPi.GPIO
先使用python idle進行簡單控制
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM) ## 編號默認BCM
GPIO.setup(22, GPIO.OUT)
GPIO.output(22, GPIO.HIGH)
GPIO.output(22, LOW)
GPIO.output(22, 1)
GPIO.output(22, 0)
在利用腳本讓其間隔一秒鐘亮滅
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO #引入RPi.GPIO庫函數命名爲GPIO
import time #引入計時time函數
# BOARD編號方式,基於插座引腳編號
GPIO.setmode(GPIO.BOARD) #將GPIO編程方式設置爲BOARD模式
# 輸出模式
GPIO.setup(15, GPIO.OUT) #將Board 15引腳(BCM 22)設置爲輸出引腳
while True: #條件爲真,下面程序一直循環執行
GPIO.output(15, GPIO.HIGH) #將15引腳電壓置高,點亮LED燈
time.sleep(1) #延時1秒
GPIO.output(15, GPIO.LOW) #將15引腳電壓置低,熄滅LED燈
time.sleep(1) #延時1秒
3.3 c/c++使用wiringPI庫
重複上面引用內容: 這裏我們選擇的名稱爲"BCM_GPIO.22",對應的是BCM編碼"22",wPi編碼"3",而實際的物理插槽BOARD編碼是"15"。
使用wiringPI庫時,IO口爲wPi編碼,爲保證和前面的實列對應相同,使用編號爲3。
編寫以下test.c代碼
編譯 gcc test.c -o test -lwiringPi
,運行 ./test
#include <stdio.h>
#include <wiringPi.h>
// LED Pin - wiringPi pin 3 is BCM_GPIO 22.(pyscial 15)
#define LED 3
int main (void)
{
if(wiringPiSetup() < 0){
printf("wiringPi setup failed.\n");
return 1;
}
pinMode(LED, OUTPUT); // 設置輸出模式
for (;;)
{
digitalWrite(LED, HIGH) ; // On
delay(500) ; // mS
digitalWrite(LED, LOW) ; // Off
delay(500) ;
}
return 0 ;
}