通过语音控制电灯、空调、房门。芝麻开门
1、先来段视频看看效果
2、基本原理
(1)几个控制器通过wifi连接到AP上,组成局域网。
(2)控制器基于arduion,使用了串口转wifi模块,它在控制器上建立了一个TCP服务器。控制端通过调用TCP服务来达到控制的目的。
下面分别介绍各个控制器。
3、电灯控制器
(1)硬件构成
arduino模块+wifi模块+继电器模块。
继电器模块的AC端接到零线开关上。
(2)Arduino代码
void setup() { Serial.begin(115200); pinMode(2,OUTPUT); digitalWrite(2, HIGH); // switch off } void loop() { // delay(500); if (Serial.available() > 0) { char val; val = Serial.read(); // read serial data if(val == '1') { digitalWrite(2, LOW); // switch on } else if(val == '0') { digitalWrite(2, HIGH); // switch off } Serial.print(val); //将收到是数据再通过串口发送出去 //delay(1000); } }
(3)PC端代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Diagnostics; using System.Timers; using System.Net; namespace WiseHouse.SI { public class LightController { // *********************************************** 全局字段 ****************************************************** TcpClient tcp = new TcpClient(); NetworkStream stream; System.Timers.Timer tmrConnecting = new System.Timers.Timer(); // 连线的周期。 若断线,在10秒后尝试建立连接 // *********************************************** 事件 ****************************************************** // *********************************************** 属性 ****************************************************** /// <summary> /// IP地址 /// </summary> public string IP { get { return _IP; } set { } } string _IP; /// <summary> /// 是否在线 /// </summary> public bool IsOnline { get { return _IsOnline; } set { } } bool _IsOnline = false; /// <summary> /// 信号强度 /// </summary> public int SignalStrength { get { return GetSignalStrength(); } set { } } // int _SignalStrength; // *********************************************** 构造函数 ****************************************************** /// <summary> /// 以IP地址为参数实例化一个对象 /// </summary> /// <param name="ip"></param> public LightController( string ip ) { _IP = ip; // 计时器1 tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed ); tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 tmrConnecting.Enabled = true; // 首次连接 Open(); } // *********************************************** 公共方法 ****************************************************** // 打开灯1 public void TurnOnLight1() { try { if( tcp.Connected == true ) { // 发送 byte[] command = Encoding.ASCII.GetBytes( "1" ); stream.Write( command, 0, command.Length ); // 写入 System.Threading.Thread.Sleep( 100 ); // // 接收 int bufferSize = 30; // 13个,00.00;00.00 // 接收字节数组 byte[] buffer = new byte[ bufferSize ]; int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串 // Console.WriteLine( data ); } else { } } catch { Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 关闭灯1 /// </summary> public void TurnOffLight1() { try { if( tcp.Connected == true ) { // 发送 byte[] command = Encoding.ASCII.GetBytes( "0" ); stream.Write( command, 0, command.Length ); // 写入 System.Threading.Thread.Sleep( 100 ); // // 接收 int bufferSize = 30; // 13个,00.00;00.00 // 接收字节数组 byte[] buffer = new byte[ bufferSize ]; int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串 // Console.WriteLine( data ); } else { } } catch { Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 释放资源 /// </summary> public void Close() { stream.Close(); tcp.Close(); } // *********************************************** 私有方法 ****************************************************** /// <summary> /// 定时进行连接。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e ) { Open(); } /// <summary> /// 打开连接。 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> void Open() { try { if( tcp.Connected == false ) //若连线失败,则尝试进行连接 { // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例 tcp.Close(); tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect(); tcp.ReceiveTimeout = 1000; tcp.SendTimeout = 1000; // timeout stream = tcp.GetStream(); _IsOnline = true; Console.WriteLine( _IP.PadRight( 20 ) + "灯连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } catch { _IsOnline = false; Trace.WriteLine( _IP.PadRight( 20 ) + "灯连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 获得信号强度 /// </summary> /// <returns></returns> int GetSignalStrength() { try { // 从页面中下载html文本 WebClient client = new WebClient(); client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证 string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //? // 初次截取文本。 int j1 = str1.IndexOf( "Link Quality" ) + 22; string str2 = str1.Substring( j1, 70 ); // 类似于:<td>Good 95%</td>\n <td rowspan=\"4\">< // 再次截取文本。在str2的基础上截取 int j2 = str2.LastIndexOf( ";" ); //信号值前的文本 int j3 = str2.IndexOf( "%</td>" ); //信号值前的文本 string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 ); // 截取信号值。 return int.Parse( str3 ); } catch { return 0; // 若读取失败,则返回 0 } } } }
4、空调控制器
(1)硬件构成
arduino模块+wifi模块+红外LED灯管。
我的空调是格力的,要控制空调首先需要捕获红外信号的原始码。关于如何捕获原始码,请参考本人的另一篇文章:http://www.cnblogs.com/dehai/p/3730156.html
(2)Arduino代码
#include <IRremote.h> IRsend irsend; unsigned int open26[300] = {9040,4438,665,1643,701,508,697,508,698,1606,702,1606,696,1610,638,1670,638,571,697,508,696,1608,663,545,698,1606,700,509,698,508,700,506,698,507,701,505,696,509,698,507,696,509,665,541,699,1606,699,509,698,507,698,506,696,510,697,509,695,509,698,1606,664,545,697,1606,664,544,699,507,697,1608,667,542,697,19939,666,1643,699,508,698,508,698,507,698,1606,666,542,696,509,698,508,698,508,699,507,699,507,698,507,698,508,699,1606,699,509,699,507,698,507,700,506,697,508,698,508,696,509,697,508,698,507,698,507,699,507,697,509,700,506,698,507,699,506,696,509,697,508,696,510,698,39948,9041,4437,669,1640,664,543,696,509,698,1606,668,1639,666,1642,699,1607,701,507,698,508,698,1606,663,545,662,1642,701,507,697,509,699,507,699,507,697,507,697,508,696,510,698,508,696,510,699,1605,699,509,697,508,699,507,699,507,699,507,699,507,697,1608,665,1642,701,1605,701,507,700,506,698,1605,664,544,698,19938,700,507,698,507,697,509,698,508,697,508,699,507,698,507,697,509,697,509,698,507,697,508,698,508,699,506,699,507,696,510,695,510,698,507,697,508,696,509,697,508,699,1605,665,543,699,1605,667,543,699,506,698,507,699,507,698,507,698,507,696,1609,699,508,698,508,698}; unsigned int close27[279] = {9004,4499,699,1609,697,511,695,511,695,510,693,1611,697,1612,696,510,695,510,695,1610,696,1609,696,512,695,1609,696,512,695,511,695,511,694,512,694,511,695,510,694,512,694,512,694,511,695,1611,696,512,693,512,694,512,694,511,694,511,694,512,694,1611,696,512,694,1610,696,512,694,511,694,1609,698,510,694,19942,698,511,694,512,694,511,694,511,694,511,694,511,695,510,695,511,694,511,696,510,692,513,694,511,694,511,694,1611,696,511,693,512,694,511,693,512,694,512,695,511,694,512,694,511,694,511,695,511,694,511,694,512,695,511,694,511,693,512,694,511,695,511,695,1609,698,39952,9037,4443,698,1609,697,511,695,511,694,510,695,1610,696,1609,697,512,693,512,694,1610,698,1610,695,511,694,1611,696,512,695,511,694,512,694,512,692,512,694,511,695,511,694,512,695,511,695,1608,697,512,694,511,693,512,692,512,693,538,694,512,694,1610,697,1610,697,1612,697,511,694,511,694,1611,697,512,695,19941,698,511,694,511,693,512,693,512,695,511,693,512,696,510,694,511,695,511,695,510,695,511,693,512,694,511,695,511,694,511,694,511,694,512,693,512,694,511,693,512,694,1610,697,511,695,1610,695,513,694,511,693,512,694,511,693,512,693,1611,698,1610,697,511,695,1610,696}; void setup() { Serial.begin(115200); } void loop() { // irsend.sendRaw2(open26, 279, 38); //delay(2000); if (Serial.available() > 0) { char val; val = Serial.read(); // read serial data if(val == '1') { irsend.sendRaw2(open26, 279, 38); } else if(val == '0') { irsend.sendRaw2(close27, 279, 38); } Serial.print(val); //将收到是数据再通过串口发送出去 //delay(1000); } }
(3)PC端代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Diagnostics; using System.Timers; using System.Net; namespace WiseHouse.SI { public class AirConditioner { // *********************************************** 全局字段 ****************************************************** TcpClient tcp = new TcpClient(); NetworkStream stream; System.Timers.Timer tmrConnecting = new System.Timers.Timer(); // 连线的周期。 若断线,在10秒后尝试建立连接 // *********************************************** 事件 ****************************************************** // *********************************************** 属性 ****************************************************** /// <summary> /// IP地址 /// </summary> public string IP { get { return _IP; } set { } } string _IP; /// <summary> /// 是否在线 /// </summary> public bool IsOnline { get { return _IsOnline; } set { } } bool _IsOnline = false; /// <summary> /// 信号强度 /// </summary> public int SignalStrength { get { return GetSignalStrength(); } set { } } // int _SignalStrength; // *********************************************** 构造函数 ****************************************************** /// <summary> /// 以IP地址为参数实例化一个对象 /// </summary> /// <param name="ip"></param> public AirConditioner( string ip ) { _IP = ip; // 计时器1 tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed ); tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 tmrConnecting.Enabled = true; // 首次连接 Open(); } // *********************************************** 公共方法 ****************************************************** // 打开空调 public void TurnOn() { try { if( tcp.Connected == true ) { // 发送 byte[] command = Encoding.ASCII.GetBytes( "1" ); stream.Write( command, 0, command.Length ); // 写入 System.Threading.Thread.Sleep( 100 ); // // 接收 int bufferSize = 30; // 13个,00.00;00.00 // 接收字节数组 byte[] buffer = new byte[ bufferSize ]; int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串 // Console.WriteLine( data ); } else { } } catch { Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 关闭空调 /// </summary> public void TurnOff() { try { if( tcp.Connected == true ) { // 发送 byte[] command = Encoding.ASCII.GetBytes( "0" ); stream.Write( command, 0, command.Length ); // 写入 System.Threading.Thread.Sleep( 100 ); // // 接收 int bufferSize = 30; // 13个,00.00;00.00 // 接收字节数组 byte[] buffer = new byte[ bufferSize ]; int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串 // Console.WriteLine( data ); } else { } } catch { Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 释放资源 /// </summary> public void Close() { stream.Close(); tcp.Close(); } // *********************************************** 私有方法 ****************************************************** /// <summary> /// 定时进行连接。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e ) { Open(); } /// <summary> /// 打开连接。 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> void Open() { try { if( tcp.Connected == false ) //若连线失败,则尝试进行连接 { // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例 tcp.Close(); tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect(); tcp.ReceiveTimeout = 1000; tcp.SendTimeout = 1000; // timeout stream = tcp.GetStream(); _IsOnline = true; Console.WriteLine( _IP.PadRight( 20 ) + "空调连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } catch { _IsOnline = false; Trace.WriteLine( _IP.PadRight( 20 ) + "空调连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 获得信号强度 /// </summary> /// <returns></returns> int GetSignalStrength() { try { // 从页面中下载html文本 WebClient client = new WebClient(); client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证 string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //? // 初次截取文本。 int j1 = str1.IndexOf( "Link Quality" ) + 22; string str2 = str1.Substring( j1, 70 ); // 类似于:<td>Good 95%</td>\n <td rowspan=\"4\">< // 再次截取文本。在str2的基础上截取 int j2 = str2.LastIndexOf( ";" ); //信号值前的文本 int j3 = str2.IndexOf( "%</td>" ); //信号值前的文本 string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 ); // 截取信号值。 return int.Parse( str3 ); } catch { return 0; // 若读取失败,则返回 0 } } } }
5、房门控制器
(1)硬件构成
arduino模块+wifi模块+场效管模块+自制的稳压模块。
我的锁是电控锁,它里面有一个线圈,当线圈通电后,它中间的钢芯被磁化,吸位锁的卡扣,门就开了。由于线圈在通电时的瞬间电流较大,为避免它对电路的其它部分造成干扰(可能会造成控制器死机),加上一个自制的稳压模块。稳压模块由一些电感和电容组成。
(2)Arduino代码
void setup() { Serial.begin(115200); pinMode(2,OUTPUT); digitalWrite(2, LOW); // switch off } void loop() { // delay(500); if (Serial.available() > 0) { char val; val = Serial.read(); // read serial data if(val == '1') { // digitalWrite(2, LOW); // switch on // delay(1000); digitalWrite(2, HIGH); // switch off } else if(val == '0') { digitalWrite(2, LOW); // switch off } Serial.print(val); //将收到是数据再通过串口发送出去 //delay(1000); } }
(3)PC端代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.Diagnostics; using System.Timers; using System.Net; namespace WiseHouse.SI { public class DoorController { // *********************************************** 全局字段 ****************************************************** TcpClient tcp = new TcpClient(); NetworkStream stream; System.Timers.Timer tmrConnecting = new System.Timers.Timer(); // 连线的周期。 若断线,在10秒后尝试建立连接 // *********************************************** 事件 ****************************************************** // *********************************************** 属性 ****************************************************** /// <summary> /// IP地址 /// </summary> public string IP { get { return _IP; } set { } } string _IP; /// <summary> /// 是否在线 /// </summary> public bool IsOnline { get { return _IsOnline; } set { } } bool _IsOnline = false; /// <summary> /// 信号强度 /// </summary> public int SignalStrength { get { return GetSignalStrength(); } set { } } // int _SignalStrength; // *********************************************** 构造函数 ****************************************************** /// <summary> /// 以IP地址为参数实例化一个对象 /// </summary> /// <param name="ip"></param> public DoorController( string ip ) { _IP = ip; // 计时器1 tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed ); tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 tmrConnecting.Enabled = true; // 首次连接 Open(); } // *********************************************** 公共方法 ****************************************************** // 打1号门 public void OpenDoor1() { try { if( tcp.Connected == true ) { // 发送 byte[] command = Encoding.ASCII.GetBytes( "1" ); stream.Write( command, 0, command.Length ); // 写入 // System.Threading.Thread.Sleep( 100 ); // // 接收 // int bufferSize = 30; // 13个,00.00;00.00 // 接收字节数组 // byte[] buffer = new byte[ bufferSize ]; // int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer // string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串 // Console.WriteLine( data ); } else { } } catch { Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } ///// <summary> ///// 释放资源 ///// </summary> //public void Close() //{ // //stream.Close(); // // tcp.Close(); //} // *********************************************** 私有方法 ****************************************************** /// <summary> /// 定时进行连接。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e ) { Open(); } /// <summary> /// 打开连接。 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> void Open() { try { if( tcp.Connected == false ) //若连线失败,则尝试进行连接 { // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例 tcp.Close(); tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect(); tcp.ReceiveTimeout = 1000; tcp.SendTimeout = 1000; // timeout stream = tcp.GetStream(); _IsOnline = true; Console.WriteLine( _IP.PadRight( 20 ) + "门连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } catch { _IsOnline = false; Trace.WriteLine( _IP.PadRight( 20 ) + "门连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) ); } } /// <summary> /// 获得信号强度 /// </summary> /// <returns></returns> int GetSignalStrength() { try { // 从页面中下载html文本 WebClient client = new WebClient(); client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证 string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //? // 初次截取文本。 int j1 = str1.IndexOf( "Link Quality" ) + 22; string str2 = str1.Substring( j1, 70 ); // 类似于:<td>Good 95%</td>\n <td rowspan=\"4\">< // 再次截取文本。在str2的基础上截取 int j2 = str2.LastIndexOf( ";" ); //信号值前的文本 int j3 = str2.IndexOf( "%</td>" ); //信号值前的文本 string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 ); // 截取信号值。 return int.Parse( str3 ); } catch { return 0; // 若读取失败,则返回 0 } } } }
6、控制端
使用了微软的语音识别和合成库,命名空间是System.Speech.Recognition和 System.Speech.Synthesis。
核心代码:
public partial class Frm控制台 : Form { // ********************************************* 全局变量 ********************************************************************** SpeechRecognitionEngine _recognizer = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("zh-CN")); // 语音识别引擎 SpeechSynthesizer speech = new SpeechSynthesizer(); // 语音合成器。默认使用女声Lily。 AirConditioner airConditioner; // 空调控制器 LightController lightController; // 电灯控制器 DoorController doorController; // 门禁控制器 bool IsStandingBy = false; // 是否进入待命模式 System.Threading.Timer tmrCurrent; // 当前的 System.Threading.Timer tmrPrevious; // 之前的 public Frm控制台() { InitializeComponent(); } private void Frm控制台_Load(object sender, EventArgs e) { // 控制器初始化 airConditioner = new AirConditioner("172.16.1.12"); lightController = new LightController("172.16.1.13"); doorController = new DoorController("172.16.1.14"); // 添加语法 GrammarBuilder gb1 = new GrammarBuilder(new Choices("小黑", "取消")); GrammarBuilder gb2 = new GrammarBuilder(new Choices("打开电灯", "关闭电灯")); GrammarBuilder gb3 = new GrammarBuilder(new Choices("打开空调", "关闭空调", "18度")); GrammarBuilder gb4 = new GrammarBuilder(new Choices("打开房门")); // 加载语法 _recognizer.LoadGrammar(new Grammar(gb1)); _recognizer.LoadGrammar(new Grammar(gb2)); _recognizer.LoadGrammar(new Grammar(gb3)); _recognizer.LoadGrammar(new Grammar(gb4)); // 绑定事件 _recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(_recognizer_SpeechRecognized); _recognizer.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(_recognizer_SpeechRecognitionRejected); _recognizer.SetInputToDefaultAudioDevice(); // 设置语音输入设备 _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启异步语音识别 } /// <summary> /// 语音识别后的处理函数 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void _recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) { // 关闭识别,防止speech说出来的话被误识别 _recognizer.RecognizeAsyncStop(); Thread.Sleep(30); if (e.Result.Confidence > 0.95) { Console.WriteLine(e.Result.Text); if (e.Result.Text == "计算机" || e.Result.Text == "小黑") { speech.Speak("在"); // 进入待命模式 IsStandingBy = true; Console.WriteLine("进入待命模式"); // 重新计时,10秒命令超时。 tmrPrevious = tmrCurrent; tmrCurrent = new System.Threading.Timer(new TimerCallback(TimerCall), this, 10000, 0); // 当前的,新的 if (tmrPrevious != null) // 取消前一个tmr. { tmrPrevious.Dispose(); } } // 待命模式下的处理 if (IsStandingBy == true && e.Result.Text != "小黑") { if (e.Result.Text == "打开电灯") { lightController.TurnOnLight1(); speech.Speak("灯成功打开"); } else if (e.Result.Text == "关闭电灯") { lightController.TurnOffLight1(); speech.Speak("灯成功关闭"); } else if (e.Result.Text == "打开空调") { airConditioner.TurnOn(); speech.Speak("空调成功打开"); } else if (e.Result.Text == "关闭空调") { airConditioner.TurnOff(); speech.Speak("空调成功关闭"); } else if (e.Result.Text == "18度") { speech.Speak("操作成功"); } else if (e.Result.Text == "打开房门") { doorController.OpenDoor1(); speech.Speak("门成功打开"); } else if (e.Result.Text == "取消") { speech.Speak("指令取消"); } IsStandingBy = false; // 退出待命模式 tmrCurrent.Dispose(); } } _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启识别 } void _recognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e) { _recognizer.RecognizeAsyncStop(); Thread.Sleep(30); speech.Speak("请再说一遍"); _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启识别 } void TimerCall(object sender) { IsStandingBy = false; Console.WriteLine("退出待命模式"); MediaHelper.Beep(); //蜂鸣声 } }