Energia - Bài 3: Giao tiếp và điều khiển ARM với Processing
Lập trình giao diện và giao tiếp với vi điều khiển nếu mới bắt đầu quả là rất khó khăn, nhưng với processing thì việc đấy trở nên đơn giản hơn bao giờ hết. Như các bài trước chúng ta đã điều khiển LED qua nút nhấn, ADC và Serial với Tiva rồi, giờ chuyển sang lập trình giao diện và điều khiển qua lại giữa TIVA và Processing thôi.
Bạn có thể tải Processing bản mới nhất tại Processing Download
Dimer LED với Processing
Trong ví dụ này mình sẽ thực hiện điều khiển dimmer LED (hay còn gọi là điều khiển độ sáng LED) thông qua một giao diện đơn giản từ processing và con trỏ chuột
Code Energia
/*
Dimmer LED
Chương trình giao tiếp với processing, tạo ra giao diện, đưa chuột lên
giao diện để tăng độ sáng tối cho LED
Mạch điện:
LED xanh lam nối với chân 40.
created 2006
by David A. Mellis
modified 30 Aug 2011
by Tom Igoe and Scott Fitzgerald
Modified 15 April 2013
By Sean Alvarado
Hardware Required:
* TIVA C LaunchPad
* LED xanh
This example code is in the public domain.
*/
const int ledPin = 40; // chân 40 nối với LED xanh
void setup()
{
// Cấu hình giao tiếp baud 9600
Serial.begin(9600);
// cấu hình LED output
pinMode(ledPin, OUTPUT);
}
void loop() {
byte brightness;
// Kiểm tra nếu có dữ liệu gửi từ máy tính:
if (Serial.available()) {
// Đọc giá trị hiện tại lưu vào biến brightness
brightness = Serial.read();
// Điều khiển độ sáng led bằng PWM
analogWrite(ledPin, brightness);
}
}
Code Processing
// Processing code
// Dimmer - gửi byte thông qua cổng serial
// by David A. Mellis
// Modified 16 April 2013
// by Sean Alvarado
// This example code is in the public domain.
import processing.serial.*;
Serial port;
void setup() {
size(256, 150);
println("Available serial ports:");
println(Serial.list());
// Khai báo cổng kết nối, thông số và tốc độ baud tương ứng với
// thông số trong chương trình của Energia
// Lệnh này sẽ tự tìm serial TIVA và kết nối
port = new Serial(this, Serial.list()[0], 9600);
// Nếu bạn biết được port của kit TIVA là COM mấy thì có thể
// cấu hình trực tiếp bằng lệnh sau
//port = new Serial(this, "COM1", 9600);
}
void draw() {
// Vẽ gradient màu đen sang trắng
for (int i = 0; i < 256; i++) {
stroke(i);
line(i, 0, i, 150);
}
// Lấy vị trí tọa độ X hiện tại của chuột máy tính
// sau đó gửi byte này qua cổng COM
port.write(mouseX);
}
Kết quả khi ta đưa chuột như hình thì độ sáng của đèn sẽ thay đổi
Biến trở và Processing hiển thị màu
Ở ví dụ này ta sẽ sử dụng 3 biến trở cấp nguồn 3v3, chân còn lại nối với chân A0 A1 A2 của kit TIVA, yêu cầu là khi xoay biến trở thì giao diện được tạo từ processing sẽ đổi màu sắc dựa theo các giá trị từ biến trở.
/*
This example reads three analog sensors (potentiometers are easiest)
and sends their values serially. The Processing code at the bottom
take those three values and use them to change the background color of the screen.
Mạch điện:
* 3 Biến trở nối với 3v3
* Các chân out của biến trở nối lần lượt với chân A0 A1 A2 của kit TIVA
created 2 Dec 2006
by David A. Mellis
modified 30 Aug 2011
by Tom Igoe and Scott Fitzgerald
modified 16 April 2013
by Sean Alvarado
Yêu cầu phần cứng:
* TIVA C LaunchPad
* (3) biến trở
* breadboard
* dây nối
This example code is in the public domain.
*/
const int redPin = A0; // Biến trở điều khiển màu đỏ
const int greenPin = A1; // Biến trở điều khiển màu xanh lá
const int bluePin = A2; // Biến trở điều khiển màu xanh lam
void setup()
{
// Cấu hình Serial baud 9600
Serial.begin(9600);
}
void loop()
{
//Gửi các giá trị lên processing
Serial.print(analogRead(redPin));
Serial.print(",");
Serial.print(analogRead(greenPin));
Serial.print(",");
Serial.println(analogRead(bluePin));
}
// Processing code for this example
// This example code is in the public domain.
import processing.serial.*;
float redValue = 0; // Giá trị LED đỏ
float greenValue = 0; // Giá trị LED xanh lá
float blueValue = 0; // Giá trị LED xanh lam
Serial myPort;
void setup() {
size(200, 200);
// Liệt kê danh sách các cổng COM kết nối
println(Serial.list());
// Mở COM của TIVA LaunchPad
myPort = new Serial(this, Serial.list()[0], 9600);
// Nếu không có Enter(chọn newline) từ người dùng thì không nhận dữ liệu
myPort.bufferUntil('\n');
}
void draw() {
// Tạo background với các màu sắc:
background(redValue, greenValue, blueValue);
}
void serialEvent(Serial myPort) {
// Nhận chuỗi mã:
String inString = myPort.readStringUntil('\n');
if (inString != null) {
// Cắt bỏ các khoảng trắng:
inString = trim(inString);
// Cắt chuỗi bởi các dấu phẩy và chuyển sang mảng integer
float[] colors = float(split(inString, ","));
// Nếu mảng có ít nhất 3 phần tử thì đã nhận được hết dữ liệu sau đó
// đưa các số nhận được vào các biến màu sắc:
if (colors.length >=3) {
// map các giá trị với ngưỡng 0-255:
redValue = map(colors[0], 0, 4096, 0, 255);
greenValue = map(colors[1], 0, 4096, 0, 255);
blueValue = map(colors[2], 0, 4096, 0, 255);
}
}
}
Kết quả ta sẽ thấy màu sắc thay đổi khi xoay các biến trở
Nút nhấn, biến trở và Processing
Tận dụng số biến trở ở bài ví dụ trước, chúng ta sẽ tạo ra một số chuyển động đơn giản với hình tròn, như xoay biến trở thì hình tròn dịch chuyển sang trái, sang phải, đi lên, đi xuống, ngoài ra còn có thể thay đổi màu sắc của hình tròn bằng 1 biến trở khác.
Về nguyên tắc hoạt động mình xin tóm tắt như sau:
- TIVA sẽ gửi 1 request tới Processing là kí tự A
- Processing nhận được yêu cầu sẽ gửi ngược lại TIVA kí tự A, đây gọi là quá trình bắt tay
- TIVA nhận được kí tự A từ Processing gửi thì kết thúc quá trình bắt tay, sau đó gửi dữ liệu lên có dạng [x,y,color] tương ứng với 3 giá trị đọc được từ biến trở. Dữ liệu này sẽ được lưu trong mảng 3 phần tử.
- Processing nhận dữ liệu và show hình ảnh và chuyển động cho chúng ta quan sát.
/*
Gửi và nhận dữ liệu qua Serial
Chương trình sẽ gửi kí tự A liên tục cho đến khi nhận được phản hồi
sau đó sẽ thực nhiện nhận dữ liệu, kiểm tra nếu có đủ 3 dữ liệu từ
biến trở thì dừng lại.
Thanks to Greg Shakar and Scott Fitzgerald for the improvements
Mạch điện:
* 3 biến trở nối với chân A0 A1 A2
* Biến trở nối nguồn 3v3
Created 26 Sept. 2005
by Tom Igoe
modified 24 April 2012
by Tom Igoe and Scott Fitzgerald
Modified 19 April 2013
By Sean Alvarado
Hardware Required:
* TIVA C LaunchPad
* (3) biến trở
* breadboard
* dây nối
This example code is in the public domain.
*/
int firstSensor = 0; // giá trị biến trở 1
int secondSensor = 0; // giá trị biến trở 2
int thirdSensor = 0; // giá trị biến trở 3
int inByte = 0; // biến lưu byte dữ liệu
void setup()
{
// Cấu hình serial baud 9600
Serial.begin(9600);
establishContact(); // Gửi dữ liệu bắt tay và chờ phản hồi.
}
void loop()
{
// Nếu có dữ liệu yêu cầu thì bắt đầu đọc dữ liệu từ các biến trở:
if (Serial.available() > 0) {
// Nhận dữ liệu:
inByte = Serial.read();
// Đọc giá trị ADC(4096) và chia cho 16 để ra ngưỡng từ 0-255:
firstSensor = analogRead(A0)/16;
// delay 10ms để thực hiện chuyển đổi
delay(10);
// Đọc giá trị ADC(4096) và chia cho 16 để ra ngưỡng từ 0-255:
secondSensor = analogRead(A1)/16;
delay(10);
// Đọc giá trị ADC(4096) và chia cho 16 để ra ngưỡng từ 0-255:
thirdSensor = analogRead(A2)/16;
delay(10);
// Gửi các giá trị cảm biến:
Serial.write(firstSensor);
Serial.write(secondSensor);
Serial.write(thirdSensor);
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.println('A'); // gửi kí tự A
delay(300);
}
}
// Chương trình Processing điều khiển chấm tròn dùng 3 biến trở
// This example code is in the public domain.
import processing.serial.*;
int bgcolor; // Màu nền Background
int fgcolor; // Màu cho hình tròn
Serial myPort; // Cổng serial
int[] serialInArray = new int[3]; // Mảng lưu các giá trị nhận được
int serialCount = 0; // Biến đếm bao nhiêu byte nhận
int xpos, ypos; // Tọa độ Vị trí của hình tròn
boolean firstContact = false; // Thiết lập ban đầu chưa có bắt tay với TIVA
void setup() {
size(256, 256); // Khai báo kích thước
noStroke(); // Không tạo biên trên hình vẽ kế tiếp
// Đặt vị trí ban đầu của hình tròn là ở giữa
xpos = width/2;
ypos = height/2;
// In ra cổng COM kết nối để debug:
println(Serial.list());
// Tự kết nối COM TIVA
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);
}
void draw() {
background(bgcolor);
fill(fgcolor);
// Vẽ hình tròn
ellipse(xpos, ypos, 20, 20);
}
void serialEvent(Serial myPort) {
// Nhận byte gửi từ TIVA:
int inByte = myPort.read();
// Nếu byte đầu tiên nhận được là A thì xóa hết buffer
// ngược lại thì nhận dữ liệu từ các biến trở.
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // Xóa buffer
firstContact = true; // Set cờ kết nối, đã thực hiện bắt tay với TIVA
myPort.write('A'); // Yêu cầu dữ liệu
}
}
else {
// Lưu các dữ liệu nhận được vào mảng:
serialInArray[serialCount] = inByte;
serialCount++;
// Kiểm tra nếu có 3 bytes:
if (serialCount > 2 ) {
xpos = serialInArray[0];
ypos = serialInArray[1];
fgcolor = serialInArray[2];
// In các giá trị này ra để debug:
println(xpos + "\t" + ypos + "\t" + fgcolor);
// Gửi A để yêu cầu dữ liệu mới:
myPort.write('A');
// Reset lại biến serialCount:
serialCount = 0;
}
}
}
Kết quả sau khi vặn từng biến trở ta sẽ thấy hình tròn di chuyển theo trục x, trục y, và màu sắc thay đổi dần từ đen về trắng
Lưu ý: Độ phân giải ADC của TIVA là 12 bit tương ứng với giá trị là 4096
Các chương trình Energia và TIVA bạn chỉ cần copy và run chạy thử nghiệm luôn cho nóng, nhưng cố gắng hiểu và nắm được code để ứng dụng các bạn nhé.
Tạm kết
Chào mừng năm mới bằng bài hướng dẫn giao tiếp giữa TIVA và máy tính thông qua Energia và Processing, chưa bao giờ lập trình giao diện và giao tiếp máy tính lại đơn giản đến thế, hi vọng các bạn sẽ có nguồn tham khảo để ứng dụng vào trong các dự án cá nhân.
Mình sẽ cập nhật một số hướng dẫn các hàm vẽ vời thông dụng trong Processing cho các bạn sớm.