STM32的DMA输出DAC的正弦波与三角波 幅度与周期可调可调(原创篇);

废话不多说,因为激光振镜驱动需要正弦波与三角波,为了省事,直接通过STM32F407实现DAC的DMA输出,省CPU资源;经过调试,在0-NkHZ之内都可以实现,目前采样点为500个;上数据吧;其中三角波自动生成500个数据,在初始化的时候实现fun12【500】个数据的填充即可;

void tri_angle_fun(void)
{
    int count;
      for(count=0;count<250;count++)
         {fun12[count] =(4095-((u16)(16.38 * count)));}
      for(count=251;count<501;count++)
        {fun12[count] = ((u16)(16.38 * (count-250)));}
}

//4095 /250 =16.38 ;DAC为12bit,其中最高4096,最低位0;500个点分布;原理很简单啦,就是按线性每次填充就OL了;
正弦波直接借用网络上的数据表实现:

const u16 function[500] = {  
    2048,2073,2099,2125,2150,2176,2202,2227,2253,2279,2304,2330,2355,2380,
    2406,2431,2456,2482,2507,2532,2557,2582,2606,2631,2656,2680,2705,2729,2753,
    2777,2801,2825,2849,2872,2896,2919,2942,2966,2988,3011,3034,3056,3079,3101,
    3123,3145,3166,3188,3209,3230,3251,3272,3292,3313,3333,3353,3372,3392,3411,
    3430,3449,3468,3486,3504,3522,3540,3558,3575,3592,3609,3625,3641,3657,3673,
    3689,3704,3719,3734,3748,3762,3776,3790,3803,3816,3829,3842,3854,3866,3878,
    3889,3900,3911,3921,3932,3942,3951,3961,3970,3978,3987,3995,4003,4010,4017,
    4024,4031,4037,4043,4048,4054,4059,4063,4068,4072,4075,4079,4082,4085,4087,
    4089,4091,4092,4094,4094,4095,4095,4095,4094,4094,4092,4091,4089,4087,4085,
    4082,4079,4075,4072,4068,4063,4059,4054,4048,4043,4037,4031,4024,4017,4010,
    4003,3995,3987,3978,3970,3961,3951,3942,3932,3921,3911,3900,3889,3878,3866,
    3854,3842,3829,3816,3803,3790,3776,3762,3748,3734,3719,3704,3689,3673,3657,
    3641,3625,3609,3592,3575,3558,3540,3522,3504,3486,3468,3449,3430,3411,3392,
    3372,3353,3333,3313,3292,3272,3251,3230,3209,3188,3166,3145,3123,3101,3079,
    3056,3034,3011,2988,2966,2943,2919,2896,2872,2849,2825,2801,2777,2753,2729,
    2705,2680,2656,2631,2606,2582,2557,2532,2507,2482,2456,2431,2406,2381,2355,
    2330,2304,2279,2253,2227,2202,2176,2150,2125,2099,2073,2048,2022,1996,1970,
    1945,1919,1893,1868,1842,1816,1791,1765,1740,1715,1689,1664,1639,1613,1588,
    1563,1538,1513,1489,1464,1439,1415,1390,1366,1342,1318,1294,1270,1246,1223,
    1199,1176,1153,1129,1107,1084,1061,1039,1016,994,972,950,929,907,886,865,
    844,823,803,782,762,742,723,703,684,665,646,627,609,591,573,555,537,520,
    503,486,470,454,438,422,406,391,376,361,347,333,319,305,292,279,266,253,
    241,229,217,206,195,184,174,163,153,144,134,125,117,108,100,92,85,78,71,
    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,
    13,16,20,23,27,32,36,41,47,52,58,64,71,78,85,92,100,108,117,125,134,144,
    153,163,174,184,195,206,217,229,241,253,266,279,292,305,319,333,347,361,
    376,391,406,422,438,454,470,486,503,520,537,555,573,591,609,627,646,665,
    684,703,723,742,762,782,803,823,844,865,886,907,929,950,972,994,1016,1039,
    1061,1084,1107,1129,1153,1176,1199,1223,1246,1270,1294,1318,1342,1366,1390,
    1415,1439,1464,1489,1513,1538,1563,1588,1613,1639,1664,1689,1715,1740,1765,
    1791,1816,1842,1868,1893,1919,1945,1970,1996,2022};     

由于STM32的DAC具有几种触发模式,本次采用定时器触发,选用TIM6定时器:初始化如下:

  TIM_TimeBaseInitTypeDef TIM6_TimeBase;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
  TIM_TimeBaseStructInit(&TIM6_TimeBase); 
  TIM6_TimeBase.TIM_Period        = 168;         
  TIM6_TimeBase.TIM_Prescaler     = 0;       
  TIM6_TimeBase.TIM_ClockDivision = 0;    
  TIM6_TimeBase.TIM_CounterMode   = TIM_CounterMode_Up;  
  TIM_TimeBaseInit(TIM6, &TIM6_TimeBase);
  TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
  TIM_Cmd(TIM6, ENABLE);

因为我的是STM32F407,直接168Mhz走起;分频168;


//DAC1的PA4脚初始化及DMA初始化;
void Dac1_Init(void)
{  
  GPIO_InitTypeDef gpio_A;
    DAC_InitTypeDef DAC_INIT;
  DMA_InitTypeDef DMA_INIT;
    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);                  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  gpio_A.GPIO_Pin  = GPIO_Pin_4;
  gpio_A.GPIO_Mode = GPIO_Mode_AN;
  gpio_A.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &gpio_A);

  DAC_INIT.DAC_Trigger        = DAC_Trigger_T6_TRGO;
  DAC_INIT.DAC_WaveGeneration = DAC_WaveGeneration_None;
  DAC_INIT.DAC_OutputBuffer   = DAC_OutputBuffer_Enable;
  DAC_Init(DAC_Channel_1, &DAC_INIT);
  DAC_SetChannel1Data(DAC_Align_12b_R,0X0000);
    DAC_SoftwareTriggerCmd(DAC_Channel_1,ENABLE);
    
  DMA_DeInit(DMA1_Stream5);
  DMA_INIT.DMA_Channel            = DMA_Channel_7; 
  DMA_INIT.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDR;//fun12
 DMA_INIT.DMA_Memory0BaseAddr    = (uint32_t)&fun12;   //对应FUN12的500个数据首地址,填充后自动啪啪输出吧;不要想歪了:)
  DMA_INIT.DMA_DIR                = DMA_DIR_MemoryToPeripheral;
  DMA_INIT.DMA_BufferSize         = 500; //每次输出500个点;
  DMA_INIT.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  DMA_INIT.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  DMA_INIT.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_INIT.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
  DMA_INIT.DMA_Mode               = DMA_Mode_Circular; //自动循环输出模式;
  DMA_INIT.DMA_Priority           = DMA_Priority_High;
  DMA_INIT.DMA_FIFOMode           = DMA_FIFOMode_Disable;         
  DMA_INIT.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;
  DMA_INIT.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
  DMA_INIT.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream5, &DMA_INIT);

  DMA_Cmd(DMA1_Stream5, ENABLE);
  DAC_Cmd(DAC_Channel_1, ENABLE);
  DAC_DMACmd(DAC_Channel_1, ENABLE);
}

#define   TIM_PERIOD        ((168000000)/((500)*(OUT_FREQ))) // Autoreload reg value =168000000/500 = 336 000 ;

#define   OUT_FREQ          4366 

//1  HZ   OUT_FREQ = 336;  //33600+6720=0.1
//120HZ   OUT_FREQ = 44000  // 8.3uS    //   RESULT = (44000 - 336)*xishu;  XISHU = 1-100%;
//#define   DAC_DHR12RD_Address 0x40007408

通过修改OUT_FREQ就可以改变频率,数值越大,频率也越高;

通过拷贝数组的值,乘以一个系数,就可以改变幅度了:

比如要改变正弦波的幅度:

void copy_arr(u16 fun11[],const u16 function[],int n)
{
    int count;
    for(count=0;count<n+1;count++)
    {
        fun11[count] =(u16)(function[count]*0.5); //0.5就是系数啦;
    }
}

这个时候调用的初始化地址应该是&fun11的首地址啦;三角波类似啦,在计算的时候就弄个系数就OL了;简单,明了,真实有效;

就这样:OL了,期望可以帮助到更多的工程师;攻城狮是真辛苦!;

Q-Q :417179642   啦啦啦啦啦啦啦啦啦啦啦啦啦.....

  • 8
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要实现stm32f4dacdma正弦波输出,需要以下步骤: 1. 配置DAC通道和DMA通道,使能时钟 在使用DACDMA前,需要先使能相应的时钟。对于DAC来说,需要使能DAC时钟和GPIO时钟。对于DMA来说,需要使能DMA时钟。同时也需要配置好DAC通道和DMA通道。 2. 构建正弦波表并放入内存 正弦波表是用来存储一段正弦波的数据。可以使用公式y=sin(2πx/N)生成正弦波表,其中N是正弦波表大小,x是当前位置,y是对应的采样值。然后将正弦波表数据放入内存中。 3. 配置DMA传输数据 使用DMA将内存中的正弦波表数据传输到DAC数据寄存器中。可以配置DMA的传输模式、方向、缓存等参数。 4. 设置DAC触发模式 设置DAC触发模式为DMA触发,并选择DMA通道。 5. 启动DACDMA传输 启动DACDMA传输即可输出正弦波信号。 总体代码示例: ``` c #define SAMPLE_RATE 100 #define TABLE_SIZE 128 uint16_t sinetable[TABLE_SIZE]; void build_sinetable() { for(int i = 0; i < TABLE_SIZE; i++) { float tmp = sinf(2 * PI * i / TABLE_SIZE) * 2047 + 2047; sinetable[i] = (uint16_t)tmp; } } void DAC_DMA_Init() { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_1, &DAC_InitStructure); DAC_Cmd(DAC_Channel_1, ENABLE); DMA_DeInit(DMA1_Stream5); DMA_InitStructure.DMA_Channel = DMA_Channel_7; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_BufferSize = TABLE_SIZE; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R1); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)sinetable; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_Init(DMA1_Stream5, &DMA_InitStructure); DAC_DMACmd(DAC_Channel_1, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / SAMPLE_RATE / TABLE_SIZE - 1; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); TIM_Cmd(TIM6, ENABLE); DMA_Cmd(DMA1_Stream5, ENABLE); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值