Skip to content

串口上位机和下位机的通信

这个章节会在上一节课的基础上进行修改

1. Form上的修改

和之前相比,主要修改了port_DataReceived 这个函数 将之前直接显示的操作,修改成了显示的同时,也将数据存储到SeriPortDataBuffer 这个缓存空间中,来使用。

C
public Form1()
{
    InitializeComponent();

    serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);      //串口数据接收事件
    serialPort1.Encoding = Encoding.GetEncoding("GB2312");
    //System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;                   //               //
}

string SeriPortDataBuffer = "";
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)             //串口接收事件
{
    string ThisNumber = "";

    try { 
        ThisNumber = serialPort1.ReadExisting(); 
    } catch { }
    if (ThisNumber != "") //传递非空数据。
    { 
        SeriPortDataBuffer = SeriPortDataBuffer + ThisNumber;
        this.BeginInvoke(new Action(() =>
        {
            richTextBox2.AppendText(ThisNumber);     //串口类会自动处理汉字,所以不需要特别转换
        }));
    }

}

2. 获取B站粉丝按钮的实现

2.1 获取B站粉丝按键

按下按键后,创建一个新的线程:childThread,线程中启动发送字符的通信

之所以需要新建一个线程是,在通信的时候会因为在处理接收的信息,所以UI界面会卡住,解决方案就是新开一个,在新开的里面去处理。

C
Thread childThread;//发送线程
/// <summary>
/// 获取B站粉丝
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{

    if (childThread != null) { try { childThread.Abort(); } catch { } }
    childThread = new Thread(sendthepath);
    childThread.Start();

    //childThread.Abort();//关进程
}

2.2 sendthepath

在这个sendthepath 函数中实现了指令的发送,以及信息的接收

C

private void sendthepath()
{

    byte[] Data = new byte[1]; //单字节发数据     
    if (serialPort1.IsOpen)
    {
        //礼貌扫描一下wifi列表
        serialPort1.Write("AT+WSCAN\r\n");
        ReadAndCheckData("OK", 5);
        //输入wifi密码,连接wifi
        serialPort1.Write("AT+WJAP=super_2G,123456798\r\n");
        ReadAndCheckData("OK", 20);
        //输入API,获取粉丝数
        serialPort1.Write("AT+HTTTPCLIENTLINE=2,2,\"text/html\",\"api.bilibili.com\",443,\"/x/relation/stat?vmid=2044983862\"\r\n");
        ReadAndCheckData("OK", 5);

    }
    else
    {
        MessageBox.Show("请打开串口");
    }

}

2.3 ReadAndCheckData

这函数实现了,从全局变量“SeriPortDataBuffer”中去读串口的值,判断是否读取到结束标志位“data”,同时也有延时等待的参数,因为只要接收完成就可以结束代码,所以延时可以将时间放长一点,也不会影响代码运行的时间。

C
//时间监控的申明
System.DateTime currentTime = new System.DateTime();
/// <summary>
/// 判断是否有“data”的数据, 超时退出
///备注:有防阻塞功能
/// </summary>
/// <param name="data"> 被判断的数据</param>
/// <param name="delay_S">  延时时间,单位秒</param>
/// <returns> 如果return true,正常结束,return false 错误或者超时结束</returns>
bool ReadAndCheckData(string data, int delay_S)
{
    Debug.WriteLine("进入循环判断");

    SeriPortDataBuffer = "";
    string SeriPortDataLast = "";
    bool EXTFlag = false;
    bool SpentFlag = false;
    currentTime = System.DateTime.Now;//更新时间
    int miao_last = currentTime.Second;//秒
    int miao = currentTime.Second;//秒
    int shijian = 0;
    Debug.WriteLine("循环中...");
    //下面的语句有几率崩溃
    do
    {
        currentTime = System.DateTime.Now;//更新时间
        miao = currentTime.Second;//秒
        shijian = miao - miao_last;
        if (shijian >= delay_S)//超时退出
        {
            Debug.WriteLine("ReadAndCheckData 超时退出 \n");
            return false;
        }

        //因为之前读串口的数据的时候是一行一行读,所以将数据读断的问题应该不大
        if (SeriPortDataLast != SeriPortDataBuffer)
        {
            SeriPortDataLast = SeriPortDataBuffer;
            SeriPortDataBuffer = "";

            try
            {
                string[] number= SeriPortDataLast.Split('\n');
                foreach (string thsinnu in number)
                {
                    try
                    {
                        if (thsinnu.Contains(data))
                        {
                            EXTFlag = true;
                            SpentFlag = true;
                        }
                    }
                    catch { Debug.WriteLine("Read And Check Data出现错误"); }
                }
            }
            catch { Debug.WriteLine("Read And Check Data出现错误"); }
        }
    } while (!EXTFlag);
    Debug.WriteLine("ReadAndCheckData 结束...");
    return SpentFlag;
}

3. 展示通信内容