一、引言
在高等院校、科研院所等单位的教学、科研活动中,经常需要测量超低频信号的波形和非周期信号的波形,但往往因为价格较低的通用示波器不具有上述功能,而具有这些功能的数字示波器或专用摸拟示波器价格昂贵,致使教学、科研受到了影响。
运用单片机技术和VB6设计的测量系统,不但具有上述功能,而且还能指示波形上任意点的值,还能送大屏幕显示(便于教学演示),尤其经费支出很少(利用单位现有微机和大屏幕,实现一机多用)。基本设计思想为:利用价格低而性能好的单片机(如AT89系列)和具有采样保持器的快速A/D实现数据采集,用VB6通信控件收发数据、用VB6设计用户界面、用VB6处理数据(标度变换、插值后绘制波形、显示波形上鼠标单击处的值等)。本文重点研究测量数据的接收、处理和程序设计。
二、界面设计
用户界面(见下图所示)是在微型计算机屏幕上显示用于控制测量的按钮和输入输出信息,用鼠标进行操作控制。下表为用户界面使用的主要控件的属性和用途。
用户界面
主要控件的属性和用途
控件 |
属性 |
设置值 |
控件用途 |
Form1 |
Caption |
|
形成面板,用Paint事件建坐标系,用Load事件初始化控件属性值 |
Picture1 |
Caption |
|
Line方法画线,Pset方法画点,Print方法显示信息,MouseDown事件计算单击处的值。 |
Option1 |
Caption
Style |
暂停
Graphical |
便于读取波形上任意点的值 |
Option2 |
Caption
Style |
测量
Graphical |
用Click事件绘制波形 |
Command1 |
Caption |
停止 |
用Click事件停止测量 |
Combo1 |
List
Style |
0.1,1,10,100
DropDown |
从列表中选择横坐标每厘米表示的时间值(ms), 用Click事件重绘波形。 |
Combo2 |
List
Style |
0.01,0.1,1,10,100
DropDown |
从列表中选择纵坐标每厘米表示的电压值(V), 用Click事件重绘波形。 |
Combo3 |
List
Style |
10,100,1000,10000
DropDown |
从列表中选择采样的时间间隔(μs), 并通过Click事件向单片机发送采样信息。 |
MSComm1 |
|
用代码设置 |
收发数据 |
三、数据的接收与处理
1.数据的接收
运用VB6提供的串行通信控件接收数据,其优点是数据的接收与处理互不影响,这一功能可由通信控件的OnComm事件实现。若把通信控件的Rthreshold属性设置为单片机每次发送给PC机的字节数,则只有当串口接收缓冲区接收到规定的字节数时,才发生OnComm事件,对OnComm事件编写代码,就可进行标度变换并存入数组中,以供绘图过程使用。在发生OnComm事件之前,串口接收缓冲区自动逐个接收数据,同时VB6执行其它代码,如对刚接收的一批数据进行插值、绘制波形等。
2.标度变换
被测模拟信号经A/D转换后,变成了相应的二进制码,不同的A/D器件对数字量的编码方法不同,对于双极性输入的A/D(为测量双极性模拟信号,应选用双极性输入的A/D),通常采用的编码方法为:符号-数值双极性码和偏移二进制双极性码。对于单字节的偏移二进制双极性码,00H对应模拟信号的最大值,80H对应模拟信号的0值,FFH对应模拟信号的最小值(负值)。显然,这些数码虽然与模拟信号有一一对应关系,但并不等于模拟值,因此必须把偏移二进制双极性码所代表的模拟量大小表示出来,常称之为标度变换。经研究,偏移二进制双极性码的标度变换公式为
VA=(1- NB / 2n-1).Vmax
式中,NB表示偏移二进制双极性码(对应的十进制值),VA表示NB代表的模拟值,n为偏移二进制双极性码的位数,Vmax为A/D的最大输入模拟值。若被测模拟信号经分压后接入A/D,则还需再乘上分压系数。
3.插值与绘制波形
采集的数据个数毕竟有限,为了把这些数据进行标度变换后绘制成波形,必须把变换后的数据进行插值,建立插值函数,再根据插值函数计算出大量数值,用描点法在坐标系中绘制波形。
当用等间隔法采样时,拉格郎日三点插值的插值函数为
u=[0.5(t-t1)(t-t2)u0 -(t-t0)(t-t2)u1+0.5(t-t0)(t-t1)u2 ]/tm2
式中,u0为t=t0时的u值,u1为t=t1时的u值,u2为t=t2时的u值,tm为采样时间间隔。时间单位为ms,电压单位为v。
当采集数据较多时,采用分组插值法,能较好地反映被测信号的波形。
4.计算波形上鼠标单击处的值
当把鼠标指针指向波形上某点且按下鼠标键时,鼠标指针当前的坐标值自动保存在x、y中,利用x、y和坐标原点oldx 、oldy值及纵横轴每厘米代表的值,就可计算出波形上单击处的值。计算公式为
u=(oldy-y).Val(Combo2.Text)
t=(x-oldx).Val(Combo1.Text)
四、程序设计
实现上述功能的核心代码如下:
'声明通用变量
Public oldx As Single, oldy As Single
Private y() As Single
'绘制波形(拉格郎日三点插值,多点时分段)
Private Sub buo()
Dim n As Integer, i As Integer, j As Integer
Dim j1 As Integer, j2 As Integer, t As Single
Dim tm As Single, tm2 As Single
Dim tm3 As Single, u As Single
lp:
If Option2.Value = True Then '按下"测量"时绘制波形
Picture1.AutoRedraw = False '绘制的波形可被清除
Picture1.Cls '清除上次绘制的波形
tm = Val(Combo3.Text) / 1000
tm2 = tm ^ 2 'tm2送tm2
tm3 = tm / 1000
n = UBound(y) '引用y()数组上界
If n >= 3 Then '测量数据3个以上时才绘制波形
n = Int((n - 1) / 2) '分组插值组数
For i = 1 To n '建立n个插值函数绘制波形
j = 2 * (i - 1) + 1
j1 = j + 1: j2 = j + 2
t0 = (j - 1) * tm: t1 = j * tm: t2 = (j + 1) * tm
For t = t0 To t2 Step tm3 '建立第i个插值函数绘波形
u = (t - t1) * (t - t2) * y(j) * 0.5
u = u - (t - t0) * (t - t2) * y(j1)
u = u + (t - t0) * (t - t1) * y(j2) * 0.5
u = u / tm2
Picture1.PSet (t / Val(Combo1.Text) + oldx, _
oldy - u / Val(Combo2.Text)), QBColor(9)
DoEvents '可响应其它控件发生的事件
Next t
Next i
GoTo lp
Else
Picture1.Print "无测量数据"
Exit Sub
End If
End If
End Sub
Private Sub Combo1_Click()
Call buo '改变横轴值/div时,重绘制波形
End Sub
Private Sub Combo2_Click()
Call buo '改变纵轴值/div时,重绘制波形
End Sub
'向单片机发送采样信息
Private Sub Combo3_Click()
Dim out(0) As Byte, fa As Single
fa = Val(Combo3.Text)
Select Case fa
Case 10 '采样间隔为10微秒时发送1
out(0) = &H1
Case 100 '采样间隔为100微秒时发送2
out(0) = &H2
Case 1000 '采样间隔为1000微秒时发送4
out(0) = &H4
Case 10000 '采样间隔为10000微秒时发送8
out(0) = &H8
End Select
MSComm1.Output = out '向单片机发送信息
End Sub
Private Sub Command1_Click()
End '停止测量
End Sub
'初始化
Private Sub Form_Load()
With MSComm1 '串口初始化
.InBufferSize = 1024 '接收缓冲区1024字节
.OutBufferSize = 512 '输出缓冲区512字节
.CommPort = 1 '串口1
.Settings = "9600,n,8,1" '波特率9600,1个停止位,无校验
.Handshaking = comNone '无协议
.InputLen = 0 '获得接收缓冲区的所有内容
.InputMode = comInputModeBinary '以二进制格式访问
.RThreshold = 100 '接收缓冲区可接收的字节数
.PortOpen = True '打开串口
End With
ReDim y(0) '定义y()动态数组
Combo1.Text = 1 '纵横轴初值:1/div
Combo2.Text = 1
Combo3.Text = 100 '采样间隔初值
End Sub
'建立图片框内的坐标系统
Private Sub Form_Paint()
With Picture1 '使图片框大小随窗体尺寸自动改变
.Top = 200
.Left = 300
.Width = Me.ScaleWidth - 600
.Height = Me.ScaleHeight - 1800
.ScaleMode = 7 '以厘米为单位
oldx = .ScaleWidth / 2 '图片框中心坐标
oldy = .ScaleHeight / 2
.AutoRedraw = True '使坐标系不被CLS清除
Picture1.Line (oldx, 0)-(oldx, .ScaleHeight), _
RGB(255, 0, 0) '画纵轴
Picture1.Line (0, oldy)-(.ScaleWidth, oldy), _
RGB(255, 0, 0) '画横轴
End With
For xt = -14 To 14 '画横轴厘米刻度线
If xt <> 0 Then
Picture1.Line (oldx + xt, oldy - 0.2)-(oldx _
+ xt, oldy), RGB(255, 0, 0)
End If
Next
For xt = -14 To 14 Step 0.1 '画横轴毫米刻度线
If xt <> 0 Then
Picture1.Line (oldx + xt, oldy - 0.1)-(oldx + _
xt, oldy), RGB(255, 0, 0)
End If
Next
For yt = -9 To 9 '画纵轴厘米刻度线
If yt <> 0 Then
Picture1.Line (oldx, oldy + yt)-(oldx + 0.2, _
oldy + yt), RGB(255, 0, 0)
End If
Next
For yt = -9 To 9 Step 0.1 '画纵轴毫米刻度线
If yt <> 0 Then
Picture1.CurrentX = oldx - 0.4
Picture1.CurrentY = oldy + st - 0.1
Picture1.Line (oldx, oldy + yt)-(oldx + 0.1, _
oldy + yt), RGB(255, 0, 0)
End If
Next
End Sub
'把串口接收的数据送y()数组
Private Sub MSComm1_OnComm()
If MSComm1.CommEvent = comEvReceive Then
Dim yy() As Byte, n As Integer
k = MSComm1.InBufferCount '串口接收的字节数送K
yy = MSComm1.Input '把串口接收的所有字节送yy()
ReDim y(0)
y(0) = yy(0) '取出被测摸拟量被衰减的倍数
For i = 2 To k
n = UBound(y) '当前y()数组上界
ReDim Preserve y(n + 1) '数组y()增加1个元素
y(n + 1) = yy(i - 1) '把Byte型数据转换为Sigle型
y(n + 1) = -y(0) * (y(n + 1) / 128 - 1) * 5 '标度变换
Next
End If
End Sub
Private Sub Option2_Click()
Call buo '按下“测量”按钮时绘制波形
End Sub
'计算、显示波形上任一点的值
Private Sub Picture1_MouseDown(Button As Integer, _
Shift As Integer, x As Single, y As Single)
x = (x - oldx) * Val(Combo1.Text) '计算单击处的值
y = (oldy - y) * Val(Combo2.Text)
Picture1.Line (0, 0)-(3, 2), _
Picture1.BackColor, BF '清除该矩形区
Picture1.CurrentX = 0 '移动光标
Picture1.CurrentY = 0
Picture1.Print "该点数据:"
Picture1.Print "t="; x; "ms" '显示t值
Picture1.Print "u="; y; "v" '显示u值
End Sub
五、结语
用VB6收发数据、设计用户界面、处理数据(标度变换、插值后绘制波形、显示波形上鼠标单击处的值等)及其程序设计的方法,有一定的理论和实用价值,也可应用于其他编程语言。
|