STM32F407使用内置DAC+DMA+TIM制作DDS信号源

本文介绍了如何利用STM32F407的内置DAC、DMA和TIM模块,结合DDS算法,实现高分辨率的信号源,通过相位累加器和频率控制字调整频率和相位,解决高频信号波动问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32F407使用内置DAC+DMA+TIM制作DDS信号源

电赛的时候需要制作能够实现分辨率到0.001Hz的信号源,平常使用的信号源模块达不到这个精度,故使用DDS算法实现

一、简单原理讲解(个人理解)

频率:

现在假设我们有2的32次方这么大个正弦波波表(当然后面教程中不会这么大,这里方便理解),然后DDS输出波表直接查表的时候频率控制字取1,本振(定时器6)为2MHz,此时输出频率为2M除以2的32次方乘以1约等于0.0004656Hz;若频率控制字取2,输出频率为2M除以2的32次方乘以2约等于0.0009312Hz。这里就能得到频率控制字的计算公式了为:2的32次方除以本振(2M)乘以输出频率。然而在实际工程中,一般情况下,我们不可能有这么大的存储空间去储存2的32次方这么大个正弦波表,这个时候相位累加器的作用就出现了,可以将正弦波波表取样量化到一个2的次方大小的数组,比如2的8次方,相位累加器为32位(也可以取其他的),取高八位作为DDS输出查表的索引,便解决了。

相位:

实际上相位累加器32位,就对应了2的32次方这么大个正弦波波表(虚拟出来的,一个周期),改变相位,只需要在当前相位累加器的基础上加减一次即可,相位控制字计算公式为:改变相位除以360°乘以2的32次方

幅度:

取决于正弦波波表

二、DDS缺陷

尽管DDS能够实现精准的频率相位控制,但在输出高频信号时,会出现不明显的上下波动的现象,笔者在使用这个算法出三角波的时候吃的亏,原因是因为,在频率越高,频率控制字越大,输出对应的DDS数组中一个周期数量少,导致,在DDS查表的时候,取峰峰值取不到。(可通过提高本振频率,相位累加器位数和数组大小改善)

三、DDS算法实现

在使用DDS算法中,有相位累加器uint32_t place=0,频率控制字 uint32_t ctrl_word,相位控制字uint32_t phase_word,DDS输出波表uin32_t pData[256],正弦波波表uint16_t Sine_WAVE[256];,输出频率uint32_t Fre=10000,输出相对相位float phase=0(0到360°)系统时钟(本振)2MHz。故分辨率为2M/2的32次方约等于0.0004656Hz,在配置好cubemx后生成代码。


在这里插入图片描述
这里我的f4主频设置成160MHz
在这里插入图片描述

一些变量

#define  WAVE_POINT  256

#define OF 2147.483648 //2的32次方除以2M

uint16_t pData[WAVE_POINT];

uint16_t Sine_WAVE[WAVE_POINT];

uint32_t place=0;

uint32_t ctrl_word=0;

uint32_t phase_word=0;

uint32_t Fre=10000;

uint8_t phaseFlag=1;

一些代码

void SineWave_Data(uint16_t num, uint16_t* D, float U)//正弦波生成波表代码

{

​	num++;uint16_t i;

​    U=U/2;for (i = 0; i < num-1; i++){

​        D[i] = (uint16_t)((U*sin((1.0 * i / (num - 1)) * 2 * 3.1415926) + U) * 4095 / 3.3)+300;}

}

void phaseChange(float phase)``//相位改变代码

{

​	phase_word=phase/360*4294967295;if(phaseFlag==1){

​		phaseFlag=0;

​		place+=phase_word;}

}

主函数代码

int main(void)

{

  /* USER CODE BEGIN 1 */



  /* USER CODE END 1 */



  /* MCU Configuration--------------------------------------------------------*/



  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();



  /* USER CODE BEGIN Init */



  /* USER CODE END Init */



  /* Configure the system clock */

  SystemClock_Config();



  /* USER CODE BEGIN SysInit */



  /* USER CODE END SysInit */



  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  MX_DMA_Init();

  MX_DAC_Init();

  MX_TIM6_Init();

  /* USER CODE BEGIN 2 */

 	SineWave_Data(WAVE_POINT ,Sine_WAVE,2);//生成正弦波数组**

	HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)pData,  WAVE_POINT, DAC_ALIGN_12B_R);//使能DAC**

  	HAL_TIM_Base_Start(&htim6);//使能定时器**

  /* USER CODE END 2 */



  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {/* USER CODE END WHILE *//* USER CODE BEGIN 3 */

	 phaseChange(phase);//更改相位

	 ctrl_word=Fre*OF;//频率控制字

  }

  /* USER CODE END 3 */

}

核心代码

在DMA传输中断中更改波表,传输完成前半段更改前半段波表,完成后半段更改后半段波表

void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac)

{for(uint16_t i=0;i<WAVE_POINT/2;i++){

​		pData[i]=Sine_WAVE[place>>24];

​		place+=ctrl_word;}

}

void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac)

{for(uint16_t i=WAVE_POINT/2;i<WAVE_POINT;i++){

​		pData[i]=Sine_WAVE[place>>24];

​		place+=ctrl_word;}

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值