完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=45785

第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_InitTypeDefGPIO_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_InitTypeDefDAC_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_tusPeriod;uint16_tusPrescaler;uint32_tuiTIMxCLK;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; /* 自动重装的值 */}elseif (_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_InitTypeDefDAC_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_InitTypeDefDMA_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);/* 配置DMA1 Stream 5channel 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 文件中 voidSetSysClock(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, TIM14APB2 定时器有 TIM1, TIM8,TIM9, TIM10, TIM11TIM 更新周期是 = 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_ti;uint32_tdac;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_ti;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_ti;uint16_tdac;uint16_tm;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 总结

本章节为大家讲解的信号发生器还是比较实用的,建议实际动手操作下,有兴趣的话,还可以进一步优化升级。

【二代示波器教程】第12章 示波器设计—DAC信号发生器的实现相关推荐

  1. dreamweaver cs5 css教程,网页设计与制作——Dreamweaver CS5标准教程第12章 CSS+Div布局.pptx...

    第12章 CSS+Div布局;1. 盒子模型2. 布局技术3. "上中下"布局4. "左中右"布局;12.1.1盒子结构网页中元素都占据一定的空间,除了元素内容 ...

  2. Hadoop基础教程-第12章 Hive:进阶(12.3 HiveServer2)(草稿)

    第12章 Hive:进阶 12.3 HiveServer2 12.3.1 HiveServer1 HiveServer是一种可选服务,允许远程客户端可以使用各种编程语言向Hive提交请求并检索结果.H ...

  3. 计算机体系结构 第1-2章 量化设计与分析基础/指令系统原理与示例

    第1章 量化设计与分析基础 计算机的分类类别 计算机系统结构定义和计算机的设计任务:指令集结构概念及要素 实现技术的趋势:技术发展的趋势 集成电路功耗的趋势:功耗的概念 可靠性:提高可靠性的方法 6. ...

  4. mySQL教程 第1章 数据库设计

    E-R设计 很多同学在学SQL语句时,觉得非常困难,那是因为你在学一个你根本不了解的数据库,数据库中的表不是你设计的,表与表之间的关系你不明白.因此在学SQL语句之前,先介绍一下数据库设计. 下面举例 ...

  5. 计算机软件设计工具,计算机基础第12章 图形设计工具软件Visio 2016.pptx

    计算机基础(第4版);计算机基础;12.1 图形文档操作;12.1.1 创建图形文档1.创建空白的图形文档 Visio 2016为15大热门的领域提供了直观和易于访问的预设模板.成百上千的智能形状.一 ...

  6. 第12章 SQL SELECT TOP, LIMIT, ROWNUM 子句教程

    SQL SELECT TOP 子句 SELECT TOP 子句用于规定要return 的记录的数目. SELECT TOP 子句对于拥有数千条记录的大型表来说,是非常有用的. **注意:**并非所有的 ...

  7. emwin读取sd图片_第12章emwin(ucgui)jpeg图片显示.pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspwindows相关 第12章emwin(ucgui)jpeg图片 ...

  8. 【二代示波器教程】第5章 示波器设计—波形快速刷新方案

    完整教程下载地址: https://www.armbbs.cn/forum.php?mod=viewthread&tid=45785 第5章        示波器设计-波形快速刷新方案 本章节 ...

  9. 【二代示波器教程】第10章 示波器设计—数字信号处理

    完整教程下载地址:https://www.armbbs.cn/forum.php?mod=viewthread&tid=45785 第10章      示波器设计-数字信号处理 本章节为大家讲 ...

最新文章

  1. 35岁不是程序员的坎儿,看不清楚这件事才是!
  2. mysql开启binlog
  3. Spring Boot 2.5.5发布:开始支持Java 17了!
  4. php 去除二维数组中的包含某一个值的数组
  5. [实践系列]Promises/A+规范
  6. Python二级笔记(6)
  7. jQuery formValidator 表单校验插件4.1.1高仿网易邮箱注册页面(已发演示链接)
  8. 间接寻址级别不同_「计算机组成原理」:常见的指令寻址方式
  9. caffe+CPU︱虚拟机+Ubuntu16.04+CPU+caffe安装笔记
  10. 拓端tecdat|决策树算法建立电信客户流失模型
  11. c mysql事务回滚_MYSQL事务回滚的2个问题分析
  12. 乌班图系统安装mysql
  13. 【016】随缘画-根据输入文字随机生成艺术画(带算法)
  14. 90%的 CTO 都做不好绩效管理?看看这个十年 IT 老兵都有什么绝活?
  15. 爆款升级!新系列南卡Neo最强旗舰杀到,业内首款无线充骨传导耳机!
  16. Java SE Development Kit (JDK) 安装
  17. java实现区块链中的区块hash难度系数的设计
  18. 嵌入式行业怎么样,有什么好的就业方向?
  19. 【已解决】No module named “win32com“ win32com 无法导入
  20. 基于51单片机的智能停车场车位收费系统原理图PCB

热门文章

  1. Problem E: 质心算法
  2. 推荐一款工具类微信小程序,感兴趣的朋友可以看看
  3. python zipfile_Python zipfile
  4. python数据如何用蓝牙发送_使用Python3通过蓝牙发送消息
  5. 百宝云注册码系统新手教程
  6. html5 div布局table,H5的div布局与table布局详解
  7. 使用 Opencv 创建类似 Instagram 的滤镜!
  8. 数据库系统 - 数据库的结构与模式
  9. uniapp--图片与文字中心线在同一水平线上
  10. Android——动画学习,界面切换