此处将为大家介绍关于电脑主板维修--示波器的使用的详细内容,并且为您解答有关如何使用示波器维修电脑主板的相关问题,此外,我们还将为您介绍关于【二代示波器教程】第11章示波器设计—功能模块划分、【二代示
此处将为大家介绍关于电脑主板维修--示波器的使用的详细内容,并且为您解答有关如何使用示波器维修电脑主板的相关问题,此外,我们还将为您介绍关于【二代示波器教程】第11章 示波器设计—功能模块划分、【二代示波器教程】第12章 示波器设计—DAC信号发生器的实现、【安富莱二代示波器教程】第 8 章 示波器设计 — 测量功能、【安富莱二代示波器教程】第7章 示波器设计—波形滑动浏览的有用信息。
本文目录一览:- 电脑主板维修--示波器的使用(如何使用示波器维修电脑主板)
- 【二代示波器教程】第11章 示波器设计—功能模块划分
- 【二代示波器教程】第12章 示波器设计—DAC信号发生器的实现
- 【安富莱二代示波器教程】第 8 章 示波器设计 — 测量功能
- 【安富莱二代示波器教程】第7章 示波器设计—波形滑动浏览
电脑主板维修--示波器的使用(如何使用示波器维修电脑主板)
该视频教程是人民邮电出版社出版的《电脑主板维修从入门到精通》(黄光 等编著)一书附带光盘,主要讲解:万用表的使用、元件的检测、示波器的使用、主板故障检测要领。
本书为讲解电脑主板维修知识的专业技术图书。书中从最基础的电路知识讲起,一步步地引导读者从入门到提高,掌握电脑主板维修技术。本书在讲述各个电路的时候,都是先从原理讲起,并配以大量图片,然后再讲解针对该电路故障的详细检测方法及维修技巧。
有兴趣学习电脑维修的朋友可以去当当网或是京东上面买这本书来看看,或是下载PDF版本的电子书。
【二代示波器教程】第11章 示波器设计—功能模块划分
第11章 示波器设计—功能模块划分
二代示波器的界面上做了五个按钮,分别用于不同功能的配置,本章节就为大家讲解这五个按钮实现的功能。
11.1 主界面上的五个按钮
11.2 Measure测量功能
11.3 ADC电压测量功能
11.4 DAC信号发生器
11.5 Math数字信号处理
11.6 Settings设置
11.7 总结
11.1 主界面上的五个按钮
为了方便各个功能的配置,主界面右侧做了五个按钮,用于实现五个不同功能的配置。
代码如下:
/* 创建需要的按钮*************************************************************/
hButton0 = BUTTON_Create(670, 40, 100, 44, GUI_ID_BUTTON0, WM_CF_SHOW);
BUTTON_SetText(hButton0, "Measure");
WM_SetHasTrans(hButton0);
WM_SetCallback(hButton0, _cbButton);
hButton1 = BUTTON_Create(670, 90-1, 100, 44, GUI_ID_BUTTON1, WM_CF_SHOW);
BUTTON_SetText(hButton1, "ADC");
WM_SetHasTrans(hButton1);
WM_SetCallback(hButton1, _cbButton);
hButton2 = BUTTON_Create(670, 140-2, 100, 44, GUI_ID_BUTTON2, WM_CF_SHOW);
BUTTON_SetText(hButton2, "DAC");
WM_SetHasTrans(hButton2);
WM_SetCallback(hButton2, _cbButton);
hButton3 = BUTTON_Create(670, 190-3, 100, 44, GUI_ID_BUTTON3, WM_CF_SHOW);
BUTTON_SetText(hButton3, "Math");
WM_SetHasTrans(hButton3);
WM_SetCallback(hButton3, _cbButton);
hButton4 = BUTTON_Create(670, 240-4, 100, 44, GUI_ID_BUTTON4, WM_CF_SHOW);
BUTTON_SetText(hButton4, "Settings");
WM_SetHasTrans(hButton4);
WM_SetCallback(hButton4, _cbButton);
这些按钮都是创建在桌面窗口上的,点击这些按钮后,会触发桌面窗口回调函数中的按钮消息,从而弹出相应的设置对话框:
/*
*********************************************************************************************************
* 函 数 名: _cbBkWin
* 功能说明: 桌面窗口的回调函数
* 形 参: pMsg
* 返 回 值: 无
*********************************************************************************************************
*/
static void _cbBkWin(WM_MESSAGE * pMsg)
{
int NCode, Id;
switch (pMsg->MsgId)
{
/* 桌面背景重绘 */
case WM_PAINT:
DSO_Init(0);
break;
/* 通过设置触发标志来更新一次触发游标的显示 */
case WM_TIMER:
g_Flag->ucWaveRefresh = 1;
//WM_RestartTimer(pMsg->Data.v, 1000);
break;
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch (Id)
{
/* 按钮0:打开Measure对话框 */
case GUI_ID_BUTTON0:
switch(NCode)
{
case WM_NOTIFICATION_RELEASED:
DSO_CreateMeasureDlg();
break;
}
break;
/* 按钮1:打开ADC对话框 */
case GUI_ID_BUTTON1:
switch(NCode)
{
case WM_NOTIFICATION_RELEASED:
DSO_CreateAdcDlg();
break;
}
break;
/* 按钮2:打开DAC对话框 */
case GUI_ID_BUTTON2:
switch(NCode)
{
case WM_NOTIFICATION_RELEASED:
DSO_CreateDacDlg();
break;
}
break;
/* 按钮3:打开Math对话框 */
case GUI_ID_BUTTON3:
switch(NCode)
{
case WM_NOTIFICATION_RELEASED:
DSO_CreateMathDlg();
break;
}
break;
/* 按钮4:打开Settings对话框 */
case GUI_ID_BUTTON4:
switch(NCode)
{
case WM_NOTIFICATION_RELEASED:
DSO_CreateSettingsDlg();
break;
}
break;
}
break;
default:
WM_DefaultProc(pMsg);
}
}
下面分别将这五个对话框所实现的功能为大家做个讲解。
11.2 Measure测量功能
测量界面的效果如下:
当前二代示波器仅支持打对勾的这六种测量值,分别是频率,峰峰值,最大值,最小值,均方根和平均值。其它的测量选项还不支持,勾选或者取消对主界面没有影响。而支持的这六个测量功能取消勾选的话,主界面对应的数值将停止更新,勾选上将继续更新。
测量对话框的创建也比较简单,采用非阻塞方式创建:
/*
*********************************************************************************************************
* 函 数 名: DSO_CreateMeasureDlg
* 功能说明: 创建测量对话框
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
WM_HWIN DSO_CreateMeasureDlg(void)
{
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreateMeasure,
GUI_COUNTOF(_aDialogCreateMeasure),
_cbDialogMeasure,
WM_HBKWIN,
0,
0);
return hWin;
}
11.3 ADC电压测量功能
ADC电压测量功能的界面比较简单,就是显示ADC2所采集的电压,并显示电压曲线。
ADC电压测量对话框的创建也比较简单,采用非阻塞方式创建:
/*
*********************************************************************************************************
* 函 数 名: DSO_CreateAdcDlg
* 功能说明: 创建对话框
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
WM_HWIN DSO_CreateAdcDlg(void)
{
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreateADC,
GUI_COUNTOF(_aDialogCreateADC),
_cbCallbackADC,
WM_HBKWIN,
0,
0);
return hWin;
}
11.4 DAC信号发生器
DAC信号发生器对话框主要实现了正弦波,方波和三角波的幅值,频率以及占空比的设置,界面效果如下:
这个界面的实现代码要稍复杂些,具体实现在第14章会为大家详细讲解。DAC信号发生器对话框的创建采用非阻塞方式创建:
/*
*********************************************************************************************************
* 函 数 名: DSO_CreateDacDlg
* 功能说明: 创建对话框
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
WM_HWIN DSO_CreateDacDlg(void)
{
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreateDAC,
GUI_COUNTOF(_aDialogCreateDAC),
_cbCallbackDAC,
WM_HBKWIN,
0,
0);
return hWin;
}
11.5 Math数字信号处理
Math数字信号处理界面用于FIR低通滤波器的截止频率配置,界面效果如下:
具体的功能实现已经在前面第10章为大家进行了讲解。DAC信号发生器对话框的创建采用非阻塞方式创建:
/*
*********************************************************************************************************
* 函 数 名: DSO_CreateMathDlg
* 功能说明: 创建对话框
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
WM_HWIN DSO_CreateMathDlg(void)
{
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreateMath,
GUI_COUNTOF(_aDialogCreateMath),
_cbDialogMath,
WM_HBKWIN,
0,
0);
return hWin;
}
11.6 Settings设置
Settings设置对话框的界面效果如下:
设置对话框主要实现了以下五个功能的配置:
1、 Motion功能设置
(1) Y motion表示选择波形垂直方向滑动。
(2) X motion 表示选择波形水平方向滑动。
2、 水平和垂直测量功能的选择
(1) Hide Cursor表示隐藏水平测量和垂直测量。
(2) Display HorizontalCursor表示显示水平测量。
(3) Display VerticalCursor表示显示垂直测量。
3、 设置水平和垂直测量游标每次移动的像素个数
(1)MoveCursorStep = 1表示每次移动1个像素。
(2)MoveCursorStep = 2 表示每次移动2个像素。
(3)MoveCursorStep = 5 表示每次移动5个像素。
(4)MoveCursorStep = 10 表示每次移动10个像素。
4、Hide RFFT2048 Display 表示隐藏FFT频谱显示。
5、Hide AmplitudeDlg, StatusDlg, ScaleDlg and SysInfoDlg表示隐藏幅值窗口,状态窗口,频率窗口和系统信息窗口。
Settings设置对话框的创建也采用非阻塞方式创建:
/*
*********************************************************************************************************
* 函 数 名: DSO_CreateSettingsDlg
* 功能说明: 创建设置对话框
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
WM_HWIN DSO_CreateSettingsDlg(void)
{
WM_HWIN hWin;
hWin = GUI_CreateDialogBox(_aDialogCreateSettings,
GUI_COUNTOF(_aDialogCreateSettings),
_cbDialogSettings,
WM_HBKWIN,
0,
0);
return hWin;
}
11.7 总结
本章节的内容比较简单,主要是让大家对这五个对话框的功能有个了解,看代码时就比较容易理解了。
【二代示波器教程】第12章 示波器设计—DAC信号发生器的实现
第12章 示波器设计—DAC信号发生器的实现
本章节为大家讲解二代示波器中信号发生器的实现。这个功能还是比较实用的,方便为二代示波器提供测试信号。实现了正弦波,方波和三角波的频率,幅度以及占空比设置。
12.1 DAC的输出阻抗和使能缓冲问题
12.2 DAC驱动实现
12.3 信号发生器配置界面设计
12.4 信号发生器波形显示效果
12.5 总结
12.1 DAC的输出阻抗和使能缓冲问题
我们这里把F429的输出阻抗和使能缓冲问题放在最前面说。
使能了多缓冲后发现有失真问题,即满幅输出的时候有削顶和削底,而禁止了输出缓冲会导致输出阻抗仅有10KΩ左右,外接负载很容易造成分压(可以根据实际情况,外接运放输出)。
F429的手册中对于DAC的几个关键特性说明如下:
1、开启缓冲的时候,外接的负载阻抗最小得是5KΩ。
2、禁止缓冲的时候,DAC输出阻抗最大可达15KΩ,比如要实现1%精度的输出,外接负载阻抗至少得是1.5MΩ。
3、开启缓冲的时候,最小输出电压0.2V,最大Vdda - 0.2V,这个应该是造成削顶问题的根本原因。
4、禁止缓冲的时候,最小输出电压的典型值是0.5mV,最大输出是Vref - 1LSB。基本正好满幅输出,所以效果比较好。
F429数据手册中几个关键参数的截图:
缓冲和外接负载时的框图:
禁止缓冲时,满幅输出效果比较漂亮:
使能缓冲时,满幅输出效果,出现削顶问题:
有了上面的感性认识后,下面为大家讲解DAC的驱动实现和相应的GUI界面实现。
12.2 DAC驱动实现
F429带有两个DAC,分别是DAC1和DAC2,我们这里使用了DAC1,驱动中还需要用到TIM6和DMA,方便我们配置不同的的频率,占空比和幅值。
12.2.1 第1步:引脚配置和DAC配置
配置代码如下,使用的PA4引脚做输出:
/*
*********************************************************************************************************
* 函 数 名: bsp_InitDAC1
* 功能说明: 配置PA4/DAC1
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitDAC1(void)
{
/* 配置GPIO */
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 配置DAC引脚为模拟模式 PA4 / DAC_OUT1 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/* DAC通道1配置 */
{
DAC_InitTypeDef DAC_InitStructure;
/* 使能DAC时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; /* 选择软件触发, 软件修改DAC数据寄存器 */
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
//DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Cmd(DAC_Channel_1, ENABLE);
}
}
特别注意。程序中关闭了DAC输出缓冲,即DAC参数成员DAC_InitStructure.DAC_OutputBuffer。关于DAC的缓冲问题,看前面12.1小节说明即可。
12.2.2 第2步:DAC的定时器触发和DMA配置
DAC的定时器触发和DMA配置如下:
/*
*********************************************************************************************************
* 函 数 名: dac1_InitForDMA
* 功能说明: 配置PA4 为DAC_OUT1, 启用DMA2
* 形 参: _BufAddr : DMA数据缓冲区地址
* _Count : 缓冲区样本个数
* _DacFreq : DAC样本更新频率
* 返 回 值: 无
*********************************************************************************************************
*/
void dac1_InitForDMA(uint32_t _BufAddr, uint32_t _Count, uint32_t _DacFreq)
{
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
DMA_Cmd(DMA1_Stream5, DISABLE);
DAC_DMACmd(DAC_Channel_1, DISABLE);
TIM_Cmd(TIM6, DISABLE);
/* TIM6配置 */
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
uiTIMxCLK = SystemCoreClock / 2;
if (_DacFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _DacFreq - 1; /* 自动重装的值 */
}
else if (_DacFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _DacFreq - 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _DacFreq - 1; /* 自动重装的值 */
}
TIM_TimeBaseStructure.TIM_Period = usPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; /* TIM1 和 TIM8 必须设置 */
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
/* 选择TIM6做DAC的触发时钟 */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
}
/* DAC通道1配置 */
{
DAC_InitTypeDef DAC_InitStructure;
/* 使能DAC时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
//DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Cmd(DAC_Channel_1, ENABLE);
}
/* DMA1_Stream5配置 */
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/* 配置DMA1 Stream 5 channel 7用于DAC1 */
DMA_InitStructure.DMA_Channel = DMA_Channel_7;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1;
DMA_InitStructure.DMA_Memory0BaseAddr = _BufAddr;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = _Count;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &DMA_InitStructure);
DMA_Cmd(DMA1_Stream5, ENABLE);
/* 使能DAC通道1的DMA */
DAC_DMACmd(DAC_Channel_1, ENABLE);
}
/* 使能定时器 */
TIM_Cmd(TIM6, ENABLE);
}
通过这个函数可以方便的设置DAC的输出波形频率。计算方法是:
配置的定时器触发频率 / DMA的缓冲个数 = 输出波形频率
其中DMA缓冲数据的个数就是输出波形一个周期的采样点数。程序中统一将其配置为128个点代表一个周期的波形,大家实际应用中配置的点数不要太少,否则波形不够漂亮。比如我们要出10KHz的波形,这个函数的配置就是:dac1_InitForDMA((uint32_t)&g_Wave1, 128, 10000 * 128); 数组g_Wave1里面是128个波形采样点。
关于这个驱动代码,要注意TIM6的配置。F429的定时器从TIM1到TIM14的主频如下:
/*
********************************************************************************
system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
HCLK = SYSCLK / 1 (AHB1Periph)
PCLK2 = HCLK / 2 (APB2Periph)
PCLK1 = HCLK / 4 (APB1Periph)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14
APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
TIM 更新周期是 = TIMCLK / (TIM_Period + 1)/(TIM_Prescaler + 1)
********************************************************************************
*/
由此可知,TIM6的主频是SystemCoreClock / 2。当主频是168MHz时,TIM6的时钟就是84MHz,TIM6更新周期 = TIM6CLK / (TIM_Period + 1)/(TIM_Prescaler + 1),其中
TIM_Period就是定时器结构体成员TIM_TimeBaseStructure.TIM_Period。
TIM_Prescaler就是定时器结构体成员TIM_TimeBaseStructure.TIM_Prescaler。
另外还有非常重要的一点,TIM6是16位定时器,这两个参范围是0-65535,切不要超过65535。正是因为这个原因,程序中对不同的输出频率做了范围区分。
12.2.3 第3步:正弦波输出配置
正弦波的输出配置如下:
/*
*********************************************************************************************************
* 函 数 名: dac1_SetSinWave
* 功能说明: DAC1输出正弦波
* 形 参: _vpp : 幅度 0-4095;
* _freq : 频率
* 返 回 值: 无
*********************************************************************************************************
*/
void dac1_SetSinWave(uint16_t _vpp, uint32_t _freq)
{
uint32_t i;
uint32_t dac;
TIM_Cmd(TIM6, DISABLE);
/* 调整正弦波幅度 */
for (i = 0; i < 128; i++)
{
dac = (g_SineWave128[i] * _vpp) / 4095;
if (dac > 4095)
{
dac = 4095;
}
g_Wave1[i] = dac;
}
dac1_InitForDMA((uint32_t)&g_Wave1, 128, _freq * 128);
}
正弦波输出128个采样点代表一个周期,同时程序里面增加了一个幅值设置功能,范围0到4095。实际DAC输出的波形频率由前面第2步函数dac1_InitForDMA实现。比如我们要实现频率10KHz,幅值4095正弦波,那么配置就是:dac1_SetSinWave(4095, 10000)。
12.2.4 第4步:方波输出配置
方波的输出配置如下:
/*
*********************************************************************************************************
* 函 数 名: dac1_SetRectWave
* 功能说明: DAC1输出方波
* 形 参: _low : 低电平时DAC,
* _high : 高电平时DAC
* _freq : 频率 Hz
* _duty : 占空比 2% - 98%, 调节步数 1%
* 返 回 值: 无
*********************************************************************************************************
*/
void dac1_SetRectWave(uint16_t _low, uint16_t _high, uint32_t _freq, uint16_t _duty)
{
uint16_t i;
TIM_Cmd(TIM6, DISABLE);
for (i = 0; i < (_duty * 128) / 100; i++)
{
g_Wave1[i] = _high;
}
for (; i < 128; i++)
{
g_Wave1[i] = _low;
}
dac1_InitForDMA((uint32_t)&g_Wave1, 128, _freq * 128);
}
方波也是输出128个采样点代表一个周期,同时支持幅值和占空比的配置,其中占空比可以配置2%到98%,直接填数值2到98就可以了。实际DAC输出的波形频率由前面第2步函数dac1_InitForDMA实现。比如我们要实现频率10KHz,幅值4095,占空比50%的方波,那么配置就是:dac1_SetRectWave (0, 4095, 10000, 50)。
12.2.5 第5步:三角波输出配置
三角波的输出配置如下:
/*
*********************************************************************************************************
* 函 数 名: dac1_SetTriWave
* 功能说明: DAC1输出三角波
* 形 参: _low : 低电平时DAC,
* _high : 高电平时DAC
* _freq : 频率 Hz
* _duty : 占空比
* 返 回 值: 无
*********************************************************************************************************
*/
void dac1_SetTriWave(uint16_t _low, uint16_t _high, uint32_t _freq, uint16_t _duty)
{
uint32_t i;
uint16_t dac;
uint16_t m;
TIM_Cmd(TIM6, DISABLE);
/* 构造三角波数组,128个样本,从 _low 到 _high */
m = (_duty * 128) / 100;
if (m == 0)
{
m = 1;
}
if (m > 127)
{
m = 127;
}
for (i = 0; i < m; i++)
{
dac = _low + ((_high - _low) * i) / m;
g_Wave1[i] = dac;
}
for (; i < 128; i++)
{
dac = _high - ((_high - _low) * (i - m)) / (128 - m);
g_Wave1[i] = dac;
}
dac1_InitForDMA((uint32_t)&g_Wave1, 128, _freq * 128);
}
三角波也是输出128个采样点代表一个周期,同时支持幅值和占空比的配置,其中占空比可以配置0%到100%,不过程序中对0%和100%做了一个特殊处理。实际DAC输出的波形频率由前面第2步函数dac1_InitForDMA实现。比如我们要实现频率10KHz,幅值4095,占空比50%的三角波,那么配置就是:dac1_SetTriWave (0, 4095, 10000, 50)。
12.3 信号发生器配置界面设计
信号发生器的界面设计如下:
这个操作界面简单易用,支持正弦波,方波和三角波的切换,支持占空比设置,支持幅值设置,同时也支持频率设置,限制频率范围1Hz到50KHz。超过50KHz的话,波形效果会变的越来越差。
关于这个对话框的代码实现就不在教程里面做讲解了,我们这里主要讲解下对话框上的小键盘实现。这里小键盘是一个独立的窗口,父窗口是信号发生器主窗口,通过函数WM_SendMessageNoPara发自定义消息给父窗口,在父窗口里面更新Graph控件的波形和波形信息,同时DAC的波形输出也得到更新。了解了这知识点后,再看代码就比较容易了。
知识点拓展:
新版emWin教程第51章:实用的官方小键盘实例讲解:
http://forum.armfly.com/forum.php?mod=viewthread&tid=19834 。
另外还有emWin提高篇例子的第一期ATM机里面也有用到小键盘。
http://forum.armfly.com/forum.php?mod=viewthread&tid=23687 。
12.4 信号发生器波形显示效果
下面为大家展示信号发生器输出波形效果:
方波:
正弦波:
三角波:
12.5 总结
本章节为大家讲解的信号发生器还是比较实用的,建议实际动手操作下,有兴趣的话,还可以进一步优化升级。
【安富莱二代示波器教程】第 8 章 示波器设计 — 测量功能
第 8 章 示波器设计 — 测量功能
二代示波器测量功能实现比较简单,使用 2D 函数绘制即可。不过也专门开辟一个章节,为大家做一个简单的说明,方便理解。
8.1 水平测量功能
8.2 垂直测量功能
8.3 总结
8.1 水平测量功能
水平测量方式的效果如下:
水平测量功能的数据显示不要以窗口的形式呈现,因为将窗口显示在波形显示区上会造成波形刷新慢。当前的方案是在绘制完毕波形后,直接 2D 函数绘制测量窗口,这种方式的实际效果好很多。对应的代码如下:
/*
*********************************************************************************************************
* 函 数 名: DSO_DrawCursorH
* 功能说明: 绘制示波器的水平测量游标,用于测量幅值。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void DSO_DrawCursorH(void)
{
char buf[60];
/* 第1步:绘制用于测量的两个游标线********************************************************/
GUI_SetColor(0x0040f0);
/* 绘制横线A */
GUI_DrawHLine(g_Cursors->sCursorHA, DSOSCREEN_STARTX, DSOSCREEN_ENDX);
GUI_DrawHLine(g_Cursors->sCursorHA+1, DSOSCREEN_STARTX, DSOSCREEN_ENDX);
GUI_FillRoundedRect(50, g_Cursors->sCursorHA+3, 61, g_Cursors->sCursorHA+18, 3);
/* 绘制横线B */
GUI_DrawHLine(g_Cursors->sCursorHB, DSOSCREEN_STARTX, DSOSCREEN_ENDX);
GUI_DrawHLine(g_Cursors->sCursorHB-1, DSOSCREEN_STARTX, DSOSCREEN_ENDX);
GUI_FillRoundedRect(50, g_Cursors->sCursorHB-18, 61, g_Cursors->sCursorHB-3, 3);
/* 在横线A和横线B旁边的小圆圈中显示字母a和字母b */
GUI_SetColor(GUI_BLACK);
GUI_SetFont(&GUI_Font20_ASCII);
GUI_SetTextMode(GUI_TEXTMODE_TRANS);
GUI_DispCharAt(''a'', 51, g_Cursors->sCursorHA);
GUI_DispCharAt(''b'', 51, g_Cursors->sCursorHB-19);
/* 第2步:绘制游标数据显示窗口********************************************************/
GUI_SetColor(GUI_BLACK);
GUI_FillRoundedRect(500, 55, 635, 135, 4);
GUI_SetColor(GUI_WHITE);
GUI_DrawRoundedRect( 499, 54, 636, 136, 4);
GUI_SetColor(0x0040f0);
GUI_FillRoundedRect(75 + 433 , 47 + 15, 86 + 433, 62 + 15, 3);
GUI_FillRoundedRect(75 + 433 , 45 + 45, 86 + 433, 60 + 45, 3);
GUI_SetColor(GUI_BLACK);
GUI_SetFont(&GUI_Font20_1);
GUI_SetTextMode(GUI_TEXTMODE_TRANS);
GUI_DispCharAt(''a'', 509, 59);
GUI_DispCharAt(''b'', 509, 88);
GUI_SetColor(GUI_YELLOW);
GUI_SetFont(&GUI_Font16_1);
GUI_DispCharAt(''#'', 511, 115);
/* 第3步:计算竖线线A的数值***********************************************************/
g_Cursors->WaveCursorA = (float)((g_Cursors->sCursorVA - 340) * g_CursorUintTable[TimeBaseId][0])/1000;
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs", g_Cursors->WaveCursorA);
}
GUI_DispStringAt(buf, 523, 63);
/* 第3步:计算竖线线B的数值***********************************************************/
g_Cursors->WaveCursorB = (float)((g_Cursors->sCursorVB - 340) * g_CursorUintTable[TimeBaseId][0])/1000;
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs", g_Cursors->WaveCursorB);
}
GUI_DispStringAt(buf, 523, 91);
/* 第5步:计算竖线A竖线B的差值***********************************************************/
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs",(g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
GUI_DispStringAt(buf, 523, 115);
/* 第6步:显示水平线的计算数值***********************************************************/
GUI_DispCharAt(''#'', 509+72, 115);
g_Cursors->WaveCursorA = (float)((240 - g_Cursors->sCursorHA) * g_AttTable[Ch1AmpId][1]) / 50000;
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorA);
GUI_DispStringAt(buf, 518+72, 63);
g_Cursors->WaveCursorB = (float)((240 - g_Cursors->sCursorHB) * g_AttTable[Ch1AmpId][1]) / 50000;
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorB);
GUI_DispStringAt(buf, 518+70, 91);
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorA - g_Cursors->WaveCursorB);
GUI_DispStringAt(buf, 520+70, 115);
}
水平测量的实现比较简单,就是 2D 函数调用和字符显示。如果大家要自己实现,按照代码中注释的步骤制作即可。测量功能的调节是通过开发板上面的摇杆实现的。
8.2 垂直测量功能
垂直测量方式的效果如下:
垂直测量功能的数据显示不要以窗口的形式呈现,因为将窗口显示在波形显示区上会造成波形刷新慢。当前的方案是在绘制完毕波形后,直接 2D 函数绘制测量窗口,这种方式的实际效果好很多。对应的代码如下:
/*
*********************************************************************************************************
* 函 数 名: DSO_DrawCursorV
* 功能说明: 绘制示波器的垂直测量游标,用于测量的时间。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void DSO_DrawCursorV(void)
{
char buf[60];
/* 第1步:绘制用于测量的两个游标线********************************************************/
GUI_SetColor(0x0040f0);
/* 绘制竖线A */
GUI_DrawVLine(g_Cursors->sCursorVA, DSOSCREEN_STARTY, DSOSCREEN_ENDY);
GUI_DrawVLine(g_Cursors->sCursorVA+1, DSOSCREEN_STARTY, DSOSCREEN_ENDY);
GUI_FillRoundedRect(g_Cursors->sCursorVA+5, 47, g_Cursors->sCursorVA+16, 62, 3);
/* 绘制竖线B */
GUI_DrawVLine(g_Cursors->sCursorVB, DSOSCREEN_STARTY, DSOSCREEN_ENDY);
GUI_DrawVLine(g_Cursors->sCursorVB-1, DSOSCREEN_STARTY, DSOSCREEN_ENDY);
GUI_FillRoundedRect(g_Cursors->sCursorVB-16, 47, g_Cursors->sCursorVB-5, 62, 3);
/* 在竖线A和竖线B旁边的小圆圈中显示字母a和字母b */
GUI_SetColor(GUI_BLACK);
GUI_SetFont(&GUI_Font20_ASCII);
GUI_SetTextMode(GUI_TEXTMODE_TRANS);
GUI_DispCharAt(''a'', g_Cursors->sCursorVA+6, 44);
GUI_DispCharAt(''b'', g_Cursors->sCursorVB-15, 45);
/* 第2步:绘制游标数据显示窗口********************************************************/
GUI_SetColor(GUI_BLACK);
GUI_FillRoundedRect(500, 55, 635, 135, 4);
GUI_SetColor(GUI_WHITE);
GUI_DrawRoundedRect( 499, 54, 636, 136, 4);
GUI_SetColor(0x0040f0);
GUI_FillRoundedRect(75 + 433 , 47 + 15, 86 + 433, 62 + 15, 3);
GUI_FillRoundedRect(75 + 433 , 45 + 45, 86 + 433, 60 + 45, 3);
GUI_SetColor(GUI_BLACK);
GUI_SetFont(&GUI_Font20_1);
GUI_SetTextMode(GUI_TEXTMODE_TRANS);
GUI_DispCharAt(''a'', 509, 59);
GUI_DispCharAt(''b'', 509, 88);
GUI_SetColor(GUI_YELLOW);
GUI_SetFont(&GUI_Font16_1);
GUI_DispCharAt(''#'', 513, 115);
/* 第3步:计算竖线A的数值***********************************************************/
g_Cursors->WaveCursorA = (float)((g_Cursors->sCursorVA - 340) * g_CursorUintTable[TimeBaseId][0])/1000;
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs",g_Cursors->WaveCursorA);
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs", g_Cursors->WaveCursorA);
}
/* 显示竖线A数值 */
GUI_DispStringAt(buf, 523, 63);
/* 第4步:计算竖线B的数值***********************************************************/
g_Cursors->WaveCursorB = (float)((g_Cursors->sCursorVB - 340) * g_CursorUintTable[TimeBaseId][0])/1000;
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs", g_Cursors->WaveCursorB);
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs", g_Cursors->WaveCursorB);
}
/* 显示竖线B数值 */
GUI_DispStringAt(buf, 523, 91);
/* 第5步:计算竖线A竖线B的差值***********************************************************/
if(g_CursorUintTable[TimeBaseId][1] == 1)
{
sprintf(buf, "%5.1fus", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 2)
{
sprintf(buf, "%5.3fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 3)
{
sprintf(buf, "%5.2fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 4)
{
sprintf(buf, "%5.1fms", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 5)
{
sprintf(buf, "%5.3fs", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 6)
{
sprintf(buf, "%5.2fs", (g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
else if(g_CursorUintTable[TimeBaseId][1] == 7)
{
sprintf(buf, "%5.1fs",(g_Cursors->WaveCursorB - g_Cursors->WaveCursorA));
}
/* 显示竖线A和竖线B的差值 */
GUI_DispStringAt(buf, 523, 115);
/* 第6步:显示水平线的计算数值***********************************************************/
GUI_DispCharAt(''#'', 509+72, 115);
g_Cursors->WaveCursorA = (float)((240 - g_Cursors->sCursorHA) * g_AttTable[Ch1AmpId][1]) / 50000;
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorA);
GUI_DispStringAt(buf, 518+72, 63);
g_Cursors->WaveCursorB = (float)((240 - g_Cursors->sCursorHB) * g_AttTable[Ch1AmpId][1]) / 50000;
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorB);
GUI_DispStringAt(buf, 518+70, 91);
sprintf(buf, "%5.3fV", g_Cursors->WaveCursorA - g_Cursors->WaveCursorB);
GUI_DispStringAt(buf, 520+70, 115);
}
垂直测量的实现比较简单,就是 2D 函数调用和字符显示。如果大家要自己实现,按照代码中注释的步骤制作即可。测量功能的调节是通过开发板上面的摇杆实现的。
8.3 总结
由于测量功能的实现比较简单,所以我们这里只是简单的进行了说明。如果大家要自己制作的话,建议实际操作下。
【安富莱二代示波器教程】第7章 示波器设计—波形滑动浏览
第7章 示波器设计—波形滑动浏览
类似手机的滑动功能用在示波器上还是比较实用的,可以用来调节波形位置和滑动浏览波形的存储记录。
7.1 滑动基础知识
7.2 滑动基础知识总结
7.3 滑动功能在窗口上的实现
7.4 总结
7.1 滑动基础知识
滑动的实现是基于emWin提供的Motion功能。在emWin的官方手册中对这部分功能讲解的比较少,但是仍然需要大家去读一下,有一个大概的了解。
7.2 滑动基础知识总结
望大家务必看了emWin官方手册中Motion章节的内容,这里将这些知识点做个汇总,方便大家后面使用。
WM_MOTION_Enable() 使能motion
WM_MOTION_SetMoveable() 使能窗口X方向或者Y方向的Motion
WM_MOTION_SetMovement() 设置窗口以指定的速度移动一段距离。
=================
WM_MOTION_SetDeceleration() 设置窗口减速度
WM_MOTION_SetSpeed() 设置窗口的移动速度。
WM_MOTION_SetMotion() 设置初始速度和加速度。等同于上面两个函数之和
=======================
WM_MOTION_SetDefaultPeriod()
设置指针输入设备(触摸,鼠标,键盘等)等释放后,减速度默认持续的时间。
1、如果窗口在移动中,将减速,直到停止运行。
2、如果窗口没有移动,但是使能了snap功能,那么窗口会在设置的时间内移动到下一个栅格内。
3、如果窗口在移动,且使能了snap功能,那么窗口会减速运动直到停止在最近的一个栅格上。
上面的这些函数都是独立的操作Motion功能,而二代示波器中使用Motion功能是基于窗口的,其实就是把上面这些函数的功能在窗口上实现。下面我们就讲解二代示波器的Motion功能实现。
7.3 滑动功能在窗口上的实现
我们这里以二代示波器的滑动功能实现过程为例,给大家做个说明。
第1步:使能滑动,设置周期。
WM_MOTION_Enable(1); /* 使能滑动 */
WM_MOTION_SetDefaultPeriod(100); /* 设置滑动周期 */
第2步:创建一个透明的窗口,正好覆盖600*400的波形显示区。
hMotion = WM_CreateWindowAsChild(40,
40,
600,
400,
WM_HBKWIN,
WM_CF_MOTION_Y | WM_CF_SHOW | WM_CF_HASTRANS,
_cbMotion,
sizeof(pPara));
WM_SetUserData(hMotion, &pPara, sizeof(pPara));
函数里面的标志WM_CF_MOTION_Y | WM_CF_SHOW | WM_CF_HASTRANS比较重要,滑动标志既可以在这里设置,也可以在窗口回调函数的WM_MOTION消息里面设置。
WM_CF_MOTION_Y:表示窗口支持垂直滑动。
WM_CF_MOTION_X:表示窗口支持水平滑动(在窗口回调里面进行了设置)。
WM_CF_HASTRANS:表示窗口透明,这个标志不要忘记设置,这样使用滑动功能的时候对示波器显示区没有任何影响。
第3步:也是最后一步,滑动窗口的回调函数。
源代码是如下这样的:
/*
*********************************************************************************************************
* 函 数 名: _cbMotion
* 功能说明: Motion窗口的回调函数,主要是桌面图标的滑动处理
* 形 参: pMsg WM_MESSAGE类型指针变量
* 返 回 值: 无
*********************************************************************************************************
*/
static void _cbMotion(WM_MESSAGE * pMsg)
{
WM_MOTION_INFO * pInfo;
WM_HWIN hWin = pMsg->hWin;
PARA * pPara;
switch (pMsg->MsgId)
{
case WM_MOTION:
WM_GetUserData(hWin, &pPara, sizeof(pPara));
pInfo = (WM_MOTION_INFO *)pMsg->Data.p;
switch (pInfo->Cmd)
{
/* Motion功能初始化,设置X方向和Y方向都支持滑动 */
case WM_MOTION_INIT:
pInfo->Flags = WM_CF_MOTION_X | WM_CF_MOTION_Y | WM_MOTION_MANAGE_BY_WINDOW;
pInfo->SnapY = 1;
pInfo->SnapX = 1;
break;
case WM_MOTION_MOVE:
pPara->FinalMove = pInfo->FinalMove;
/* Y轴方向,上下滑动 */
if(g_Flag->ucMotionXY == 0)
{
if((pInfo->pState->Pressed == 1)&&(pInfo->pState->x <= 340))
{
pPara->iCH1Pos += pInfo->dy;
if(pPara->iCH1Pos >= 440)
{
pPara->iCH1Pos = 440;
}
if(pPara->iCH1Pos <= 40)
{
pPara->iCH1Pos = 40;
}
g_DSO1->usRefPos = pPara->iCH1Pos;
}
else if((pInfo->pState->Pressed == 1)&&(pInfo->pState->x > 340))
{
pPara->iCH2Pos += pInfo->dy;
if(pPara->iCH2Pos >= 440)
{
pPara->iCH2Pos = 440;
}
if(pPara->iCH2Pos <= 40)
{
pPara->iCH2Pos = 40;
}
g_DSO2->usRefPos = pPara->iCH2Pos;
}
WM_InvalidateArea(&rRefPos);
}
/* X轴方向,左右滑动 */
else
{
if(pInfo->pState->Pressed == 1)
{
g_DSO1->sCurTriStep -= pInfo->dx;
}
if(TriggerFlag == 0)
{
}
else
{
if(g_DSO1->sCurTriStep <= -724)
{
g_DSO1->sCurTriStep = -724;
}
if(g_DSO1->sCurTriStep >= 724)
{
g_DSO1->sCurTriStep = 724;
}
TriggerFlag = 2;
}
WM_InvalidateArea(&rTrigPos);
}
/* 更新当前的数据位置的箭头 */
g_Flag->ucWaveRefresh = 1;
break;
case WM_MOTION_GETPOS:
pInfo->yPos = pPara->iCH1Pos;
//pInfo->xPos = pPara->iCH1Pos;
break;
}
break;
}
}
为了方便看这个函数实现的功能,这里将其进一步简化成如下这样:
static void _cbMotion(WM_MESSAGE * pMsg)
{
WM_MOTION_INFO * pInfo;
WM_HWIN hWin = pMsg->hWin;
PARA * pPara;
switch (pMsg->MsgId)
{
case WM_MOTION:
WM_GetUserData(hWin, &pPara, sizeof(pPara));
pInfo = (WM_MOTION_INFO *)pMsg->Data.p;
switch (pInfo->Cmd)
{
/* Motion功能初始化,设置X方向和Y方向都支持滑动 */
case WM_MOTION_INIT: //-----------(1)
pInfo->Flags = WM_CF_MOTION_X | WM_CF_MOTION_Y | WM_MOTION_MANAGE_BY_WINDOW;
pInfo->SnapY = 1;
pInfo->SnapX = 1;
break;
case WM_MOTION_MOVE: //-----------(2)
pPara->FinalMove = pInfo->FinalMove;
/* Y轴方向,上下滑动 */
if(g_Flag->ucMotionXY == 0)
{
if(pInfo->pState->Pressed == 1)
{
}
}
/* X轴方向,左右滑动 */
else
{
if(pInfo->pState->Pressed == 1)
{
}
}
/* 更新当前的数据位置的箭头 */
g_Flag->ucWaveRefresh = 1;
break;
case WM_MOTION_GETPOS: //-----------(3)
pInfo->yPos = pPara->iCH1Pos;
//pInfo->xPos = pPara->iCH1Pos;
break;
}
break;
}
}
滑动功能实现的关键就在这个WM_MOTION消息里面。
1、WM_MOTION_INIT消息
在初始化消息里面设置pInfo->Flags来使能水平滑动和垂直滑动,并且通过标志WM_MOTION_MANAGE_BY_WINDOW使能窗口管理器来管理Motion功能。标志pInfo->SnapY和pInfo->SnapX是用来设置滑动停止后的栅格区域,详情看7.2小节中函数WM_MOTION_SetDefaultPeriod的作用说明。
2、WM_MOTION_MOVE消息
这个消息在二代示波器中的使用比较简单,主要是判断是否按下,然后根据按下的位置设置波形的水平或者上下移动即可。当前按下的位置在参数pInfo->pState->x和pInfo->pState->y里面。实际的波形更新是通过设置标志g_Flag->ucWaveRefresh = 1实现的。
3、WM_MOTION_GETPOS消息
这个消息未用到,用于获取按下的位置。
7.4 总结
关于滑动的实现,关键的知识点就这么多,需要大家实际操作下,有个深入的认识。
关于电脑主板维修--示波器的使用和如何使用示波器维修电脑主板的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于【二代示波器教程】第11章 示波器设计—功能模块划分、【二代示波器教程】第12章 示波器设计—DAC信号发生器的实现、【安富莱二代示波器教程】第 8 章 示波器设计 — 测量功能、【安富莱二代示波器教程】第7章 示波器设计—波形滑动浏览等相关知识的信息别忘了在本站进行查找喔。
本文标签: