上一次解决了PDU编码的解码问题。这次就来写从串口中读取数据。
与串口通讯,在net里面提供了十分方便的控件和类库,如果你要简单的话,可以从工具栏里拖出serialport 这个控件,使用控件的好处在于,当有数据回传的时候,会触发控件的一个方法,我们在该方法下进行操作,就可以省去自己再写一个方法去试探有没有从串口来的数据了。不过,经过我测试,觉得还是要自己写比较好。
首先,我们要定义个读写串口的类
Dim ser as new system.io.ports.serialport
然后让设置一下这个类的一些属性,如串口名称
Ser.portname="COM3"
接着就打开串口
Ser.open()
接着就往串口里写命令
Ser.writeline("命令")
再接着就是自己写一个判断,判断是否有数据从串口里过来,如果有则执行读数据
ser.ReadLine()
接着就是把这个读取的一行数据进行判断,如果是pdu码则去进行解码,如果是结束符号则结束,如果是错误符号就去执行其他操作。
接着就是又回到上面的判断有没有第二行数据,然后就循环到没东西为止。
思路大概就是这样子,然后把成功读出的内容显示到程序界面的listview中,并把它存到数据库中。
整个程序功能简单,设计也不复杂,实现起来大概200行不到。以下是我做的程序的一些介绍。我使用了:
一个combobox 作为选择COM之用,
一个button,用来连接和断开串口;
一个button,用来开始和停止监听是否有短信到达;
一个listview,用来显示数据;
一个timer,用来定时向串口发送检查信息,检查是否有新短信到达;
一个timer,用来读取串口发来的消息,直到没有消息了就停止。
界面就是这样子。还用到了一个access数据库,里面有一个表(msm)用来记录短信信息。
程序初始化时,先找出所有的com口,赋值给combobox,并检查数据库文件是否存在
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Button2.Enabled = False
Dim arrport As String() = IO.Ports.SerialPort.GetPortNames
ComboBox1.Items.AddRange(arrport)
ComboBox1.SelectedIndex = 0
Dim aaa As New db
End Sub
接着,当单击连接按钮时,就与串口连接
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If ComboBox1.SelectedItem.ToString = "" Then Exit Sub
If Button1.Text = "连接" Then
ser.PortName = ComboBox1.SelectedItem.ToString
ser.Open()
Button1.Text = "关闭"
Button2.Enabled = True
ElseIf Button1.Text = "关闭" Then
Timer1.Enabled = False
Timer2.Enabled = False
ser.Close()
Button1.Text = "连接"
Button2.Text = "监听新短信"
Button2.Enabled = False
End If
End Sub
如果链接成功,则可以点击开始监听按钮,该按钮主要是让timer1启动,timer1的主要功能就是定时的向串口发送请求,询问是否有新短信的到达。
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If Button2.Text = "监听新短信" Then
Timer1.Enabled = True
Button2.Text = "停止监听"
ElseIf Button2.Text = "停止监听" Then
Timer1.Enabled = False
Timer2.Enabled = False
Button2.Text = "监听新短信"
End If
End Sub
Timer1 的工作很简单,就是向串口发送一个信息,并启动timer2继续工作。
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
ser.WriteLine(mess)
Timer1.Enabled = False
Timer2.Enabled = True
End Sub
Timer2 的工作就多点,它首先是判断串口接收缓冲区里面有没有数据,如果没有则过,如果有则读取一行数据,并进行判断,如果是结束符就结束,如果是pdu码则进行处理。
Private Sub Timer2_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer2.Tick
Dim i As Integer = ser.BytesToRead
If i = 0 Then Exit Sub
Dim strtemp As String = ser.ReadLine
Dim iii As Integer = strtemp.Length
If strtemp = vbCr Then '空行
'不处理
ElseIf Trim(strtemp) = mess Then '是发送出去的字符集
'不处理
ElseIf Trim(strtemp) = "OK" + vbCr Then '是结束行
'结束这个timer2,启动timer1继续监听
Timer2.Enabled = False
Timer1.Enabled = True
ElseIf strtemp.StartsWith("+CMGL") Then '是信息摘要行
'不处理
ElseIf Trim(strtemp) = "ERROR" + vbCr Then '是错误
'结束这个timer,发送错误信息
Timer2.Enabled = False
Timer1.Enabled = True
Else '是pdu码
'发去解码
Dim jieguo As String() = chuli(strtemp)
addlist(jieguo)
End If
End Sub
整个过程大概就是如此了。
下面就不多说了,认真看一下就明了。
Sub addlist(ByVal data() As String) '执行添加
Dim myitem As New ListViewItem
myitem.Text = data(0) '手机号码
Dim mysubitem(2) As ListViewItem.ListViewSubItem
mysubitem(0) = New ListViewItem.ListViewSubItem()
mysubitem(1) = New ListViewItem.ListViewSubItem()
mysubitem(2) = New ListViewItem.ListViewSubItem()
mysubitem(0).Text = data(1) '内容
mysubitem(1).Text = data(2) '短信中心码
mysubitem(2).Text = data(3) '时间
myitem.SubItems.AddRange(mysubitem)
ListView1.Items.Add(myitem)
Dim mycl As New db
mycl.insertduanxin(data(0), data(1), data(2), data(3))
End Sub
下面的就是上一次说的pdu解码函数了,只是粗略的改了几行而已:
Function chuli(ByVal data As String) As String() '处理pdu码的函数
Dim seek As Integer = 0
Dim sclength As Integer = CType(data.Substring(0, 2), Integer) '手机中心码长度
Dim zhongxinma As String = data.Substring(seek + 2, sclength * 2) '手机中心码的pdu码
zhongxinma = number(zhongxinma.Substring(2)) '解码后的手机中心码
seek = sclength * 2 + seek + 2 '指针移动
Dim weizhi As String = data.Substring(seek, 2) '读取下一个参数,未知的参数
seek += 2 '指针继续移动
Dim haomalength As Double = Val("&H" + data.Substring(seek, 2)) / 2 '手机号码长度
seek += 2
haomalength = Math.Ceiling(haomalength)
Dim haoma As String
haoma = number(data.Substring(seek + 2, haomalength * 2)) '解码后的手机号码
seek = seek + 2 + haomalength * 2
Dim weizhi2 As String = data.Substring(seek + 1, 2) '未知参数
seek += 2
Dim putong As String = data.Substring(seek, 2) '如果为08则为普通短信
seek += 2
Dim time As String = times(number(data.Substring(seek, 14))) '日期
seek += 14
Dim contentlength As Double = Val("&H" + data.Substring(seek, 2)) / 2 '内容有多少个字符
Dim neirong As String = content(data.Substring(seek + 2, contentlength * 4)) '获取解码后的内容
Dim jieguo(3) As String
jieguo(0) = haoma
jieguo(1) = neirong
jieguo(2) = zhongxinma
jieguo(3) = time
Return jieguo
End Function
Function number(ByVal data As String) As String '号码解码
Dim str As String = ""
For i As Integer = 0 To data.Length / 2 - 1
str += Strings.StrReverse(data.Substring(i * 2, 2))
Next
str = str.Replace("F", "")
Return str
End Function
Function content(ByVal data As String) As String '内容解码
Dim str As String = ""
For i As Integer = 0 To data.Length / 4 - 1
Dim temp As String = "&H" + data.Substring(i * 4, 4)
Dim word As Char = ChrW(CType(Val(temp), Integer))
str += word
Next
Return str
End Function
Function times(ByVal data As String) As String '时间解码
Dim yy, mm, dd, hh, ff, ss, riqi As String
yy = data.Substring(0, 2)
mm = data.Substring(2, 2)
dd = data.Substring(4, 2)
hh = data.Substring(6, 2)
ff = data.Substring(8, 2)
ss = data.Substring(10, 4)
riqi = mm + "/" + dd + " " + hh + ":" + ff
Return riqi
End Function
下面的就是写入数据库的db类:
Imports System.Data.OleDb
Public Class db
Dim cmdstr As String
Dim cmd As New OleDb.OleDbCommand
Public connstr As String
Dim conn As New OleDb.OleDbConnection(connstr)
Dim dbadd As String = "db.mdb" 'access名称
Sub New()
Dim mypath As String = My.Application.Info.DirectoryPath
If IO.File.Exists(mypath + "/" + dbadd) Then
connstr = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Persist Security Info=False", mypath + "/" + dbadd)
Else
Throw New Exception("在程序的同目录下找不到数据库" + dbadd)
End If
End Sub
Function execno() As Boolean
cmd.CommandText = cmdstr
cmd.Connection = conn
conn.ConnectionString = connstr
conn.Open()
Dim i As Integer = cmd.ExecuteNonQuery()
If i = 1 Then Return True
End Function
Function insertduanxin(ByVal haoma As String, ByVal content As String, ByVal zhongxinma As String, ByVal riqi As String) As Boolean
cmdstr = "insert into msm(haoma,content,zhongxinma,riqi) values(@haoma,@content,@zhongxinma,@riqi) "
cmd.Parameters.Add("@haoma", OleDbType.Char).Value = haoma
cmd.Parameters.Add("@content", OleDbType.Char).Value = content
cmd.Parameters.Add("@zhongxinma", OleDbType.Char).Value = zhongxinma
cmd.Parameters.Add("@riqi", OleDbType.Char).Value = riqi
execno()
End Function
End Class
注:如果你照抄一定错,因为有几个变量是没有写出来的,不过细心的你一定看的出来。
至此,一个能够读取出手机新短信的程序就完成了。经过测试,正常。