找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3187|回复: 2
收起左侧

ZigBee智能家居的C#上位机源码

[复制链接]
ID:1023010 发表于 2022-5-4 17:19 | 显示全部楼层 |阅读模式
烟雾,光敏亮度,火焰等传感器数据的采集,上位机实现窗帘的开关
51hei.png

C#源程序如下:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. using System.IO.Ports;

  11. namespace smartLed
  12. {
  13.     public partial class FormMain : Form
  14.     {

  15.         private SerialPort sp = new SerialPort();           //串口类
  16.         private bool isOpen = false;                        //打开串口的标志位
  17.         private bool usart_closing = false;                 //是否正在关闭串口
  18.         private bool usart_listening = false;               //监听是否在执行串口
  19.         private List<byte> buffer = new List<byte>(4096);   //分配1页内存
  20.         private long SendCount = 0;
  21.         private long ReceiveCount = 0;

  22.         //串口窗体初始化
  23.         private void SerialSettingInit()
  24.         {
  25.             for (int i = 0; i < 32; i++)
  26.             {
  27.                 cboxCOM.Items.Add("COM" + (i + 1).ToString());
  28.             }
  29.             cboxCOM.SelectedIndex = 0;
  30.             //列出波特率
  31.             cboxBaudRate.Items.Add("1200");
  32.             cboxBaudRate.Items.Add("2400");
  33.             cboxBaudRate.Items.Add("4800");
  34.             cboxBaudRate.Items.Add("9600");
  35.             cboxBaudRate.Items.Add("19200");
  36.             cboxBaudRate.Items.Add("38400");
  37.             cboxBaudRate.Items.Add("43000");
  38.             cboxBaudRate.Items.Add("56000");
  39.             cboxBaudRate.Items.Add("57600");
  40.             cboxBaudRate.Items.Add("115200");
  41.             cboxBaudRate.SelectedIndex = 9;
  42.             //列出停止位
  43.             cboxStopBits.Items.Add("0");
  44.             cboxStopBits.Items.Add("1");
  45.             cboxStopBits.Items.Add("1.5");
  46.             cboxStopBits.Items.Add("2");
  47.             cboxStopBits.SelectedIndex = 1;
  48.             //列出数据位
  49.             cboxDataBits.Items.Add("8");
  50.             cboxDataBits.Items.Add("7");
  51.             cboxDataBits.Items.Add("6");
  52.             cboxDataBits.Items.Add("5");
  53.             cboxDataBits.SelectedIndex = 0;
  54.             //列出奇偶校验位
  55.             cboxParity.Items.Add("无");
  56.             cboxParity.Items.Add("奇校验");
  57.             cboxParity.Items.Add("偶校验");
  58.             cboxParity.SelectedIndex = 0;

  59.             countClear();
  60.         }

  61.         //检测可用串口
  62.         private void buttonCheck_Click(object sender, EventArgs e)
  63.         {
  64.             bool comExistence = false;          //有可用串口标志位
  65.             cboxCOM.Items.Clear();              //清除串口号中所有串口
  66.             for (int i = 0; i < 32; i++)
  67.             {
  68.                 try
  69.                 {
  70.                     SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
  71.                     sp.Open();
  72.                     sp.Close();
  73.                     cboxCOM.Items.Add("COM" + (i + 1).ToString());
  74.                     comExistence = true;
  75.                 }
  76.                 catch (Exception)
  77.                 {
  78.                     continue;
  79.                 }
  80.             }
  81.             if (comExistence)
  82.             {
  83.                 cboxCOM.SelectedIndex = 0;          //使ListBox显示
  84.             }
  85.             else
  86.             {
  87.                 MessageBox.Show("没有找到可用串口!", "错误提示");
  88.             }
  89.         }

  90.         //检测串口设置
  91.         private bool CheckPortSetting()
  92.         {
  93.             if (cboxCOM.Text.Trim() == "") return false;
  94.             if (cboxBaudRate.Text.Trim() == "") return false;
  95.             if (cboxDataBits.Text.Trim() == "") return false;
  96.             if (cboxParity.Text.Trim() == "") return false;
  97.             if (cboxStopBits.Text.Trim() == "") return false;
  98.             return true;
  99.         }

  100.         //开启串口按键响应
  101.         private void buttonOpen_Click(object sender, EventArgs e)
  102.         {
  103.             if (isOpen == false)
  104.             {
  105.                 if (CheckPortSetting())
  106.                 {
  107.                     sp.PortName = cboxCOM.Text.Trim();//设置串口名
  108.                     sp.BaudRate = Convert.ToInt32(cboxBaudRate.Text.Trim());//设置串口的波特率
  109.                     float f = Convert.ToSingle(cboxStopBits.Text.Trim());//设置停止位
  110.                     if (f == 0)
  111.                     {
  112.                         sp.StopBits = StopBits.None;
  113.                     }
  114.                     else if (f == 1.5)
  115.                     {
  116.                         sp.StopBits = StopBits.OnePointFive;
  117.                     }
  118.                     else if (f == 1)
  119.                     {
  120.                         sp.StopBits = StopBits.One;
  121.                     }
  122.                     else if (f == 2)
  123.                     {
  124.                         sp.StopBits = StopBits.Two;
  125.                     }
  126.                     else
  127.                     {
  128.                         sp.StopBits = StopBits.One;
  129.                     }
  130.                     sp.DataBits = Convert.ToInt16(cboxDataBits.Text.Trim());//设置数据位
  131.                     string s = cboxParity.Text.Trim(); //设置奇偶校验位
  132.                     if (s.CompareTo("无") == 0)
  133.                     {
  134.                         sp.Parity = Parity.None;
  135.                     }
  136.                     else if (s.CompareTo("奇校验") == 0)
  137.                     {
  138.                         sp.Parity = Parity.Odd;
  139.                     }
  140.                     else if (s.CompareTo("偶校验") == 0)
  141.                     {
  142.                         sp.Parity = Parity.Even;
  143.                     }
  144.                     else
  145.                     {
  146.                         sp.Parity = Parity.None;
  147.                     }
  148.                 }
  149.                 else
  150.                 {
  151.                     return;
  152.                 }

  153.                 //设置超时读取时间
  154.                 sp.ReadTimeout = -1;
  155.                 sp.RtsEnable = true;
  156.                 //定义DataReceived 事件,当串口收到数据后触发事件
  157.                 sp.DataReceived -= new SerialDataReceivedEventHandler(sp_DataReceived);
  158.                 sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);

  159.                 try//打开串口
  160.                 {
  161.                     sp.Open();
  162.                     isOpen = true;
  163.                     buttonOpen.Text = "关闭串口";
  164.                     //串口打开后则相关的串口设置按钮便不可再用
  165.                     cboxCOM.Enabled = false;
  166.                     cboxBaudRate.Enabled = false;
  167.                     cboxStopBits.Enabled = false;
  168.                     cboxDataBits.Enabled = false;
  169.                     cboxParity.Enabled = false;
  170.                     buttonCheck.Enabled = false;

  171.                 }
  172.                 catch (Exception)
  173.                 {
  174.                     //打开串口失败后,相应标志位取消
  175.                     isOpen = false;
  176.                     MessageBox.Show("串口无效或已被占用!", "错误提示");
  177.                 }
  178.             }
  179.             else
  180.             {
  181.                 try//关闭串口
  182.                 {
  183.                     usart_closing = true;//告诉Invoke串口正在关闭
  184.                     while (usart_listening) Application.DoEvents();//等待到Invoke执行完
  185.                     sp.Close();
  186.                     usart_closing = false;//以上代码旨在防止关闭串口时发生锁死现象

  187.                     isOpen = false;
  188.                     buttonOpen.Text = "打开串口";
  189.                     //串口打开后则相关的串口设置按钮便不可再用
  190.                     cboxCOM.Enabled = true;
  191.                     cboxBaudRate.Enabled = true;
  192.                     cboxStopBits.Enabled = true;
  193.                     cboxDataBits.Enabled = true;
  194.                     cboxParity.Enabled = true;
  195.                     buttonCheck.Enabled = true;

  196.                     countClear();
  197.                 }
  198.                 catch (Exception)
  199.                 {
  200.                     //打开串口失败后,相应标志位取消
  201.                     isOpen = false;
  202.                     MessageBox.Show("关闭串口时发生错误!", "错误提示");
  203.                 }
  204.             }
  205.         }

  206.         //串口发送字符串
  207.         private void UartSend(String str)
  208.         {
  209.             if (isOpen == true)
  210.             {
  211.                 try
  212.                 {
  213.                     sp.Write(str);
  214.                     SendCount += Encoding.Default.GetBytes(str).Length;
  215.                     refreshSendCount();
  216.                 }
  217.                 catch
  218.                 {
  219.                     PortErrorDeal();
  220.                 }
  221.             }
  222.             else
  223.             {
  224.                 MessageBox.Show("串口未打开!", "错误提示");
  225.             }
  226.         }

  227.         //发送数组
  228.         private void UartSend(byte[] buf, int len)
  229.         {
  230.             if (isOpen == true)
  231.             {
  232.                 try
  233.                 {
  234.                     sp.Write(buf, 0, len);
  235.                     SendCount += len;
  236.                     refreshSendCount();
  237.                 }
  238.                 catch
  239.                 {
  240.                     PortErrorDeal();
  241.                 }
  242.             }
  243.             else
  244.             {
  245.                 MessageBox.Show("串口未打开!", "错误提示");
  246.             }
  247.         }

  248.         //发送数组
  249.         private void UartSend(byte[] buf)
  250.         {
  251.             UartSend(buf, buf.Length);
  252.         }

  253.         //串口接收事件
  254.         private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
  255.         {
  256.             if (usart_closing)
  257.             {
  258.                 return;
  259.             }
  260.             else
  261.             {
  262.                 usart_listening = true;                     
  263.             }

  264.             //this.Invoke跨线程访问ui
  265.             try
  266.             {
  267.                 this.Invoke((EventHandler)(delegate
  268.                 {
  269.                     int Bytes_n = sp.BytesToRead;                 //避免缓存不一致
  270.                     Byte[] ReceivedDatabuf = new Byte[Bytes_n];   //创建接收字节数组
  271.                     sp.Read(ReceivedDatabuf, 0, Bytes_n);         //读取所接收到的数据
  272.                     buffer.AddRange(ReceivedDatabuf);             //缓存数据
  273.                     ReceiveCount += Bytes_n;
  274.                     refreshReceiveCount();
  275.                 }));
  276.             }
  277.             catch
  278.             {
  279.                 PortErrorDeal();
  280.             }
  281.             finally
  282.             {
  283.                 usart_listening = false;                       
  284.             }
  285.         }

  286.         //串口出错处理
  287.         private void PortErrorDeal()
  288.         {
  289.             MessageBox.Show("串口断开或者拔下!", "错误提示");
  290.             try
  291.             {
  292.                 sp.Close();
  293.             }
  294.             catch
  295.             {

  296.             }
  297.             isOpen = false;
  298.             buttonOpen.Text = "打开串口";
  299.             //串口打开后则相关的串口设置按钮便不可再用
  300.             cboxCOM.Enabled = true;
  301.             buttonCheck.Enabled = true;
  302.         }

  303.         //刷新接收计数
  304.         private void refreshReceiveCount()
  305.         {
  306.             labReiveCount.Text = "接收:" + ReceiveCount.ToString();
  307.         }

  308.         //刷新发送计数
  309.         private void refreshSendCount()
  310.         {
  311.             labSendCount.Text = "发送:" + SendCount.ToString();
  312.         }

  313.         //计数值清零
  314.         private void countClear()
  315.         {
  316.             SendCount = 0;
  317.             ReceiveCount = 0;
  318.             refreshReceiveCount();
  319.             refreshSendCount();
  320.         }

  321.         //发送数据变化
  322.         private void labSendCount_TextChanged(object sender, EventArgs e)
  323.         {

  324.         }

  325.         //接收数据变化
  326.         private void labReiveCount_TextChanged(object sender, EventArgs e)
  327.         {
  328.             if (ReceiveCount == 0)
  329.             {
  330.                 buffer.Clear();
  331.             }
  332.             else
  333.             {
  334.                 recevivedData();
  335.             }
  336.         }

  337.         /*@end Serial Base*********************************************/

  338.         /*@start command Base******************************************/
  339.         private string createCommand(string comm, int param)
  340.         {
  341.             return (comm + param.ToString() + "\r\n");
  342.         }

  343.         private string createCommand(string comm, string param)
  344.         {
  345.             return (comm + param + "\r\n");
  346.         }

  347.         private int getCommand(string source, string comm, out int param)
  348.         {
  349.             int commPos = source.IndexOf(comm);
  350.             int endPos = source.IndexOf("\r\n");
  351.             int valueLen = endPos - commPos - comm.Length;

  352.             if (commPos > -1 && endPos > -1 && valueLen > 0)
  353.             {
  354.                 string value = source.Substring(endPos - valueLen, valueLen);
  355.                 try
  356.                 {
  357.                     param = int.Parse(value);
  358.                     return getFirstEndFlag();
  359.                 }
  360.                 catch
  361.                 {

  362.                 }
  363.             }

  364.             param = 0;
  365.             return -1;
  366.         }

  367.         private int getCommand(string source, string comm, out string param)
  368.         {
  369.             int commPos = source.IndexOf(comm);
  370.             int endPos = source.IndexOf("\r\n");
  371.             int valueLen = endPos - commPos - comm.Length;

  372.             if (commPos > -1 && endPos > -1 && valueLen > 0)
  373.             {
  374.                 param = source.Substring(endPos - valueLen, valueLen);
  375.                 return getFirstEndFlag();
  376.             }

  377.             param = "";
  378.             return -1;
  379.         }

  380.         private int getFirstEndFlag()
  381.         {
  382.             int i = buffer.IndexOf((byte)'\r');
  383.             int j = buffer.IndexOf((byte)'\n');
  384.             if (i > -1)
  385.             {
  386.                 if (j == (i + 1))
  387.                 {
  388.                     return i;
  389.                 }
  390.                 else
  391.                 {
  392.                     buffer.RemoveRange(0, i + 1);
  393.                     return getFirstEndFlag();
  394.                 }
  395.             }
  396.             return -1;
  397.         }

  398.         private void recevivedData()
  399.         {
  400.             if (getFirstEndFlag() > -1)
  401.             {
  402.                 analysisData();
  403.             }
  404.         }

  405.         /*
  406.          * 作用:解析串口接收过来的数据,根据字符标志位进行数据截取到对应的显示地方
  407.          */
  408.         private void analysisData()
  409.         {
  410.             bool getDataFlag = false;

  411.             {//光敏亮度显示
  412.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  413.                 string param;
  414.                 int dataLen = getCommand(source, LIGHT, out param);
  415.                 if (dataLen > 0)
  416.                 {
  417.                     label_light.Text = "LIGHT\r\n" + param[1] + param[2] + param[3];
  418.                     buffer.RemoveRange(0, dataLen + 2);

  419.                     if (param[1] >= '6')            //当亮度大于600时,关闭灯光
  420.                     {
  421.                         for (int i = 0; i < 10; i++)
  422.                         {
  423.                             UartSend(createCommand(LIGHT, "0"));
  424.                         }
  425.                     }
  426.                     else                            //否则,灯光一直显示亮起
  427.                     {
  428.                         for (int i = 0; i < 10; i++)
  429.                         {
  430.                             UartSend(createCommand(LIGHT, "1"));
  431.                         }
  432.                     }

  433.                     getDataFlag = true;
  434.                 }
  435.             }

  436.             {//火焰显示
  437.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  438.                 string param;
  439.                 int dataLen = getCommand(source, FIRE, out param);
  440.                 if (dataLen > 0)
  441.                 {
  442.                     label_fire.Text = "FIRE\r\n" + param[2] + param[3];

  443.                     if (param[3] == '1')            //当检测到火焰气体 param[3] == '1' 时,发出警报1
  444.                     {
  445.                         for (int i = 0; i < 10; i++)
  446.                         {
  447.                             UartSend(createCommand(FIRE, "1"));
  448.                         }
  449.                     }
  450.                     else                            //此时若没监测火焰气体 param[3] == '0',关闭警报2,也可以在上位机的按钮关掉
  451.                     {
  452.                         for (int i = 0; i < 10; i++)
  453.                         {
  454.                             UartSend(createCommand(FIRE, "0"));
  455.                         }
  456.                     }

  457.                     buffer.RemoveRange(0, dataLen + 2);
  458.                     getDataFlag = true;
  459.                 }
  460.             }

  461.             {//烟雾显示
  462.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  463.                 string param;
  464.                 int dataLen = getCommand(source, SMOKE, out param);
  465.                 if (dataLen > 0)
  466.                 {
  467.                     label_smoke.Text = "SMOKE\r\n" + param[2] + param[3];
  468.                     buffer.RemoveRange(0, dataLen + 2);
  469.                     getDataFlag = true;
  470.                 }
  471.             }

  472.             {//人体显示
  473.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  474.                 string param;
  475.                 int dataLen = getCommand(source, HUMAN, out param);
  476.                 if (dataLen > 0)
  477.                 {
  478.                     label_human.Text = "HUMAN\r\n" + param[2] + param[3];

  479.                     if (param[3] == '1')        //当检测到人体 param[3] == '1' 时,发出警报2
  480.                     {
  481.                         for (int i = 0; i < 10; i++)
  482.                         {
  483.                             UartSend(createCommand(HUMAN, "1"));
  484.                         }
  485.                     }
  486.                     else                       //此时若没监测到人体 param[3] == '0',关闭警报2,也可以在上位机的按钮关掉
  487.                     {
  488.                         for (int i = 0; i < 10; i++)
  489.                         {
  490.                             UartSend(createCommand(HUMAN, "0"));
  491.                         }
  492.                     }

  493.                     buffer.RemoveRange(0, dataLen + 2);
  494.                     getDataFlag = true;
  495.                 }
  496.             }

  497.             {//PM2.5显示
  498.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  499.                 string param;
  500.                 int dataLen = getCommand(source, PM, out param);
  501.                 if (dataLen > 0)
  502.                 {
  503.                     label_pm.Text = "PM2.5\r\n" + param[2] + param[3];
  504.                     buffer.RemoveRange(0, dataLen + 2);
  505.                     getDataFlag = true;
  506.                 }
  507.             }

  508.             {//温度显示
  509.                 string source = System.Text.Encoding.Default.GetString(buffer.ToArray());
  510.                 string param;
  511.                 int dataLen = getCommand(source, TEMPERATURE, out param);
  512.                 if (dataLen > 0)
  513.                 {
  514.                     label_temperature.Text = "温度\r\n" + param[0] + param[1] + "°C";
  515.                     label_humidity.Text = "湿度\r\n" + param[3] + param[4] + "%";
  516.                     buffer.RemoveRange(0, dataLen + 2);
  517.                     getDataFlag = true;
  518.                 }
  519.             }

  520.             //如果还存在结束符
  521.             int endPos = getFirstEndFlag();
  522.             if (endPos > -1)
  523.             {
  524.                 if (!getDataFlag)
  525.                 {
  526.                     buffer.RemoveRange(0, endPos + 2);
  527.                 }
  528.                 analysisData();
  529.             }
  530.         }

  531.         /*@end command Base********************************************/

  532.         public FormMain()
  533.         {
  534.             InitializeComponent();
  535.         }

  536.         private void FormMain_Load(object sender, EventArgs e)
  537.         {
  538.             SerialSettingInit();
  539.             //gboxSwithSetting.Enabled = false;
  540.             //gboxSwith2Setting.Enabled = false;
  541.             //gboxSwith3Setting.Enabled = false;
  542.         }

  543.         /*
  544.          * 作用:定义数据标志位,进而获取对应终端节点的数据
  545.          */
  546.         private const string LIGHT = "L";       //光敏亮度
  547.         private const string HUMAN = "H";       //人体感应
  548.         private const string FIRE = "F";        //火焰
  549.         private const string SMOKE = "S";       //烟雾
  550.         private const string PM = "P";          //PM2.5
  551.         private const string CURTAIN = "C";     //窗帘
  552.         private const string TEMPERATURE = "T"; //温度
  553.         private const string HUMIDITY = "D";    //湿度

  554.         private void txtThreshol_KeyPress(object sender, KeyPressEventArgs e)
  555.         {
  556.             if ((e.KeyChar < 48 || e.KeyChar > 57) && (e.KeyChar != 8))
  557.             {
  558.                 e.Handled = true;
  559.             }
  560.             base.OnKeyPress(e);
  561.         }

  562.         /*
  563.          * 作用:下发数据命令进行终端节点的控制,“L1”,“L0”,“S1”,“S0”
  564.          */

  565.         //
  566.         private void button1_Click_1(object sender, EventArgs e)
  567.         {
  568.             UartSend(createCommand(HUMAN, "1"));
  569.         }

  570.         //关警报2
  571.         private void button2_Click(object sender, EventArgs e)
  572.         {
  573.             UartSend(createCommand(HUMAN, "0"));
  574.         }

  575.         //
  576.         private void button3_Click(object sender, EventArgs e)
  577.         {
  578.             UartSend(createCommand(FIRE, "1"));
  579.         }

  580.         //关警报1
  581.         private void button4_Click(object sender, EventArgs e)
  582.         {
  583.             UartSend(createCommand(FIRE, "0"));
  584.         }

  585.         //开风扇
  586.         private void button5_Click(object sender, EventArgs e)
  587.         {
  588.             UartSend(createCommand(SMOKE, "1"));
  589.         }

  590.         //关风扇
  591.         private void button6_Click(object sender, EventArgs e)
  592.         {
  593.             UartSend(createCommand(SMOKE, "0"));
  594.         }

  595.         //开窗帘
  596.         private void button7_Click_1(object sender, EventArgs e)
  597.         {
  598.             UartSend(createCommand(CURTAIN, "1"));
  599.         }

  600.         //关窗帘
  601.         private void button8_Click(object sender, EventArgs e)
  602.         {
  603.             UartSend(createCommand(CURTAIN, "0"));
  604.         }

  605.         //开灯
  606.         private void button9_Click(object sender, EventArgs e)
  607.         {
  608.             UartSend(createCommand(LIGHT, "1"));
  609.         }

  610.         //关灯
  611.         private void button10_Click(object sender, EventArgs e)
  612.         {
  613.             UartSend(createCommand(LIGHT, "0"));
  614.         }
复制代码

C#代码下载: 智能家居(上位机).7z (703.6 KB, 下载次数: 83)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:84600 发表于 2022-11-24 09:13 | 显示全部楼层
现在正在学习这个,谢谢了。
回复

使用道具 举报

ID:1060941 发表于 2023-1-12 16:37 | 显示全部楼层
您好,我想请教一下 下位机如何处理上位机发送的指令L0、L1的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表