你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32F303开发】(二)DAC+定时器+DMA实例  

[复制链接]
风子 提问时间:2015-5-27 17:29 /
本帖最后由 风子 于 2017-2-16 17:59 编辑

嗯,又是我,来分享一下昨天晚上捣弄的东西。小弟献丑了,写得不好,不对的地方请各位大神指正。

Nucleo板子简单便宜,提供的资源自然也很少,所以要尽可能多的利用仅有的资源来学习更多的功能。看原理图和数据手册可以发现,唯一一个用户LED即LD2连接的PA5引脚,刚好是DAC1的通道2输出引脚,于是我们就可以用这个LED来学习使用DAC,顺带学习下定时器基本功能和DMA。


  • DAC—数模转换器
DAC即是数模转换器,就是将数字量转换成模拟量,原理什么的大家应该都懂,直接跳入如何使用:
STM32的DAC使用起来非常简单,首先将连接DAC通道的GPIO引脚配置为模拟状态,然后初始化DAC,一共只有四个参数需要初始化,其中最重要的是触发源:这个参数的作用是,每来一个触发源信号,DAC就刷新一次输出,也就是将需要转换的数字量转换为电压输出,这里选择定时器2作为触发源。
代码:

  1. void DAC_Config(void)
  2. {
  3.         GPIO_InitTypeDef      GPIO_InitStructure;
  4.         DAC_InitTypeDef                DAC_InitStructure;

  5.         DAC_TRIGTIM_Config();//定时器配置,见第2点

  6.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC1,ENABLE);

  8.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                //模拟
  10.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  11.         GPIO_Init(GPIOA,&GPIO_InitStructure);

  12.         DAC_InitStructure.DAC_Buffer_Switch=DAC_BufferSwitch_Disable;                //增大电流的,不需要
  13.         DAC_InitStructure.DAC_Trigger=DAC_Trigger_T2_TRGO;                                //定时器2做触发源
  14.         DAC_InitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None;        //不需要
  15.         DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits2_0;//这个是针对上一个参数的,所以也不重要
  16.         DAC_Init(DAC1,DAC_Channel_2,&DAC_InitStructure);

  17.         DAC_SetChannel2Data(DAC1,DAC_Align_12b_R,0);//设置一下初始值,其实也可以不用
  18.         DAC_Cmd(DAC1,DAC_Channel_2,ENABLE);
  19. }
复制代码
2.         定时器TIM基础

定时器是非常常用的功能,它的功能也比较多,这里只用最基础的定时功能,来为DAC提供触发信号,让DAC定时更新输出电压。

假设我们需要每毫秒更新一次数据,定时器定为1ms,时钟频率72M,则周期会超过最大值,所以设置预分频,使时钟周期为36M,Period=36M/1k=36k,计数模式向上,最后选择Trigger输出信号,并打开计时器

代码:

  1. void DAC_TRIGTIM_Config(void)
  2. {
  3.          TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;

  4. RCC_APB1PeriphClockCmd(DAC_TRIGTIM_CLK, ENABLE);
  5. TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  6.           TIM_TimeBaseStructure.TIM_Period = 36000-1;          //定时1ms
  7. TIM_TimeBaseStructure.TIM_Prescaler = 2-1;       //二分频,计时器频率36M
  8.           TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;   
  9.           TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
  10.           TIM_TimeBaseInit(DAC_TRIGTIM, &TIM_TimeBaseStructure);

  11. TIM_SelectOutputTrigger(DAC_TRIGTIM, TIM_TRGOSource_Update);//选择输出Trigger信号
  12.           TIM_Cmd(DAC_TRIGTIM, ENABLE);
复制代码

做好上面两步,DAC就可以使用了,下面写一个测试函数来测试这两部分的功能(也可以直接写在主函数中,不过我习惯让主函数更简单)

  1. void DAC_test(void)
  2. {
  3.         uint16_t i=0;
  4.         DAC_Config();
  5.         while(1)
  6.                 {
  7.                         for(i=1500;i<0xFFF;i+=5)
  8.                                 {
  9.                                         DAC_SetChannel2Data(DAC1,DAC_Align_12b_R,i);
  10.                                         delay_ms(5);
  11.                                 }
  12.                         for(i=0xFFF;i>1500;i-=5)
  13.                                 {
  14.                                         DAC_SetChannel2Data(DAC1,DAC_Align_12b_R,i);
  15.                                         delay_ms(5);
  16.                                 }
  17.                 }
  18. }
复制代码

变量i从1500——4095——1500,输出电压从1.2v——3.3v——1.2v,LED2灭——暗——亮——暗——灭(即使能导通,但是电流过小,所以会完全熄灭)

效果如图:

1.png 2.png 3.png


3.         DMA

DMA(Derict Memory Access),一个很强大很方便的功能,只需要配置好之后就能自动传输数据,不需要消耗更多CPU资源。STM32大多数外设都有DMA通道,但是使用方法都一样,所以只要学会了一个,其他的也基本能掌握。

主要参数:

外设地址,在这个例子中外设例子当然是DAC的数据存储地址,但是DAC的ODR寄存器不能直接写入,要通过缓冲寄存器DAC_DHR(原文data holding register,我觉得缓冲寄存器更容易理解),把要转换的数据写入缓冲寄存器,触发源到来的时候DAC自动把DAC_DHR中的数据传送到ODR并转换输出,所以外设地址应该是DAC_DHR(有多个)中的一个

内存地址,程序中建立数组存放数据,作为内存数据缓冲区,这个参数就是数组的地址

发送发向,分为内存->外设和外设->内存,即外设作为目的地(DST)和源头(SRC),本例为第一种。

datasize,DAC可设12位和8位模式,12位时size设为16位(halfword),8位时设为byte,还有其他地方可能需要32位(word)

设置好后最后打开DMA,同时还需要打开DAC的DMA使能位。

  1. uint16_t OUTPUT_BUFFER[20]={1500,1800,2100,2400,2700,3000,3300,3600,3900,4095,
  2.                                                         4095,3900,3600,3300,3000,2700,2400,2100,1800,1500};
  3. void DAC_DMA_Config(void)
  4. {
  5.         DMA_InitTypeDef DMA_InitStructure;
  6.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);

  7.         DMA_DeInit(DMA2_Channel4);
  8.         DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2_ADDR;//DHR12R2寄存器的地址
  9.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&OUTPUT_BUFFER;//内存缓冲区
  10.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//发向外设(DAC)
  11.         DMA_InitStructure.DMA_BufferSize = 20;//数据个数
  12.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不增加
  13.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//增加
  14.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//16位
  15.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  16.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
  17.         DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  18.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止
  19.         DMA_Init(DMA2_Channel4, &DMA_InitStructure);
  20.         
  21.         DMA_Cmd(DMA2_Channel4, ENABLE);
  22. DAC_DMACmd(DAC1,DAC_Channel_2,ENABLE);
  23. }
复制代码

由于自己写的数组数据很少,如果按2中的频率刷新,人眼根本看不到LED的变化,所以需要将频率变小,在定时器函数中改掉这两句:

  1.    TIM_TimeBaseStructure.TIM_Period = 10000-1;          //定时100ms
  2.           TIM_TimeBaseStructure.TIM_Prescaler = 720-1;       //计时器频率100k
复制代码

这样一秒钟电压改变10次,运行效果和前面基本相同,不过这个频率人眼已经能分辩出来,所以能明显看到LED在闪烁。

DAC_App.rar (1.74 KB, 下载次数: 683)

2 收藏 6 评论46 发布时间:2015-5-27 17:29

举报

46个回答
党国特派员 回答时间:2015-5-28 07:44:14
谢谢分享。。。 null.png null.png null.png null.png null.png null.png null.png null.png null.png null.png
风继续吹QAQ 回答时间:2015-6-11 09:38:49
风子 发表于 2015-6-10 18:38
不是有问题,是因为我要用板子上的LED,而LED连接的引脚是通道2

您有空帮我看下我这个DAC程序,我的通道1输出不正常
地址:https://www.stmcu.org.cn/module/ ... p;extra=#pid2096459
czhuanqilai 回答时间:2017-11-21 21:16:43
风子 发表于 2015-5-27 17:30
PPS:沐紫姐姐的社区QQ群:STM32&STM8社区群3   427779516
         多多支持啊,进来大家一起交流学习
...

新手表示想进
风子 回答时间:2015-5-27 17:30:19
本帖最后由 风子 于 2015-5-29 12:43 编辑

PPS:沐紫姐姐的社区QQ群:STM32&STM8社区群3   427779516
         多多支持啊,进来大家一起交流学习
creep 回答时间:2015-5-27 17:37:53
感谢分享
沐紫 回答时间:2015-5-27 17:54:47
30金币已打赏
上达到 回答时间:2015-5-27 18:01:30
天天赚金币啊
风子 回答时间:2015-5-27 18:12:27

谢谢群主
风子 回答时间:2015-5-27 18:12:43

你也可以
creep 回答时间:2015-5-27 18:23:09
工程是用keil5建的吗?
风子 回答时间:2015-5-27 18:24:59
creep 发表于 2015-5-27 18:23
工程是用keil5建的吗?

是的哦,看我帖在最后的第一篇帖子,里面有说
Paderboy 回答时间:2015-5-27 18:35:44
多谢分享
Anchor_Yu 回答时间:2015-5-27 19:03:24
厉害 这么快就上手了啊
风子 回答时间:2015-5-27 19:10:20
MrYin 发表于 2015-5-27 19:03
厉害 这么快就上手了啊

DAC使用很简单,另外两个内容以前就接触过的,所以比较快就弄出来了
Anchor_Yu 回答时间:2015-5-27 19:12:42
没开嵌入式课程哦 想弄块板子玩玩  不过以前只玩过430跟51
风子 回答时间:2015-5-27 19:15:01
MrYin 发表于 2015-5-27 19:12
没开嵌入式课程哦 想弄块板子玩玩  不过以前只玩过430跟51

我连51都没玩好直接上STM32的,觉得看着教程做还是挺容易学的,51我至今只会很简单的基础
Anchor_Yu 回答时间:2015-5-27 19:21:56
我还是学的很好的 51基本玩通了 430也还行
1234下一页

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版