DAC是STM32系列的一個基本外設,可以將數字信號轉化成模擬信號,這次我將使用DAC來輸出一個特定波形。 首先確定工作方法,由於我目前在做的簡易示波器在輸出波形的同時還需要顯示輸入信號,所以不能占用太多CPU時間,於是就選用了基於DMA的ADC。 使用DMA只需告訴DMA外設它要怎麼搬移數據就可以 ...
DAC是STM32系列的一個基本外設,可以將數字信號轉化成模擬信號,這次我將使用DAC來輸出一個特定波形。
首先確定工作方法,由於我目前在做的簡易示波器在輸出波形的同時還需要顯示輸入信號,所以不能占用太多CPU時間,於是就選用了基於DMA的ADC。
使用DMA只需告訴DMA外設它要怎麼搬移數據就可以處理其他事。
首先定義一下
#define DAC_DHR12R1 (u32)&(DAC->DHR12R1) //DAC DATA buff
作為DMA的外設數據地址
首先是初始化輸出管腳
DAC1對應PA4
void Wave_GPIO_Config(void)//DAC!-------PA5 { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ; GPIO_SetBits(GPIOA,GPIO_Pin_4) ; GPIO_Init(GPIOA, &GPIO_InitStructure); }
需要註意的是,ST官方文檔上的說明
一旦使能DACx通道,相應的GPIO引腳(PA4或者PA5)就會自動與DAC的模擬輸出相連
(DAC_OUTx)。為了避免寄生的干擾和額外的功耗,引腳PA4或者PA5在之前應當設置成模擬輸
入(AIN)。
然後是DAC外設的初始化
void Wave_DAC_Config( void) { DAC_InitTypeDef DAC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); DAC_StructInit(&DAC_InitStructure); DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//不使用波形發生器 DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//TIM2 Trigger DAC_Init(DAC_Channel_1, &DAC_InitStructure); DAC_Cmd(DAC_Channel_1, ENABLE); DAC_DMACmd(DAC_Channel_1, ENABLE); }
DAC_OutputBuffer,即是否使用輸出緩存。輸出緩存的功能主要用來減小輸出阻抗,是STM32的DAC無需外部運放就可以直接驅動負載。(一般不用,因為不確定要求
使用TIM2來觸發一次DAC,DAC的輸出緩存有兩個,一個是DAC_DORx ,用戶不能直接寫入,另一個是DAC_DHRx (DAC_DHR8Rx、 DAC_DHR12Lx、 DAC_DHR12Rx、 DAC_DHR8RD、DAC_DHR12LD、或者DAC_DHR12RD寄存器 )如果沒有選中硬體觸發 ,存入寄存器DAC_DHRx的數據會在
一個APB1時鐘周期後自動傳至寄存器DAC_DORx。如果選中硬體觸發 ,數據傳輸在觸發發生以後3個APB1時鐘周期後完成。
下麵是TIM初始化,TIM的工作決定了DMA與DAC的工作頻率
void Wave_TIM_Config(u32 Wave1_Fre)//TIM2 Init { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; TIM_TimeBaseStructure.TIM_Period = Wave1_Fre; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); }
預設情況下TIM的時鐘頻率為36Mhz,經過分頻為36M/((Prescaler+1)*ClockDivision)。
當計數溢出時就會產生觸發事件,TIM_TRG
接著是DMA的初始化
void Wave_DMA_Config(uint16_t* wave)//DMA2 { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); DMA_StructInit( &DMA_InitStructure); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//peripherals to memory DMA_InitStructure.DMA_BufferSize = 512; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)wave; DMA_Init(DMA2_Channel3, &DMA_InitStructure); DMA_Cmd(DMA2_Channel3, ENABLE); }
對於DMA要搞清楚要搬的數據的地址在哪,要搬到哪,這裡要搬的數據在存儲器中,地址為(uint32_t)wave,外設地址為DAC_DHR12R1,是從記憶體到外設,所以工作模式為
DMA_DIR_PeripheralDST,為雙向傳輸,禁止M2M,存儲至存儲。觸發源為TIM2
最後為總體調用
void Wave_Init(uint16_t* wave) { Wave_GPIO_Config(); Wave_TIM_Config(3000); //72000000/3000=24000 points per second Wave_DAC_Config(); Wave_DMA_Config(wave); TIM_Cmd(TIM2, ENABLE); }
總結:多看官方文檔,程式分段寫函數