杭電嵌入式課程設計——上位機
阿新 • • 發佈:2021-01-03
TCP伺服器
課程設計要求
如下圖:
我們選擇採用C#進行開發,因為串列埠有距離限制不方便我們採集資料,所以我們決定用C#做一個TCP的伺服器,進行資料觀察以及資料採集。
將電腦作為TCP伺服器
C#提供了豐富的網路開發API,根據socket通訊基本流程圖
總結通訊的基本步驟:
- 建立一個用於監聽連線的Socket對像;
- 用指定的埠號和伺服器的ip建立一個EndPoint對像;
- 用socket對像的Bind()方法繫結EndPoint;
- 用socket對像的Listen()方法開始監聽;
- 接收到客戶端的連線,用socket對像的Accept()方法建立一個新的用於和客戶端進行通訊的socket對像;
- 第六步:通訊結束後一定記得關閉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的資料,分別代表三個軸上的加速度計和陀螺儀資料。具體步驟如下:
- 對收到的首位資料進行判斷,若不為幀頭,那麼在緩衝區陣列中移除改資料,並等待下一個資料,以保證資料的準確性。
- 將接收到的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;
綜上,我們的曲線繪製部分就完成了。
檔案寫入
為了方便資料的處理,需要將接受到的資料寫入到檔案中,具體實現步驟如下:
- 將接收到的資料寫入緩衝區
- 將緩衝區的資料寫入到檔案
為了方便資料儲存以及寫入,我定義了一個類(偷懶了,寫的不嚴謹):
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