Arduino Uno 全彩呼吸燈 三色LED燈串口控制高刷新率漸變實例 20210512更新串口中斷寫法,實現終極絲滑變色


點燈就是單片機界的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釋放內存

至於為啥會等一秒才變色,這是Serial.readString()的特點,   解釋來了    Arduino 串口讀寫函數快慢/時間花費_shenfuwang的博客-CSDN博客_arduino串口速度
Serial.readString()會默認等一秒以確保完全讀取完串口緩沖區。 為了反應更快,應該使用Serial.readStringUntil(),這會在遇到終止符號后立刻返回數據。
既然遇到終止符號后就返回數據了,那直接就有了分割字符串的辦法了,那也不用麻煩的調用網友的庫了。於是有了最上邊的代碼。
 
 
只用黑不溜秋的串口調試助手該顏色多不sexy,這里用wx ai2  做一個手機控制程序,基於wx  ai2里的串口調試例子,這里先感謝下原作者。加入如下代碼塊

 

測試如果在水平滑動條事件里直接發送數據,會導致發送過於頻繁,單片機串口數據還沒接受完就又收到數據,導致燈的變色過程不正常。可以把串口波特率改高緩解這種情況。這里只用了個定時程序固定時間刷新顏色,避免數據發送太頻繁。實測可以不那么絲滑的變色。

 

 

 

完整代碼    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);
   }
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM