Bài 4 : Lập trình Raspberry Pi sử dụng cổng truyền thông UART
14:53 - 15/01/2019
Bài 4 : Lập trình Raspberry Pi sử dụng cổng truyền thông UART
Remote Desktop Raspberry Pi không cần Wifi, mạng LAN và IP
Camera nhiệt giải pháp tuyệt vời cho mùa Covid-19
Lập trình cơ bản với OpenPLC trên Raspberry Pi
Hướng dẫn cài đặt OpenPLC trên Raspberry Pi
Giao tiếp qua cổng UART với Raspberry Pi1. Giới thiệu UART trên Raspberry PiRaspberry Pi hỗ trợ chuẩn Uart trên chân BCM14 (TX) và BCM15 (RX). Mặc định uart được sử dụng làm serial console; nó sẽ gửi toàn bộ thông tin của kernel trong quá trình Pi khởi động. Bạn có thể kết nối trực tiếp uart của pi thông qua mạch USB-TTL để xem thêm. Để sử dụng Uart với mục đích riêng bạn phải giải phóng chân Uart. Lưu ý với Raspberry Pi 3 Uart còn được sử dụng để kết nối bluetooth, và chân BCM14 và BCM15 trở thành mini uart port. Để Setup UART cho Pi dùng trong kết nối với các MCU khác, các bạn có thể tham khảo hướng dẫn trong video sau :
2. Giao tiếp UART với Raspberry Pi
Hình 1 : chân GPIO của Raspberry Pi 2 model B Dưới đây là hai ví dụ đơn giản giao tiếp giữa Raspberry và Arduino Vn01: - Ví dụ 1 : Gửi chuỗi ký tự từ Raspberry tới Arduino. - Ví dụ 2 : Gửi chuỗi ký tự từ Arduino tới Raspberry. Thông tin : raspberry Pi 2 model B và Arduino Vn01 2.1 Kết nối phần cứngKết nối giữa Arduino và Pi như sau : RX của arduio <-> TX của Pi và ngược lại TX của arduino <-> RX của Pi, kết nối chung 2 chân GND với nhau. 2.2.1 Lập trình giao tiếp UART Chuẩn bị thư viện cho C là wiring-pi như trong bài 1 đã đề cập tới. Thư viện cho python là pySerial sudo apt-get install python-serial Khi cần dùng thư viện chỉ cần thực hiện “import serial” a. Lập trình bằng CVí dụ 1 Chương trình “uart-send.c” trên Raspberry // Compile : gcc -Wall uart-send.c -o uart-send -lwiringPi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main() {
int fd;
printf("Raspberry's sending : \n");
while(1) {
if((fd = serialOpen ("/dev/ttyAMA0", 9600)) < 0 ){
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno));
}
serialPuts(fd, "hello");
serialFlush(fd);
printf("%s\n", "hello");
fflush(stdout);
delay(1000);
}
return 0;
}
Chương trình trên Pi sẽ gửi chuỗi ký tự “hello” thông qua uart tới arduino. Nó sẽ gửi liên tục sau 1s. Thư viện sử dụng : #include <wiringSerial.h> - Mở cổng kết nối Serial. int serialOpen (char *device, int baud); Luôn nhớ rằng cổng uart có tên là ttyAMA0. Hàm này sẽ trả về file-descriptor. Nễu file-descritor lỗi sẽ có giá trị là -1. - Hàm gửi dữ liệu Void serialPutchar (int fd, unsigned char c) ; Hàm này gửi sẽ gửi 1 byte. Nếu muốn gửi một mảng (hoặc chuỗi ký tự) có thể sử dụng hàm sau. void serialPuts (int fd, char *s) ; - Hàm void serialFlush (int fd) : chờ đến khi dữ liệu được gửi xong hoặc bỏ qua tất cả dữ liệu được gửi tới. Hàm này rất cần với uart, nếu không có sẽ không thể gửi chính xác được. Bạn nên bỏ hàm này đi và xem thử. Có lẽ đây là một bug nhỏ đối với chương trình này vì đáng lý ra chương trình sau khi thực hiện lệnh gửi dữ liệu có thể thực hiện ngay lập tức lệnh tiếp theo, dữ liệu sẽ được uart tự động ngầm gửi đi. Chương trình không cần phải chờ. Các hàm được hỗ trợ : wiringPi Để compile được chương trình thực hiện lệnh gcc -Wall uart-send.c -o uart-send -lwiringPi Chương trình “uart-receive.ino” trên Arduino void setup() {
Serial.begin(9600); // opens serial port, baudrate : 9600 bps
}
void loop() {
if (Serial.available() > 0) {
String str = Serial.readString();
Serial.print("Received: ");
Serial.println(str);
}
} - Khởi tạo Uart : Serial.begin(9600); Lưu ý rằng baudrate bằng 9600 giống như trên Pi. - Hàm kiểm tra xem có dữ liệu tới uart không : Serial.available() Hàm này trả về số byte nhận được. - Đọc dữ liệu chuỗi ký tự : Serial.readString(); Trả về dữ liệu kiểu String. - Lưu ý: Serial.print(); Mục đích để hiện thị lên màn hình kết quả, nhưng nó gửi qua Uart nên cũng đồng thời nó gửi dữ liệu tới Pi. Kết quả : Ví dụ 2 Chương trình “uart-receive.c” trên Raspberry // Compile : gcc -Wall uart-receive.c -o uart-receive -lwiringPi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main() {
int fd;
char c;
printf("Raspberry's receiving : \n");
while(1) {
if((fd = serialOpen ("/dev/ttyAMA0", 9600)) < 0 ){
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
}else{
do{
c = serialGetchar(fd);
printf("%c",c);
fflush (stdout);
}while(serialDataAvail(fd));
}
}
return 0;
} - Kiểm tra xem có dữ liệu tới không : int serialDataAvail (int fd); Hàm này trả về số byte dữ liệu xuất hiện. Trả về -1 nếu bị lỗi. - Đọc dữ liệu int serialGetchar (int fd); Trả về một byte dữ liệu tới. Con trỏ của nó sẽ tự tăng sau mỗi lần gọi. Hàm sẽ chờ tới tận 10s nếu không có dữ liệu. Trả về -1 nếu bị lỗi. Chương trình “uart-send.ino” trên Arduino
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("arduino say hello!");
delay(1000);
} Kết quả :
b. Lập trình PythonXem một số ví dụ về thư viện serial Ví dụ 1 Chương trình “uart-send.py” trên Raspberry #!/usr/bin/python3
import time
import serial
ser = serial.Serial(
port = '/dev/ttyAMA0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
print("Raspberry's sending : ")
try:
while True:
ser.write(b'hehe')
ser.flush()
print("hehe")
time.sleep(1)
except KeyboardInterrupt:
ser.close() - Thiết lập serial serial.Serial() Nếu không thể khởi tạo Serial được sau timeout thì sẽ thông báo lỗi. Ở đây đặt timeout = 1s. - Gửi dữ liệu : int write(data); Hàm nãy có thể gửi nhiều byte dữ liệu cùng lúc. Hàm trả vè là số byte đã gửi. - Hàm flush() Cũng như với chương trình C, cần flush nếu không serial sẽ không gửi đúng. - Đóng Serial close(); Nếu có interrupt xảy ra, ví dụ như CTR+C thì chương trình sẽ bắt được sự kiện đó và sẽ đóng serial. Lí do vì Serial sẽ không tự đóng lại khi chương trình bị ngắt không kiểm soát. Như vậy nó sẽ tiếp tục được mở và không cho phép chương trình nào khác sử dụng nó –> chương trình chạy sẽ bị lỗi ở lần tiếp theo. Đây là python version 3 nên khi chạy bạn thực hiện lệnh python3 uart-send.py Kết quả tương tự như chương trình C Ví dụ 2 Chương trình “uart-receive.py” trên Raspberry #!/usr/bin/python3
import time
import serial
ser = serial.Serial(
port = '/dev/ttyAMA0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
print("Raspberry's receiving : ")
try:
while True:
s = ser.readline()
data = s.decode() # decode s
data = data.rstrip() # cut "\r\n" at last of string
print(data) # print string
except KeyboardInterrupt:
ser.close() - Đọc dữ liệu readline() Hàm trả về là những byte đọc được. Hàm đọc kết thúc với timeout=1 được thiết lập bên trên. - Lưu ý : Ở trên có sử dụng 2 hàm dưới đây trước khi hiển thị kết quả data=s.decode() data=data.rstrip() Mọi người nên kiểm tra kết quả khi không có 2 hàm trên để hiểu thêm về kết quả nhận được. Kết quả tương tự với chương trình C 3. Sử dụng cổng USB để kết nốiUart được Raspberry Pi với mục đích log cho kernel. Nếu không thiếu thốn hay bắt buộc phải sử dụng cổng uart các bạn có thể chuyển sang cổng usb để thay thế. Với hệ điều hành linux các kênh xuất nhập đều có thể kết nối thông qua file-descriptor, dù uart hay usb thì chỉ cân thay đổi file-descriptor thì có thể kết nối tới nó. Toàn bộ code bên trên có thể dùng kết nối qua cổng USB, chỉ cần thay “ttyAMA0” bằng tên cổng USB có dạng “ttyUSB*”. Các bạn có thể kết nối arduino với thiết bị USB-TTL như PL2303 và sau đó cắm thiết bị vào Pi qua cổng USB là có thể kết nối. Lưu ý đây là sử dụng cổng USB để kết nối chứ không phải kết nối hoàn tòan bằng giao thức USB vì phía bên arduino sử dụng phương thức uart. Khi PL2303 kết nối tới Raspberry, cần kiểm tra thiết bị đang nằm trên cổng USB nào dmesg | grep tty Kết quả sẽ trả về các Serial trên Pi. Trong đó sẽ có kết quả dạng như bên dưới: pl2303 converter now attached to ttyUSB0 PL2303 đang kết nối tới cổng ttyUSB0. Kết quả chương trình sẽ giống hệt như với kết nối trực tiếp với Uart.
Thông tin tham khảo : [1] https://electrosome.com/uart-raspberry-pi-python/ [2] http://elinux.org/RPi_Serial_Connection [3] http://www.briandorey.com/post/Raspberry-Pi-3-UART-Overlay-Workaround [4] http://pyserial.readthedocs.io/en/latest/pyserial_api.html |
Để cập nhật các tin tức công nghệ mới các bạn làm theo hướng dẫn sau đây :
Các bạn vào Trang chủ >> Tin tức. ở mục này có các bài viết kỹ thuật thuộc các lĩnh vực khác nhau các bạn có thể lựa chọn lĩnh vực mà mình quan tâm để đọc nhé !!!
Các bạn cũng có thế kéo xuống cuối trang để xem những tin tức công nghệ mới nhất.