STM32CubeMX | STM32使用DAC+DMA+TIM生成10KHz正弦波

2022-01-07 14:00:02

STM32CubeMX | STM32使用DAC+DMA+TIM生成10KHz正弦波


工程環境:

  • STM32F103RC
  • KEIL MDK 5.20
  • STM32CubeMX 6.0

前言

  • 正弦波曲線的函數公式是:y=sin(x)

  • y的範圍區間是[-1:1]

  • x的取值範圍是任意實數

  • 週期為2π

如下圖所示的藍色函數曲線:

使用DAC生成正弦波比較方便的方法是預先生成一個正弦波的資料點表,為了能夠快速設定到DAC上所有會使用到DMA,然後通過定時器控制DAC的出樣頻率就達到了生成正弦波的效果。

那麼這個正弦波資料點表是怎麼生成的呢?下面就來講解一下。

將這個y=sin(x)函數對映成我們現在的這個正弦波,那麼y就是代表的電壓,x代表的週期。

由於y=sin(x)的值範圍在[-1:1]之間,DAC設定的時候不存在負數,所以就需要加1讓公式生成的值都在正數範圍內,公式就變成了y=six(x) + 1,現在值範圍就成了[0:2],但是這樣最高能表示到2V,而DAC是能輸出到3.3V的,也就是說y=six(x) + 1輸出2V的時候代表3.3V,所以就需要對y=six(x) + 1進行擴大,比值關係就是3.3V:2V,所以公式又變成了y=(sin(x) + 1)*(3.3/2),這樣值範圍就變為了[0:3.3],然後再將電壓轉為DAC數值就可以了。

因為正弦波每週期的波形都是一樣的,所以我們生成一個週期的資料表即可。

經試驗所得,一個週期內滿足32個點就能近似逼近正弦波的效果,這裡為了波形更好看,我選擇了100個點。

週期為2π,一共100個點,那麼每兩個點的間距就是2π/100。

/**
 * 生成正弦波資料點函數
 * @param NPoints       一個週期內的點數
 * @param VMaxRange     輸出的電壓最大值,取值範圍0~3.3V
 * @param SineWaveTable 存放生成的資料點
 */
void SineWaveGen(uint32_t NPoints, float VMaxRange, uint16_t* SineWaveTable)
{
#ifndef PI
#define PI 3.14159265358979323846
#endif

	int    i       = 0;
	double radian  = 0;  // 弧度
	double setup   = 0;  // 弧度和弧度之間的大小
	double voltage = 0;  // 輸出電壓

	setup = (2 * PI) / NPoints;  // 兩點之間的間距

	while (i < NPoints)
	{
		voltage = VMaxRange / 2.0 * (sin(radian) + 1.0);              // 計算電壓
		SineWaveTable[i] = (uint16_t)(voltage * 4096 / 3.3);          // 電壓轉為DAC數值
		radian += setup;                                              // 下一個點的弧度
		i++;
	}
}

工程設定

時鐘設定到72M主頻:

設定DAC

說明:

Output Buffer:輸出快取

DAC 整合了 2 個輸出快取,可以用來減少輸出阻抗,無需外部運放即可直接驅動外部負載。每個 DAC 通道輸出快取可以通過設定 DAC_CR 暫存器的 BOFFx 位來使能或者關閉。如果帶載能力還不行,後面就接一個電壓跟隨器,選擇運放一定要選擇電流大的型號。
使能輸出緩衝後,DAC 輸出的最小電壓為 0.2V,最大電壓為 VREF±0.2,而未使能輸出緩衝則輸出可達到0V。

Tigger:觸發方式

選擇DAC的觸發方式,可以選擇為定時器觸發、外部中斷觸發和軟體觸發。這裡我選擇了定時器6來觸發DAC,因為通過設定定時器的頻率就可以很方便的控制DAC輸出的正弦波頻率。

Wave generation mode:波形發生器

我這裡沒有使用。

設定DMA

設定定時器

定時器6的時鐘主頻為72MHz,我這裡沒有分頻,那麼把過載值設定為72,這樣就得到了72M/72=1MHz的觸發頻率。

上面說到過我的設定是一個週期內100個點,定時器觸發頻率為1MHz,觸發一百次才能完成一個週期的波形,所以生成的波形頻率就是1MHz/100個點=10KHz。

最後啟動定時器和DMA傳輸即可:

	HAL_TIM_Base_Start(&htim6);
	HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)SineWaveTable, POINTS, DAC_ALIGN_12B_R);

生成的波形用示波器檢視如下: