Đa số các project thực hiện trên STM32 khi trao đổi dữ liệu với máy tính hoặc các thiết bị khác thường sử dụng chức năng UART (Universal asynchronous receiver transmitter), tuy nhiên để thực hiện chức năng này bạn sẽ tốn 2 chân TX và RX trên chip STM32. Đồng thời UART không phải là chuẩn truyền thông nên muốn giao tiếp UART cần phải kết hợp với các IC giao tiếp như CH340 để tạo thành các chuẩn giao tiếp RS232,… Vì vậy để giảm thiểu chi phí phần cứng cũng như đơn giản hóa việc truyền/nhận dữ liệu giữa STM32 với máy tính, bài viết này sẽ hướng dẫn cách sử dụng tính năng USB CDC (Communication Device Class) trên chip STM32F103C8T6.
[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]
CubeMX generated files
Để tạo thiết bị USB CDC cơ bản với CubeMX, các bạn thực hiện theo các bước sau:
Bước 1:
– Ở mục RCC -> chọn Crystal Ceramic Resonator (thạch anh ngoại)
– SYS -> chọn Serial Wire (nạp code và debug)
– USB -> kích chọn Device (FS)
– Kéo lên mục MiddleWares, ở mục USB_DEVICE chọn Communication Device Class (Virtual Port)
Bước 2: Chuyển qua tab Clock Configuration và cấu hình clock cho STM32 như hình dưới
– Bước 3: Chọn Project -> Setting, sau đó đặt tên cho project của bạn, chọn Toolchain là MDK-Arm 5
– Bước 4: Project -> Generate code
Chương trình code trên Keil C
Sau khi tạo code từ CubeMX, các bạn build chương trình rồi load vào kit. Ra lại màn hình Desktop, kích chuột phải vào This PC chọn Manage -> Device Manager -> Ports (COM & LPT)
Nếu tại Ports (COM & LPT) xuất hiện cổng Com ảo của chip STM32 thì hệ điều hành máy tính của bạn đã tìm thấy driver phù hợp cho thiết bị USB. Còn nếu không xuất hiện cổng Com ảo bạn có thể làm như sau: vào trang https://www.st.com/en/development-tools/stsw-stm32102.html rồi chọn Get Software -> Download. Giải nén file vừa down về và thực hiện cài đặt theo hướng dẫn trong file readme.txt
Trở lại chương trình code trên phần mềm KeilC, để thực hiện việc truyền/nhận dữ liệu các bạn vào file usbd_cdc_if.c trong thư mục Application/User.
1 2 3 4 5 |
/* USER CODE BEGIN PRIVATE_DEFINES */ /* Define size for the receive and transmit buffer over CDC */ /* It's up to user to redefine and/or remove those define */ #define APP_RX_DATA_SIZE 2048 #define APP_TX_DATA_SIZE 2048 |
– APP_RX_DATA_SIZE và APP_TX_DATA_SIZE là kích thước của bộ đệm nhận và truyền dữ liệu. Kích thước là tùy từng user định nghĩa, bạn có thể điều chỉnh lại hoặc giữ nguyên như thiết lập ban đầu.
0 1 2 3 4 |
/* Received Data over USB are stored in this buffer */ uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; /* Send Data over USB CDC are stored in this buffer */ uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; |
– Dữ liệu sau khi truyền hoặc nhận được sẽ được lưu trữ ở 2 bộ đệm: UserRxBufferFS và UserTxBufferFS.
– Trong file usbd_cdc_if.c mục /* USER CODE BEGIN PRIVATE_VARIABLES */:
0 1 2 3 4 5 |
/* USER CODE BEGIN PRIVATE_VARIABLES */ uint32_t time; char ReceivedData[100] = {0}; uint8_t Rxcount = 0; uint32_t dataSize = 0; uint8_t check = 0; |
Trong bài viết này các bạn sẽ được hướng dẫn cách truyền dữ liệu từ STM32 lên máy tính sau đó dữ liệu được truyền lại từ máy tính về STM32, quan sát quá trình truyền nhận dữ liệu thông qua phần mềm Hercules.
Nhận dữ liệu
0 |
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) |
– Hàm CDC_Receive_FS() dùng để nhận dữ liệu về, được gọi (callback) tự động mỗi khi có dữ liệu từ USB Stack.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 6 */ dataSize = *Len; if(HAL_GetTick() - time > 1000) { Rxcount = 0; for(int i = 0; i < dataSize; i++) { ReceivedData[Rxcount++] = Buf[i]; } } USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); check = 1; //nhan biet co du lieu den time = HAL_GetTick(); return (USBD_OK); /* USER CODE END 6 */ }<br> |
– Mỗi lần hàm CDC_Receive_FS() được gọi, dữ liệu sẽ được đưa vào mảng ReceivedData. Sau một giây biến đếm Rxcount được reset về 0 và dữ liệu trong bộ đệm sẽ bị xóa đi.
Truyền dữ liệu
0 |
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) |
Quay trở lại file main.c, các bạn include thư viện usbd_cdc_if.h để sử dụng hàm CDC_Transmit_FS()
0 1 |
/* USER CODE BEGIN Includes */ #include "usbd_cdc_if.h" |
Ở mục /* USER CODE BEGIN PV */, bạn thêm vào các biến sau:
0 1 2 3 4 5 6 |
/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ extern char ReceivedData[100]; extern uint8_t Rxcount; extern uint32_t dataSize; extern uint8_t check; extern uint32_t time; |
Ở while(1), gọi lại hàm CDC_Transmit_FS() để truyền dữ liệu đi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(check == 1) //neu co du lieu den thi truyen di du lieu vua nhan duoc { CDC_Transmit_FS((uint8_t *)ReceivedData, strlen(ReceivedData)); for(int i = 0; i < dataSize; i++) { ReceivedData[i] = 0; } check = 0; } } /* USER CODE END 3 */ |
– Rút dây USB ra và nạp chương trình, sau đó cắm dây USB vào lại và xem kết quả.
Link video demo:
Xem thêm: Tổng hợp các bài hướng dẫn Lập trình vi điều khiển STM32 tại đây.
Nhóm TAPIT ARM R&D