Hướng dẫn xử lý chuỗi trong lập trình vi điều khiển (P3)

Khi lập trình vi điều khiển, nhiều trường hợp chúng ta cần làm việc với các dữ liệu ở dạng chuỗi ký tự, ví dụ như đóng gói các dữ liệu thành một chuỗi để lưu trữ hoặc gửi đi, nhận dữ liệu, bóc tách dữ liệu từ các bản tin nhận được để sử dụng. Xử lý chuỗi là một chủ đề quan trọng khi lập trình vi điều khiển, nhất là khi các hệ thống nhúng, IoTs ngày càng phát triển dẫn đến việc trao đổi dữ liệu giữa các thiết bị ngày càng nhiều. Xử lý chuỗi là một thử thách với rất nhiều bạn sinh viên / kỹ sư phần mềm nhúng – những người mới bắt đầu. Với tài liệu này, các kiến thức cơ bản liên quan đến khai báo, lưu trữ, xử lý chuỗi sẽ được tổng hợp lại và được mô tả, hướng dẫn thông qua những ví dụ, tình huống cụ thể, thường gặp. 

Phần 1 – Một số khái niệm và các hàm chức năng

Phần 2 – Các hàm chức năng thường gặp

Tiếp tục với phần 1 và phần 2 của chuỗi bài viết, tại phần 3 (phần cuối) mình sẽ hướng dẫn các bạn thực hiện Ví dụ thực hành xử lý chuỗi trên Vi điều khiển STM32.

Phần 3. Hướng dẫn ví dụ thực hành xử lý chuỗi trên Vi điều khiển

3.1. Ví dụ thực hành

Vi điều khiển (device) và máy tính giao tiếp với nhau qua giao tiếp UART thông qua giao diện terminal (ví dụ Hercules). Trên thiết bị sẽ có một mã ID của thiết bị và có 2 đèn led (LED1 và LED2). Trên máy tính, thông qua giao diện terminal có thể cấu hình và đọc được ID của thiết bị, thay đổi trạng thái của các đèn LED. Viết chương trình điều khiển đơn giản sử dụng các lệnh sau để giao tiếp giữa máy tính và thiết bị:

  • Cú pháp cài đặt mã ID cho thiết bị và phản hồi:
    • Máy tính: +SET_DEV_ID:<ID>\r\n ; ID dài 6 ký tự.
    • Thiết bị: +OK\r\n hoặc +ERROR\r\n
  • Lấy mã ID của thiết bị
    • Máy tính: +GET_DEV_ID\r\n
      • Thiết bị: +ID:123456\r\nOK\r\n hoặc +ERROR:undefined\r\n hoặc +ERROR
  • Cấu hình trạng thái của đèn LED
    • Máy tính: +SET_LED_ STATE:n,s\r\n
      • n là đèn led muốn cấu hình (n = 1, 2)
      • s là trạng thái muốn cấu hình, s = 0: tắt LED, s = 1: bật LED.
    • Thiết bị: +OKE\r\n hoặc +ERROR\r\n
  • Lấy trạng thái của đèn LED
    • Máy tính: +GET_LED_STATE:n\r\n
      • n là đèn LEDmuốn lấy trạng thái (n = 1, 2)
    • Thiết bị: +LED:n,s\r\nOK\r\n
      • n là đèn LEDmuốn lấy cấu hình (n = 1, 2)
      • s là trạng thái (ON, OFF).

3.2. Phân tích bài toán

Chúng ta cần phải xem qua các command và phản hồi của nó để lựa chọn cách xử lý. 

  • Để nhận dạng các lệnh thì phải xem trong dữ liệu nhận được có các command hay không bằng cách sử dụng lệnh strstr() hoặc sử dụng lệnh so sánh chuỗi strcmp().
  • Như các command ở trên, mình nhận thấy rằng các command đều có độ dài chuỗi sẽ không thay đổi, lúc này mình sẽ dựa vào đó để kiểm tra lệnh có đúng hay không, lúc này mình sẽ sử dụng hàm strlen().
  • Ở các câu lệnh cấu hình thì sẽ chứa mã ID, đèn LED và trạng thái của LED cần cấu hình, chúng ta cần phải tách được các tham số và giá trị này để có thể xử lý đúng. Mình thường sử dụng hàm strtok() để ngắt chuỗi nhận được thành các token rồi xử lý.
  • Một số phản hồi chứa nhiều định dạng khác nhau như số nguyên, mảng ký tự cần chuyển thành một chuỗi để truyền đi thì sử dụng hàm sprintf().
  • Ngoài ra, mình còn sử dụng các hàm như atoi() để chuyển từ ký tự thành số nguyên.

3.3. Cấu hình phần cứng

  • Khởi tạo giao tiếp UART với các tham số mặc định, bật ngắt.
  • Cấu hình 2 chân OUTPUT cho 2 đèn LED.

3.4. Mã chương trình tham khảo

3.5. Kết quả thực hiện

Hình 1. Cài đặt mã ID và lấy mã ID trên thiết bị

Hình 2. Cấu hình trạng thái LED và lấy trạng thái LED trên thiết bị

TỔNG KẾT

Qua chuỗi bài viết này, chúng ta đã tìm hiểu về khai báo chuỗi và xử lý chuỗi bằng những hàm thường sử dụng được hỗ trợ bởi các thư viện C, các ví dụ cụ thể của các hàm cũng đã được trình bày một cách chi tiết. Chuỗi bài viết cũng đưa ra một ví dụ trường hợp sử dụng trên vi điều khiển STM32. Có thể thấy, xử lý chuỗi là một chủ đề rất quan trọng khi lập trình vi điều khiển với các bài toán truyền, nhận, đóng gói, bóc tách, phân tích dữ liệu. Bên cạnh những vấn đề phổ biến được nêu ra trong bài viết, các bạn cũng có thể tìm hiểu thêm các vấn đề nâng cao như toàn vẹn dữ liệu với các phương pháp kiểm tra lỗi như CRC, checksum, hash, cũng như bảo mật dữ liệu với các kỹ thuật mã hóa và giải mã. 

Chúc các bạn thành công! 

H.V.Binh, N.T.Nhien & N.H.N.Thuong

Tìm hiểu thêm:
Fanpage Cộng đồng Kỹ thuật TAPIT: TAPIT – Learning, Research and Sharing Community