Giới thiệu
Bảng nút nhấn gọi số có màn hinh LCD LDNam với 5 nút nhấn hỗ trợ giao tiếp qua WiFi hoặc Ethernet bằng giao thức UDP. Thiết bị hiển thị dữ liệu trên màn hình LCD1602 (2 dòng, mỗi dòng tối đa 16 ký tự) và đọc trạng thái của 5 nút nhấn. Dữ liệu hiển thị được lưu trong hai dòng, và trạng thái nút nhấn được biểu diễn dưới dạng chuỗi (ví dụ: 0;0;0;0;0 khi không có nút nào được nhấn, hoặc 1;1;1;1;1 khi tất cả các nút được nhấn).
Lập trình viên có thể sử dụng máy tính để:
- Gửi nội dung hiển thị cho dòng 1 và dòng 2 của LCD1602.
- Đọc nội dung hiện tại của dòng 1 và dòng 2.
- Đọc trạng thái của 5 nút nhấn.
- Cấu hình mạng (IP tĩnh/DHCP, MAC) hoặc reset thiết bị.
Bài hướng dẫn này cung cấp chi tiết về các lệnh UDP mà bảng hỗ trợ và cách viết code Python để giao tiếp với bảng LED từ máy tính.
Yêu cầu
Phần cứng
- Bảng nút nhấn gọi số có màn hinh LCD LDNam với 5 nút nhấn.
- Máy tính: Có kết nối mạng (WiFi hoặc Ethernet) để giao tiếp với bảng LED.
- Mạng: Bảng nút nhấn gọi số có màn hinh LCD LDNam với 5 nút nhấn và máy tính phải nằm trong cùng một mạng LAN.
Phần mềm
- Python 3.x: Cài đặt Python trên máy tính.
- Thư viện Python:
- socket: Để gửi/nhận gói tin UDP (có sẵn trong Python).
- time: Để thêm độ trễ giữa các lệnh.
- Thông tin mạng của bảng LED:
- WiFi IP: Địa chỉ IP của bảng khi kết nối WiFi (mặc định DHCP hoặc tĩnh, ví dụ: 192.168.1.100).
- Ethernet IP: Địa chỉ IP của bảng khi kết nối Ethernet (mặc định DHCP hoặc tĩnh, ví dụ: 192.168.1.100).
- Cổng UDP:
- WiFi: Mặc định cổng 80 (DHCP) hoặc cổng tĩnh được lưu trong bộ nhớ (kiểm tra qua GET_WIFI_CONFIG).
- Ethernet: Mặc định cổng 80 (DHCP) hoặc cổng tĩnh được lưu trong bộ nhớ (kiểm tra qua GET_ETH_CONFIG).
Các lệnh UDP được hỗ trợ
Bảng LED nhận và phản hồi các gói tin UDP với các lệnh sau:
| Lệnh | Mô tả | Định dạng | Phản hồi |
|---|---|---|---|
| READ_SCORE | Lấy nội dung hiện tại của dòng 1 và dòng 2 trên LCD1602. | READ_SCORE | Chuỗi dạng <dong_1>:<dong_2> (ví dụ: 1:2) hoặc không phản hồi nếu lỗi. |
| READ_BT | Lấy trạng thái của 5 nút nhấn. | READ_BT | Chuỗi dạng <bt1>;<bt2>;<bt3>;<bt4>;<bt5> (ví dụ: 0;0;0;0;0 hoặc 1;1;1;1;1) hoặc không phản hồi nếu lỗi. |
| SET_S:<dong><nội dung> | Tương tự SET_SCORE, đặt nội dung cho dòng 1 hoặc dòng 2. | SET_S:1Hello hoặc SET_S:2World | “OK” nếu thành công, “ERROR” nếu nội dung rỗng. |
| GET_WIFI_CONFIG | Lấy cấu hình mạng WiFi (IP, subnet, gateway, MAC). | GET_WIFI_CONFIG | “STATIC|<IP>|<Subnet>|<Gateway>|<MAC>” hoặc “DHCP|<IP>|<Subnet>|<Gateway>|<MAC>” hoặc “ERROR|||” nếu WiFi không kết nối. |
| GET_ETH_CONFIG | Lấy cấu hình mạng Ethernet (IP, subnet, gateway, MAC). | GET_ETH_CONFIG | “STATIC|<IP>|<Subnet>|<Gateway>|<MAC>” hoặc “DHCP|<IP>|<Subnet>|<Gateway>|<MAC>” hoặc “ERROR|||” nếu Ethernet không kết nối. |
| SET_WIFI_IP:<mode> | Đặt cấu hình IP cho WiFi (tĩnh hoặc DHCP). | – Tĩnh: SET_WIFI_IP:STATIC|IP:<ip>|MASK:<mask>|GATEWAY:<gateway>|PORT:<port> – DHCP: SET_WIFI_IP:DHCP | “OK” nếu thành công, “ERROR” nếu định dạng không hợp lệ. |
| SET_ETH_IP:<mode> | Đặt cấu hình IP cho Ethernet (tĩnh hoặc DHCP). | – Tĩnh: SET_ETH_IP:STATIC|IP:<ip>|MASK:<mask>|GATEWAY:<gateway>|PORT:<port> – DHCP: SET_ETH_IP:DHCP | “OK” nếu thành công, “ERROR” nếu định dạng không hợp lệ. |
| SET_MAC:<mac> | Đặt địa chỉ MAC cho Ethernet. | SET_MAC:DE:AD:BE:EF:FE:ED | “OK” nếu MAC hợp lệ, “ERROR” nếu không hợp lệ. |
| RESET | Khởi động lại bảng LED. | RESET | “OK” trước khi reset. |
Lưu ý:
- <dong>: 1 (dòng 1) hoặc 2 (dòng 2).
- <nội dung>: Chuỗi ký tự bất kỳ (tối đa 16 ký tự để phù hợp với LCD1602).
- <bt1>;<bt2>;<bt3>;<bt4>;<bt5>: Trạng thái nút nhấn (0 = không nhấn, 1 = nhấn).
- <ip>, <mask>, <gateway>: Địa chỉ IPv4 hợp lệ (ví dụ: 192.168.1.100).
- <port>: Số cổng UDP (ví dụ: 80).
- <mac>: Địa chỉ MAC dạng XX:XX:XX:XX:XX:XX (hexadecimal, 6 byte).
- Các lệnh gửi qua UDP phải là chuỗi ký tự (text) và kết thúc bằng ký tự null (\0).
Viết code Python để giao tiếp
Dưới đây là các ví dụ Python sử dụng thư viện socket để gửi và nhận gói tin UDP từ bảng LED. Các ví dụ giả định bảng LED có địa chỉ IP là 192.168.1.100 và cổng UDP là 80.
1. Gửi nội dung hiển thị lên dòng 1 hoặc dòng 2 của LCD1602
Gửi lệnh SET_SCORE:1Hello để hiển thị “Hello” trên dòng 1 hoặc SET_SCORE:2World để hiển thị “World” trên dòng 2.
import socket
# Thông tin bảng LED
LED_IP = "192.168.1.100" # Thay bằng IP thực tế của bảng
LED_PORT = 80 # Thay bằng cổng thực tế
# Tạo socket UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Gửi nội dung cho dòng 1
command = "SET_S:1Hello"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
sock.settimeout(2.0) # Đợi tối đa 2 giây
try:
data, addr = sock.recvfrom(1024)
print(f"Phản hồi từ bảng LED (dòng 1): {data.decode()}")
except socket.timeout:
print("Không nhận được phản hồi cho dòng 1")
# Gửi nội dung cho dòng 2
command = "SET_SCORE:2World"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
try:
data, addr = sock.recvfrom(1024)
print(f"Phản hồi từ bảng LED (dòng 2): {data.decode()}")
except socket.timeout:
print("Không nhận được phản hồi cho dòng 2")
sock.close()
Giải thích:
- Gửi lệnh SET_SCORE:1<chuỗi> hoặc SET_SCORE:2<chuỗi> để đặt nội dung cho dòng 1 hoặc dòng 2.
- Phản hồi là “OK” nếu thành công hoặc “ERROR” nếu chuỗi rỗng.
- Đảm bảo chuỗi gửi có độ dài tối đa 16 ký tự để phù hợp với LCD1602.
2. Đọc nội dung hiển thị trên LCD1602
Gửi lệnh READ_SCORE để lấy nội dung hiện tại của dòng 1 và dòng 2.
import socket
# Thông tin bảng LED
LED_IP = "192.168.1.100"
LED_PORT = 80
# Tạo socket UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Gửi lệnh đọc nội dung
command = "READ_SCORE"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
sock.settimeout(2.0)
try:
data, addr = sock.recvfrom(1024)
dong_1, dong_2 = data.decode().split(":")
print(f"Dòng 1: {dong_1}")
print(f"Dòng 2: {dong_2}")
except socket.timeout:
print("Không nhận được phản hồi")
sock.close()
Giải thích:
- Gửi lệnh READ_SCORE và nhận phản hồi dạng <dong_1>:<dong_2> (ví dụ: Hello:World).
- Tách chuỗi phản hồi bằng dấu : để lấy nội dung của dòng 1 và dòng 2.
- Nếu không nhận được phản hồi trong 2 giây, in thông báo lỗi.
3. Đọc trạng thái nút nhấn
Gửi lệnh READ_BT để lấy trạng thái của 5 nút nhấn.
import socket
# Thông tin bảng LED
LED_IP = "192.168.1.100"
LED_PORT = 80
# Tạo socket UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Gửi lệnh đọc trạng thái nút nhấn
command = "READ_BT"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
sock.settimeout(2.0)
try:
data, addr = sock.recvfrom(1024)
buttons = data.decode().split(";")
print(f"Trạng thái nút nhấn: {buttons}")
for i, state in enumerate(buttons, 1):
print(f"Nút {i}: {'Nhấn' if state == '1' else 'Không nhấn'}")
except socket.timeout:
print("Không nhận được phản hồi")
sock.close()
Giải thích:
- Gửi lệnh READ_BT và nhận phản hồi dạng <bt1>;<bt2>;<bt3>;<bt4>;<bt5> (ví dụ: 0;0;0;0;0).
- Tách chuỗi phản hồi bằng dấu ; để lấy trạng thái từng nút.
- In trạng thái mỗi nút (0 = không nhấn, 1 = nhấn).
4. Cấu hình IP tĩnh cho Ethernet
Gửi lệnh SET_ETH_IP:STATIC|IP:192.168.1.102|MASK:255.255.255.0|GATEWAY:192.168.1.1|PORT:80 để đặt IP tĩnh cho Ethernet.
import socket
# Thông tin bảng LED
LED_IP = "192.168.1.100"
LED_PORT = 80
# Tạo socket UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Lệnh đặt IP tĩnh cho Ethernet
command = "SET_ETH_IP:STATIC|IP:192.168.1.102|MASK:255.255.255.0|GATEWAY:192.168.1.1|PORT:80"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
sock.settimeout(2.0)
try:
data, addr = sock.recvfrom(1024)
print(f"Phản hồi từ bảng LED: {data.decode()}")
except socket.timeout:
print("Không nhận được phản hồi")
sock.close()
Giải thích:
- Gửi lệnh cấu hình IP tĩnh với các thông số IP, subnet mask, gateway, và cổng.
- Phản hồi là “OK” nếu thành công hoặc “ERROR” nếu định dạng không hợp lệ.
- Sau khi đặt IP tĩnh, cập nhật LED_IP và LED_PORT trong code Python.
5. Reset bảng LED
Gửi lệnh RESET để khởi động lại bảng LED.
import socket
# Thông tin bảng LED
LED_IP = "192.168.1.100"
LED_PORT = 80
# Tạo socket UDP
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Gửi lệnh reset
command = "RESET"
sock.sendto(command.encode(), (LED_IP, LED_PORT))
# Nhận phản hồi
sock.settimeout(2.0)
try:
data, addr = sock.recvfrom(1024)
print(f"Phản hồi từ bảng LED: {data.decode()}")
except socket.timeout:
print("Không nhận được phản hồi")
sock.close()
Giải thích:
- Gửi lệnh RESET để khởi động lại bảng LED.
- Phản hồi là “OK” trước khi bảng reset.
6. Ví dụ tích hợp (Giao diện điều khiển LCD và nút nhấn)
Dưới đây là một chương trình Python tích hợp, cho phép người dùng gửi nội dung hiển thị, đọc nội dung LCD, đọc trạng thái nút nhấn, hoặc reset bảng LED.
import socket
import time
# Thông tin bảng LED
LED_IP = "192.168.1.100"
LED_PORT = 80
def send_udp_command(command):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(command.encode(), (LED_IP, LED_PORT))
sock.settimeout(2.0)
try:
data, addr = sock.recvfrom(1024)
response = data.decode()
print(f"Phản hồi: {response}")
return response
except socket.timeout:
print("Không nhận được phản hồi")
return None
finally:
sock.close()
# Menu điều khiển
while True:
print("\n=== Điều khiển bảng LED (LCD1602 và Nút Nhấn) ===")
print("1. Gửi nội dung cho dòng 1")
print("2. Gửi nội dung cho dòng 2")
print("3. Đọc nội dung LCD")
print("4. Đọc trạng thái nút nhấn")
print("5. Reset bảng LED")
print("6. Thoát")
choice = input("Chọn (1-6): ")
if choice == "1":
text = input("Nhập nội dung cho dòng 1 (tối đa 16 ký tự): ")
if len(text) <= 16:
send_udp_command(f"SET_SCORE:1{text}")
else:
print("Nội dung quá dài (tối đa 16 ký tự)")
elif choice == "2":
text = input("Nhập nội dung cho dòng 2 (tối đa 16 ký tự): ")
if len(text) <= 16:
send_udp_command(f"SET_SCORE:2{text}")
else:
print("Nội dung quá dài (tối đa 16 ký tự)")
elif choice == "3":
response = send_udp_command("READ_SCORE")
if response:
dong_1, dong_2 = response.split(":")
print(f"Dòng 1: {dong_1}")
print(f"Dòng 2: {dong_2}")
elif choice == "4":
response = send_udp_command("READ_BT")
if response:
buttons = response.split(";")
for i, state in enumerate(buttons, 1):
print(f"Nút {i}: {'Nhấn' if state == '1' else 'Không nhấn'}")
elif choice == "5":
send_udp_command("RESET")
elif choice == "6":
break
else:
print("Lựa chọn không hợp lệ")
time.sleep(0.1) # Tránh gửi lệnh quá nhanh
Giải thích:
- Cung cấp menu để người dùng chọn gửi nội dung cho dòng 1/dòng 2, đọc nội dung LCD, đọc trạng thái nút nhấn, hoặc reset.
- Kiểm tra độ dài chuỗi (tối đa 16 ký tự) để đảm bảo tương thích với LCD1602.
- Thêm độ trễ 100ms giữa các lệnh để tránh quá tải.
Lưu ý khi lập trình
- Tìm IP và cổng của bảng LED:
- Nếu bảng sử dụng DHCP, kiểm tra IP được cấp qua Serial Monitor hoặc gửi lệnh GET_WIFI_CONFIG/GET_ETH_CONFIG.
- Nếu sử dụng IP tĩnh, kiểm tra cấu hình qua các lệnh trên.
- Sử dụng công cụ quét mạng (như nmap) hoặc kiểm tra trên router để tìm IP nếu cần.
- Xử lý lỗi:
- Luôn đặt sock.settimeout() để tránh chương trình treo khi không nhận được phản hồi.
- Kiểm tra định dạng lệnh trước khi gửi (chuỗi cho SET_S không được rỗng, IP/MAC phải đúng định dạng).
- Hiệu suất:
- Gửi các lệnh cách nhau ít nhất 100ms để tránh quá tải bảng LED.
- Đảm bảo máy tính và bảng LED nằm trong cùng subnet để giao tiếp UDP hoạt động.
- Debugging:
- Kết nối bảng LED với máy tính qua cổng Serial (115200 baud) để xem log chi tiết (IP, trạng thái kết nối, lỗi).
- Serial Monitor sẽ hiển thị các thông báo như “WiFi connected”, “Ethernet connected”, hoặc “Received packet via WiFi/Ethernet”.
- Tùy chỉnh hiển thị:
- Hàm hiển thị (trong hien_thi.h) xử lý việc gửi nội dung tới LCD1602 qua SoftwareSerial (baud rate 74880). Đảm bảo phần cứng LCD được cấu hình đúng.
- Trạng thái nút nhấn được lưu trong biến chuoi_nut. Đảm bảo hàm truyen_nhan_atmega8 (trong code Arduino) cập nhật đúng chuoi_nut.
Xử lý sự cố
- Không kết nối được với bảng LED:
- Kiểm tra IP và cổng có đúng không (dùng GET_WIFI_CONFIG hoặc GET_ETH_CONFIG).
- Đảm bảo máy tính và bảng LED trong cùng mạng LAN.
- Kiểm tra trạng thái kết nối qua Serial Monitor.
- Không hiển thị nội dung trên LCD:
- Kiểm tra kết nối phần cứng LCD (chân TX/RX, IC điều khiển LCD).
- Xác minh hàm hiển thị trong hien_thi.h hoạt động đúng.
- Không đọc được trạng thái nút nhấn:
- Kiểm tra hàm truyen_nhan_atmega8 trong code Arduino để đảm bảo nó cập nhật đúng chuoi_nut.
- Xác minh kết nối phần cứng của 5 nút nhấn.
- Phản hồi “ERROR”:
- Kiểm tra định dạng lệnh (ví dụ: chuỗi trong SET_S không được rỗng, IP/MAC hợp lệ).
- Đảm bảo bảng LED đang chạy và kết nối mạng ổn định.
Kết luận
Bảng LED với LCD1602 và 5 nút nhấn là một hệ thống linh hoạt, hỗ trợ giao tiếp qua WiFi và Ethernet bằng UDP. Với các ví dụ Python trên, lập trình viên có thể dễ dàng gửi nội dung hiển thị, đọc nội dung LCD, đọc trạng thái nút nhấn, hoặc cấu hình mạng. Nếu cần thêm tính năng (ví dụ: giao diện đồ họa, gửi nội dung định kỳ), bạn có thể mở rộng code Python bằng các thư viện như tkinter hoặc thêm logic xử lý nâng cao.
Nếu bạn gặp vấn đề hoặc cần hỗ trợ thêm, hãy cung cấp log từ Serial Monitor hoặc mô tả chi tiết lỗi để được hỗ trợ!
