上位機的程序主要是解析圖片和生成較好的代碼,如今實現的功能有灰度打印,二值打印,輪廓打印,骨骼打印。固然,必不可少的是打印大小的控制。測試了一些圖片,整體來講,打印速度依次加快,由於打印的內容依次減小。可是還有一些不太滿意的地方,例如用輪廓和骨骼打印來打印文字時,東一塊西一塊,尚未空閒寫行識別以後的排序。其實思路挺簡單,膨脹文字或腐蝕背景使一行變爲位置相鄰的點集,而後在外包矩形內進行按x遞增排序就能夠了。數組
上位機整體功能分爲三部分:ide
一、與下位機通信,這部分建議先寫好,才更利於後面的測試。函數
二、圖片處理——灰度、二值、邊緣、骨骼。測試
三、灰度、二值、邊緣、骨骼點數組轉命令。線程
1、圖片處理3d
我nuget了一個opencvsharp,因此不少基礎代碼都不用寫了。只須要稍加封裝使frm中的代碼更簡潔易易懂於維護就能夠了。這裏簡單說一下mat類點的顏色設置:指針
ImgEdge = New Mat(ImgBinary.Size, MatType.CV_8U)
ImgEdge.Set(Of Byte)(p.Y, p.X, 0)
由於這是二值化的圖像,因此用Byte寫就能夠了,0爲黑色。固然,也能夠直接操做內存指針:對象
For i As Integer = ImgEdge.DataStart To ImgEdge.DataEnd Marshal.WriteByte(i, 255) Next
這是我清理圖片背景的代碼。這樣作很慢,你能夠嘗試用API函數來完成內存數據置零。blog
2、點數組轉命令排序
Private Shared Function Info2Command(ps() As Point) As List(Of Command) Dim result As New List(Of Command) Dim dx, dy As Integer For i As Integer = 1 To ps.Count - 1 dx = ps(i).X - ps(i - 1).X dy = ps(i).Y - ps(i - 1).Y If dx = dy Then result.Add(New Command(Message.c_13Move, dx * 2)) ElseIf dx = -dy Then result.Add(New Command(Message.c_24Move, dy * 2)) Else If dx <> 0 Then result.Add(New Command(Message.c_xMove, dx)) End If If dy <> 0 Then result.Add(New Command(Message.c_yMove, dy)) End If End If Next Return result End Function
這是我解釋一個連續點集的時候使用的代碼,代碼中將座標轉化爲命令。與xy結構不一樣,除了解釋了x,y軸方向移動,還解釋了象限角分線方向的動——它們很是容易實現,由於只需轉動一個電機。這樣作的好處就是僅斜向相連的點不會被解釋爲兩次動做——除非經過更復雜的代碼造成更多的指令(關閉並迅速開啓激光器或擡起並落下舵機)才能使繪製的圖像不比原圖多出某些拐角。
3、與下位機通信
Private WithEvents mPort As SerialPort
這就是所使用的核心對象,它有幾個頗有用的事件,其中DataReceived是咱們最關心的:
Private Sub mPort_DataReceived(sender As Object, e As SerialDataReceivedEventArgs) Handles mPort.DataReceived Dim inData As String = CType(sender, SerialPort).ReadLine.TrimEnd({CChar(vbCr), CChar(vbLf)}) If inData = (r_RequestData) Then RaiseEvent RequestData() ElseIf inData = (r_Ready) Then RaiseEvent Ready() ElseIf inData = (r_Interrupt) Then RaiseEvent Interrupt() ElseIf inData = r_RerequestData Then RaiseEvent RerequestData() ElseIf inData <> String.Empty Then Debug.Print("收到下位機的未知請求。[" & inData & "]") End If End Sub
這用於解釋下位機的不一樣請求。而發送數據也很是簡單:
Protected Friend Sub SendCommand(cmd As Command) mPort.BaseStream.Flush() mPort.Write(cmd.Data, 0, 6) End Sub
OK,最後簡單說一下獲取COM口名稱:
Dim WM_DEVICECHANGE As Integer = &H219 Dim DBT_DEVICEREMOVECOMPLETE As Integer = &H8004 Dim DBT_DEVICEARRIVAL As Integer = &H8000 Protected Overrides Sub WndProc(ByRef m As Message) MyBase.WndProc(m) If m.Msg = WM_DEVICECHANGE Then If m.WParam.ToInt32 = DBT_DEVICEARRIVAL Then 'usb插入 Timer1.Enabled = True ElseIf m.WParam.ToInt32 = DBT_DEVICEREMOVECOMPLETE Then Timer1.Enabled = True End If End If End Sub
實際上應該用單獨線程來處理,可是實在是懶得寫,就用定時器來處理了。
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Dim b = New ManagementObjectSearcher("select * from Win32_PnPEntity").Get '檢測即插即用設備 Dim lst As New List(Of String) Try For Each c In b Try If c.GetPropertyValue("Name").ToString.Contains("CH340") Then lst.Add(c.GetPropertyValue("Name")) End If Catch ex As Exception End Try Next Catch ex As Exception End Try
用WMI來獲取,會獲得不少設備名,而後都存在lst裏面,剩下就是肯定當前使用的是否發生了變化來肯定使用哪個了。
最近幾天偷閒完善了一下上位機的程序,界面以下:
紅色的部分是已經打印的部分,隨着打印進行,紅色的部分同步增加,這比進度條看起來更好一些。而後作了一下文字打印,主要是針對在必定的範圍內打印必定的行數:
點擊肯定以後,獲得的圖像以下:
這就能夠方便的打印一些文字咯。。。