请教PC机通过串口与单片机通信问题

acstar 2007-09-14 03:24:45
我最近在做一个PC机(通过VB)与单片机(红外温度传感器)通信的程序。单片机汇编语言部分保证正确,因为我用公司里现成的delphi写的程序读过数据且正确。但是我用VB写的程序却读不到数据,请大大们帮我看看,万分感谢! 程序如下:

(控制字5A是请求单片机发温度数据,用Text2暂时保存接收到的6个字节的温度数据)

Dim Text1 As String
Dim Text2 As String
Dim BytReceived() As Byte
Dim Lbljieshou As String
Dim lenInput As String
Dim strData As String
Dim strDataInteger As String
Option Explicit

Private Sub Form_Load()
MSComm1.CommPort = 1 'COM1串口
MSComm1.Settings = "1200,n,8,1" '串口设置
MSComm1.InputMode = comInputModeBinary '采用二进制传输
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
MSComm1.InBufferSize = 512 '接收缓冲区大小
MSComm1.OutBufferSize = 512 '发送缓冲区大小
MSComm1.RThreshold = 1 '产生MSComm事件
MSComm1.PortOpen = True '开串口
Timer1.Interval = 200 '200ms Timer1使strData清空
End Sub


Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As String
Dim ReceiveTemp As String
Dim n As Integer
'发控制字5A
CmdByte = "5A"
'CmdByte = Val(CmdByte)
CmdByte = h_to_b(CmdByte) '十六进制转二进制
MSComm1.Output = CmdByte '5A = 0101 1010
'接收6个字节数据
For n = 1 To 1000
Next n
'收到数据触发OnComm事件
ReceiveTemp = Text1
ReceiveTemp = b_to_d(ReceiveTemp)
TxtReceiveTemp.Text = ReceiveTemp '输出十进制温度数值
TxtRD.Text = Text2 'RD显示
End Sub

Private Sub CmdSendPara_Click() '发送参数
Dim CmdByte As String
Dim sj() As Byte
Dim sj_Txt As String
Dim i As Integer
'发控制字A5
CmdByte = "A5"
'CmdByte = Val(CmdByte)
CmdByte = h_to_b(CmdByte) '十六进制转二进制
MSComm1.Output = CmdByte
sj_Txt = TxtSendPara.Text '取得要发送的数据
ReDim sj(Len(sj_Txt) / 2 - 1) 'i从0开始
For i = 0 To Len(sj_Txt) - 1 Step 2
sj(i / 2) = Val("&H" & Mid(sj_Txt, i + 1, 2)) 'Val:字符型转数据型
Next
MSComm1.Output = sj
End Sub

Private Sub CmdReceivePara_Click() '接收参数
Dim CmdByte As String
'发控制字AA
CmdByte = "AA" '发控制字AA
'CmdByte = Val(CmdByte)
CmdByte = h_to_b(CmdByte) '十六进制转二进制
MSComm1.Output = CmdByte
'然后接收串口送来的4个字节数据(OnComm事件)
TxtReceivePara.Text = Text1
End Sub


Private Sub MSComm1_OnComm()
On Error Resume Next
Dim strBuff As String
Dim intInputLen As Integer
Text1 = ""
Select Case MSComm1.CommEvent
Case comEvReceive
MSComm1.InputLen = 0
intInputLen = MSComm1.InBufferCount
ReDim BytReceived(intInputLen)
BytReceived() = MSComm1.Input
Call Receive
'数据处理代码
End Select
End Sub

Public Sub Receive()
Dim i As Integer
For i = 0 To UBound(BytReceived)
strData = strData & hex(BytReceived(i))
Next
'strDataInteger = hex(BytReceived(1))
'Text1 = strDataInteger '温度值整数部分,十六进制
'Text1 = HexToDec(Text1)
Text2 = strData 'RD显示的
'Text1 = strData
'Text1 = b_to_d(Text1) '二进制转十进制
End Sub

Private Sub Timer1_Timer()
strData = ""
strDataInteger = ""
End Sub


再次感谢。
...全文
378 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
acstar 2007-09-21
  • 打赏
  • 举报
回复
改成 Dim CmdByte as String 就不会出现上述错误,但是依然没收到数据
acstar 2007-09-21
  • 打赏
  • 举报
回复
of123 大大:

CmdByte = &H5A
MSComm1.Output = CmdByte '数据传送时就是二进制,不要搞成字符串

实时错误380 Invalid Property Value
acstar 2007-09-21
  • 打赏
  • 举报
回复
BusHound是监控USB口的吧?
of123 2007-09-21
  • 打赏
  • 举报
回复
看了一下你的代码,你对数据进制的理解错误。不要把数据转成 16 或 2 进制字符串。
串口传送的一般就是 2 进制的数字或 ASCII 码。
你的错误致使下位机收不到正确的命令,当然也就没有正确的应答。

Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As Byte

CmdByte = &H5A
MSComm1.Output = CmdByte '数据传送时就是二进制,不要搞成字符串
MSComm1.RThreshold = 6
End Sub


Private Sub MSComm1_OnComm()
On Error Resume Next
Dim vrtBuff As Variant

Text1 = ""
Select Case MSComm1.CommEvent
Case comEvReceive

vrtBuff = MSComm1.Input '二进制数据必须这样接收
BytReceived = vrtBuff '再从 Variant 转存

Call Receive
End Select
End Sub

Public Sub Receive()
Dim i As Integer
For i = 0 To UBound(BytReceived)
strData = strData & Right("0" & Hex(BytReceived(i), 2)
Next
TxtRD.Text = strData 'RD显示
End Sub
of123 2007-09-21
  • 打赏
  • 举报
回复
建议用 BusHound 等监控软件看看是否有数据传送。这样对于判断问题出在哪里很有帮助。
acstar 2007-09-21
  • 打赏
  • 举报
回复
是上位机询问,下位机应答,通过上位机发送控制字实现。
acstar 2007-09-21
  • 打赏
  • 举报
回复
我用现成的Delphi程序测试过,下位机只要能收到上位机发送的5A控制字,就能向上位机发送温度数据。
zdingyun 2007-09-21
  • 打赏
  • 举报
回复
发送16进制数据字节可变化:
Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte() As Byte
Dim i As Integer
Dim sj_txt As String
sj_txt = "5A"
ReDim CmdByte(Len(sj_txt) / 2 - 1)
For i = 0 To Len(sj_txt) - 1 Step 2
CmdByte(i / 2) = Val("&H" & Mid(sj_txt, i + 1, 2))
Next
MSComm1.Output = CmdByte
End Sub
acstar 2007-09-21
  • 打赏
  • 举报
回复
"串口是字符设备,经串口传送的是ASCII字符的二进制数据流:
Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As Byte
CmdByte = &H5A
MSComm1.Output = Chr(CmdByte)
End Sub"

chr()解决了所有问题,太感谢了。

最后用很简短的程序:
Option Explicit
Dim BytReceived() As Byte
Dim lenInput As String
Dim strData As String
Dim strDataInteger As String
Dim Text1 As String
Dim Text2 As String

Private Sub Form_Load()
MSComm1.CommPort = 1 'COM1
MSComm1.Settings = "1200,n,8,1" '串口设置
MSComm1.InputMode = comInputModeBinary '二进制传输
MSComm1.InBufferSize = 512 '接收缓冲区大小
MSComm1.OutBufferSize = 512 '发送缓冲区大小
MSComm1.RThreshold = 7 '产生MSComm事件
MSComm1.PortOpen = True
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
Timer1.Interval = 200 '200ms Timer1使strData清空
End Sub


Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As Byte
CmdByte = &H5A
MSComm1.Output = Chr(CmdByte)
End Sub


Private Sub MSComm1_OnComm()
On Error Resume Next
Dim vrtBuff As Variant

Text1 = ""
Select Case MSComm1.CommEvent
Case comEvReceive

vrtBuff = MSComm1.Input '二进制数据接收
BytReceived = vrtBuff '再从 Variant 转存

Call Receive
End Select
End Sub

Public Sub Receive()
Dim i As Integer
For i = 0 To UBound(BytReceived)
strData = strData & hex(BytReceived(i))
Next
TxtRD.Text = strData 'RD显示
End Sub

Private Sub Timer1_Timer()
strData = ""
strDataInteger = ""
End Sub

就可以实现功能。

问题解决了,再次感谢,加分给你。
zdingyun 2007-09-21
  • 打赏
  • 举报
回复
用以下代码更恰当:
Private Sub Command1_Click()
Dim CmdByte(0) As Byte
CmdByte(0) = &H5A
MSComm1.Output = CmdByte
End Sub
zdingyun 2007-09-21
  • 打赏
  • 举报
回复
串口是字符设备,经串口传送的是ASCII字符的二进制数据流:
Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As Byte
CmdByte = &H5A
MSComm1.Output = Chr(CmdByte)
End Sub
acstar 2007-09-21
  • 打赏
  • 举报
回复
"你的CmdReceiveTemp_Click事件发送的是
16进制的3031303131303130
数据,根本未发送16进制
5A命令,所以无法是下位机返回数据,所谓二进制数据
你的CmdReceivePara_Click事件发送的是
16进制的3130313031303130
数据,根本未发送16进制
5A命令
从你对串口通信的理解看,存在误解,串口是字符设备,经串口传送的是ASCII码的二进制数据流。
这可从你代码中的注释看出:
'十六进制转二进制
'5A = 0101 1010
你把16进制的5A以字符理解,所以会得出上述错误。"

---------我现在也认识到了这点。你的程序我慢慢看下。

我还有个问题:

Private Sub CmdReceiveTemp_Click() '接收温度
Dim CmdByte As Byte
CmdByte = &H5A
MSComm1.Output = CmdByte
End Sub

用这段程序发送控制字5A应该没错吧? 为什么到这里显示 Invalid Property Value呢?
zdingyun 2007-09-21
  • 打赏
  • 举报
回复
你的CmdReceiveTemp_Click事件发送的是
16进制的3031303131303130
数据,根本未发送16进制
5A命令,所以无法是下位机返回数据,所谓二进制数据
你的CmdReceivePara_Click事件发送的是
16进制的3130313031303130
数据,根本未发送16进制
5A命令
从你对串口通信的理解看,存在误解,串口是字符设备,经串口传送的是ASCII码的二进制数据流。
这可从你代码中的注释看出:
'十六进制转二进制
'5A = 0101 1010
你把16进制的5A以字符理解,所以会得出上述错误。

以下是依据你通信协议做的代码,供参考:
Option Explicit
Dim BytReceived() As Byte
Dim strData As String
Dim lenInput As Integer
Dim bytSendByte() As Byte '发送二进制数据
Dim strSendText As String '发送文本数据
Dim blnAutoSendFlag As Boolean
Dim openFlag As Boolean
Private Sub cmdRecv_Click()
Dim bytDataShow() As Byte
Dim varData As Variant
Dim strData As String
Dim i As Integer
MSComm1.InputLen = 0
varData = MSComm1.Input
bytDataShow = varData
For i = 0 To UBound(bytDataShow) - 1
strData = strData + Chr(bytDataShow(i))
Next i
Text3.Text = strData
End Sub

Private Sub CmdReceivePara_Click() '接收参数
TxtSend = "AA"
cmdSend_Click
End Sub

Private Sub cmdSend_Click()
Dim longth As Integer
strSendText = Me.TxtSend.Text
longth = strHexToByteArray(strSendText, bytSendByte())
If longth > 0 Then
If MSComm1.PortOpen = True Then
Me.MSComm1.Output = bytSendByte
End If
End If
End Sub
'字符串表示的十六进制数据转化为相应的字节串,返回转化后的字节数
Function strHexToByteArray(strText As String, bytByte() As Byte) As Integer
Dim HexData As Integer '十六进制(二进制)数据字节对应值
Dim hstr As String * 1 '高位字符
Dim lstr As String * 1 '低位字符
Dim HighHexData As Integer '高位数值
Dim LowHexData As Integer '低位数值
Dim HexDataLen As Integer '字节数
Dim StringLen As Integer '字符串长度
Dim Account As Integer
Dim n As Integer
'计数
'txtSend = "" '设初值
HexDataLen = 0
strHexToByteArray = 0
StringLen = Len(strText)
Account = StringLen \ 2
ReDim bytByte(Account)
For n = 1 To StringLen
Do '清除空格
hstr = Mid(strText, n, 1)
n = n + 1
If (n - 1) > StringLen Then
HexDataLen = HexDataLen - 1
Exit For
End If
Loop While hstr = " "
Do
lstr = Mid(strText, n, 1)
n = n + 1
If (n - 1) > StringLen Then
HexDataLen = HexDataLen - 1
Exit For
End If
Loop While lstr = " "
n = n - 1
If n > StringLen Then
HexDataLen = HexDataLen - 1
Exit For
End If
HighHexData = ConvertHexChr(hstr)
LowHexData = ConvertHexChr(lstr)

If HighHexData = -1 Or LowHexData = -1 Then '遇到非法字符中断转化
HexDataLen = HexDataLen - 1
Exit For
Else
HexData = HighHexData * 16 + LowHexData
bytByte(HexDataLen) = HexData
HexDataLen = HexDataLen + 1
End If
Next n
If HexDataLen > 0 Then '修正最后一次循环改变的数值
HexDataLen = HexDataLen - 1
ReDim Preserve bytByte(HexDataLen)
Else
ReDim Preserve bytByte(0)
End If
If StringLen = 0 Then '如果是空串,则不会进入循环体
strHexToByteArray = 0
Else
strHexToByteArray = HexDataLen + 1
End If
End Function

Private Sub CmdReceiveTemp_Click() '接收温度
TxtSend = "5A"
cmdSend_Click
End Sub

Private Sub MSComm1_OnComm()
On Error Resume Next
Dim strBuff As String
Text1 = ""
Select Case MSComm1.CommEvent
Case 2
MSComm1.InputLen = 0
strBuff = MSComm1.Input
BytReceived() = strBuff
jieshou
LblJieshou = Text1
lenInput = Len(LblJieshou)
Text3 = lenInput \ 2
Text2 = Mid(LblJieshou, 1, 2)
'数据处理代码
If Mid(LblJieshou, 1, 2) = "00" Then
Text4 = Mid(LblJieshou, 3, lenInput - 8)
Text5 = ""
ElseIf Mid(LblJieshou, 1, 2) = "01" Then
Text5 = Mid(LblJieshou, 3, lenInput - 10)
Text4 = ""
End If
End Select
End Sub
Private Sub Form_Load()
Dim port As Integer
port = 1
MSComm1.CommPort = port 'COM端口
MSComm1.Settings = "9600,n,8,1"
MSComm1.InputMode = comInputModeBinary '采用二进制传输
MSComm1.InBufferCount = 0 '清空接受缓冲区
MSComm1.OutBufferCount = 0 '清空传输缓冲区
MSComm1.RThreshold = 1 '产生MSComm事件
MSComm1.InBufferSize = 1024
MSComm1.PortOpen = True '打开端口
Text1 = ""
Text3 = ""
LblJieshou = ""
Text4 = ""
Timer1.Interval = 200
TxtSend = ""
End Sub

Private Sub Timer1_Timer()
strData = ""
End Sub
Function ConvertHexChr(str As String) As Integer
Dim test As Integer
test = Asc(str)
If test >= Asc("0") And test <= Asc("9") Then
test = test - Asc("0")
ElseIf test >= Asc("a") And test <= Asc("f") Then
test = test - Asc("a") + 10
ElseIf test >= Asc("A") And test <= Asc("F") Then
test = test - Asc("A") + 10
Else
test = -1 '出错信息
End If
ConvertHexChr = test
End Function

Public Sub jieshou()
Dim i As Integer
'Text3 = UBound(BytReceived)
For i = 0 To UBound(BytReceived)
If Len(hex(BytReceived(i))) = 1 Then
strData = strData & "0" & hex(BytReceived(i))
Else
strData = strData & hex(BytReceived(i))
End If
Next
Text1 = strData
'Text2 = strData
End Sub
zdingyun 2007-09-20
  • 打赏
  • 举报
回复
你的TxtRD控件控件我没用过。假如控件无问题,请将Text1和Text2变量改成Txt1和Txt2名,不要与VB自带的控件名相同。
acstar 2007-09-20
  • 打赏
  • 举报
回复
我在窗体上添加的控件是 TxtRD,后用TxtRD.Text = Text2值传递,无法显示。调试可以看到Text2没收到数据。
zdingyun 2007-09-20
  • 打赏
  • 举报
回复
你用串口调试精灵代码调试过下位机吗?我的感觉,你发送部分代码能正确发送数据.接收部分代码较零乱,需修改.但MSComm1_OnComm事件代码应该无问题.
另外问题可能出在下位机.也请检查串口接线是否正确.
并请说明是上位机询问,下位机应答?
还是下位机定时返回数据?
zdingyun 2007-09-20
  • 打赏
  • 举报
回复
你就用我2007-9-20 13:45:49 的答贴代码,就可接收,如接收数据长度较长,且字节长度固定,应将MSComm1属性RThreshold 设置接收字节长度.
此外修改OnComm事件代码:
Private Sub MSComm1_OnComm()
On Error Resume Next
Dim strBuff As String
Dim intInputLen As Integer
Text1 = ""
Select Case MSComm1.CommEvent
Case comEvReceive
MSComm1.InputLen = 0
intInputLen = MSComm1.InBufferCount
ReDim BytReceived(intInputLen)
BytReceived() = MSComm1.Input
Call Receive
CmdReceiveTemp_Click
'数据处理代码
End Select
End Sub
acstar 2007-09-20
  • 打赏
  • 举报
回复
我的代码是用OnComm来接收的,CmdReceiveTemp按钮的Click事件只是起到把从OnComm中接收的数据传递给TextBox显示的作用,至于CmdReceiveTemp_Click事件中发送的控制字是为了通知单片机发送数据到串口,以触发OnComm事件的。

在CmdSendPara_Click事件和我们现在讨论的问题无关,这个事件的作用是发送一个校准参数给单片机,我现在数据都没收到,就不存在校准了 - -!

我还是倾向于保留OnComm来接收数据,还望大大明示。
zdingyun 2007-09-20
  • 打赏
  • 举报
回复
acstar()
更正,前述方案中
在CmdSendPara_Click事件中增加代码,而不用MSComm1_OnComm事件接收
的叙述有错误,调试未通过,MSComm1_OnComm事件代码必须保留,实际接收起作用的仍是MSComm1_OnComm事件。其它与前叙述相同。
acstar 2007-09-20
  • 打赏
  • 举报
回复
谢谢,学习中,有问题再请教。顺利解决的话我会来结贴。
加载更多回复(12)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧