⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 waveformdisplay.cpp

📁 一个简单示波器的源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    // Revert to the original pen.
    //
    pDC->SelectObject(pcPenOld);
}

//*****************************************************************************
//
// Calculates the horizontal pixel offset required to center the waveform
// trace on the display.
//
// \param pCapData points to a structure containing information on the
// oscilloscope data which is to be rendered.
//
// This function is called to calculate the correct offset required to
// position the rendered waveform such that the middle sample in the
// waveform will appear at the center of the display area.
//
// \return The required offset to correctly center the waveform.
//
//*****************************************************************************
long CWaveformDisplay::GetCenterOffset(void)
{
    long lX;
    long lCenterIndex;

    //
    // If called before we have anything to render, just return 0.
    //
    if(m_pScopeData == NULL)
    {
        return(0);
    }

    //
    // First determine where the center sample is. If this is dual channel
    // data, the number of sample periods is effectively half what it would
    // be if we were dealing with single channel data.
    //
    lCenterIndex = m_pScopeData->ulTotalElements / 2;

    //
    // Now determine the total number of microseconds from the start of the
    // buffer to the center sample.
    //
    lX = lCenterIndex * m_pScopeData->ulSamplePerioduS;

    //
    // Convert from microseconds to pixels given the selected timebase. At
    // this point, we have a distance in pixels from the earliest sample.
    //
    lX = (lX * m_iGraticuleSide)/m_uluSPerDivision;

    //
    // The correction we apply to the x coordinates is the center offset minus
    // half the width of the display.
    //
    return(lX - (m_sizeWaveform.cx / 2));
}

//***************************************************************************
//
// Update the timebase and, optionally, redraw the waveform.
//
//***************************************************************************
void CWaveformDisplay::SetTimebase(unsigned long uluSPerDivision, BOOL bUpdate)
{
    m_uluSPerDivision = uluSPerDivision;

    if(bUpdate)
    {
        InternalRenderWaveform();
    }
}

//***************************************************************************
//
// Update the trigger level and, optionally, redraw the waveform.
//
//***************************************************************************
void CWaveformDisplay::SetTriggerLevel(long lTriggerLevelmV, BOOL bUpdate)
{
    m_lTriggerLevelmV = lTriggerLevelmV;

    if(bUpdate)
    {
        InternalRenderWaveform();
    }
}

//***************************************************************************
//
// Update the trigger position and, optionally, redraw the waveform.
//
//***************************************************************************
void CWaveformDisplay::SetTriggerPos(int iTriggerPos, BOOL bUpdate)
{

    //
    // The supplied trigger position is in the range (-60, 60) to match
    // the waveform display size on the device. Rescale this so that
    // the same bounds map to the complete width of the window here.
    //
    m_iTriggerPos = (iTriggerPos * m_sizeWaveform.cx) /
        (TRIGGER_POS_SLIDER_MAX - TRIGGER_POS_SLIDER_MIN);

    if(bUpdate)
    {
        InternalRenderWaveform();
    }
}

//***************************************************************************
//
// Update the vertical offset for one channel and, optionally, redraw the
// waveform.
//
//***************************************************************************
void CWaveformDisplay::SetChannelPos(int iChannel, long lVerticalOffsetmV,
                                    BOOL bUpdate)
{
    ASSERT((iChannel == CHANNEL_1) || (iChannel == CHANNEL_2));

    m_lVerticalOffsetmV[iChannel] = lVerticalOffsetmV;

    if(bUpdate)
    {
        InternalRenderWaveform();
    }
}

//***************************************************************************
//
// Update the vertical scale for one channel and, optionally, redraw the
// waveform.
//
//***************************************************************************
void CWaveformDisplay::SetChannelScale(int iChannel,
                                      unsigned long ulmVPerDivision,
                                      BOOL bUpdate)
{
    ASSERT((iChannel == CHANNEL_1) || (iChannel == CHANNEL_2));

    m_ulmVPerDivision[iChannel] = ulmVPerDivision;

    if(bUpdate)
    {
        InternalRenderWaveform();
    }
}

//*****************************************************************************
//
// Convert a sample index in the current data set into a horizontal (x)
// pixel coordinate on the display.
//
//*****************************************************************************
long CWaveformDisplay::SampleIndexToX(unsigned long ulSampleIndex, int iChannel)
{
    long lX;
    bool bApplyOffset;

    //
    // If we don't have any dataset to play with, just return 0.
    //
    if(m_pScopeData == NULL)
    {
        return(0);
    }

    //
    // Determine whether or not we need to apply the second sample time
    // offset.
    //
    bApplyOffset = (((iChannel == CHANNEL_1) &&
                     (m_pScopeData->bCh2SampleFirst)) ||
                    ((iChannel == CHANNEL_2) &&
                     (!m_pScopeData->bCh2SampleFirst)));

    //
    // First determine the number of microseconds from the start of the capture
    // to this sample. Note that we ensure we add the sample offset if this is
    // a sample for the second channel.
    //
    // ulSampleIndex <= 1024 (typically 512)
    // ulSamplePerioduS <= 10000 (min rate of 10mS per sample or 100Hz)
    // ulSampleOffsetuS <= 8
    //
    // so lX <= 10240008, hence no overflow in this calculation.
    //
    lX = (ulSampleIndex * m_pScopeData->ulSamplePerioduS) +
         (bApplyOffset ? m_pScopeData->ulSampleOffsetuS : 0);

    //
    // Now convert from microseconds to pixels given the selected timebase. At
    // this point, we have a distance in pixels from the earliest sample.
    //
    lX = (lX * m_iGraticuleSide)/m_uluSPerDivision;

    //
    // Adjust the pixel position for the current display window. We center the
    // window on the full trace then apply an offset to allow the user to pan
    // the window across the captured waveform (effectively changing the
    // trigger position from their point of view).
    //
    lX = lX - GetCenterOffset() + m_iTriggerPos;

    //
    // All done. Return the result to the caller.
    //
    return(lX);
}

//*****************************************************************************
//
// Convert an ADC sample to a Y coordinate on the display taking into account
// all display parameters in the passed rendering structure.
//
//*****************************************************************************
long CWaveformDisplay::SampleToY(short sSamplemV, int iChannel)
{
    long lY;
    long lMillivolts;

    //
    // Adjust this with the client-supplied offset value for the channel.
    //
    lMillivolts = sSamplemV + m_lVerticalOffsetmV[iChannel];

    //
    // Calculate the actual y coordinate representing this voltage given the
    // voltage scaling supplied by the client.
    //
    lY = MV_TO_Y(lMillivolts, m_ulmVPerDivision[iChannel]);

    return(lY);
}

//*****************************************************************************
//
// Draw the waveform for a single set of captured samples.
//
//*****************************************************************************
void CWaveformDisplay::DrawSingleWaveform(CDC *pDC, int iChannel, COLORREF clrColor)
{
    unsigned long ulLoop;
    short sSample;
    long lX;
    long lY;
    CPen cPen(PS_SOLID, 1, clrColor);
    CPen cDotPen(PS_DOT, 1, clrColor);
    CPen *pOldPen;

    //
    // Check for cases where we are asked to render a waveform for a channel
    // whose data we don't have.
    //
    if(!m_pScopeData->bDualChannel)
    {
        //
        // This is single channel data. Does it contain the channel we are
        // being asked to draw?
        //
        if(((iChannel == CHANNEL_2) && !m_pScopeData->bCh2SampleFirst) ||
           ((iChannel == CHANNEL_1) && m_pScopeData->bCh2SampleFirst))
        {
            return;
        }
    }

    //
    // Draw the ground level if required.
    //
    if(m_bShowGround)
    {
        //
        // Select the dotted pen.
        //
        pOldPen = pDC->SelectObject(&cDotPen);

        //
        // Determine where the ground line should go.
        //
        lY = SampleToY(0, iChannel);

        //
        // If ground is visible, draw the line.
        //
        if((lY >= 0) && (lY < m_sizeWaveform.cy))
        {
            pDC->MoveTo(0, lY);
            pDC->LineTo(m_sizeWaveform.cx, lY);
        }

        pDC->SelectObject(pOldPen);
    }

    //
    // Set the solid pen for the waveform.
    //
    pOldPen = pDC->SelectObject(&cPen);

    //
    // Loop through each of the captured samples to draw the waveform onto
    // the display.
    //
    for(ulLoop = 0; ulLoop < m_pScopeData->ulTotalElements; ulLoop++)
    {
        //
        // Get the screen X coordinate for this sample number given the
        // renderer timebase and offset.
        //
        lX = SampleIndexToX(ulLoop, iChannel);

        //
        // Get the screen Y coordinate for this sample given the renderer
        // voltage scaling factor and offset.
        //
        sSample = GetSample(ulLoop, iChannel);
        lY = SampleToY(sSample, iChannel);

        //
        // If this is not the first pixel, draw a line segment
        //
        if(ulLoop)
        {
            //
            // Draw one line segment.
            //
            pDC->LineTo(lX, lY);
        }
        else
        {
            //
            // Move the cursor to the start position.
            //
            pDC->MoveTo(lX, lY);
        }
    }

    //
    // Reinstate the old pen.
    //
    pDC->SelectObject(pOldPen);
}

//***************************************************************************
//
// Return the ulIndex-th sample for channel iChannel from the current
// dataset taking into account all the weird and wonderful combinations of
// single vs dual channel capture and channel swapping.
//
//***************************************************************************
short CWaveformDisplay::GetSample(unsigned long ulIndex, int iChannel,
                                  unsigned long *pulTime)
{
    ASSERT(m_pScopeData);

    //
    // Do we have single or dual channel data?
    //
    if(m_pScopeData->bDualChannel)
    {
        //
        // Dual channel data.
        //
        if(((iChannel == CHANNEL_1) && !m_pScopeData->bCh2SampleFirst) ||
            ((iChannel == CHANNEL_2) && m_pScopeData->bCh2SampleFirst))
        {
            if(pulTime)
            {
                *pulTime = ulIndex * m_pScopeData->ulSamplePerioduS;
            }
            return(m_pDualElement[ulIndex].sSample1mVolts);
        }
        else
        {
            if(pulTime)
            {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -