Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Từ 2019 MLAB có thêm một website cho riêng Raspberry Pi và trở thành website chính về Raspberry Pi tại MLAB, các thông tin về sản phẩm - tin tức cập nhật về Raspberry Pi - Bài viết kỹ thuật hỗ trợ cho Raspberry Pi, ... MLAB cập nhật tại website : pivietnam.com.vn

MLAB trân trọng thông báo tới quý khách hàng!!!

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Các bạn có thể tham khảo các bài viết hỗ trợ kỹ thuật và các tin tức mới nhất tại phần "tin tức"trên website PVIETNAM.COM.VN

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Bài viết hỗ trợ kỹ thuật tại website PIVIETNAM.COM.VN - Bài 3: Lập trình Raspberry giao tiếp SPI (Link here)


1. Giới thiệu SPI


SPI (Serial Peripheral Bus) là một chuẩn truyền thông nối tiếp tốc độ cao do hang Motorola đề xuất. Đây là kiểu truyền thông Master-Slave, trong đó có 1 chip Master điều phối quá trình tuyền thông và các chip Slaves được điều khiển bởi Master vì thế truyền thông chỉ xảy ra giữa Master và Slave. SPI là một cách truyền song công (full duplex) nghĩa là tại cùng một thời điểm quá trình truyền và nhận có thể xảy ra đồng thời.

1.1. Mô hình kết nối

Mô hình gồm có các chân kết nối :

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

- MOSI hay SI – cổng ra của bên Master ( Master Out Slave IN). Đây là chân dành cho việc truyền tín hiệu từ thiết bị chủ động đến thiết bị bị động.

- MISO hay SO – Công ra bên Slave (Master IN Slave Out). Đây là chân dành cho việc truyền dữ liệu từ Slave đến Master.

- SCLK hay SCK là tín hiệu clock đồng bộ (Serial Clock). Xung nhịp chỉ được tạo bởi Master.

- CS hay SS là tín hiệu chọn vi mạch ( Chip Select hoặc Slave Select). SS sẽ ở mức cao khi không làm việc. Nếu Master kéo SS xuông thấp thì sẽ xảy ra quá trình giao tiếp. Chỉ có một đường SS trên mỗi slave nhưng có thể có nhiều đường điều khiển SS trên master, tùy thuộc vào thiết kế của người dùng.

Mỗi master và slave có một thanh ghi 8 bit. Cứ mỗi xung nhịp do Master tạo ra trên đường giữ nhịp SCK, một bit trong thanh ghi dữ liệu của Master được truyền qua Slave trên đường MOSI, đồng thời một bit trong thanh ghi dữ liệu của chip Slave cũng được truyền qua Master trên đường MISO. Do 2 gói dữ liệu trên 2 chip được gởi qua lại đồng thời nên quá trình truyền dữ liệu này được gọi là “song công”.

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Việc đọc và nhận cũng chỉ trên duy nhất một thanh ghi. Khi master muốn đọc 1 byte dữ liệu thì master phải gửi 1 byte đi trước. muốn đọc n bytes thì phải gửi đúng n bytes.

1.2. So sánh với I2C

Chuẩn giao tiếp I2C chỉ cần 2 dây là có thể giao tiếp trong khi chuẩn SPI cần tới ít nhất 3-4 dây để có thể hoạt động. Lắp đặt phần cứng I2C sẽ trở nên dễ dàng thuận tiện hơn. I2C có thẻ kết nối với số lượng lớn (7bit/ 10bit địa chỉ) mà không cần thêm kết nối, SPI muốn thêm slave cần thêm chân nối SS, càng lớn sẽ càng trở nên phức tạp

Về tốc độ thì SPI tỏ ra vượt trội so với I2C. SPI là full-duplex, không giới hạn tốc độ tối đa thường hơn 10Mbps. Trong khi đó I2C giới hạn tốc độ thông thường 1Mbps nếu ở fasst mode và 3.4Mbps ở High speed mode

2. Giao tiếp SPI cho Raspberry Pi


Raspberry có hỗ trợ 2 cổng SPI là SPI-0 và SPI-1. Tại SPI-0 có 2 chân CS0 và CS1 có thể giao tiếp với 2 slave còn tại SPI-1 chỉ có duy nhất 1 chân CS0 nên chỉ giao tiếp được 1 slave.

Trong phần này sẽ hướng dẫn giao tiếp Pi với Arduino. Các bạn cần chú ý rằng cả 2 vi điều khiển này đều hướng tập trung là master, nên thiết lập slave trở nên phức tạp hơn. Ở đây sẽ thiết lập Master là Pi và Slave là Arduino

2.1. Kết nối phần cứng

Các bạn kết nối phần cứng giữa Pi và Arduino

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Raspberry Arduino MOSI MOSI MISO MISO CSO SS SCK SCK GND GND

2.1. Lập trình giao tiếp

Cũng giống như I2C và một số giao tiếp khác, Raspbian mặc định không mở kích hoạt cho SPI. Chúng ta sẽ mở cổng SPI trước.

- Mở terminal lên gõ lệnh Raspi-config

sudo raspi-config

Lựa chọn Advanced options → SPI → Yes → Finish. Sau đó reboot

- Kiểm tra lại thiết lập

ls /dev/spi

Kết quả sẽ hiện ra :

/dev/spidev0.0 /dev/spidev0.1 - Cài đặt thư viện cho SPI (thư viện spi cho python)

sudo apt-get install python-dev sudo apt-get install python3-dev sudo apt-get update sudo apt-get install git git clone https://github.com/doceme/py-spidev.git cd py-spidev sudo python setup.py install sudo python3 setup.py install

Dưới đây sẽ là 2 bài tập giao tiếp SPI

Bài tập 1 : Gửi dữ liệu từ Rasp qua Arduino

Bài tập 2 : Rasp nhận dữ liệu từ qua Arduino

a) Lập trình với C

Bài tập 1

Chương trình Master "spi-send.c" cho Raspberry Pi

Lựa chọn Port SPI – 0 và chip select SS0 nằm trên GPIO8

include <stdio.h>

include <string.h>

include <stdlib.h>

include <unistd.h>

include <errno.h>

include <wiringPi.h>

include <wiringPiSPI.h>

define chanel 0

define speed 500000

define SS0 8 // GPIO 8

int main(){ unsigned char buff[4] = "abc\n"; pinMode(SS0, OUTPUT); digitalWrite(SS0, 1); int fd; if( (wiringPiSPISetup(chanel, speed)) <0){

fprintf (stderr, "SPI Setup failed: %s\n", strerror (errno));  
return 0;  
} fd = wiringPiSPIGetFd (0) ; while(1){
printf("%s",buff);  
fflush(stdout);  
digitalWrite(SS0, 0);  
write (fd, buff, 4) ;  
digitalWrite(SS0, 1);  
delay(1000);  
} return 0; } - Thiết lập SPI-0 :

wiringPiSPISetup(chanel, speed): chanel là 0 chọn port 0, chanel 1 chọn port 1. Speed là tốc độ của SPI (500,000 - 32,000,000). Nó trả về file-descriptor với giá trị -1 nghĩa là bị lỗi.

Vi xung nhịp chỉ được tạo bởi master nên tốc độ cũng do master quyết định. Chú ý rằng tốc độ này không được vượt quá tốc độ của arduino (Các bạn xem bên dưới )

- Gắn file-descriptor:

fd = wiringPiSPIGetFd (chanel) : file-descriptor được dùng để đại diện cho input/output của linux.Ta sẽ dùng file này để dùng các hàm gửi/nhận thông qua nó.

- Gửi và nhận :

write(int fd, const void *buf, size_t count);

read(int fd, void *buf, size_t count);

fd : là file-descriptor, buf là mảng kí tự, count là số byte gửi/ nhận.

- Trong quá trình gửi và nhận phải đưa chân SS xuống thấp, sau đó được đưa lên mức cao để kết thúc.

Các hàm được hỗ trợ : wirinpi - spi

Chương trình Slave cho Arduino

include <SPI.h>

void setup (void){

Serial.begin (9600);  
// chon che do slave  
SPCR |= bit (SPE);  
// chuyen MISO sang master in, *slave out*  
pinMode(MISO, OUTPUT);  
// bat che do interrupts  
SPI.attachInterrupt();  
Serial.println("Receive via SPI: ");  
} // SPI interrupt routine ISR (SPI_STC_vect){
byte c = SPDR;  
Serial.write(c);  
} void loop (void){
delay(10);  
}

- Chọn chế độ slave cho arduino

SPCR |= bit (SPE);

pinMode(MISO, OUTPUT);

- Gắn hàm interrupt cho SPI. Khi Master bắt đầu gửi dữ liệu, Arduino phát hiện interrupt và gọi hàm xử lý.

- Mỗi byte từ Master gửi tới sẽ được gửi lên màn hình qua serial.

Arduino uno sử dụng thạch anh 16Mhz thì SPI có thể đạt tới 16,000,000Hz

Kết quả

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

Bài tập 2

Thay thế chương trình Master "spi-send.c" của Raspberry như sau : "spi-send-receive.c"

while(1){

printf("Send:%s",buff);  
fflush(stdout);  
digitalWrite(SS0, 0);  
write (fd, buff, 1);  
delayMicroseconds(20);  
read (fd, c, 1);  
digitalWrite(SS0, 1);  
printf(",Receive:%s\n",c);  
fflush(stdout);  
delay(1000);  
}

- Master sẽ gửi 1 byte tới Arduino sau đó sẽ đọc 1 byte trả về. (byte trả về này nằm trên thanh ghi)

Thay thế chương trình interrupt của Slave như sau :

ISR (SPI_STC_vect){

byte c = SPDR;  
if(c != NULL){  
    byte C = c - 32;  
    SPDR = C;  
    Serial.print("\nReceive:");  
    Serial.write(c);  
    Serial.print(",Respond:");  
    Serial.write(C);  
}  
}

- Khi nhận 1 byte từ Master là một ký tự. Slave sẽ chuyển ký tự đó sang chữ viết hoa bằng cách trừ đi 32 trong bảng ASCII.

- Sau đó ghi ký tự đó vào thanh ghi.

Kết quả

Lỗi phân đoạn khi kết nối serialport raspbian năm 2024

  1. Lập trình Python

Bài tập 1

Chương trình Master "spi-send.py" cho Raspberry Pi

#!/usr/bin/python3 import spidev import time import binascii spi = spidev.SpiDev() # Tạo đối tượng cho SPI spi.open(0, 0) # mở port 0, device (CS) 0 spi.max_speed_hz = 500000 try:

while True:  
    print("abc")  
    resp = spi.xfer2([0x61,0x62,0x63,0xA]) _# ['a','b','c','\n']_  
    time.sleep(1)                         # sleep for 1 seconds  
except KeyboardInterrupt: spi.close()

-Thiết lập SPI-0 :

spi = spidev.SpiDev()

spi.open(0, 0)

spi.max_speed_hz = 5000

- Gửi / nhận dữ liệu :

xfer2( [val1,val2,val3]) : gửi dữ liệu dưới dạng list.

readbytes(n) : đọc n bytes dữ liệu, kết quả trả về dạng list

Thư viện SPI sẽ tự động lựa chọn chân SS qua hàm open(). Và tự động xuống mức thấp để gửi byte và đưa lên cao để kết thúc.

- [0x61,0x62,0x63,0xA] : dữ liệu dưới dạng hex của [‘a’,’b’,’c’,’\n’]

Các hàm được hỗ trợ : python-spi

Kết quả tương tự như chương trình C.

Chú ý : nếu mọi người copy trực tiếp code python từ trang web rất có thể có khả năng lỗi sai "khoảng cách" - những câu lệnh trong cùng một khối bắt buộc phải có khoảng cách căn dòng dấu nhau (gồm dấu cách, dấu tab).