赞
踩
电赛的时候需要制作能够实现分辨率到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算法中,有相位累加器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; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。