利用DAC輸出三角波、方波與正弦波(HAL庫)


利用STM32開發板制作一個簡單的信號發生器,能輸出三角波、方波以及正弦波。

這里選用到的芯片型號是STM32F103ZET6,先利用CUBE對其進行配置吧~
先配置RCC:

然后打開SYS,調整相應的Debug,我這里是用ST_LINK,所以用到Serial Wire。

配置時鍾樹,HCLK直接拉滿:

然后打開DAC,任意選擇通道1或2,並進行基礎配置(如果只是想生成三角波,那么在Wave generation mode中可以直接選擇Triangle wave generation,程序中只需要打開DAC輸出就能自行生成三角波):

將Trigger(觸發方式)選擇為定時器2事件觸發,再配置其DMA:

值得一提的是,DMA請求設置中,我們需選用Circular(循環)模式,因為只有如此配置才能產生一條可以持續的波形。

由於DAC觸發方式為定時器2觸發,所以我們需要打開定時器2,時鍾源為內部時鍾,再配置PSC與ARR:

該處配置會影響到你的波形頻率。同時我們需將它的觸發事件調整為Update Event,這很重要,如果遺漏,你就無法控制DAC輸出了。

打開串口一,並開啟中斷,讓我們可以使用串口的功能來實現波形的切換:

配置到這里就基本結束了,那么可以生成程序進KEIL5來進行程序的編譯。

先在串口的頭文件中重定向printf,具體細節可以參考我之前的隨筆。
然后編寫用於輸出波形的數組,可將其置於主函數內:

	for(i=0;i<1000;i++)
	{
		if(i<500)
			Sine12bit[i]=1500*sin(i*2*3.1415926/100)+2000;
		else
			Sine12bit[i]=1500*sin((i-500)*2*3.1415926/100)+2000;
	}
	for(i=0;i<1000;i++)
	{
		if(i<250)	
			fangbo[i]=500;
		else if(i>=250&&i<500)
			fangbo[i]=2000;
		else if(i>=500&&i<750)	
			fangbo[i]=500;
		else if(i>=750&&i<1000)
			fangbo[i]=2000;
	}
	for(i=0;i<1000;i++)
	{
		if(i<250)
			sjbo[i]=10*i+1000;
		else if(i>=250&&i<500)
			sjbo[i]=10*250+1000-10*(i-250);
		else if(i>=500&&i<750)	
			sjbo[i]=10*(i-500)+1000;
		else if(i>=750&&i<1000)	
			sjbo[i]=10*250+1000-10*(i-750);
	}

由於可寫入寄存器的最大值為2^12即4096,那么DAC輸出的可調范圍也就在0~4095之間,所以寫波形計算公式的時候需要注意數值會不會溢出。也許你們注意到我每個數組中都有一千個數據,而用於輸出的數據實質上只有五百個,我以每五百個數據為一個波形周期,設置兩個周期是為了方便調整相位差。而波形的噪音大小、平滑程度則與顯示一個周期所給出的數據個數有關,個數越多,波形越好看。
如果運用Sin函數會報錯,那一定是沒有添加math.h,將它加在include中即可。
至此,三種波形的輸出數組已經給值完成,打開定時器和接收中斷就可以開始輸出了:

	printf("please tell me : (S輸出正弦波,F輸出方波,P輸出三角波)\r\n");
	
	HAL_TIM_Base_Start(&htim2);
	HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)
                     Sine12bit,500,DAC_ALIGN_12B_R);
	HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)
                     (Sine12bit+k),500,DAC_ALIGN_12B_R);
	UART_Start_Receive_IT(&huart1,&Receive_date,1);

運用HAL_DAC_Start_DMA(),兩個通道都給出初始波形(正弦波),而其中的k則是我設置的相位差,理論范圍可以是0~500,我給出的初始值是80,調整k的值可以實現調整相位差。

while(1)里面什么都不用放,將頁面拉到末尾來編寫串口中斷回調:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	
	if(huart->Instance == USART1)
	{
		if(Receive_date=='S')
		{
			printf("輸出正弦波");	
			ki=1;
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)Sine12bit,500,DAC_ALIGN_12B_R);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(Sine12bit+k),500,DAC_ALIGN_12B_R);
		}
		else if(Receive_date=='F')
		{
			printf("輸出方波");
			ki=2;
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)fangbo,500,DAC_ALIGN_12B_R);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(fangbo+k),500,DAC_ALIGN_12B_R);
		}
		else if(Receive_date=='P')
		{
			printf("輸出三角波");
			ki=3;
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
			HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_1);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_2,(uint32_t *)sjbo,500,DAC_ALIGN_12B_R);
			HAL_DAC_Start_DMA(&hdac ,DAC_CHANNEL_1,(uint32_t *)(sjbo+k),500,DAC_ALIGN_12B_R);
		}
        }
        UART_Start_Receive_IT(&huart1,&Receive_date,1);
}

串口中斷結束時務必重新打開串口接收中斷,不然你的串口接收中斷就只能用一次了~

編程結束,上電來試試三種波形的輸出吧~

分別能輸出720Hz的方波與三角波,和3600Hz的正弦波。當然這里生成的波形都是用於顯示,交交作業還可以,切不可作為穩定信號源。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM