Excel VBA RunBlock and BlockReady Implementation

Post your VB and VBA discussions here
Post Reply
tintin305
Newbie
Posts: 0
Joined: Mon Dec 14, 2015 8:23 am

Excel VBA RunBlock and BlockReady Implementation

Post by tintin305 »

Hi,

I am trying to implement an excel macro where I use rapid block mode to take data from the picoscope.
I am using the 4824.
The programmers guide suggests the use of ps4000aRunBlock start the oscilloscope running.
Then it requires the last two parameters of this function to be used for the ps4000aBlockReady function.
There are no example implementations of these functions online or on your SDK with using the rapid block mode.
I am not using triggers in the implementation, as I would like to replicate the way that the picoscope software does when saving data without any triggers.
As I am not using block mode the guide does not suggest the use of polling.
How do I implement the aBlockReady function in conjunction with the aRunBlock to gather data?

I am trying to follow the sample code that is presented in the SDK, but it does not use these functions.


Thanks for any help.

Hitesh

Re: Excel VBA RunBlock and BlockReady Implementation

Post by Hitesh »

Hi tintin305,

Excel VBA does not support the use of C style callbacks so you will need to use the RunBlock() and IsReady() functions provided by the ps4000aWrap dll in order to collect the data as per the block capture example provided in the Excel VBA file.

The ps4000aWrap.dll file is located in the lib folder of the SDK installation directory.

The main difference between Block and Rapid Block capture when using the API functions is calling ps4000aSetNoOfCaptures() after segmenting the memory using ps4000aMemorySegments(), followed by setting up the data buffers for each channel/segment combination and calling ps4000aGetValuesBulk() to retrieve the data.

Hope this helps.

tintin305
Newbie
Posts: 0
Joined: Mon Dec 14, 2015 8:23 am

Re: Excel VBA RunBlock and BlockReady Implementation

Post by tintin305 »

Thanks for the help Hitesh,

Unfortunately I am now presented with another problem.
When I call the MemorySegments function inside Excel the program crashes with no error message.
This is the code that I have in the program declaration:

Code: Select all

Declare Function ps4000aMemorySegments Lib "ps4000a.dll" (ByVal handle As Integer, ByVal nSegments As Integer, ByVal nMaxSamples As Long) As Integer

and this is how it is implemented:

Code: Select all

Call ps4000aMemorySegments(handle, 1, maxSamples)
The function is called after GetTimeBase and before SetNoOfCaptures.

Without the code for the MemorySegments the code will run, but the cells are filled with zeroes.


Thanks for the help.

Hitesh

Re: Excel VBA RunBlock and BlockReady Implementation

Post by Hitesh »

Hi tintin305,

You need to pass the nMaxSamples parameter by reference as it is defined as a pointer to a 32-bit integer in the Programmer's Guide. Also, nSegments is defined as an unsigned 32-bit integer as is the PICO_STATUS type (see the PicoStatus.h header file in the SDK) so you should use a Long:

Code: Select all

Declare Function ps4000aMemorySegments Lib "ps4000a.dll" (ByVal handle As Integer, ByVal nSegments As Long, ByRef nMaxSamples As Long) As Long
Hope this helps.

tintin305
Newbie
Posts: 0
Joined: Mon Dec 14, 2015 8:23 am

Re: Excel VBA RunBlock and BlockReady Implementation

Post by tintin305 »

Hi Hitesh,

Thank you so much for the help.
I am still struggling to get the device to record in Rapid Block Mode.
It seems that the channels are not recording the data sequentially.
Is there any way that you can provide me with an example excel macro,
that can record, for example 2 or 3 channels from the picoscope in rapid block mode.

Hitesh

Re: Excel VBA RunBlock and BlockReady Implementation

Post by Hitesh »

Hi tintin305,

Could you please provide your source code so that we can see how you are implementing the data capture and setting up the data buffers?

There is another thread which might be of interest although it is VB .NET code.

Regards,

tintin305
Newbie
Posts: 0
Joined: Mon Dec 14, 2015 8:23 am

Re: Excel VBA RunBlock and BlockReady Implementation

Post by tintin305 »

Hi Hitesh,

I seem to have got the system to take measurements from 6 channels. Although I am not sure if the scope is taking the data sequentially, by that I mean each channel samples the voltage and then that is stored and then each channel samples the voltage at the next timestep and so on.

Code: Select all

Declare Function ps4000aOpenUnit Lib "ps4000a.dll" (handle As Integer, ByVal serial As Byte) As Integer
Declare Sub ps4000aCloseUnit Lib "ps4000a.dll" (ByVal handle As Integer)
Declare Function ps4000aChangePowerSource Lib "ps4000a.dll" (ByVal handle As Integer, ByVal status As Integer) As Integer

Declare Function ps4000aGetUnitInfo Lib "ps4000a.dll" (ByVal handle As Integer, ByVal str As String, ByVal lth As Integer, requiredSize As Integer, ByVal info As Integer) As Integer


Declare Function ps4000aSetChannel Lib "ps4000a.dll" (ByVal handle As Integer, ByVal channel As Integer, ByVal enabled As Integer, ByVal dc As Integer, ByVal range As Integer, ByVal analogEffset As Single) As Integer
Declare Function ps4000aSetSimpleTrigger Lib "ps4000a.dll" (ByVal handle As Integer, ByVal enable As Integer, ByVal source As Integer, ByVal threshold As Integer, ByVal direction As Integer, ByVal delay As Long, ByVal autotrigger As Integer) As Integer
Declare Function ps4000aGetTimebase Lib "ps4000a.dll" (ByVal handle As Integer, ByVal timebase As Long, ByVal noSamples As Long, timeIntervalNanoseconds As Long, maxSamples As Long, ByVal segment As Integer) As Integer
Declare Function ps4000aSetDataBuffer Lib "ps4000a.dll" (ByVal handle As Integer, ByVal channel As Integer, buffer As Integer, ByVal length As Long, ByVal segmentIndex As Long, ByVal ratiomode As Integer) As Integer
Declare Function ps4000aGetValues Lib "ps4000a.dll" (ByVal handle As Integer, ByVal startIndex As Long, numSamples As Long, ByVal downSampleRatio As Long, ByVal downsampleRatioMode As Integer, ByVal segmentIndex As Integer, overflow As Integer) As Integer
Declare Function ps4000aGetValuesBulk Lib "ps4000a.dll" (ByVal handle As Integer, numSamples As Long, ByVal startIndex As Long, ByVal endIndex As Long, ByVal downSampleRatio As Long, ByVal downsampleRatioMode As Integer, overflow As Integer) As Integer
Declare Function ps4000aStop Lib "ps4000a.dll" (ByVal handle As Integer) As Integer

Declare Function RunBlock Lib "ps4000aWrap.dll" (ByVal handle As Integer, ByVal noPreTriggerSamples As Long, ByVal noPostTriggerSamples As Long, ByVal timebase As Long, ByVal segmentIndex As Integer) As Integer
Declare Function IsReady Lib "ps4000aWrap.dll" (ByVal handle As Integer) As Integer
Declare Function ps4000aSetBandwidthFilter Lib "ps4000a.dll" (ByVal handle As Integer, ByVal channel As Integer, ByVal bandwidth As Integer) As Long

Declare Function ps4000aMemorySegments Lib "ps4000a.dll" (ByVal handle As Integer, ByVal nSegments As Long, ByRef nMaxSamples As Long) As Long
Declare Function ps4000aSetNoOfCaptures Lib "ps4000a.dll" (ByVal handle As Integer, ByVal nCaptures As Integer) As Long


Declare Sub Sleep Lib "kernel32.dll" (ByVal time As Long)

Dim handle As Integer
Dim status As Integer
Dim str As String * 255
Dim serial As String * 255


Sub GetData()
    
    Dim overflow As Integer
    Dim maxSamples As Long
    Dim timeInterval As Long
    Dim required As Integer
    Dim timebase As Integer
    Dim threshold As Integer
    
    handle = 0
    serial = ""
    
    status = ps4000aOpenUnit(handle, 0)
  
    If handle = 0 Then
        MsgBox "Unit not opened", vbOKOnly, "Error Message"
        Exit Sub
    End If
    
    If status = 286 Then
        status = ps4000aChangePowerSource(handle, status)
    End If
  
    
    ' Set Channels
    Call ps4000aSetChannel(handle, 0, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 1, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 2, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 3, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 4, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 5, 1, 1, 11, 0)
    Call ps4000aSetChannel(handle, 6, 0, 1, 10, 0)
    Call ps4000aSetChannel(handle, 7, 0, 1, 10, 0)
    
    
    
    timebase = 799
    numSamples = 5000

    ReDim valuesChA(numSamples - 1) As Integer
    ReDim valuesChB(numSamples - 1) As Integer
    ReDim valuesChC(numSamples - 1) As Integer
    ReDim valuesChD(numSamples - 1) As Integer
    ReDim valuesChE(numSamples - 1) As Integer
    ReDim valuesChF(numSamples - 1) As Integer
    
    status = ps4000aGetTimebase(handle, timebase, numSamples, timeInterval, maxSamples, 0)
    
    
   Call ps4000aMemorySegments(handle, 6, maxSamples)
   Call ps4000aSetNoOfCaptures(handle, 1)
  
    
          Call ps4000aSetDataBuffer(handle, 0, valuesChA(0), numSamples, 0, 0)
          Call ps4000aSetDataBuffer(handle, 1, valuesChB(0), numSamples, 0, 0)
          Call ps4000aSetDataBuffer(handle, 2, valuesChC(0), numSamples, 0, 0)
          Call ps4000aSetDataBuffer(handle, 3, valuesChD(0), numSamples, 0, 0)
          Call ps4000aSetDataBuffer(handle, 4, valuesChE(0), numSamples, 0, 0)
          Call ps4000aSetDataBuffer(handle, 5, valuesChF(0), numSamples, 0, 0)
     
  pParameter = False
  
Call ps4000aSetBandwidthFilter(handle, 0, 1000)
Call ps4000aSetBandwidthFilter(handle, 1, 1000)
Call ps4000aSetBandwidthFilter(handle, 2, 1000)
Call ps4000aSetBandwidthFilter(handle, 3, 1000)
Call ps4000aSetBandwidthFilter(handle, 4, 1000)
Call ps4000aSetBandwidthFilter(handle, 5, 1000)
Call ps4000aSetBandwidthFilter(handle, 6, 1000)
Call ps4000aSetBandwidthFilter(handle, 7, 1000)
     
    threshold = (32767 * (1000 / 2000))
     
    Call ps4000aSetSimpleTrigger(handle, 0, 0, threshold, 0, 0, 0)
    

    status = RunBlock(handle, 0, numSamples, timebase, 0)
    
    While IsReady(handle) = 0
        Sleep (5)
    Wend
    
    Call ps4000aStop(handle)
    overflow = 0
    
    status = ps4000aGetValues(handle, 0, numSamples, 0, 0, 0, overflow)
    
    For i = 0 To (numSamples - 1)
      Cells(i + 5, "A").Value = (timeInterval * i) * 0.000001
      Cells(i + 5, "B").Value = ConvertADCToMv(valuesChA(i), 32767, 50)
      Cells(i + 5, "C").Value = ConvertADCToMv(valuesChB(i), 32767, 50)
      Cells(i + 5, "D").Value = ConvertADCToMv(valuesChC(i), 32767, 50)
      Cells(i + 5, "E").Value = ConvertADCToMv(valuesChD(i), 32767, 50)
      Cells(i + 5, "F").Value = ConvertADCToMv(valuesChE(i), 32767, 50)
      Cells(i + 5, "G").Value = ConvertADCToMv(valuesChF(i), 32767, 50)
    Next i
    

    
    
    
    ps4000aCloseUnit (handle)
    
Sheets("Pivot Sheet (unscaled data)").Select
   ActiveSheet.PivotTables("PivotTable2").RefreshTable
    
    
Sheets("Pivot Sheet (scaled data)").Select
   ActiveSheet.PivotTables("PivotTable1").RefreshTable
    
    
    
Sheets("Instantaneous Power").Select
   ActiveSheet.PivotTables("PivotTable2").RefreshTable
    
  
End Sub

Function ConvertADCToMv(ByVal adcCount As Integer, ByVal maxADCCount As Integer, ByVal voltageRange As Integer) As Single

    ConvertADCToMv = (adcCount / maxADCCount) * voltageRange

End Function

Thanks for the help

Hitesh

Re: Excel VBA RunBlock and BlockReady Implementation

Post by Hitesh »

Hi tintin305,

The PicoScope 4824 has simultaneous sampling on channels, so you should find that in each segment, a reading should be taken at the same time for each channel for each sample number. If you are seeing something different, please provide a display of what you are seeing or provide the same settings in the PicoScope 6 application and see if the problem persists.

I did notice that the example Excel VBA file is using incorrect data types e.g. the functions should return a Long and enumeration values should also be passed as Long values. I have pasted updated Function declarations below - please also check the additional functions that you are using. The updated examples will be available via the next SDK release.

Code: Select all

Declare Function ps4000aOpenUnit Lib "ps4000a.dll" (handle As Integer, ByVal serial As Byte) As Long
Declare Sub ps4000aCloseUnit Lib "ps4000a.dll" (ByVal handle As Integer)
Declare Function ps4000aChangePowerSource Lib "ps4000a.dll" (ByVal handle As Integer, ByVal status As Long) As Long

Declare Function ps4000aGetUnitInfo Lib "ps4000a.dll" (ByVal handle As Integer, ByVal str As String, ByVal lth As Integer, ByRef requiredSize As Integer, ByVal info As Long) As Long

Declare Function ps4000aSetChannel Lib "ps4000a.dll" (ByVal handle As Integer, ByVal channel As Long, ByVal enabled As Integer, ByVal dc As Long, ByVal range As Long, ByVal analogOffset As Single) As Long
Declare Function ps4000aSetSimpleTrigger Lib "ps4000a.dll" (ByVal handle As Integer, ByVal enable As Integer, ByVal source As Long, ByVal threshold As Integer, ByVal direction As Long, ByVal delay As Long, ByVal autotrigger As Integer) As Long
Declare Function ps4000aGetTimebase Lib "ps4000a.dll" (ByVal handle As Integer, ByVal timebase As Long, ByVal noSamples As Long, ByRef timeIntervalNanoseconds As Long, ByRef maxSamples As Long, ByVal segmentIndex As Long) As Long
Declare Function ps4000aSetDataBuffer Lib "ps4000a.dll" (ByVal handle As Integer, ByVal channel As Long, ByRef buffer As Integer, ByVal length As Long, ByVal segmentIndex As Long, ByVal ratioMode As Long) As Long
Declare Function ps4000aGetValues Lib "ps4000a.dll" (ByVal handle As Integer, ByVal startIndex As Long, ByRef numSamples As Long, ByVal downSampleRatio As Long, ByVal downsampleRatioMode As Long, ByVal segmentIndex As Long, ByRef overflow As Integer) As Long
Declare Function ps4000aStop Lib "ps4000a.dll" (ByVal handle As Integer) As Long
Declare Function ps4000aMaximumValue Lib "ps4000a.dll" (ByVal handle As Integer, ByRef value As Integer) As Long

Declare Function RunBlock Lib "ps4000aWrap.dll" (ByVal handle As Integer, ByVal noPreTriggerSamples As Long, ByVal noPostTriggerSamples As Long, ByVal timebase As Long, ByVal segmentIndex As Long) As Long
Declare Function IsReady Lib "ps4000aWrap.dll" (ByVal handle As Integer) As Integer
Your code only shows the collection of a single segment - is that intended?

Hope this helps.

tintin305
Newbie
Posts: 0
Joined: Mon Dec 14, 2015 8:23 am

Re: Excel VBA RunBlock and BlockReady Implementation

Post by tintin305 »

Hi Hitesh,

The explanation is useful, however, I am confused about the last part. You asked why my code only collects from a single segment. Is the data from each channel stored in a separate segment. ie. Channel A data is stored in segment 1, Channel B data is stored in segment 2... can you clarify on this.
I did a test with an arduino where I used 6 inputs which turned on and off a few milliseconds apart, the last channel was off. The image below shows the voltage of the 6 channels, 5 are seen in it, as the last one was 0V. The graphs seems to be in accordance with how I expected the data to be taken into the scope.
Is this just luck that the data looks how I expected it to look?
As an end product I want to take voltage levels from the 6 channels at the same time (or as close to the exact same time as possible) and then place these voltage values from the channels into excel to work with.

Thanks for the help
Attachments
voltage.png

Hitesh

Re: Excel VBA RunBlock and BlockReady Implementation

Post by Hitesh »

Hi tintin305,

It might be worth referring to the Rapid trigger mode entry in our A to Z of PC Oscilloscopes for an explanation of this mode of capture as well as the Programmer's Guide.

When you segment the memory of a PicoScope device, the onboard buffer memory is divided into a number of 'chunks'. The memory in each 'chunk' is then shared between the enabled channels.

For example, if you specify 4 segments in the call to ps4000aMemorySegments, you should get 4 segments of 64MS (256MS/4). If you have 4 channels enabled, then each segment would effectively be sub-divided into 16MS blocks for each channel.

When collecting data, waveforms would captured into the first segment for each channel on the occurrence of the first trigger event (normally segment 0 if this has been specified in the call to ps4000aRunBlock/RunBlock). On the next trigger event, the waveform data for each channel would be captured into the next segment and so on.

If you only need to capture a single waveform for each channel, you do not need to use Rapid Block mode and should be able to adapt the existing Excel VBA example accordingly. In the event of a single Block Mode capture, calling ps4000aGetValues would result in data being written into each of the data buffer(s) set-up for a channel as long as it has been enabled.

I hope that this clarifies things.

Regards,

Post Reply