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);
   }
}

 

 

posted @ 2021-05-09 02:46  kyo413  阅读(1882)  评论(0编辑  收藏  举报