语音情景灯/zh
概述
本次教程我们使用Microduino产品模块快速搭建一个可以识别人类语音的灯光控制系统,玩家可以迅速上手,并且可以通过说话,控制灯光模块的亮灭,选色等功能。 材料清单
实验原理语音情景灯模块的原理是记录语音和情景的一一映射关系,通过拼音识别输入的语音,返回给核心对应的情景编号,核心根据得到的情景编号,通过模拟口控制灯光模块每盏led灯的亮灭,实现不同情境下的不同颜色组合。 整个灯光控制系统包括四个部分:
使用[Microduino-BM]电源管理模块和外接电池组合为语音灯供电
中央处理器是语音情景灯系统的核心。采用Microduino-Core+作为核心。
语音情景灯系统采用Bluetooth无线通讯方案,使用[Microduino-BT(4.0)]模块,通讯速度响应快,在空阔地域的控制范围大概8米左右。
采集并识别语音内容。
套件使用Microduino-Lamp模块作为发光设备,该模块级联了6盏RGB3色彩灯,并可以使用相应的库函数控制每盏彩灯的颜色,为了清晰说明彩灯的控制方法,用一个简单的程序举例。 打开Arduino IDE,在文件(File)—>示例(Examples)—>_99_LCD_NeoPixel目录下,点开例程strandtest。 #include <Adafruit_NeoPixel.h>
#define PIN 6 //定义控制引脚
// 参数 1 = strip中彩灯的数目
// 参数 2 = 引脚号
// 参数 3 = 彩灯类型, 可多选(前两个中选一个,后两个中选一个):
// NEO_RGB Pixels are wired for RGB bitstream
// NEO_GRB Pixels are wired for GRB bitstream
// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels)
// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
void setup()
{
strip.begin();
strip.show(); //初始化所有彩灯都为灭
}
void loop()
{
// 点亮彩灯的方法
colorWipe(strip.Color(255, 0, 0), 50); // 点亮红色
colorWipe(strip.Color(0, 255, 0), 50); // 点亮绿色
colorWipe(strip.Color(0, 0, 255), 50); // 点亮蓝色
rainbow(20);
rainbowCycle(20);
}
//用“c”所代表的颜色依次点亮各盏彩灯,每点亮一盏等“wait”秒
void colorWipe(uint32_t c, uint8_t wait)
{
for(uint16_t i = 0; i < strip.numPixels(); i++) //依次点亮
{
strip.setPixelColor(i, c); //这个函数用于把第i盏灯用“c”所指颜色点亮
strip.show(); //这个函数会将setPixelColor函数所写入的控制信息显示
//出来,也就是靠它点亮LAMP模块
delay(wait);
}
}
void rainbow(uint8_t wait) //彩虹显示
{
uint16_t i, j;
for(j = 0; j < 256; j++) //渐变255种颜色
{
for(i = 0; i < strip.numPixels(); i++) //依次点亮彩灯,间隔wait毫秒
{
strip.setPixelColor(i, Wheel((i + j) & 255));
}
strip.show();
delay(wait);
}
}
// 与上面的函数稍有区别,添加了彩虹的循环
void rainbowCycle(uint8_t wait)
{
uint16_t i, j;
for(j = 0; j < 256 * 5; j++) //彩虹循环5次
{
for(i = 0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); //为了循环而添加的数学变换
}
strip.show();
delay(wait);
}
}
// 输入0-255任意一个数得到对应的唯一的一种颜色
// 颜色会从红-绿->蓝->红依次渐变循环
uint32_t Wheel(byte WheelPos)
{
if(WheelPos < 85)
{
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if(WheelPos < 170)
{
//因为WheelPos * 3在85到170的情况下会超过255,因此要先自减85
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else
{
//因为WheelPos * 3在170以上的情况下会超过255,因此要先自减170
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
文档调试过程
将Microduino Core+/zh、Microduino USBTTL/zh堆叠在一起.用数据线将写好的程序通过Microduino USBTTL/zh上传到Microduino Core+/zh上。 注意:最好不要将所有模块堆叠在一起之后再上传程序 找到该程序的物理位置,"语音情景灯/ EGGROOM/ EGGROOM.ino",双击即可 程序下载 点击"√",编译程序。 点击【工具】,选择正确的板+处理器+端口。 点击"→",进行上传。
搭建硬件电路,将用到的设备叠加起来(无上下顺序) Microduino-Core+ Microduino-USBTTL Microduino-BT(4.0) Microduino-BM Microduino-Duo-H Microduino-sensorhub Microduino-Lamp 锂电池 安装发光二极管 将发光二极管的负极插在Microduino-Sensorhub/zh传感器扩展模块的A7管脚,正极插在SDA管脚 将传感器数据线插入第三行第一列插槽,观察这里插线的部分,4根线从左到右分别是GND,VCC,D2,D3接脚(不要看颜色,实物颜色可能与本例不同) 安装语音话筒 语音话筒无正负极,将两端分别插在语音传感器的MIP和MIN上即可
安装app 将课件中“app-debug.apk”移动到手机上 安装该手机APP 在提供的开发包中,包含安卓手机语音情景灯的app,安装app并打开 屏幕右上方有两个按键,UPLOAD和NEW。首先介绍NEW,这个按键是用来新建或修改语音命令的 ff这行是这条语音指令的编号,16进制编码,范围从00-ff,编号不能重复。pin yin这行是语音识别的语音拼音,也就是这里输入什么,就要对着话筒说对应的内容才会触发该情景的灯光状态。名称这行是这个情景的描述。新建好后就可以点击save了,这时主界面就会多出一个情景,当要删除这个情景时,在主界面点击它,进入上图界面后,点击Delete即可。 之后点击UPLOAD按键,会进入下图的界面 进入到该界面后,打开语音灯系统,点击屏幕右上角的SCAN按钮,可以搜索到蓝牙的地址序列号,点击这个搜索到的蓝牙,进入下图界面 在这个界面点击Upload,会将之前手机配置的各种命令上传到开发板中,上传完毕后,手机端的配置就结束了。
打开语音情景灯的电源,并点开手机App,使用默认的配置或者配置自己的语音命令,这里需要注意,f1编号的命令(默认为美科meike)是语音输入的开关语句,也就是说要先说这句话,看到语音输入指示灯(发光二极管)亮起后,再说各种语音命令,并且每次输入新命令都要先说f1里的内容。配置好后,点击UPLOAD,选择语音灯的蓝牙,之后上传配置到语音灯的系统。手机端的工作就完成了。 最后,拿起话筒,本例的语音开关f1指令用的是“美科”,所以请用普通话清晰发声“美科”,观察发光二极管是否点亮,如果点亮就继续说出命令,如“开灯”,灯光模块就会被点亮,如果发光二极管没有变化,则继续说“美科”直到二极管点亮再说指令。每次提出新的指令都需要先说“美科”。 注意问题
程序说明
#include "Micromenu_user.h"
#include <Servo.h>
#include <Adafruit_NeoPixel.h>
//EEPROM---------------------
#include <EEPROM.h>
//用户自定义部分------------------------
#include <SoftwareSerial.h>
void setup()
{
SETUP_begin(); //该函数定义于 Micromenu_user.h
//用户自定义部分========================
}
void loop()
{
{
LOOP_priority_1ST(); //该函数定义于 Micromenu_user.h
}
}
#include "Arduino.h"
//用户自定义部分------------------------
#include "def.h"
#include "led.h"
#include "eep.h"
//用户自定义部分------------------------
int num_cache = 0;
//用户自定义部分------------------------
//#include <Servo.h>
//Servo myservo; 创建一个舵机对象 ,在本套件中没有涉及
int card_sta = 0; //nothing,true,false
unsigned long door_time = 0;
//用户自定义部分------------------------
char pkj[128];
int num = 0;
boolean buffer_sta = false;
boolean start = false;
unsigned long timer_voice = millis();
boolean voice_sta = false;
//SETUP===================================
void SETUP_begin()
{
pinMode(SDA, OUTPUT);// 语音输入指示灯的正极
pinMode(A7, OUTPUT); //语音输入指示灯的负极
DEBUG.begin(9600);
VOICE.begin(9600);
FROM.begin(9600); //串口通信波特率为9600
//EEPROM---------------------
eeprom_READ();
/*servo 用A3口控制舵机,本套件不涉及
myservo.attach(A3);
myservo.write(20);
*/
//led
strip.begin(); //初始化LED
for (int i = 0; i < 6; i++) // 初始化所有灯都为灭
{
strip.setPixelColor(i, strip.Color(0, 0, 0));
}
strip.show();
analogWrite(A7, LOW); //将A7口设置为低电平,用作语音指示灯负极
}
//LOOP====================================
void LOOP_priority_1ST()
{
if (FROM.available()) //如果串口收到蓝牙发送的数据
{
char c = FROM.read();
if (c == '{') //如果接收到的是左括号,说明蓝牙有数据发过来而且是接收的开始
buffer_sta = true;
if (c == '}') //如果接收到的是右括号说明传输结束了
{
start = true; //标志位置为true,开始后续的处理
buffer_sta = false; //蓝牙状态接收结束,标志位置为false
}
if (buffer_sta) //当蓝牙正在传数据时
pkj[num++] = c; //将收到的字符存入字符数组保存
delay(1);
}
if (start) //如果接收到了蓝牙的配置信息就显示在串口监视器上
{
DEBUG.print("pkj:"); //在串口打印出接收到的内容
for (int a = 1; a < num; a++)
DEBUG.print(pkj[a]); //打印出接收到的所有字符
DEBUG.println(); //打印一个空格
VOICE.write("{"); //向语音芯片中写入接收到的配置数据
for (int a = 1; a < num; a++)
VOICE.write(pkj[a]);
VOICE.write("}");
delay(10);
for (int a = 0; a < num; a++)//清空接收的信息
pkj[a] = NULL;
num = 0;
DEBUG.println("Change OK!");
start = false; //显示完把状态设为false避免重复处理
}
//---------------------------
if (millis() < timer_voice)
{
timer_voice = millis(); //若计时器重新计时,同步
}
if (millis() - timer_voice < 5000) //从有配置指令声音输入开始计时
{
voice_sta = true; //5秒内语音输入指示灯点亮
}
else
{
voice_sta = false; //超过5秒指示灯关闭
}
digitalWrite(SDA, voice_sta);//通过控制SDA电平的高低开关语音指示灯
if (VOICE.available()) //如果从语音芯片接收到用户的语音输入数据
{
int c = VOICE.read(); //读出串口内的内容
//DEBUG.print(c);
if (c == 0xf1) //如果是语音开关指令f1对应的内容
{
DEBUG.println("Voice IN!"); //在串口提示 输入声音
timer_voice = millis(); //记录当前的系统运行时间
}
if (voice_sta) //如果进入了语音输入状态
{
switch (c) //根据不同的语音指令,选择对应的应答
{
case 0xa1:
DEBUG.println("Door Open!");
timer_voice = 0;
// myservo.write(90); 本套件不涉及舵机
break;
case 0xa2:
DEBUG.println("Door Close!");
timer_voice = 0;
// myservo.write(20); 本套件不涉及舵机
break;
case 0xb1: //点亮6盏彩灯
DEBUG.println("Light ON!");
timer_voice = 0;
led_sta = true;
break;
case 0xb2: //关闭6盏彩灯
DEBUG.println("Light OFF!");
timer_voice = 0;
led_sta = false;
break;
case 0xc1:
DEBUG.println("Light TemperatureA!");
timer_voice = 0;
eeprom_WRITE();
led_style = 1;//选择模式,1是冷暖色调,2是不同单种颜色,
//3是彩虹循环
led_style_vol = 1; //各种颜色模式0-7分别对应灭红澄黄绿青蓝紫
break;
case 0xc2:
DEBUG.println("Light TemperatureB!");
timer_voice = 0;
eeprom_WRITE();
led_style = 1;
led_style_vol = 2;
break;
case 0xd1:
DEBUG.println("Light Colorful1!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 1;
break;
case 0xd2:
DEBUG.println("Light Colorful2!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 2;
break;
case 0xd3:
DEBUG.println("Light Colorful3!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 3;
break;
case 0xd4:
DEBUG.println("Light Colorful4!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 4;
break;
case 0xd5:
DEBUG.println("Light Colorful5!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 5;
break;
case 0xd6:
DEBUG.println("Light Colorful6!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 6;
break;
case 0xd7:
DEBUG.println("Light Colorful7!");
timer_voice = 0;
eeprom_WRITE();
led_style = 2;
led_style_vol = 7;
break;
case 0xe1:
DEBUG.println("Light RainbowA!");
timer_voice = 0;
eeprom_WRITE();
led_style = 3;
led_style_vol = 1;
break;
case 0xe2:
DEBUG.println("Light RainbowB!");
timer_voice = 0;
eeprom_WRITE();
led_style = 3;
led_style_vol = 2;
break;
}
}
}
if (millis() < led_time) led_time = millis();//和之前同理,同步时间
if (millis() - led_time > 50)
{
led_time = millis();
if (led_sta) //如果是亮灯状态
{
switch (led_style) //根据LED的类型决定亮的方式
{
case 1://冷暖色
colorWipe(color_t[led_style_vol]);
break;
case 2://单色
colorWipe(color[led_style_vol]);
break;
case 3://彩虹循环
rainbowCycle((led_style_vol - 1) * 3);
break;
}
}
else
{
colorWipe(color[0]); //如果是关灯状态
}
}
}
#include "Arduino.h"
#include <SoftwareSerial.h>
//定义蓝牙通信串口
SoftwareSerial mySerial(4, 5); // RX, TX
//定义串口
#define FROM mySerial
//#define FROM Serial
#define VOICE Serial1
#define DEBUG Serial
int led_style = 0;
int led_style_vol = 0;
//int led_style_cache=0;
boolean led_sta = true;
//定义亮度
#define led_brightness 3
unsigned long led_time;
#include "Arduino.h"
//USER-----------------------------
#include <EEPROM.h>
#define EEPROM_write(address, p) {
int i = 0;
byte *pp = (byte *) & (p);
for(; i < sizeof(p); i++) EEPROM.write(address + i, pp[i]);
}
#define EEPROM_read(address, p) {
int i = 0;
byte *pp = (byte *) & (p);
for(; i < sizeof(p); i++) pp[i] = EEPROM.read(address + i);
}
struct config_type
{
int EEPROM_led_style_vol;
int EEPROM_led_style;
};
//向EEPROM里写数据
void eeprom_WRITE()
{
config_type config; // 定义结构变量config,并定义config的内容
config.EEPROM_led_style_vol = led_style_vol;
config.EEPROM_led_style = led_style;
EEPROM_write(0, config); // 变量config存储到EEPROM,地址0写入
}
//从EEPROM里读数据
void eeprom_READ()
{
config_type config_readback;
EEPROM_read(0, config_readback);
led_style_vol = config_readback.EEPROM_led_style_vol;
led_style = config_readback.EEPROM_led_style;
}
unsigned int freeRam ()
{
extern unsigned int __heap_start, *__brkval;
unsigned int v;
return (unsigned int) &v - (__brkval == 0 ?
(unsigned int) &__heap_start : (unsigned int) __brkval);
}
#include "arduino.h"
#include <Adafruit_NeoPixel.h>
//定义Lamp模块所用引脚
#define LED_PIN A0
//定义Lamp灯对象,控制6盏彩灯并通过A0口控制
Adafruit_NeoPixel strip =
Adafruit_NeoPixel(6, LED_PIN, NEO_GRB + NEO_KHZ800);
//先定义8种颜色,分别是灭,红,澄,黄,绿,青,蓝,紫
uint32_t color[8] =
{
strip.Color(0, 0, 0),
strip.Color(255 / led_brightness, 0, 0),
strip.Color(255 / led_brightness, 165 / led_brightness, 0),
strip.Color(255 / led_brightness, 255 / led_brightness, 0),
strip.Color(0, 255 / led_brightness, 0),
strip.Color(0, 127 / led_brightness, 255 / led_brightness),
strip.Color(0, 0, 255 / led_brightness),
strip.Color(139 / led_brightness, 0, 255 / led_brightness)
};
uint32_t color_t[3] = //3种颜色分别为,灭,暖色,冷色
{
strip.Color(0, 0, 0),
strip.Color(255/led_brightness,137/led_brightness,18/led_brightness),
strip.Color(254/led_brightness,249/led_brightness,255/led_brightness)
};
//设置全部彩灯颜色,参数c是strip.Color(int a, int b, int c)的返回值
//相当于对应颜色的编码
void colorWipe(uint32_t c)
{
for(uint16_t i = 0; i < strip.numPixels(); i++)
//通过循环达到控制6盏灯的效果
{
strip.setPixelColor(i, c);//设置第i个彩灯为c编码对应的颜色
}
strip.show();
}
// 输入0-255任意一个数得到对应的唯一的一种颜色
// 颜色会从红-绿->蓝->红依次渐变循环
uint32_t Wheel(byte WheelPos)
{
if(WheelPos < 85)
{
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
else if(WheelPos < 170)
{
//因为WheelPos * 3在85到170的情况下会超过255,因此要先自减85
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else
{
//因为WheelPos * 3在170以上的情况下会超过255,因此要先自减170
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
uint16_t i, j;
//控制6盏彩灯以彩虹方式显示颜色
void rainbowCycle(uint8_t wait)
{
if(j < 256 * 5)
{
j++;
for(i = 0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i,
Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
else
j = 0;
}
视频 |