點燈就是單片機界的hello world。說起點燈,我就會想三國里董卓被肚臍眼放燈芯燃燒脂肪,俗稱點天燈。。。。。。。
正常的例子,這位朋友 Arduino Uno 全彩呼吸燈 三色LED燈漸變實例_凌順實驗室-CSDN博客
現在我們想用串口控制三色燈的顏色。正好試下Arduino IDE 2.0 自帶代碼補全。 如果不能自動補全或者出現代碼提示,先下載好core庫。 有時候需要保存下程序然后再重啟下ide
第一個問題,串口一次只能傳遞一組數據,而三色燈亮需要三色參數,就需要把串口傳遞的參數按rgb拆成三個。(相當於自制一個通信協議)。我這里用r,g,b; 這樣的形式傳遞一個字符串表示rgb值,例如:“255,255,0;” 表示紅255綠255藍0.
太長不看直接復制粘貼代碼版:
//良好習慣之代碼里不要出現讓人無法理解的魔法數字
int redPin = 11; int greenPin = 10; int bluePin = 9; unsigned int red = 10; unsigned int green = 10; unsigned int blue = 10; //顏色控制函數 void color(unsigned int red,unsigned int green,unsigned int blue){ analogWrite(redPin, 255- red); analogWrite(bluePin, 255- blue); analogWrite(greenPin, 255- green); } void setup() { // put your setup code here, to run once: pinMode(redPin,OUTPUT); pinMode(greenPin,OUTPUT); pinMode(bluePin,OUTPUT); pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); } void loop() { // put your main code here, to run repeatedly: if(Serial.available()>0) { delay(50);// 延時以確保完全接受串口數據,可以提高波特率,減小延時時間實現更高速響應 // Serial.println(Serial.readStringUntil(stopChar)); // Serial.println(Serial.readStringUntil(stopChar)); // Serial.println(Serial.readStringUntil(stopChar)); //Serial.readStringUntil可以立刻讀取緩沖區數據。 red = Serial.readStringUntil(',').toInt();//注意這里是單引號表示char類型,用作函數的讀取終止符號,不能用雙引號,那是字符串 green = Serial.readStringUntil(',').toInt();//
Serial.readStringUntil(',')讀取多少字符就會自動清理多少緩沖區里的數據
blue = Serial.readStringUntil(';').toInt();
while(Serial.read()>= 0){}//清空串口緩沖區,避免意外多余數據干擾運行
digitalWrite(LED_BUILTIN, HIGH); //這里用自帶的腳13燈看程序是否運行
color(red, green, blue);
delay(5);
實際效果,用串口調試助手發送 255,0,0;三色燈立刻變紅。
為什么這么寫的原因(踩坑例程):一開始作為用慣了appinvnentor保姆式文本函數的人,此刻想起了被C語言字符數組指針支配的恐懼 (艹皿艹)
第一步 ,用Serial.readSring()讀取一個字符串
if(Serial.available()>0) { delay(200);// 延時以確保完全接受串口數據 rgb = Serial.readString();
下一步是用符號分解字符串,作為懶人,在ide里搜索StringSplitt,還真有現成的(本來想用json,發現cJSON有點費內存)。
代碼示范
StringSplitter *splitter = new StringSplitter(rgb, ',', 3);//c++中用new創建的對象返回的都是指針 red = splitter->getItemAtIndex(0);//用指針調用方法需要用->,new創建的對象不是用“*”或“.”來訪問該對象的成員函數的 green = splitter->getItemAtIndex(1); blue = splitter->getItemAtIndex(2);
實際效果, 輸入“255,0,0,”,燈等了一秒才變紅,而且不一會程序就跑飛了(放飛自我)。
先說這個跑飛問題,單片機內存(RAM)很小,uno R3的atm328就2K(sram,靜態內存,比dram快且不用刷新充電)。我把new對象寫在loop()無限循環函數里,這一會就爆內存了(C++語言沒有自動內存垃圾清理),所以需要添加一句 delete splitter釋放內存
測試如果在水平滑動條事件里直接發送數據,會導致發送過於頻繁,單片機串口數據還沒接受完就又收到數據,導致燈的變色過程不正常。可以把串口波特率改高緩解這種情況。這里只用了個定時程序固定時間刷新顏色,避免數據發送太頻繁。實測可以不那么絲滑的變色。
完整代碼 https://pan.baidu.com/s/1mt6c53IpCUWl5apuc4USYw 提取碼1234
終極更新,用串口事件來處理點燈,實測可以扛得住非常快速的發送數據.然后手機端終於可以用滑動條改變事件了,實測完全看不出來變色間隔
int redPin = 11; int greenPin = 10; int bluePin = 9; unsigned int red = 10; unsigned int green = 10; unsigned int blue = 10; //顏色控制函數 void color(unsigned int red,unsigned int green,unsigned int blue){ analogWrite(redPin, 255- red); analogWrite(bluePin, 255- blue); analogWrite(greenPin, 255- green); } void setup() { // put your setup code here, to run once: pinMode(redPin,OUTPUT); pinMode(greenPin,OUTPUT); pinMode(bluePin,OUTPUT); pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); } void loop() {
}
void serialEvent()
{ if (Serial.available() > 0)
{ red = Serial.readStringUntil(',').toInt();
green = Serial.readStringUntil(',').toInt();
blue = Serial.readStringUntil(';').toInt();
color(red, green, blue);
}
}
