1. 程式人生 > 其它 >杭電嵌入式課程設計——上位機

杭電嵌入式課程設計——上位機

技術標籤:微控制器socket嵌入式

TCP伺服器



課程設計要求

如下圖:
在這裡插入圖片描述
我們選擇採用C#進行開發,因為串列埠有距離限制不方便我們採集資料,所以我們決定用C#做一個TCP的伺服器,進行資料觀察以及資料採集。


將電腦作為TCP伺服器

C#提供了豐富的網路開發API,根據socket通訊基本流程圖
總結通訊的基本步驟:

  1. 建立一個用於監聽連線的Socket對像;
  2. 用指定的埠號和伺服器的ip建立一個EndPoint對像;
  3. 用socket對像的Bind()方法繫結EndPoint;
  4. 用socket對像的Listen()方法開始監聽;
  5. 接收到客戶端的連線,用socket對像的Accept()方法建立一個新的用於和客戶端進行通訊的socket對像;
  6. 第六步:通訊結束後一定記得關閉socket;
//建立socket物件
Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
	//繫結IP和申請埠
    tcpServer.Bind(new IPEndPoint(IPAddress.Any, 8888));
}
catch (Exception ex)
{
    MessageBox.Show
("錯誤: ip地址設定失敗,請正確連線熱點並檢查ip地址", "提示",MessageBoxButtons.OK); t.Abort();//結束本執行緒 } server_open_flag = true; //標誌伺服器開啟成功 server_open_change = true; //標誌伺服器開啟狀態改變 tcpServer.Listen(100);//設定客戶端最大連線數 clientSocket = tcpServer.Accept(); //會一直阻塞等待連線 若沒有連結則不會進行

# 處理接收到的資料 處理接收到的資料就較為簡單,我們每個資料包會發送14個位元組的資料,也就是兩位的校驗位和6個int16的資料,分別代表三個軸上的加速度計和陀螺儀資料。具體步驟如下:
  1. 對收到的首位資料進行判斷,若不為幀頭,那麼在緩衝區陣列中移除改資料,並等待下一個資料,以保證資料的準確性。
  2. 將接收到的byte資料進行移位操作後得到正確的int16的資料。
while (true)
 {
     int buffer_num = data_buffer.Count;    //提前存好,防止處理過程中Count變化
     if (buffer_num >= 14)   //至少14位元組
     {
         if (data_buffer[0] == 0x5A)     //幀頭
         {
             if (data_buffer[1] == 0x01)  //判斷這一幀是否是心跳波形資料
             {
                 Action act = delegate () {  cur_data.a_x = (Int16)(data_buffer[2] | data_buffer[3] << 8);
                                             cur_data.a_y = (Int16)(data_buffer[4] | data_buffer[5] << 8);
                                             cur_data.a_z = (Int16)(data_buffer[6] | data_buffer[7] << 8);
                                             cur_data.g_x = (Int16)(data_buffer[8] | data_buffer[9] << 8);
                                             cur_data.g_y = (Int16)(data_buffer[10]| data_buffer[11] << 8);
                                             cur_data.g_z = (Int16)(data_buffer[12]| data_buffer[13] << 8);
                                             ecg_add_data(cur_data.a_x, cur_data.a_y, cur_data.a_z, cur_data.g_x, cur_data.g_y, cur_data.g_z);
                 };
                 data_save.Add(new datatype(cur_data.a_x, cur_data.a_y, cur_data.a_z, cur_data.g_x, cur_data.g_y, cur_data.g_z));
                 this.Invoke(act);
                 data_buffer.RemoveRange(0, 13);      //從快取中刪除前14個位元組
             }
         }
         else
         {
             //這裡是很重要的,如果資料開始不是幀頭,就刪除一位
             data_buffer.RemoveAt(0);
         }
     }
     if (main_form_close_flag == true)
     {
         t1.Abort();      //結束本執行緒
     }
 }

曲線繪製

圖表

我們採用自帶的chart控制元件,在form中點選工具箱搜尋即可尋找到該控制元件。

在這裡插入圖片描述
將chart移動到合適的位置後,我們可以在窗體載入函式中,將chart進行初始化配置,具體程式碼如下:

ChartArea chartArea = new ChartArea();
chartArea.Name = "FirstArea";

chartArea.CursorX.AutoScroll = true;            //是否滾動
chartArea.AxisX.ScrollBar.Enabled = true;       //開啟滾動條
chartArea.CursorX.IsUserEnabled = true;
chartArea.CursorX.IsUserSelectionEnabled = true;
chartArea.AxisX.ScaleView.Zoomable = true;
chartArea.CursorX.SelectionColor = Color.SkyBlue;

chartArea.CursorY.IsUserEnabled = true;
chartArea.CursorY.AutoScroll = true;
chartArea.CursorY.IsUserSelectionEnabled = true;
chartArea.CursorY.SelectionColor = Color.SkyBlue;

chartArea.CursorX.IntervalType = DateTimeIntervalType.Auto;


chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.All;//啟用X軸滾動條按鈕


chartArea.BackColor = Color.AliceBlue;                      //背景色
chartArea.BackSecondaryColor = Color.White;                 //漸變背景色
chartArea.BackGradientStyle = GradientStyle.TopBottom;      //漸變方式
chartArea.BackHatchStyle = ChartHatchStyle.None;            //背景陰影
chartArea.BorderDashStyle = ChartDashStyle.NotSet;          //邊框線樣式
chartArea.BorderWidth = 1;                                  //邊框寬度
chartArea.BorderColor = Color.Black;


chartArea.AxisX.MajorGrid.Enabled = false;
chartArea.AxisY.MajorGrid.Enabled = false;

// Axis
chartArea.AxisY.Title = @"數值";
chartArea.AxisY.LabelAutoFitMinFontSize = 5;
chartArea.AxisY.LineWidth = 2;
chartArea.AxisY.LineColor = Color.Black;
chartArea.AxisY.Enabled = AxisEnabled.True;

chartArea.AxisX.Title = @"時間";
chartArea.AxisX.IsLabelAutoFit = true;
chartArea.AxisX.LabelAutoFitMinFontSize = 5;
chartArea.AxisX.LabelStyle.Angle = -15;


chartArea.AxisX.LabelStyle.IsEndLabelVisible = true;        //show the last label
chartArea.AxisX.Interval = 10;
chartArea.AxisX.IntervalAutoMode = IntervalAutoMode.FixedCount;
chartArea.AxisX.IntervalType = DateTimeIntervalType.NotSet;
chartArea.AxisX.TextOrientation = TextOrientation.Auto;
chartArea.AxisX.LineWidth = 2;
chartArea.AxisX.LineColor = Color.Black;
chartArea.AxisX.Enabled = AxisEnabled.True;
chartArea.AxisX.ScaleView.MinSizeType = DateTimeIntervalType.Months;
chartArea.AxisX.Crossing = 0;

chartArea.Position.Height = 85;
chartArea.Position.Width = 85;
chartArea.Position.X = 5;
chartArea.Position.Y = 7;

chart_ecg.ChartAreas.Add(chartArea);
chart_ecg.BackGradientStyle = GradientStyle.TopBottom;
//圖表的邊框顏色、
chart_ecg.BorderlineColor = Color.FromArgb(26, 59, 105);
//圖表的邊框線條樣式
chart_ecg.BorderlineDashStyle = ChartDashStyle.Solid;
//圖表邊框線條的寬度
chart_ecg.BorderlineWidth = 2;
//圖表邊框的面板
//chart_ecg.BorderSkin.SkinStyle = BorderSkinStyle.FrameThin3;

chart_ecg.ChartAreas[0].AxisX.Interval = 0.5;        //設定橫座標的解析度
chart_ecg.ChartAreas[0].AxisX.ScaleView.Size = 1000; //設定橫座標長度

曲線

除了圖表,我們還需要繪製曲線,我們採用Series進行繪製,一共需要6條曲線,初始化操作相同,下面就給出一條曲線的初始化操作:

series1 = new Series();
series1.ChartArea = "FirstArea";
chart_ecg.Series.Add(series1);

//Series1 style
series1.ToolTip = "#VALX,#VALY";    //滑鼠停留在資料點上,顯示XY值

series1.Name = "a_x";
series1.ChartType = SeriesChartType.Line;  // type:折線
series1.BorderWidth = 2;
series1.Color = Color.Black;
series1.XValueType = ChartValueType.Time;//x axis type
series1.YValueType = ChartValueType.Int32;//y axis type

//Marker
series1.MarkerStyle = MarkerStyle.Square;
series1.MarkerSize = 2;
series1.MarkerColor = Color.Black;

然後就是繪製曲線了,程式碼如下:

series1.Points.AddXY(osc_x, data1);

最後還有選擇顯示的曲線,直接用check控制元件即可,程式碼如下:

series1.Enabled = check1.Checked;

綜上,我們的曲線繪製部分就完成了。

檔案寫入

為了方便資料的處理,需要將接受到的資料寫入到檔案中,具體實現步驟如下:

  1. 將接收到的資料寫入緩衝區
  2. 將緩衝區的資料寫入到檔案

為了方便資料儲存以及寫入,我定義了一個類(偷懶了,寫的不嚴謹):

class datatype
{
      public Int16 a_x, a_y, a_z;
      public Int16 g_x, g_y, g_z;

      public datatype(Int16 ax = 0, Int16 ay = 0, Int16 az = 0, Int16 gx = 0, Int16 gy = 0, Int16 gz = 0)
      {
          this.a_x = ax;
          this.a_y = ay;
          this.a_z = az;

          this.g_x = gx;
          this.g_y = gy;
          this.g_z = gz;
      }
	
      public string data_to_string()
      {
          return a_x + "," + a_y + "," + a_z + "," + g_x + "," + g_y + "," + g_z ;
      }
}

定義一個緩衝區,用於存放資料:

private List<datatype> data_save = new List<datatype>();

寫入緩衝區很簡單,直接寫入該list即可。
然後便是寫入檔案:

if (data_save.Count == 0)
{
    MessageBox.Show("錯誤:快取區為空", "提示", MessageBoxButtons.OK);
    return;
}
//檔名為當前時間
string Child_Address = Save_File_Address + "\\" + DateTime.Now.ToString().Replace(@"/", ".").Replace(":", ".") + ".dyy";//建立檔案
FileStream fs = new FileStream(Child_Address, FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter sw = new StreamWriter(fs); // 建立寫入baidu流

for (int i = 0; i < data_save.Count; i++)
{
    sw.WriteLine(data_save[i].data_to_string());
}
//刪除快取區資料
data_save.RemoveRange(0, data_save.Count);
sw.Close(); //關閉檔案

最後加個按鍵控制就完事了。

工程連結

工程連結:https://pan.baidu.com/s/11celASODrhJEwRoCH_7OVQ
提取碼:dfds