首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

串口数据处理写进数据库的有关问题,请高手赐教

2012-01-08 
串口数据处理写进数据库的问题,请高手赐教!我下位机是一个单片机,用来做数据采集,总共有四个采集的通道。下

串口数据处理写进数据库的问题,请高手赐教!
我下位机是一个单片机,用来做数据采集,总共有四个采集的通道。下位机的数据样式如下。
AD channel 1 Vin = 105 mV
AD channel 2 Vin = 804 mV
AD channel 3 Vin = 94 mV
AD channel 4 Vin = 4370 mV
AD channel 1 Vin = 49 mV
AD channel 2 Vin = 479 mV
AD channel 3 Vin = 95 mV
AD channel 4 Vin = 4705 mV
我通过串口接收到了数据,以文本的形式读入,然后通过正则表达式来提取数字,提取的第一个数字就是通道号,第二个数字就是采集的结果,再写进数据库,然后再调出来画图。现在单片机这样不停的循环发输送采集的数据,这时候只有一路能够写进数据库,有时候是第一通道的,有时候是第二通道的,有时候是三四的,不知道是什么原因,按理说,这四路应该是循环的被提取数字,然后写入数据库的。我原以为是数据库的原因,可是我用虚拟串口一路一路的发送上面的数据,每一路都可以写进数据库去,可用单片机这样连续发就不行。我设置的串口的数据MSComm1.RThreshold = 30 ,每读进来30个字符就处理一次,恳请各位高手赐教,帮我找一下为什么连续处理数据就不能写进数据库的问题。我把程序的源代码贴出来。
Private Sub Command1_Click()
If MSComm1.PortOpen = False Then
MSComm1.PortOpen = True '...打开串口
End If

End Sub

Private Sub Command2_Click()
MSComm1.PortOpen = False
End Sub

Private Sub Command3_Click()

MSComm1.CommPort = Combo2.Text '...使用选择的Com口

MSComm1.PortOpen = True '...打开串口

If MSComm1.PortOpen = True Then

MsgBox "串口已经打开", , "提示"

End If

End Sub
Private Sub Form_Load()

Combo1.Text = Combo1.List(0)
Combo2.Text = Combo2.List(0)
Combo3.Text = Combo3.List(0)

MSComm1.InputMode = 0 '以文本的形式读入,如果为1,就是二进制读取

MSComm1.InBufferCount = 0

MSComm1.InputLen = 30 '设置每次接受的长度为一个字节

MSComm1.RThreshold = 30 '设置为1,是一次接受一个字节,设置为0是把缓冲区的所有字节都读出来

MSComm1.Settings = "115200,n,8,1" '...设置通讯参数

End Sub

'串口通信的特点就是串行,数据并非一次传过来多少个,而是一个一个的接收到串口缓冲区中,
'你只能选择一次从串口缓冲区中读多少个,这个可以由MSComm控件的RThreshold属性实现,

Private Sub MSComm1_OnComm()

'...通讯事件发生

Select Case MSComm1.CommEvent

Case comEvReceive '...有接受事件发生

 '...接受显示数据
 
Text1.Text = Text1.Text + MSComm1.Input & Chr(10) & Chr(13) '换行显示,紧接着下一行显示

MSComm1.InBufferCount = 0 '...清空输入寄存器

'....从接收的文本中提取数据
'用vbscript正则表达式提取字符串中的数字,工程-引用-Microsoft VBScript RegularExpressions 5.5打钩-确定
Dim str As String, num() As Single 'str用来存储待处理的字符串,num()用来存储提取的数字
str = Text1.Text '为str赋值
Set re = New RegExp '初始化re为RegExp正则匹配模式
re.Global = True '设置匹配时搜索str的整个字符串,若为false,只搜索str里符合条件的第一项
re.Pattern = "[0-9\-]+(?:\.[0-9]+)?" '定义正则表达式,这里为数字
Set mc = re.Execute(str) '返回符合正则表达式匹配对象,并存储在mc中,mc为MatchCollection对象,其count属性返回匹配对象的总数
ReDim num(1 To mc.Count) '重新定义num数组,下限为1,上限为由str提取到的数字个数即mc.count
i = 1 '初始化数组sum脚标
For Each ma In mc '循环读取mc中的每一匹配对象,并存储在ma中,ma为Match对象,其value属性返回匹配对象所匹配的值,即str里的数字。
num(i) = ma.Value '将数字存储在数组sum中
i = i + 1
Next
For i = 1 To UBound(num) '打印数组
'Print num(i)
Next
'Print num(1)
'Print num(2)

'把数据写入数据库内部
sql = "select * from table1"
 Set rst = run_SQL(sql)
  rst.AddNew
  rst.Fields("channel").Value = num(1)
  rst.Fields("voltage").Value = num(2) * 0.001 '电压单位为伏
  If num(2) = 0 Or num(2) > 2500 Then
  rst.Fields("resistance").Value = 0
  Else: '此公式为计算电阻值的公式
  rst.Fields("resistance").Value = (2.5 - rst.Fields("voltage").Value * 0.001) * Val(Combo3.Text) / (num(2) * 0.001) 'Int(Rnd() * 10000) / 100
  End If
  rst.Fields("datetime").Value = Now()
  rst.Update
  Set rst = Nothing



'从数据库中把数据读出来并且画出来

List1.Clear
Picture1.Cls

If Combo1.Text = "第一通道" Then ch = 1
If Combo1.Text = "第二通道" Then ch = 2
If Combo1.Text = "第三通道" Then ch = 3
If Combo1.Text = "第四通道" Then ch = 4

sql = "select * from table1 where channel=" & ch & " order by datetime desc"
  Set rst = run_SQL(sql)
  kccount = 0
  List1.AddItem " "
  If Not rst Is Nothing Then
  Do While Not rst.EOF And kccount < 65
  List1.AddItem "通道号:" & rst.Fields("channel").Value & " 电阻:" & Left(rst.Fields("resistance").Value & "欧姆 ", 8) & " 采集时间:" & rst.Fields("datetime").Value
  If Not IsNull(rst.Fields("Voltage").Value) Then
  Picture1.Circle ((64 - kccount) * 140, (100 - rst.Fields("Voltage").Value) * 25), 30
  If kccount > 0 Then
  Picture1.Line ((64 - (kccount - 1)) * 140, (100 - dianya) * 25)-((64 - kccount) * 140, (100 - rst.Fields("Voltage").Value) * 25), RGB(255, 0, 0)
  End If
  dianya = rst.Fields("Voltage").Value
  End If
  kccount = kccount + 1
  rst.MoveNext
  Loop
  Set rst = Nothing
  End If
End Select
End Sub



 

[解决办法]
打断点调试一下。
[解决办法]

协议不合理,自找麻烦。

你把发送的每一帧设计成定长(例如数据补前导 0),每次处理一条记录,会容易很多。
[解决办法]

而且。也用不着什么正则表达式,用 Split 分隔,成员(2)和(5)就是通道号和数据。

[解决办法]
1)没有看到自动切换端口的功能,所以你操作时手工指定连哪个端口就只会收到这一路的数据。
2)更改 CommPort 之前要先关闭端口,而关闭会清除缓冲区,是否允许丢掉未处理的数据。
3)没有看到本方发送通知的操作,可以认为对方是不停地发送数据的?
 由于你打开端口可以在任何时间,那么收到的数据不一定正好是块的开始,可能是下面这样的
   in = 105 mV AD channel 1 Vin = 105 mV AD channel 1 Vin = 105 mV...
 因此你的解析结果就是 channel=105, voltage=0.001

[解决办法]
既然 COM 口连接的下位机是一个多通道控制器,那么就不存在丢数据的问题。
唯一出错的是你的处理程序。
下位机发送的多笔数据其实会在缓冲区中串连起来的,而你每次固定处理 30 个字符,实际就分成这样的批次了:
[code=txt]AD channel 1 Vin = 105 mVAD ch
annel 2 Vin = 804 mVAD channel
3 Vin = 94 mVAD channel 4 Vin
= 4370 mVAD channel 1 Vin = 4
9 mVAD channel 2 Vin = 479 mVA
D channel 3 Vin = 95 mVAD chan
nel 4 Vin = 4705 mV[/code]
第 3 次就出现了 3 个数字,通道号 4 被你丢掉了。
第 4 次就解析出通道号 4370 了。
……

应该逐字符接收,存放在一个模块级字符串变量中。
等到构成一个完整的 AD 开头 mV 结束的字符串后再进行一次处理。

[解决办法]

探讨
我下位机是一个单片机,用来做数据采集,总共有四个采集的通道。下位机的数据样式如下。
AD channel 1 Vin = 105 mV
AD channel 2 Vin = 804 mV
AD channel 3 Vin = 94 mV
AD channel 4 Vin = 4370 mV
AD channel 1 Vin = 49 mV
AD channel 2 Vin = 479 ……

[解决办法]
探讨不过这个地方我不太明白怎么搞,你说的应该逐字符接收,存放在一个模块级字符串变量中。等到构成一个完整的 AD 开头 mV 结束的字符串后再进行一次处理。能给点提示吗大哥?

[解决办法]
字节长度不等,所以会带来处理数据的难度。
另外:调试时可以不写到数据库中,直接debug.print出来看看,是不是确实接收到4路的数据。
[解决办法]
你到现在都没说计算机和下位机之间是否有交互控制的功能。
如果没有控制,下位机持续发,计算机可以在任何时点打开端口读取,
那么改成定长的还要注意第一段收到的可能是两个段的数据,需要调整 RThreshold 将后一段读完整,然后再回复成 RThreshold = 30。


[解决办法]
假如流水线上不停循环产出 30 个一组的瓶子,每组的批次都不同。
你从任意时刻开始,取连续 30 个瓶子装箱,只有 1/30 的概率瓶子的批号是一致的。
那么如何才能每箱 30 个批号都是一样的?

就是在第 1 组 30 个中丢弃前 n 上个批号的,然后再取 n 个这个批号的,一起装箱。
以后都是 30 个一取肯定是同一批号的了。

热点排行