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

【经验分享】STM32F103使用DAC功能输出正弦波

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:17
在DAC的主要特征中可以看出,DAC内部带有波形发生器。
# j# O- ?* h' E# f% e
' U/ v8 N5 j. S6 P7 `3 QDAC 主要特征
! F! m+ {, o% e- Q* F- p6 u2个DAC转换器:每个转换器对应1个输出通道- X, @& E2 S0 k, K% A. p0 w
8位或者12位单调输出$ G+ N* p9 Z% P8 Y
12位模式下数据左对齐或者右对齐  f/ ^7 X- |! w* r6 }- k
同步更新功能
* c8 x/ X9 X( \: k! V( J. Q0 s噪声波形生成
% {9 G4 Q) E0 y- H0 H9 [三角波形生成
! S. D; F0 _* O! B9 e双DAC通道同时或者分别转换. v: V: |, ]6 s( E  F) T
每个通道都有DMA功能
+ I3 W0 o) A0 R1 L" w# n外部触发转换$ G8 e( _. C+ V" `( `- b1 X
输入参考电压V REF+& e5 _4 e' e2 x2 p& ~4 r, e
  但是这里面只有三角波和噪声波,那么正弦波要如何生成呢?6 m$ H6 e+ H0 D

" E4 O! ^3 S% y8 y& W虽然DAC没有自带正弦波的功能,但是我们可以先生成一个符合正弦规律的数组,然后通过定时器,将正弦数组中的值依次发送出去,这样输出的电压值也就会成正弦规律变化了。; h( ]" d' N- B

7 M. h7 F7 \& q  下面直接通过代码来演示如何输出正弦波# f# D  l  ?  e: E
, n8 |8 w1 G- B& S
  1. #include "dac_sin.h"4 P+ n* X: Y3 p8 Y

  2. 7 B" T- @( m( h
  3. #define DAC_DHR12RD_Address      0x40007420
    - x3 @6 L5 j( D! b

  4. ) [4 S( [8 Z6 ?2 K0 C0 b7 b8 Y

  5. ) _7 n. Q4 l, z1 R& H: w
  6. uc16 Sine12bit[32] = {2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
    " B3 h$ a2 ], ?/ s
  7.                       3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909,
    6 I# ~( A" s5 G5 O! V$ R9 T
  8.                       599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647
    1 r. k. a  t6 Z, ^5 N1 w2 K
  9.                      };
    $ P8 d9 c4 h  z- H

  10. 2 D) k) s  G. p
  11. u32 DualSine12bit[32];
    " p. w& {+ I5 L' m3 o; u
  12. u8 Idx = 0;
    : f' N! B$ y4 _6 z1 x
  13.   }* H( ~5 e8 j4 I
  14. //用DMA在PA4、PA5上产生正弦波
    & K, E5 k6 J. I4 \+ r% Z  U( J
  15. void DAC_SIN_Init(void)$ J0 w8 N0 @) s% u# Q# J( O
  16. {
    / r, O3 p  U9 Y) V
  17.     GPIO_InitTypeDef GPIO_InitStructure;9 [' T1 l/ l9 ?/ `4 h7 O* f
  18.     DAC_InitTypeDef  DAC_InitStructure;
    , A& e. ]) G! ?* B0 n
  19.     TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;8 s( X% F* C/ {$ M
  20.     DMA_InitTypeDef  DMA_InitStructure;0 }7 X# @( @  R2 P: M  O
  21.     //时钟设置3 e% F) T$ F% d- {# }/ u# v6 D
  22.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);2 {! b: D  @7 d+ z# |0 R& G6 I
  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
    ) H- p* }1 \# l1 a
  24.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);. y# R  X( L6 L# f2 X$ k& x
  25.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);: b9 c; E8 F/ `8 e( w
  26.     //GPIO设置# a1 F! M3 b% y
  27.     GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5;
    & J3 i# L9 o# [$ m; K
  28.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; W5 h7 T( J  O0 C0 {7 k3 {
  29.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    ( V( X4 g2 }' I# o0 O6 k/ R2 b( y( z
  30.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    , |# E0 h5 t3 j+ j
  31.     //高级定时器设置' x$ X4 |% a) }! i+ z% p9 ]# ?! G
  32.     TIM_TimeBaseStructure.TIM_Period = 0x19;
    0 V% P$ X7 S- K* F. H% B+ H
  33.     TIM_TimeBaseStructure.TIM_Prescaler = 0x00;& ]) e! N, q" j4 _* G& [/ ^# o* S. |
  34.     TIM_TimeBaseStructure.TIM_ClockDivision = 0x00;
    & ]6 D3 D2 ?2 N/ {7 V
  35.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    0 n( g( N4 z' ]- p
  36.     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00;
    : V2 A9 v4 u  t  n6 r# T
  37.     TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
    / N8 j2 t  g6 w) u& F' N2 s0 ?8 c
  38. ! J9 t# V7 d* Z# f; a0 n
  39.     TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);" a9 r+ A, W8 W2 C
  40.     //DAC设置1 I- `5 |9 K; k
  41.     DAC_InitStructure.DAC_Trigger = DAC_Trigger_T8_TRGO;                                        //TIM8触发
    ) P3 V% l8 a+ H: b7 ~
  42.     DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;: D# X* ~3 ?/ U% `- L
  43.     DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
    , l! o' A1 S# z5 F
  44.     DAC_Init(DAC_Channel_1, &DAC_InitStructure);$ }2 e) @- T1 q+ m; G3 J

  45. 8 A' o( n" v4 ]3 W/ {
  46.     DAC_Init(DAC_Channel_2, &DAC_InitStructure);
    9 H! Q* {7 R7 o) x- V0 H0 C
  47. 7 W. _8 N9 `3 {" K) O
  48.     for(Idx = 0; Idx < 32; Idx++)
    ; b) O' s$ o: i
  49.     {1 \1 T% k4 R. _; Z2 i
  50.         DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);
    # J# [# l4 p2 g4 y
  51.     }- _& L4 R$ j  Z  u
  52.     //DMA设置/ H: b# k; B' Q  o3 R3 _% _; p7 G
  53.     DMA_DeInit(DMA2_Channel4);
    % z7 z) K( L2 E
  54. % J; J  B$ g. d
  55.     DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address;                        //DMA外设基地址
    4 p& H$ F& e1 ]5 R7 {0 k& ]  ^
  56.     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&DualSine12bit;                                //DMA内存基地址
    - o6 m/ g( z/ g4 m  E- P' l5 V
  57.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                                //数据传输方向,从存储器读( t9 Z9 n- X( R3 L' g: I. Z% z. @# J2 K
  58.     DMA_InitStructure.DMA_BufferSize = 32;                                                                        //DMA通道的DMA缓存的大小
    3 H( I) c6 B5 P/ A  ~$ P0 o5 r
  59.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外设地址寄存器不变
    4 Q* E% @6 Q8 N: z) n
  60.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                        //内存地址寄存器递增
    / a4 a5 x3 Z  T$ p0 d
  61.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
    8 }8 p4 \8 s7 G9 x2 ^
  62.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;                        //数据宽度为32位* S( }1 `- J; m
  63.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                        //工作模式为循环模式
    2 X& e/ X5 L/ f7 R
  64.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                                //DMA通道 x拥有高优先级
    1 q0 j+ ]7 U6 k" A2 x% T# N
  65.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                        //DMA通道x 非存储器到存储器模式
    7 [2 j0 E: q; l
  66.     DMA_Init(DMA2_Channel4, &DMA_InitStructure);
    + M. w: j2 C: B( `
  67. . c6 P5 F1 W7 A+ w3 V
  68.     DMA_Cmd(DMA2_Channel4, ENABLE);                                //使能DMA2通道4, A4 f' e+ [2 D& l1 @; S
  69. ) j: K  E$ X8 V& c; W
  70.     DAC_Cmd(DAC_Channel_1, ENABLE);                                //使能DAC通道1+ m* l" N' ~6 B( T" v, f4 j7 U
  71.     DAC_Cmd(DAC_Channel_2, ENABLE);                                //使能DAC通道2
      W4 c# i& J) j
  72. 6 ]# B& W* {( j! I) L
  73.     DAC_DMACmd(DAC_Channel_2, ENABLE);                        //使能DAC的DMA功能8 c, D8 }5 ]1 j# `) B; B4 C" O

  74. 4 W/ V) o: `) t
  75.     TIM_Cmd(TIM8, ENABLE);                                                //使能定时器
    6 r9 _6 G3 m: V) Z5 N  H; s* Z
  76. }
复制代码

' c- ^1 E/ ]7 W3 aSine12bit数组中存放的数据就是按照正弦规律变化了,可以将数组中的数据复制到表格中,观察一下。
8 E6 l$ Y% R( B5 g$ B- d! F- K: P5 X$ I
}BCB6PSFB]3}~H282TA3[.png * V, A: X" D( a3 |; ]
1 J- n" q. E# c) w8 D
可以看出数组中的数据组成了一个标准的正弦波。' _/ I* {* l+ B5 d; D

! e- T- p. r/ x% W' A& r  数据有了之后开始初始化DAC,这里DAC依然使用定时器触发,使用定时8触发,波形的产生方式设置为无,因为这里不使用内部的波形发生器。
4 l8 l* g9 a) @$ ^# |3 `$ _8 |+ O/ t- D  }
  接下来数据的传输选择使用DMA模式,当然也可是通过程序设置一个循环来依次将数据中的值放到DAC寄存器中去,但是这样比较占用单片机的资源,为了节省资源,可以让单片机自己来实现这个功能。
0 [) h9 w# e1 X% K- q
7 {7 n* j5 ]4 @3 u B7J37K39MGL~%}MQH5T]RAK.png
; K- f3 U* [% {1 E' v0 J- S/ ~& k+ ~* R2 j0 }) D
  将DMA的外设地址设置为DAC寄存器的地址,将DMA的内存地址设置为存储正弦波数据的数组,这样每次定时器8的中断发生之后,DMA就会自动从数组中拿出一个数据设置到DAC的寄存器中。通过DMA功能就可以实现数组中的数据依次被放到DAC的数据保持寄存器中。; Q( x+ z5 `" u, g+ \5 {+ C
* N9 v; X+ p: v# F2 e
  最后使能定时器,DAC,DMA功能后,DAC的两个输出端口PA4和PA5就会自动输出成正弦规律变化的波形了。6 y' h9 O2 u2 y3 x- O

: U5 z. l, i3 _6 p  W. Q+ z. V, C$ g- E( q# f
赞 收藏 评论0 发布时间:2022-3-20 13:17

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版