[其他ST产品] 使用stm32产生三角波和正弦波

[复制链接]
1254|19
 楼主| 9dome猫 发表于 2022-10-31 23:22 | 显示全部楼层 |阅读模式
32的功能还是很强大的,F4有168MHZ的主频,时钟频率可以达到84MHZ,对于产生波形来说,如果只是产生中低频率的波形来说是完全够用的,借助DMA后产生5MHZ的正弦波是没什么问题的。
       我也分享一下我产生三角波和正弦波的方式,因为方波的产生基本上都能做出来,是比较简单的,当然也有不少的大神在研究如何产生更高频率的方波,使32的速度最大化,但我还没有做那方面的深入了解,所以以后学习后再做记录。

 楼主| 9dome猫 发表于 2022-10-31 23:23 | 显示全部楼层
首先是三角波

        STM32的DAC控制器就支持生成三角波,Datesheet的截图如下
47728635fe86d5459e.png
 楼主| 9dome猫 发表于 2022-10-31 23:24 | 显示全部楼层
通过阅读以上内容我们可以知道,DAC产生三角波的方式是:设定一个最大振幅(MAMPx[3:0]),使用事件触发,每次触发后DAC值就自增1,当达到最大幅值后,每次事件触发后DAC的值就自减1,直到为0,至此一个周期结束,循环往复,由此可知产生三角波的方式并不需要CPU控制,只需要提供触发事件比如定时器等,然后DAC就能一直产生三角波,如果需要更改三角波的频率只需要更改定时器的分频系数以及自动重装载值即可。
 楼主| 9dome猫 发表于 2022-10-31 23:28 | 显示全部楼层
   与生成三角波相关的寄存器如下
65489635fe98011ee3.png
81203635fe99043e50.png
89601635fe995a018c.png
 楼主| 9dome猫 发表于 2022-10-31 23:30 | 显示全部楼层
   MAMP1[3:0]是用来设置通道1三角波的幅值的,如果设置为4096,那么产生的三角波就是0-3.3伏的,如果改为2047,那么产生的就是0-1.65伏的三角波,我一开始以为这个寄存器更改的只是三角波产生的精度,后来使用示波器测量后发现并不是这样。
 楼主| 9dome猫 发表于 2022-10-31 23:32 | 显示全部楼层
   WAVE1[1:0]是用来设置通道1产生的波形的,可以设置为噪声波、三角波以及不生成。

        TSEL1[2:0]是用来设置通道1触发器的选择,可以使用定时器TRGO时间触发,也可以使用外部中断以及软件触发的方式,但后俩者我并没有尝试。

        TEN1是通道1触发使能,*注意*这个必须首先置1否则波形设置以及触发器设置都是无法进行的。
 楼主| 9dome猫 发表于 2022-10-31 23:34 | 显示全部楼层
  TEN1是通道1触发使能,*注意*这个必须首先置1否则波形设置以及触发器设置都是无法进行的。
31274635feae35df29.png
96535635feae9c2fa8.png
 楼主| 9dome猫 发表于 2022-10-31 23:37 | 显示全部楼层
  这个是定时器相关的寄存器的设置,设置分频系数以及自动重装载值的就不说了,最主要的设置就是MMS(主模式选择),在上面的DAC的寄存器你设置了定时器触发以后,一定要更改对应定时器的MMS位,它默认的是复位产生TRGO,显然这不是我们想要的,我们要将它更改为更新触发,也就是每次重装载时触发一次DAC,这样波形的频率也就与定时器的更新频率挂钩了。
 楼主| 9dome猫 发表于 2022-10-31 23:38 | 显示全部楼层
我的源代码如下大家可以进行参考:        

  1. //DAC通道1输出初始化
  2. void Dac1_Init(void)
  3. {      
  4.     RCC->APB1ENR|=1<<29;       //使能DAC时钟      
  5.     RCC->AHB1ENR|=1<<0;      //使能PORTA时钟      
  6.     GPIO_Set(GPIOA,PIN4,GPIO_MODE_AIN,0,0,GPIO_PUPD_PU);//PA4,模拟输入,下拉   

  7.     DAC->CR|=1<<2;    //使能触发功能 TEN1=1
  8.     DAC->CR|=1<<1;    //DAC1输出缓存不使能 BOFF1=1
  9.     DAC->CR|=4<<3;    //DAC TIM2 TRGO,不过要TEN1=1才行
  10.     DAC->CR|=2<<6;    //生成三角波
  11.     DAC->CR|=12<<8;  //设置振幅4095
  12.     DAC->CR|=0<<12;    //DAC1 DMA不使能   
  13.     DAC->CR|=1<<0;    //使能DAC1
  14.     DAC->DHR12R1=0;
  15. }
  16. //TIM2初始化
  17. //arr:自动重装载值  psc:预分频系数
  18. void TIM2_Int_Init(u16 arr,u16 psc)
  19. {
  20.     RCC->APB1ENR|=1<<0;    //TIM2时钟使能   
  21.      TIM2->ARR=arr;      //设定计数器自动重装值
  22.     TIM2->PSC=psc;      //预分频器      
  23.     TIM2->CR2|=2<<4;      //选择更新事件作为触发输出(TRGO)  
  24.     TIM2->CR1|=0x01;    //使能定时器2
  25. }

        主函数只需要调用这俩个初始化函数,在三个APB1周期后在PA4就会产生三角波。
 楼主| 9dome猫 发表于 2022-10-31 23:39 | 显示全部楼层
接下来是介绍如何产生正弦波

        与三角波不同,32DAC并不支持自动生成正弦波,所以我们采用读表法来生成,事先计算正弦波一个周期500个点对应的DAC的值,将它存在一个数组中,然后每次时钟更新时使用DAC输出电压,当然我们为了提高速率并且解放CPU使正弦波生成独立运行我们可以采用DMA的方式。
 楼主| 9dome猫 发表于 2022-10-31 23:41 | 显示全部楼层
      寄存器配置

      2306635fec620793a.png

        TSEL1[2:0]、TEN1也是必须配置的,此外还需要配置
 楼主| 9dome猫 发表于 2022-10-31 23:42 | 显示全部楼层
   这一位是用来使能DAC1通道1的DMA模式   
64020635fecd6efa3d.png
 楼主| 9dome猫 发表于 2022-10-31 23:44 | 显示全部楼层
/*DAC1通道2初始化*/         
    RCC->APB1ENR|=1<<29;       //使能DAC时钟      
    RCC->AHB1ENR|=1<<0;      //使能PORTA时钟      
    GPIO_Set(GPIOA,PIN5,GPIO_MODE_AIN,0,0,GPIO_PUPD_PU);//PA5,模拟输入,下拉   

    DAC->CR|=1<<18;    //使能触发功能 TEN1=1
    DAC->CR|=1<<17;    //DAC1输出缓存不使能 BOFF1=1
    DAC->CR|=5<<19;    //DAC TIM4 TRGO,不过要TEN1=1才行
    DAC->CR|=0<<22;    //禁止生成波形
    DAC->CR|=1<<28;    //DAC1 通道2 DMA使能   
    DAC->CR|=1<<16;    //使能DAC1 通道2
    DAC->DHR12R2=0;
 楼主| 9dome猫 发表于 2022-10-31 23:50 | 显示全部楼层
接下来我们定义一个只读数组来存放点以及一个同样大小的数组一会儿进行数据的暂存
  1. const  u16   Sine12bit2[500] =
  2. {  
  3.                     2048,2073,2099,2125,2150,2176,2202,2227,2253,2279,2304,2330,2355,2380,
  4.                     2406,2431,2456,2482,2507,2532,2557,2582,2606,2631,2656,2680,2705,2729,2753,
  5.                     2777,2801,2825,2849,2872,2896,2919,2942,2966,2988,3011,3034,3056,3079,3101,
  6.                     3123,3145,3166,3188,3209,3230,3251,3272,3292,3313,3333,3353,3372,3392,3411,
  7.                     3430,3449,3468,3486,3504,3522,3540,3558,3575,3592,3609,3625,3641,3657,3673,
  8.                     3689,3704,3719,3734,3748,3762,3776,3790,3803,3816,3829,3842,3854,3866,3878,
  9.                     3889,3900,3911,3921,3932,3942,3951,3961,3970,3978,3987,3995,4003,4010,4017,
  10.                     4024,4031,4037,4043,4048,4054,4059,4063,4068,4072,4075,4079,4082,4085,4087,
  11.                     4089,4091,4092,4094,4094,4095,4095,4095,4094,4094,4092,4091,4089,4087,4085,
  12.                     4082,4079,4075,4072,4068,4063,4059,4054,4048,4043,4037,4031,4024,4017,4010,
  13.                     4003,3995,3987,3978,3970,3961,3951,3942,3932,3921,3911,3900,3889,3878,3866,
  14.                     3854,3842,3829,3816,3803,3790,3776,3762,3748,3734,3719,3704,3689,3673,3657,
  15.                     3641,3625,3609,3592,3575,3558,3540,3522,3504,3486,3468,3449,3430,3411,3392,
  16.                     3372,3353,3333,3313,3292,3272,3251,3230,3209,3188,3166,3145,3123,3101,3079,
  17.                     3056,3034,3011,2988,2966,2943,2919,2896,2872,2849,2825,2801,2777,2753,2729,
  18.                     2705,2680,2656,2631,2606,2582,2557,2532,2507,2482,2456,2431,2406,2381,2355,
  19.                     2330,2304,2279,2253,2227,2202,2176,2150,2125,2099,2073,2048,2022,1996,1970,
  20.                     1945,1919,1893,1868,1842,1816,1791,1765,1740,1715,1689,1664,1639,1613,1588,
  21.                     1563,1538,1513,1489,1464,1439,1415,1390,1366,1342,1318,1294,1270,1246,1223,
  22.                     1199,1176,1153,1129,1107,1084,1061,1039,1016,994,972,950,929,907,886,865,
  23.                     844,823,803,782,762,742,723,703,684,665,646,627,609,591,573,555,537,520,
  24.                     503,486,470,454,438,422,406,391,376,361,347,333,319,305,292,279,266,253,
  25.                     241,229,217,206,195,184,174,163,153,144,134,125,117,108,100,92,85,78,71,
  26.                     64,58,52,47,41,36,32,27,23,20,16,13,10,8,6,4,3,1,1,0,0,0,1,1,3,4,6,8,10,
  27.                     13,16,20,23,27,32,36,41,47,52,58,64,71,78,85,92,100,108,117,125,134,144,
  28.                     153,163,174,184,195,206,217,229,241,253,266,279,292,305,319,333,347,361,
  29.                     376,391,406,422,438,454,470,486,503,520,537,555,573,591,609,627,646,665,
  30.                     684,703,723,742,762,782,803,823,844,865,886,907,929,950,972,994,1016,1039,
  31.                     1061,1084,1107,1129,1153,1176,1199,1223,1246,1270,1294,1318,1342,1366,1390,
  32.                     1415,1439,1464,1489,1513,1538,1563,1588,1613,1639,1664,1689,1715,1740,1765,
  33.                     1791,1816,1842,1868,1893,1919,1945,1970,1996,2022

  34. };  

  35.                                                                
  36. u16   DualSine12bit[500];
 楼主| 9dome猫 发表于 2022-10-31 23:52 | 显示全部楼层
还有一个步骤就是将数值读入暂存数组
    /*读入正弦波数据*/
     for (u16 i = 0; i < 500; i++)  {
        DualSine12bit[i]  =  ( Sine12bit2[i] << 16 ) + ( Sine12bit2[i] );  
    }  
        接下来配置DMA,这里就不详细介绍了,只需要将存储器地址设置为数组DualSine12bit,外设地址设为DAC1的DHR12R2寄存器,并且设置循环传输模式,其他的就和其他外设使用DMA大同小异了。
 楼主| 9dome猫 发表于 2022-10-31 23:55 | 显示全部楼层
  值得注意的是与各个外设相连的DMA通道是固定的,需要选择DAC1专用的通道,而不是随便选择一个通道
36197635fef69d8e93.png
 楼主| 9dome猫 发表于 2022-10-31 23:56 | 显示全部楼层
根据映射图可知,与DAC1相连的DMA为DMA1通道7数据流5

       配置代码如下:

  1. //初始化DMA通道
  2. void SinWave_DMA_Config()
  3. {
  4.     RCC->AHB1ENR|=1<<21;//DMA1时钟使能
  5.     DMA1_Stream6->PAR=(u32)&(DAC->DHR12R2);        //DMA外设地址
  6.     DMA1_Stream6->M0AR=(u32)DualSine12bit;        //DMA 存储器0地址
  7.     DMA1_Stream6->NDTR=500;        //传输500个数据
  8.     DMA1_Stream6->CR=0;            //先全部复位CR寄存器值
  9.    
  10.     DMA1_Stream6->CR|=1<<6;        //存储器到外设模式
  11.     DMA1_Stream6->CR|=1<<8;        //循环模式
  12.     DMA1_Stream6->CR|=0<<9;        //外设非增量模式
  13.     DMA1_Stream6->CR|=1<<10;        //存储器增量模式
  14.    
  15.     DMA1_Stream6->CR|=1<<11;        //外设数据长度:16位
  16.     DMA1_Stream6->CR|=1<<13;        //存储器数据长度:16位
  17.     DMA1_Stream6->CR|=1<<16;        //中等优先级
  18.     DMA1_Stream6->CR|=0<<21;        //外设突发单次传输
  19.     DMA1_Stream6->CR|=0<<23;        //存储器突发单次传输
  20.     DMA1_Stream6->CR|=(u32)7<<25;//通道选择(5通道)
  21. }
 楼主| 9dome猫 发表于 2022-10-31 23:56 | 显示全部楼层
    接下来再配置定时器,我上面DAC中选择了TIM4的TRGO时间触发,所以我们要配置TIM4,与生成三角波的代码几乎完全相同,就不做过多的介绍了

//初始化TIM4
void SinWave_TIM_Config(u16 arr,u16 psc)
{
    RCC->APB1ENR|=1<<2;    //TIM2时钟使能   
     TIM4->ARR=arr;      //设定计数器自动重装值
    TIM4->PSC=psc;      //预分频器      
    TIM4->CR2|=2<<4;      //选择更新事件作为触发输出(TRGO)  
    TIM4->CR1|=0x01;    //使能定时器4
}
      最后使能DMA传输,所有的配置就完成了。

     通过以上的配置PA5就能生成正弦波了,通过改变TIM4 的预分频系数和预加载值就可以改变正弦波的频率。
 楼主| 9dome猫 发表于 2022-10-31 23:57 | 显示全部楼层
以上就是使用STM32生成三角波和正弦波的讲解与代码,还是比较简单的,如果使用32来做一个函数信号发生器,只要改变定时器的配置就能改变波形的频率,但是幅值就不是那么好改变了,三角波明显幅值是不可变的,如果要改变可能必须要外接一个降压电路,正弦波倒是可以通过在将点读到暂存数组的时候乘一个数来实现幅值的改变。
 楼主| 9dome猫 发表于 2022-10-31 23:58 | 显示全部楼层
就是把一个正弦波从连续变到离散,等分500个点,每个点都有一个对应的电压值,然后把这个电压值换算成DAC的数值,512个也是完全可以的.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

142

主题

1593

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部