51采集PCF8591数据通过ESP8266上传C#上位机

来源:互联网 发布:mac怎么打开mobi文件 编辑:程序博客网 时间:2024/05/24 06:08

效果

     

如果想用手机做可以参考这篇文章,自己的协议规定在文章中

android 之TCP客户端编程

 

---恢复内容开始---

请问一下博客为什么又不能直接复制粘贴图片了呢............

 

先看8266的配置,8266我是用的Lua语言写的,,因为方便快捷....这次写的当然比以前完善......

关于WIFI模块可以看这几篇

ESP8266使用详解

NodeMCU初探

ESP8266刷AT固件与nodemcu固件

(一)Lua脚本语言入门
(二)Lua脚本语言入门
(三)Lua脚本语言入门
(四)Lua脚本语言入门
(五)Lua脚本语言入门

ESP8266使用详解--基于Lua脚本语言

最后加上一篇有人的WIFI模块,有人的做的也不错,当初项目就是用的有人的

有人WIFI模块使用详解

自己的ESP8266是建立服务器

我的init.lua

 

lighton=0pin = 4gpio.mode(pin,gpio.OUTPUT)tmr.alarm(0,500,1,function()  if lighton==0 then      lighton=1      gpio.write(pin,1)  else      lighton=0       gpio.write(pin,0)  endend)tmr.alarm(1, 3000, 0, function()      print("dofile wifi.lua...")      dofile("wifi.lua")end)

初始化呢,和我以前的一个地方不一样

tmr.alarm(1, 3000, 0, function()
      print("dofile wifi.lua...")
      dofile("wifi.lua")

我让模块3s以后再去加载的wifi.lua

说一下原因,,,因为我在wifi.lua里面设置的串口的数据直接发送到网口,,如果没有这个延时加载,一下子就执行了串口的数据直接发送到网口

那么下次想通过串口向模块发指令或者重新写入LUA程序就会出现问题,因为直接执行了串口的数据直接发送到网口,,有了这个延时我可以在复位的3s之前去操作模块了

再看一下wifi.lua

 

ConnectCnt = 0wifi.setmode(wifi.STATIONAP)cfg={}cfg.ssid="HiWifi8266"--模块的WIFI信号名字cfg.pwd="11223344"--密码wifi.ap.config(cfg)--写入配置wifi.sta.config("qqqqq","11223344")--模块连接的路由器名称和密码wifi.sta.connect()tmr.alarm(2, 3000, 1, function()--3s检测一次是否连接上路由器     if wifi.sta.getip() ~= nil then         tmr.stop(2)         print("Connected, IP is "..wifi.sta.getip())--打印分得的IP     endend)srv=net.createServer(net.TCP,28800)--创建TCP服务 tmr.alarm(3, 1000, 1, function()--1s进入一次看是否需要建立新的监听     if ConnectCnt == 0 then           srv:listen(8080,function(conn0)            print("Connect0")            ConnectCnt = 1                   if connect1 ~= nil then             connect1:close()          end            connect0 = conn0           conn0:on("receive",function(conn0,payload)            print(payload)            end)         end)    end        if ConnectCnt == 1 then        srv:listen(8080,function(conn1)             print("Connect1")             ConnectCnt = 2          if connect2 ~= nil then             connect2:close()          end            connect1 = conn1            conn1:on("receive",function(conn1,payload)                 print(payload)                 end)             end)       end                  if ConnectCnt == 2 then        srv:listen(8080,function(conn2)             print("Connect2")              ConnectCnt = 3          if connect3 ~= nil then             connect3:close()          end            connect2 = conn2            conn2:on("receive",function(conn2,payload)                 print(payload)                 end)             end)       end             if ConnectCnt == 3 then        srv:listen(8080,function(conn3)             print("Connect3")             ConnectCnt = 0          if connect0 ~= nil then             connect0:close()          end            connect3 = conn3            conn3:on("receive",function(conn3,payload)                 print(payload)                 end)             end)       endend)uart.setup(0,9600,8,0,1,0) uart.on("data",       function(data)       if connect0 ~= nil then         connect0:send(data)      end      if connect1 ~= nil then         connect1:send(data)      end       if connect2 ~= nil then          connect2:send(data)      end       if connect3 ~= nil then          connect3:send(data)      end          end, 0)

这次的建立服务可以连接3个客户端,也不知道到底能连接多少个,,,没测试,,就先写了3个

注意看一下哈,我是这样设置的

 if ConnectCnt == 0 then           srv:listen(8080,function(conn0)            print("Connect0")            ConnectCnt = 1                   if connect1 ~= nil then             connect1:close()          end            connect0 = conn0           conn0:on("receive",function(conn0,payload)            print(payload)            end)         end)    end

conn0连接就把conn1关掉,

conn1连接就把conn2关掉,

conn2连接就把conn3关掉,

conn03接就把conn0关掉,

所以呢现在做的最多可以3个客户端连接,,,,改天试一试能不能做到65535个连接......看看最多能连接多少个

最后的串口发送就不用说了,,,只是在原先的基础上先判断了是不是 nil 然后再发送

那就测试一下

连接模块的无线

其实也可以不用连接模块的无线,,因为模块连接路由器了,所以电脑或者手机连接路由器后可以连接模块连接路由器后分得的IP来测试

就用这四个来测试,用串口助手看信息,,对了模块默认内部IP:192.168.4.1

 

然后我挨个点击连接

现在连接了三个

 

现在发送数据

好再连接一个

再看一下发送数据

wifi模块算是做好了

对了可以连接路由器测试

只不过IP地址是刚才模块连接路由器后分得的IP

连接路由器的好处是可以做到远程控制

android客服端+eps8266+单片机+路由器之远程控制系统

现在做上位机部分

整体规划成这样

先写个函数获取本机的IP地址,然后填写到IP地址框

 

/// <获取本机 IP 地址>        ///         /// </summary>        /// <returns></returns>        private void getIPAddress()        {            IPAddress[] hostipspool = Dns.GetHostAddresses("");            comboBoxIPAdress.Items.Clear();            foreach (IPAddress ipa in hostipspool)            {                if (ipa.AddressFamily == AddressFamily.InterNetwork)                {                    comboBoxIPAdress.Items.Add(ipa.ToString());                    comboBoxIPAdress.SelectedIndex = comboBoxIPAdress.Items.Count > 0 ? 0 : -1;                }            }        }

程序加载的时候就搜索一下

 

 private void Form1_Load(object sender, EventArgs e)        {            getIPAddress();        }

然后在点击下拉框IP地址的下拉框的时候再搜索一下

 

/// <点击IP下拉框>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void comboBoxIPAdress_DropDown(object sender, EventArgs e)        {            getIPAddress();        }

启动一下看效果

这两个IP是这两个的

现在写点击按钮连接函数

先定义一个连接线程,一个保存IP地址的变量,一个保存端口号的变量,一个连接断开的标志变量,还有TcpClient

 

public partial class Form1 : Form    {        private Thread ConnectThread;//连接线程        private IPAddress ipAddress;//ip地址        int Port = 0;//端口号        Boolean ConnectFlage = false;//连接标志        private TcpClient myTcpClient = null;// TcpClient        public Form1()        {            InitializeComponent();        }

 

然后写个连接函数

 

 /// <连接线程方法>        ///         /// </summary>        private void ConnectMethod()        {            myTcpClient = new TcpClient();                      //实例化myTcpClient            try            {                myTcpClient.Connect(ipAddress, Port);//连接服务器                buttonConnect.Invoke(buttonConnectDelegate, "断开");                ConnectFlage = true;            }            catch (Exception)            {                //异常处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { myTcpClient.Close(); }                catch { }            }        }

 

 

然后在点击事件中获取IP和端口号,然后启动连接任务

 

/// <连接点击事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonConnect_Click(object sender, EventArgs e)        {            if (ConnectFlage == false)            {                if (string.IsNullOrEmpty(comboBoxIPAdress.Text) == false)                {                    ipAddress = IPAddress.Parse(comboBoxIPAdress.Text);//获取IP地址                    Port = Convert.ToInt32(textBoxPort.Text);          //获取端口号                    ConnectThread = new Thread(ConnectMethod);                    ConnectThread.Start();                }                else                {                    MessageBox.Show("请检查IP地址!", "提示");                }            }            else            {                //断开处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { myTcpClient.Close(); }                catch { }            }        }

 

对了写个按钮的回调来显示按钮的连接和断开

 

 Boolean ConnectFlage = false;//连接标志        private TcpClient myTcpClient = null;// TcpClient        private delegate void ButtonConnectDelegate(string str);//定义连接按钮回调        ButtonConnectDelegate buttonConnectDelegate;        public Form1()        {            InitializeComponent();        }        private void Form1_Load(object sender, EventArgs e)        {            buttonConnectDelegate = new ButtonConnectDelegate(buttonConnectMethod);//实例化            getIPAddress();        }


回调函数

/// <打开按钮回调函数>        ///         /// </summary>        private void buttonConnectMethod(string str)        {            buttonConnect.Text = str;        }

 

现在可以测试一下连接模块

 

对了这个现在模块好像是很长时间不和模块通信,模块就自动断开了服务,,,,好像为了低功耗吗....最后看一下怎么唤醒他,我现在是复位了一下

 

现在做一个函数来接收数据,然后把接收的数据显示到数据接收的显示框,数据框的回调函数也是必不可少的,还有定义一个接收任务

关于回调可以看一下

C#委托+回调详解

先定义一个networkstrem用来接收和发送网络数据流

其实C#的和JAVA的很类似

可以看一下

android 之TCP客户端编程

 

看一下现在的工程

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Windows.Forms;namespace TCPClient{    public partial class Form1 : Form    {        private Thread ConnectThread;//连接线程        private IPAddress ipAddress;//ip地址        int Port = 0;//端口号        Boolean ConnectFlage = false;//连接标志        private TcpClient myTcpClient = null;// TcpClient                private delegate void ButtonConnectDelegate(string str);//定义连接按钮回调        ButtonConnectDelegate buttonConnectDelegate;        private delegate void ShowReMsgTcpDelegate(byte[] by);//定义显示TCP接收消息回调        private ShowReMsgTcpDelegate showReMsgTcpDelegate;        private NetworkStream networkstrem = null;//网络数据流        private Thread ReceiveThread;//接收消息线程        public Form1()        {            InitializeComponent();        }        private void Form1_Load(object sender, EventArgs e)        {            buttonConnectDelegate = new ButtonConnectDelegate(buttonConnectMethod);//实例化            showReMsgTcpDelegate = new ShowReMsgTcpDelegate(ShowReMsgTcpMethod);//实例化显示回调            getIPAddress();        }        /// <获取本机 IP 地址>        ///         /// </summary>        /// <returns></returns>        private void getIPAddress()        {            IPAddress[] hostipspool = Dns.GetHostAddresses("");            comboBoxIPAdress.Items.Clear();            foreach (IPAddress ipa in hostipspool)            {                if (ipa.AddressFamily == AddressFamily.InterNetwork)                {                    comboBoxIPAdress.Items.Add(ipa.ToString());                    comboBoxIPAdress.SelectedIndex = comboBoxIPAdress.Items.Count > 0 ? 0 : -1;                }            }        }        /// <点击IP下拉框>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void comboBoxIPAdress_DropDown(object sender, EventArgs e)        {            getIPAddress();        }        /// <连接点击事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonConnect_Click(object sender, EventArgs e)        {            if (ConnectFlage == false)            {                if (string.IsNullOrEmpty(comboBoxIPAdress.Text) == false)                {                    ipAddress = IPAddress.Parse(comboBoxIPAdress.Text);//获取IP地址                    Port = Convert.ToInt32(textBoxPort.Text);          //获取端口号                    ConnectThread = new Thread(ConnectMethod);                    ConnectThread.Start();                }                else                {                    MessageBox.Show("请检查IP地址!", "提示");                }            }            else            {                //断开处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }                catch { }                try { networkstrem.Dispose(); }                catch { }                try { myTcpClient.Close(); }                catch { }            }        }        /// <连接线程方法>        ///         /// </summary>        private void ConnectMethod()        {            myTcpClient = new TcpClient();                      //实例化myTcpClient            try            {                myTcpClient.Connect(ipAddress, Port);//连接服务器                networkstrem = myTcpClient.GetStream();//获取数据流                ReceiveThread = new Thread(ReceiveDataMethod);//启动接收数据任务                ReceiveThread.Start();                buttonConnect.Invoke(buttonConnectDelegate, "断开");                ConnectFlage = true;            }            catch (Exception)            {                //异常处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }//销毁任务                catch { }                try { networkstrem.Dispose(); }//释放资源                catch { }                try { myTcpClient.Close(); }//关闭TCP                catch { }            }        }        /// <打开按钮回调函数>        ///         /// </summary>        private void buttonConnectMethod(string str)        {            buttonConnect.Text = str;        }        /// <显示串口接收到的信息--回调函数>        ///         /// </summary>        private void ShowReMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            if (checkBoxHexShow.Checked)//16进制显示            {                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串             }            else            {                getMsg = new ASCIIEncoding().GetString(by);            }            textBoxDataRes.AppendText(getMsg);        }        /// <字节数组转16进制字符串>        ///         /// </summary>        /// <param name="bytes"></param>        /// <returns></returns>        public static string byteToHexStr(byte[] bytes)        {            string returnStr = "";            try            {                if (bytes != null)                {                    for (int i = 0; i < bytes.Length; i++)                    {                        returnStr += bytes[i].ToString("X2");                    }                }                return returnStr;            }            catch (Exception)            {                return returnStr;            }        }        /// <接收消息线程>        ///         /// </summary>        private void ReceiveDataMethod()        {            int RecvCnt = 0;            byte[] recvBytes = new byte[1024];            while (true)            {                try                {                    if ((myTcpClient.Client.Poll(20, SelectMode.SelectRead)) && (myTcpClient.Client.Available == 0))                    {                        myTcpClient.Close();//引发异常                    }                    RecvCnt = networkstrem.Read(recvBytes, 0, recvBytes.Length);                    byte[] receive = new byte[RecvCnt];//设置缓冲区  RecvCnt  个字节                    for (int i = 0; i < receive.Length; i++)                    {                        receive[i] = recvBytes[i];                    }                    textBoxDataRes.Invoke(showReMsgTcpDelegate, receive);                }                catch (Exception)                {                    //异常处理函数                    ConnectFlage = false;                    buttonConnect.Invoke(buttonConnectDelegate, "连接");                    try { ReceiveThread.Abort(); }//销毁任务                    catch { }                    try { networkstrem.Dispose(); }//释放资源                    catch { }                    try { myTcpClient.Close(); }//关闭TCP                    catch { }                }            }        }    }}

 


看一下显示回调函数

/// <显示串口接收到的信息--回调函数>        ///         /// </summary>        private void ShowReMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            if (checkBoxHexShow.Checked)//16进制显示            {                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串             }            else            {                getMsg = new ASCIIEncoding().GetString(by);            }            textBoxDataRes.AppendText(getMsg);        }

这个函数 byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串

/// <字节数组转16进制字符串>        ///         /// </summary>        /// <param name="bytes"></param>        /// <returns></returns>        public static string byteToHexStr(byte[] bytes)        {            string returnStr = "";            try            {                if (bytes != null)                {                    for (int i = 0; i < bytes.Length; i++)                    {                        returnStr += bytes[i].ToString("X2");                    }                }                return returnStr;            }            catch (Exception)            {                return returnStr;            }        }

 

那么接收数据的函数

 

/// <接收消息线程>        ///         /// </summary>        private void ReceiveDataMethod()        {            int RecvCnt = 0;            byte[] recvBytes = new byte[1024];            while (true)            {                try                {                    if ((myTcpClient.Client.Poll(20, SelectMode.SelectRead)) && (myTcpClient.Client.Available == 0))                    {                        myTcpClient.Close();//引发异常                    }                    RecvCnt = networkstrem.Read(recvBytes, 0, recvBytes.Length);                    byte[] receive = new byte[RecvCnt];//设置缓冲区  RecvCnt  个字节                    for (int i = 0; i < receive.Length; i++)                    {                        receive[i] = recvBytes[i];                    }                    textBoxDataRes.Invoke(showReMsgTcpDelegate, receive);                }                catch (Exception)                {                    //异常处理函数                    ConnectFlage = false;                    buttonConnect.Invoke(buttonConnectDelegate, "连接");                    try { ReceiveThread.Abort(); }//销毁任务                    catch { }                    try { networkstrem.Dispose(); }//释放资源                    catch { }                    try { myTcpClient.Close(); }//关闭TCP                    catch { }                }            }        }

 

里面的这里是判断TCP是不是断开了连接,,如果断开了执行myTcpClient.Close()就会引发异常

if ((myTcpClient.Client.Poll(20, SelectMode.SelectRead)) && (myTcpClient.Client.Available == 0))
  {
        myTcpClient.Close();//引发异常
  }


 

现在连接模块然后用串口助手发数据

 

 已经能接收到数据了,现在呢,做发送数据

 

 /// <发送按钮点击事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonSend_Click(object sender, EventArgs e)        {            if (!checkBoxHexSend.Checked)//字符发送            {                byte[] sendbyte = Encoding.Default.GetBytes(textBoxSend.Text);                try { networkstrem.Write(sendbyte, 0, sendbyte.Length); }                catch (Exception) { MessageBox.Show("请检查连接", "提示!"); }            }            else//16形式进制发送            {                byte[] sendbyte = strToToHexByte(textBoxSend.Text);//字符串转16进制格式,不够自动前面补零                try { networkstrem.Write(sendbyte, 0, sendbyte.Length); }                catch (Exception) { MessageBox.Show("请检查连接", "提示!"); }            }        }


 

/// <字符串转16进制格式,不够自动前面补零>        ///         /// </summary>        /// <param name="hexString"></param>        /// <returns></returns>        private static byte[] strToToHexByte(String hexString)        {            int i;            bool Flag = false;            hexString = hexString.Replace(" ", "");//清除空格            if ((hexString.Length % 2) != 0)            {                Flag = true;            }            if (Flag == true)            {                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];                try                {                    for (i = 0; i < (hexString.Length - 1) / 2; i++)                    {                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);                    }                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);                }                catch                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = 0;                    }                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");                }                return returnBytes;            }            else            {                byte[] returnBytes = new byte[(hexString.Length) / 2];                try                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);                    }                }                catch                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = 0;                    }                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");                }                return returnBytes;            }        }

 

 

现在测试一下发送数据

 

 

对了

当点击这两个的时候,对应数据框里面的内容应该相应的变化

直接在点击函数里面设置

 

 /// <发送Hex和字符串选择>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void checkBoxHexSend_CheckedChanged(object sender, EventArgs e)        {            if (checkBoxHexSend.Checked)            {                try                {                    byte[] by = StringToByte(textBoxSend.Text);                    textBoxSend.Clear();                    textBoxSend.BeginInvoke(showSeMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }            else            {                try                {                    byte[] by = strToToHexByte(textBoxSend.Text);                    textBoxSend.Clear();                    textBoxSend.BeginInvoke(showSeMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }        }        /// <接收Hex和字符串选择>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void checkBoxHexShow_CheckedChanged(object sender, EventArgs e)        {            if (checkBoxHexShow.Checked)            {                try                {                    byte[] by = StringToByte(textBoxDataRes.Text);                    textBoxDataRes.BeginInvoke(showReMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }            else            {                try                {                    byte[] by = strToToHexByte(textBoxDataRes.Text);                    textBoxDataRes.Clear();                    textBoxDataRes.BeginInvoke(showReMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }        }

其实在优化应是用回调来做,,,,等做下一个画波形图的时候在说,现在做界面看不出来卡顿

现在呢做的差不多了,,规定一下协议

 

上位机发送0xaa,0x55,0x01,CRC//读取采集的电压数据单片机返回0xaa,0x55,0x01,采集电压数据AD0(4字节Float型),AD1,AD2,AD3,CRC//单片机返回//上位机发送0xaa,0x55,0x02,设置的输出电压(单字节),CRC//设置输出的电压

就写一个任务,,方便点用定时器吧,,然后如果判断连接上服务器了每隔100ms发送一次采集数据的命令

 

/// <定时发送事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void timer1_Tick(object sender, EventArgs e)        {            byte[] sendbyte = new byte[3];            sendbyte[0] = 0xaa;            sendbyte[1] = 0x55;            sendbyte[2] = 0x01;            SerialSend(sendbyte);        }

 

/// <网络发送数据函数>        ///         /// </summary>        /// <param name="sendbyte"></param>        private void SerialSend(byte[] byt)        {            int crc = 0;            byte[] sendbyte = new byte[byt.Length + 2];            for (int i = 0; i < byt.Length; i++)            {                sendbyte[i] = byt[i];            }            crc = crc16_modbus(byt, byt.Length);//计算CRC            byte[] Crcbyte = System.BitConverter.GetBytes(crc);//得到CRC            sendbyte[sendbyte.Length - 2] = Crcbyte[0];            sendbyte[sendbyte.Length - 1] = Crcbyte[1];            try             {                 networkstrem.Write(sendbyte, 0, sendbyte.Length);             }            catch (Exception)             {                //异常处理函数                ConnectFlage = false;                timer1.Stop();//停止定时器                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }//销毁任务                catch { }                try { networkstrem.Dispose(); }//释放资源                catch { }                try { myTcpClient.Close(); }//关闭TCP                catch { }                                MessageBox.Show("请检查连接", "提示!");             }        }

 

定时器呢在这里面启动

 

/// <打开按钮回调函数>        ///         /// </summary>        private void buttonConnectMethod(string str)        {            if (str == "断开")            {                timer1.Enabled = true;                timer1.Start();//启动定时器            }            else            {                timer1.Enabled = false;                timer1.Stop();//停止定时器            }            buttonConnect.Text = str;        }


现在的代码

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;using System.Windows.Forms;namespace TCPClient{    public partial class Form1 : Form    {        private Thread ConnectThread;//连接线程        private IPAddress ipAddress;//ip地址        int Port = 0;//端口号        Boolean ConnectFlage = false;//连接标志        private TcpClient myTcpClient = null;// TcpClient                private delegate void ButtonConnectDelegate(string str);//定义连接按钮回调        ButtonConnectDelegate buttonConnectDelegate;        private delegate void ShowReMsgTcpDelegate(byte[] by);//定义显示TCP接收消息回调        private ShowReMsgTcpDelegate showReMsgTcpDelegate;        private NetworkStream networkstrem = null;//网络数据流        private Thread ReceiveThread;//接收消息线程        private Thread ShowDataThread;//显示任务,点击Hex显示时        private delegate void ShowSeMsgTcpDelegate(byte[] by);//定义显示TCP发送消息回调        private ShowSeMsgTcpDelegate showSeMsgTcpDelegate;        public Form1()        {            InitializeComponent();        }        private void Form1_Load(object sender, EventArgs e)        {            timer1.Stop();//启动定时器            buttonConnectDelegate = new ButtonConnectDelegate(buttonConnectMethod);//实例化            showReMsgTcpDelegate = new ShowReMsgTcpDelegate(ShowReMsgTcpMethod);//实例化显示回调            showSeMsgTcpDelegate = new ShowSeMsgTcpDelegate(showSeMsgTcpMethod);//实例化发送回调            getIPAddress();        }        /// <获取本机 IP 地址>        ///         /// </summary>        /// <returns></returns>        private void getIPAddress()        {            IPAddress[] hostipspool = Dns.GetHostAddresses("");            comboBoxIPAdress.Items.Clear();            foreach (IPAddress ipa in hostipspool)            {                if (ipa.AddressFamily == AddressFamily.InterNetwork)                {                    comboBoxIPAdress.Items.Add(ipa.ToString());                    comboBoxIPAdress.SelectedIndex = comboBoxIPAdress.Items.Count > 0 ? 0 : -1;                }            }        }        /// <点击IP下拉框>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void comboBoxIPAdress_DropDown(object sender, EventArgs e)        {            getIPAddress();        }        /// <连接点击事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonConnect_Click(object sender, EventArgs e)        {            if (ConnectFlage == false)            {                if (string.IsNullOrEmpty(comboBoxIPAdress.Text) == false)                {                    ipAddress = IPAddress.Parse(comboBoxIPAdress.Text);//获取IP地址                    Port = Convert.ToInt32(textBoxPort.Text);          //获取端口号                    ConnectThread = new Thread(ConnectMethod);                    ConnectThread.Start();                }                else                {                    MessageBox.Show("请检查IP地址!", "提示");                }            }            else            {                //断开处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }                catch { }                try { networkstrem.Dispose(); }                catch { }                try { myTcpClient.Close(); }                catch { }            }        }        /// <连接线程方法>        ///         /// </summary>        private void ConnectMethod()        {            myTcpClient = new TcpClient();                      //实例化myTcpClient            try            {                myTcpClient.Connect(ipAddress, Port);//连接服务器                networkstrem = myTcpClient.GetStream();//获取数据流                ReceiveThread = new Thread(ReceiveDataMethod);//启动接收数据任务                ReceiveThread.Start();                               buttonConnect.Invoke(buttonConnectDelegate, "断开");                ConnectFlage = true;            }            catch (Exception)            {                //异常处理函数                ConnectFlage = false;                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }//销毁任务                catch { }                try { networkstrem.Dispose(); }//释放资源                catch { }                try { myTcpClient.Close(); }//关闭TCP                catch { }            }        }        /// <打开按钮回调函数>        ///         /// </summary>        private void buttonConnectMethod(string str)        {            if (str == "断开")            {                timer1.Enabled = true;                timer1.Start();//启动定时器            }            else            {                timer1.Enabled = false;                timer1.Stop();//停止定时器            }            buttonConnect.Text = str;        }        /// <显示串口接收到的信息--回调函数>        ///         /// </summary>        private void ShowReMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            if (checkBoxHexShow.Checked)//16进制显示            {                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串             }            else            {                getMsg = new ASCIIEncoding().GetString(by);            }            textBoxDataRes.AppendText(getMsg);        }        private void showSeMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            if (checkBoxHexSend.Checked)//16进制显示            {                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串             }            else            {                getMsg = new ASCIIEncoding().GetString(by);            }            textBoxSend.AppendText(getMsg);        }        /// <字节数组转16进制字符串>        ///         /// </summary>        /// <param name="bytes"></param>        /// <returns></returns>        public static string byteToHexStr(byte[] bytes)        {            string returnStr = "";            try            {                if (bytes != null)                {                    for (int i = 0; i < bytes.Length; i++)                    {                        returnStr += bytes[i].ToString("X2");                    }                }                return returnStr;            }            catch (Exception)            {                return returnStr;            }        }        /// <接收消息线程>        ///         /// </summary>        private void ReceiveDataMethod()        {            int RecvCnt = 0;            byte[] recvBytes = new byte[1024];            while (true)            {                try                {                    if ((myTcpClient.Client.Poll(20, SelectMode.SelectRead)) && (myTcpClient.Client.Available == 0))                    {                        myTcpClient.Close();//引发异常                    }                    RecvCnt = networkstrem.Read(recvBytes, 0, recvBytes.Length);                    byte[] receive = new byte[RecvCnt];//设置缓冲区  RecvCnt  个字节                    for (int i = 0; i < receive.Length; i++)                    {                        receive[i] = recvBytes[i];                    }                    textBoxDataRes.Invoke(showReMsgTcpDelegate, receive);                }                catch (Exception)                {                    //异常处理函数                    ConnectFlage = false;                    buttonConnect.Invoke(buttonConnectDelegate, "连接");                    try { ReceiveThread.Abort(); }//销毁任务                    catch { }                    try { networkstrem.Dispose(); }//释放资源                    catch { }                    try { myTcpClient.Close(); }//关闭TCP                    catch { }                }            }        }        /// <发送按钮点击事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonSend_Click(object sender, EventArgs e)        {            if (!checkBoxHexSend.Checked)//字符发送            {                byte[] sendbyte = Encoding.Default.GetBytes(textBoxSend.Text);                try { networkstrem.Write(sendbyte, 0, sendbyte.Length); }                catch (Exception) { MessageBox.Show("请检查连接", "提示!"); }            }            else//16形式进制发送            {                byte[] sendbyte = strToToHexByte(textBoxSend.Text);//字符串转16进制格式,不够自动前面补零                try { networkstrem.Write(sendbyte, 0, sendbyte.Length); }                catch (Exception) { MessageBox.Show("请检查连接", "提示!"); }            }        }        /// <字符串转16进制格式,不够自动前面补零>        ///         /// </summary>        /// <param name="hexString"></param>        /// <returns></returns>        private static byte[] strToToHexByte(String hexString)        {            int i;            bool Flag = false;            hexString = hexString.Replace(" ", "");//清除空格            if ((hexString.Length % 2) != 0)            {                Flag = true;            }            if (Flag == true)            {                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];                try                {                    for (i = 0; i < (hexString.Length - 1) / 2; i++)                    {                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);                    }                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);                }                catch                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = 0;                    }                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");                }                return returnBytes;            }            else            {                byte[] returnBytes = new byte[(hexString.Length) / 2];                try                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);                    }                }                catch                {                    for (i = 0; i < returnBytes.Length; i++)                    {                        returnBytes[i] = 0;                    }                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");                }                return returnBytes;            }        }        /// <字符串转换成字节数组>        ///         /// </summary>        /// <param name="stringToConvert"></param>        /// <returns></returns>        public static byte[] StringToByte(string stringToConvert)        {            return (new ASCIIEncoding()).GetBytes(stringToConvert);        }        /// <发送Hex和字符串选择>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void checkBoxHexSend_CheckedChanged(object sender, EventArgs e)        {            if (checkBoxHexSend.Checked)            {                try                {                    byte[] by = StringToByte(textBoxSend.Text);                    textBoxSend.Clear();                    textBoxSend.BeginInvoke(showSeMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }            else            {                try                {                    byte[] by = strToToHexByte(textBoxSend.Text);                    textBoxSend.Clear();                    textBoxSend.BeginInvoke(showSeMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }        }        /// <接收Hex和字符串选择>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void checkBoxHexShow_CheckedChanged(object sender, EventArgs e)        {            if (checkBoxHexShow.Checked)            {                try                {                    byte[] by = StringToByte(textBoxDataRes.Text);                    textBoxDataRes.BeginInvoke(showReMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }            else            {                try                {                    byte[] by = strToToHexByte(textBoxDataRes.Text);                    textBoxDataRes.Clear();                    textBoxDataRes.BeginInvoke(showReMsgTcpDelegate, by);                }                catch (Exception)                {                    //MessageBox.Show(ex.ToString());                }            }        }        /// <清除接收>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonClearRecv_Click(object sender, EventArgs e)        {            textBoxDataRes.Clear();        }        /// <清除发送>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void buttonClearSend_Click(object sender, EventArgs e)        {            textBoxSend.Clear();        }        /// <设置DA输出>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void trackBarDAout_Scroll(object sender, EventArgs e)        {            textBoxDAout.Text = trackBarDAout.Value.ToString();        }        /// <CRC  效验  >        ///         /// </summary>        /// <param name="modbusdata"></param>        /// <param name="length"></param>        /// <returns></returns>        private int crc16_modbus(byte[] modbusdata, int length)        {            int i, j;            int crc = 0xffff;            try            {                for (i = 0; i < length; i++)                {                    crc ^= modbusdata[i];                    for (j = 0; j < 8; j++)                    {                        if ((crc & 0x01) == 1)                        {                            crc = (crc >> 1) ^ 0xa001;                        }                        else                        {                            crc >>= 1;                        }                    }                }            }            catch (Exception)            {                throw;            }            return crc;        }        /*          modbusdata   要校验的数据          length       数据长度          返回值 1 正确  0 错误        */        private int crc16_flage(byte[] modbusdata, int length)        {            int Receive_CRC = 0, calculation = 0;//接收到的CRC,计算的CRC            Receive_CRC = crc16_modbus(modbusdata, length);            calculation = modbusdata[length + 1];            calculation <<= 8;            calculation += modbusdata[length];            if (calculation != Receive_CRC)            {                return 0;            }            return 1;        }        /// <定时发送事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void timer1_Tick(object sender, EventArgs e)        {            byte[] sendbyte = new byte[3];            sendbyte[0] = 0xaa;            sendbyte[1] = 0x55;            sendbyte[2] = 0x01;            SerialSend(sendbyte);        }        /// <网络发送数据函数>        ///         /// </summary>        /// <param name="sendbyte"></param>        private void SerialSend(byte[] byt)        {            int crc = 0;            byte[] sendbyte = new byte[byt.Length + 2];            for (int i = 0; i < byt.Length; i++)            {                sendbyte[i] = byt[i];            }            crc = crc16_modbus(byt, byt.Length);//计算CRC            byte[] Crcbyte = System.BitConverter.GetBytes(crc);//得到CRC            sendbyte[sendbyte.Length - 2] = Crcbyte[0];            sendbyte[sendbyte.Length - 1] = Crcbyte[1];            try             {                 networkstrem.Write(sendbyte, 0, sendbyte.Length);             }            catch (Exception)             {                //异常处理函数                ConnectFlage = false;                timer1.Stop();//停止定时器                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }//销毁任务                catch { }                try { networkstrem.Dispose(); }//释放资源                catch { }                try { myTcpClient.Close(); }//关闭TCP                catch { }                                MessageBox.Show("请检查连接", "提示!");             }        }    }}
View Code

测试一下

然后呢,设置一下这个好弄得

 

 协议的规定

//上位机发送
0xaa,0x55,0x02,设置的输出电压(单字节),CRC//设置输出的电压

 

/// <设置DA输出>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void trackBarDAout_Scroll(object sender, EventArgs e)        {            byte[] sendbyte = new byte[4];            sendbyte[0] = 0xaa;            sendbyte[1] = 0x55;            sendbyte[2] = 0x02;            sendbyte[3] = Convert.ToByte(trackBarDAout.Value);            SerialSend(sendbyte);            textBoxDAout.Text = trackBarDAout.Value.ToString();        }

只要滑动这个滑动条就把当前滑动条的数据发给Wifi模块

现在写接收数据的函数,然后显示在相应的位置

 

 

/// <显示串口接收到的信息--回调函数>        ///         /// </summary>        private void ShowReMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            if (checkBoxHexShow.Checked)//16进制显示            {                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串             }            else            {                getMsg = new ASCIIEncoding().GetString(by);            }            if (by[0] == 0xaa && by[1] == 0x55)            {                if (crc16_flage(by, by.Length - 2) == 1)//CRC校验正确                {                    if (by[2] == 0x01)                    {                        float f1 = BitConverter.ToSingle(by, 3);                        float f2 = BitConverter.ToSingle(by, 7);                        float f3 = BitConverter.ToSingle(by, 11);                        float f4 = BitConverter.ToSingle(by, 15);                        textBoxAD0.Text = f1.ToString();                        textBoxAD1.Text = f2.ToString();                        textBoxAD2.Text = f3.ToString();                        textBoxAD3.Text = f4.ToString();                    }                }            }            textBoxDataRes.AppendText(getMsg);        }

 

 就加上这几句

 if (by[0] == 0xaa && by[1] == 0x55)            {                if (crc16_flage(by, by.Length - 2) == 1)//CRC校验正确                {                    if (by[2] == 0x01)                    {                        float f1 = BitConverter.ToSingle(by, 3);                        float f2 = BitConverter.ToSingle(by, 7);                        float f3 = BitConverter.ToSingle(by, 11);                        float f4 = BitConverter.ToSingle(by, 15);                        textBoxAD0.Text = f1.ToString();                        textBoxAD1.Text = f2.ToString();                        textBoxAD2.Text = f3.ToString();                        textBoxAD3.Text = f4.ToString();                    }                }            }

关于FLoat的转换,先给大家一篇文章

链接:http://pan.baidu.com/s/1ck2m7O%20密码:rmsg

 单片机程序中会做转换介绍,其实就是用共用体,,上位机呢就是用那个方法解析

现在测试一下,把数据220.5发给上位机

 

 好了上位机测试没有问题了

我后来改了一些地方

协议变成了一条

0xaa,0x55,0x01,(设置的电压值),CRC16校验

 

 /// <定时发送事件>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void timer1_Tick(object sender, EventArgs e)        {            byte[] sendbyte = new byte[4];            sendbyte[0] = 0xaa;            sendbyte[1] = 0x55;            sendbyte[2] = 0x01;            sendbyte[3] = trackBarValue[0];//滑动条的值            SerialSend(sendbyte);        }

 

滑动控件的事件

 

 /// <设置DA输出>        ///         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void trackBarDAout_Scroll(object sender, EventArgs e)        {            trackBarValue[0] = Convert.ToByte(trackBarDAout.Value);            textBoxDAout.Text = trackBarDAout.Value.ToString();        }

 

 

这里面加了个try,,是因为不能保证数据传输的时候没有错误的时候

/// <显示串口接收到的信息--回调函数>        ///         /// </summary>        private void ShowReMsgTcpMethod(byte[] by)        {            string getMsg = string.Empty;            try            {                if (checkBoxHexShow.Checked)//16进制显示                {                    getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串                 }                else                {                    getMsg = new ASCIIEncoding().GetString(by);                }                if (by[0] == 0xaa && by[1] == 0x55)                {                    if (crc16_flage(by, by.Length - 2) == 1)//CRC校验正确                    {                        if (by[2] == 0x01)                        {                            float f1 = BitConverter.ToSingle(by, 3);                            float f2 = BitConverter.ToSingle(by, 7);                            float f3 = BitConverter.ToSingle(by, 11);                            float f4 = BitConverter.ToSingle(by, 15);                            textBoxAD0.Text = f1.ToString();                            textBoxAD1.Text = f2.ToString();                            textBoxAD2.Text = f3.ToString();                            textBoxAD3.Text = f4.ToString();                        }                    }                }            }            catch (Exception)            {            }                        textBoxDataRes.AppendText(getMsg);        }

 

 

现在做单片机的程序

程序呢说几个地方

 

typedef union Resolverf//51是大端模式,32默认小端模式{    float Data;    unsigned char  Data_Table[4];}ResolverfData;typedef union ResolverLong{    long Data;    unsigned char  Data_Table[4];}ResolverLongData;

最后做完了发现了一个问题,这个模块刷入Lua语言后,把数据通过WIFI发给模块,模块内部默认的是遇到'\0'后认为是一条数据,,所以呢

当发送的byte数组里面的值是0的时候数据就会出现问题,直接把0以前的数据发过去了.

所以自己做了下设置

 

 /// <网络发送数据函数>        ///         /// </summary>        /// <param name="sendbyte"></param>        private void SerialSend(byte[] byt)        {            int crc = 0;            byte[] sendbyte = new byte[byt.Length + 4];//加一个检测数据的,CRC,最后结尾判断CRC            byte[] Change0 = new byte[1];//检测数据用            Change0[0] = 0xff;//初始化为FF,哪位数据为0就把相应的数据位变为1,检测的为变为0            for (int i = 0; i < byt.Length; i++)            {                sendbyte[i] = byt[i];                if (sendbyte[i] == 0x00)                {                    sendbyte[i] = 0x01;                    switch(i)                    {                        case 0: Change0[0] &= 0xfe; break;                        case 1: Change0[0] &= 0xfd; break;                        case 2: Change0[0] &= 0xfb; break;                        case 3: Change0[0] &= 0xf7; break;                        case 4: Change0[0] &= 0xef; break;                        case 5: Change0[0] &= 0xdf; break;                        case 6: Change0[0] &= 0xbf; break;                    }                }            }            sendbyte[sendbyte.Length-4] = Change0[0];            crc = crc16_modbus(sendbyte, sendbyte.Length-3);//计算CRC            byte[] Crcbyte = System.BitConverter.GetBytes(crc);//得到CRC            sendbyte[sendbyte.Length - 3] = Crcbyte[0];            sendbyte[sendbyte.Length - 2] = Crcbyte[1];            sendbyte[sendbyte.Length - 1] = 0xff;            if (sendbyte[sendbyte.Length - 3] == 0x00)            {                sendbyte[sendbyte.Length - 3] = 0x01;                sendbyte[sendbyte.Length - 1] = 0xF0;            }            if (sendbyte[sendbyte.Length - 2] == 0x00)            {                sendbyte[sendbyte.Length - 2] = 0x01;                sendbyte[sendbyte.Length - 1] = 0x0F;            }            try             {                if (networkstrem.CanWrite)                {                    networkstrem.Write(sendbyte, 0, sendbyte.Length);                }            }            catch (Exception)             {                //异常处理函数                ConnectFlage = false;                timer1.Stop();//停止定时器                buttonConnect.Invoke(buttonConnectDelegate, "连接");                try { ReceiveThread.Abort(); }//销毁任务                catch { }                try { networkstrem.Dispose(); }//释放资源                catch { }                try { myTcpClient.Close(); }//关闭TCP                catch { }                                MessageBox.Show("请检查连接", "提示!");             }        }

想法就是在数据的后面用一个字节来标识前面的数据哪些是0,对了如果数据是0,就把数据改为1,

0xaa, 0x55, 0x01, DA值, 标识前面哪些数据是0, CRC低位, CRC高位, 标识CRC有没有0

 

假如说 DA值是0,那么把数据变成0x01,然后标识下

0xaa,0x55,0x01,0x01,0xf7,CRC低位,CRC高位,0xFF(假设校验没有0)

 

如果CRC低位也是0那么

0xaa,0x55,0x01,0x01,0xf7,CRC低位,CRC高位,0xF0

 

如果CRC高位也是0那么

0xaa,0x55,0x01,0x01,0xf7,CRC低位,CRC高位,0x0F

其实可以用字符串格式发送,就不用麻烦了

 

 

单片机解析

/*** @brief  数据发送方法* @param  * @param  None* @param  None* @retval None* @example **/void DataSendMethod(){  if(UsartFlage == 1)//接收到数据    {        if(UsartReceive[7] != 0xff)//CRC校验有0数据        {           if(UsartReceive[7] == 0xf0)//看一下CRC低位是0还是高位是0            {UsartReceive[5] = 0;}            if(UsartReceive[7] == 0x0f)            {UsartReceive[6] = 0;}        }                if(crc16_flage(UsartReceive, UsartReadCntCopy-5))//校验数据        {            if(UsartReceive[4]!=0xFF)//有0数据            {                switch(UsartReceive[4])//找到哪一位是0数据,修改过来                {                    case 0xFE: UsartReceive[0] = 0; break;//0位                    case 0xFD: UsartReceive[1] = 0; break;//1位                    case 0xFB: UsartReceive[2] = 0; break;//2位                    case 0xF7: UsartReceive[3] = 0; break;//3位                    case 0xEF: UsartReceive[4] = 0; break;//4位                    case 0xDF: UsartReceive[5] = 0; break;//5位                    case 0xBF: UsartReceive[6] = 0; break;//6位                }            }            if(UsartReceive[0] == 0xaa && UsartReceive[1] == 0x55)            {                UsartFlage = 0;                                switch(UsartReceive[2])                {                    case 0x01:  SetDAValue(); SendADValue(); break;//设置输出的电压,发送采集的电压                    default:  break;                }            }        }        else        {           UsartFlage = 0;        }    } }

 

 

 

 

一,关于大小端

关于大小端---数据的低位存在低地址,高位存在高地址就是小端模式

关于大小端---数据的低位存在高地址,高位存在低地址就是大端模式

传输float数据直接用共用体解决,可以看看上面的青智仪表的文章,,,这个用的挺多的,,几乎所有设备的浮点型数据都是这样存储的,,,,,,

 

二,51单片机使用printf,,,我程序里能使用printf,,不过说一点注意的地方

如果51想用printf发送数据,加上这个函数,其实也可以不加,,,不过必须在初始化的时候TI必须一直为 1 但是这样的话就会有问题,程序一直进入串口中断......会造成主程序卡卡卡卡.......

 

/* 用自带的printf 发送数据 */char putchar(char c)  {      UartSend(c);      return c;  }  

别忘了包含

 

#include "stdio.h"#include <stdarg.h> 

可以看一下这篇文章

http://blog.csdn.net/googlemi/article/details/8996605

发送数据

printf("%d",(unsigned int)Value);注意Value如果是char 或者 unsigned char 这样的时候要加强制转换

可以看一下这篇

http://taihang604.blog.163.com/blog/static/20834216520125185579173/

 

三,关于51单片机里面的CRC16校验

记住:操作的数据,,定义的数据类型要定义成 unsigned char  或者 unsigned int 类型的,,否则会算错的

/*** @brief  计算CRC* @param  *modbusdata:数据指针* @param  length:数据长度* @param  * @retval 计算的CRC值* @example **/unsigned int crc16_modbus(unsigned char *modbusdata, char length){    char i, j;    unsigned int crc = 0xffff;    for (i = 0; i < length; i++)    {        crc ^= modbusdata[i];        for (j = 0; j < 8; j++)        {                if ((crc & 0x01) == 1)                {                        crc = (crc >> 1) ^ 0xa001;                }                else                {                        crc >>= 1;                }        }    }        return crc;}/*** @brief  判断数据的CRC校验是否正确* @param  *modbusdata:数据指针* @param  length:数据长度* @param  * @retval 1 正确  0 错误* @example **/char crc16_flage(unsigned char *modbusdata, char length){    unsigned int Receive_CRC=0,calculation=0;//接收到的CRC,计算的CRC    int i = 0;        Receive_CRC = crc16_modbus(modbusdata, length);        calculation = modbusdata[length+1];    calculation <<= 8;    calculation += modbusdata[length];        if(calculation != Receive_CRC)    {        return 0;    }    return 1;}


 

四,51单片机的发送数据我是用中断发送的

只需要把准备好的数据调用这个函数

 

/*** @brief  串口发送函数中断函数* @param  * @param  None* @param  None* @retval None* @example **/void UartSendTI(unsigned char *value,int DataLen) {    UsartSendData = value;    UsartSendDataCnt = DataLen;    TI = 1;}

 

 

 

/*** @brief  串口发送函数中断函数* @param  * @param  None* @param  None* @retval None* @example **/void UartSendTI(unsigned char *value,int DataLen) {    UsartSendData = value;    UsartSendDataCnt = DataLen;    TI = 1;}void UARTInterrupt(void) interrupt 4{    if(RI)    {        RI=0;        UsartReceive[UsartReadCnt]=SBUF;//接收串口数据        UsartReadCnt++;        if(UsartReadCnt>8)//防止溢出        {            UsartReadCnt = 0;        }    }    if(TI)    {        TI = 0;        if(UsartSendDataCnt>0)        {          SBUF = *UsartSendData++;          UsartSendDataCnt--;        }        else        {          TI = 0;        }  }}

 

 

五,串口接收和以前一样用的空闲检测

 

void Timer0Interrupt(void) interrupt 1{    TH0 = (65536 - 1000)/256;    TL0 = (65536 - 1000)%256;        //TimeCnt ++;        if (UsartReadCnt != 0)//如果接收到数据了    {            if (UsartIdleCnt == UsartReadCnt)//1ms时间数据没了变化            {                UsartReadCntCopy = UsartReadCnt;                UsartReadCnt = 0;//清零数据个数                UsartIdleCnt = 0;//清零                UsartFlage = 1;            }            else            {                UsartIdleCnt = UsartReadCnt;            }    }}

 


说一下IIC,,因为当初一个学弟问过我,简要说一下

IIC协议规定发送数据的时候要先发一个起始信号,,,也就是告诉对方我开始和你通信了

函数原型: void  Start_I2c();  功能:     启动I2C总线,即发送I2C起始条件.  ********************************************************************/void Start_I2c(){  SDA=1;         /*发送起始条件的数据信号*/  _Nop();  SCL=1;  _Nop();        /*起始条件建立时间大于4.7us,延时*/  _Nop();  _Nop();  _Nop();  _Nop();      SDA=0;         /*发送起始信号*/  _Nop();        /* 起始条件锁定时间大于4μs*/  _Nop();  _Nop();  _Nop();  _Nop();         SCL=0;       /*钳住I2C总线,准备发送或接收数据 */  _Nop();  _Nop();}


 

然后呢,发送器件的地址,,因为可能挂接了好几个IIC设备,目的是找到我想与之通信的那个,

看一下发送数据,,,SCL=0;注意IIC规定只有SCL=0;的时候SDA上的数据才允许改变.....

void  SendByte(unsigned char  c){ unsigned char  BitCnt; //SCL=0; 起始信号最后是SCL=0;所以不用写了 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/    {     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/       else  SDA=0;                     _Nop();     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/      _Nop();       _Nop();             /*保证时钟高电平周期大于4μs*/      _Nop();      _Nop();      _Nop();              SCL=0;     }

 

发送数据的时候先发的高位,,SCL为低电平的时候SDA准备数据,,,然后SCL为高电平,数据就传过去了(就是告诉对方你接收SDA上的电平数据哈),

接着

8位数据传完之后,主机(单片机)把SDA置为高电平,,,然后SCL置为高电平这个时候呢如果从机(PCF8591)确实接收完了8位数据,就会把SDA拉低

这就是从机的应答信号,说明数据传输成功,,,非应答就是不用管它

void  SendByte(unsigned char  c){ unsigned char  BitCnt; //SCL=0; 起始信号最后是SCL=0;所以不用写了 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/    {     if((c<<BitCnt)&0x80)SDA=1;   /*判断发送位*/       else  SDA=0;                     _Nop();     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/      _Nop();       _Nop();             /*保证时钟高电平周期大于4μs*/      _Nop();      _Nop();      _Nop();              SCL=0;     }        _Nop();    _Nop();    SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/    _Nop();    _Nop();       SCL=1;    _Nop();    _Nop();    _Nop();    if(SDA==1)ack=0;            else ack=1;        /*判断是否接收到应答信号*/    SCL=0;    _Nop();    _Nop();}

接着就是发命令或者说数据了,,,,这个数据呢,就和芯片有关了,,看芯片资料才知道

源码链接

 

链接:http://pan.baidu.com/s/1qX8gfA8%20密码:8xiy

实物链接

https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084sH7efy&id=557671967654

哎呀!为什么博客又不能直接复制粘贴图片了呢........这样的话每写一篇文章就会很耽误时间了.............