1.原理: 通過定時器每隔一段時間觸發一次DAC轉換,然後通過DMA發送正玄波碼表值給DAC. 當需要改變頻率HZ時,只需要修改定時器頻率即可(最高只能達到20KHz) 當需要改變正玄波的正峰峰值/負峰峰值時,只需要修改正玄波碼表即可 2.實現 代碼如下所示(採用的是定時器2,DAC引腳是PA4) ...
1.原理:
通過定時器每隔一段時間觸發一次DAC轉換,然後通過DMA發送正玄波碼表值給DAC.
- 當需要改變頻率HZ時,只需要修改定時器頻率即可(最高只能達到20KHz)
- 當需要改變正玄波的正峰峰值/負峰峰值時,只需要修改正玄波碼表即可
2.實現
代碼如下所示(採用的是定時器2,DAC引腳是PA4)
#define HZ(x) (u16)(72000000/sizeof(Sine12bit)*2/x) //計算Hz #define DAC_DHR12R1 0x40007408 //外設DAC通道1的基地址 u16 Sine12bit[256] = { //正弦波描點 2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496, 2545, 2594, 2642, 2690, 2737, 2785, 2831, 2877, 2923, 2968, 3013, 3057, 3100, 3143, 3185, 3227, 3267, 3307, 3347, 3385, 3423, 3460, 3496, 3531, 3565, 3598, 3631, 3662, 3692, 3722, 3750, 3778, 3804, 3829, 3854, 3877, 3899, 3920, 3940, 3958, 3976, 3992, 4007, 4021, 4034, 4046, 4056, 4065, 4073, 4080, 4086, 4090, 4093, 4095, 4095, 4095, 4093, 4090, 4086, 4080, 4073, 4065, 4056, 4046, 4034, 4021, 4007, 3992, 3976, 3958, 3940, 3920, 3899, 3877, 3854, 3829, 3804, 3778, 3750, 3722, 3692, 3662, 3631, 3598, 3565, 3531, 3496, 3460, 3423, 3385, 3347, 3307, 3267, 3227, 3185, 3143, 3100, 3057, 3013, 2968, 2923, 2877, 2831, 2785, 2737, 2690, 2642, 2594, 2545, 2496, 2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098, 2047, 1997, 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1501, 1453, 1405, 1358, 1310, 1264, 1218, 1172, 1127, 1082, 1038, 995, 952, 910, 868, 828, 788, 748, 710, 672, 635, 599, 564, 530, 497, 464, 433, 403, 373, 345, 317, 291, 266, 241, 218, 196, 175, 155, 137, 119, 103, 88, 74, 61, 49, 39, 30, 22, 15, 9, 5, 2, 0, 0, 0, 2, 5, 9, 15, 22, 30, 39, 49, 61, 74, 88, 103, 119, 137, 155, 175, 196, 218, 241, 266, 291, 317, 345, 373, 403, 433, 464, 497, 530, 564, 599, 635, 672, 710, 748, 788, 828, 868, 910, 952, 995, 1038, 1082, 1127, 1172, 1218, 1264, 1310, 1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697, 1747, 1797, 1847, 1897, 1947, 1997 }; /************************************************************* Function : set_Sine12bit Description : 設置正玄波碼表 Input : MAX(正峰峰值) MIN(負峰峰值) return : none *************************************************************/ void Set_Sine12bit(float MAX,float MIN) { int i; float jiaodu=0; float MID=(MAX+MIN)/2.0; //中間峰值 if(MAX>3.3) MAX=3.3; else if(MAX<=MIN) MIN=0; for(i=0;i<256;i++) { jiaodu=i*0.0247369; //當i =127時,表示為180度,由於sin()是弧度制,所以需要轉換 Sine12bit[i]= ((float)sin(jiaodu)*(MAX-MID)+MID)*1241.212; //1241.212是比例,等於4096/3.3 } } /************************************************************* Function : Set_Period Description : 設置頻率hz Input : value(需要設置的頻率hz值) return : none *************************************************************/ void Set_Period(u32 value) { TIM_ARRPreloadConfig(TIM2,DISABLE); TIM2->ARR=HZ(value); //更新預裝載值 TIM_ARRPreloadConfig(TIM2,ENABLE); } /************************************************************* Function : TIM2_Int_Init Description: 初始化定時器2 Input : Hz (需要初始化的頻率hz值) return : none *************************************************************/ void TIM2_Int_Init(u32 Hz) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//初始化定時器2與6的時鐘 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = HZ(Hz); //正弦波頻率設置 TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //沒有預分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時鐘不分頻 72M TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //增計數 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//更新TIM2輸出觸發 } /************************************************************* Function : DAC_DMA_Config Description: 初始化DAC和DMA Input : none return : none *************************************************************/ void DAC_DMA_Config(void) { DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//初始化DAC的時鐘 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//初始化DMA2的時鐘 /*初始化GPIO*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;//DAC channel1和channel2對應的引腳 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推輓輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /*初始化DAC寄存器*/ DAC_StructInit(&DAC_InitStructure); DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//指定DAC1的觸發定時器TIM2 DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//無波形產生 DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //不是能DAC輸出緩衝 DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化DAC channel1 DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC channel1 DAC_DMACmd(DAC_Channel_1, ENABLE); //使能DAC Channel1的DMA
/*初始化DMA寄存器*/ DMA_DeInit(DMA2_Channel3); //將DMA配置成預設值 DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//指定DMA2通道3的目標地址為DAC1_DHR12R1 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;//指定DMA的源地址為數組Sine12bit DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設作為數據傳輸的目的地 DMA_InitStructure.DMA_BufferSize = sizeof(Sine12bit)/2;//DMA緩衝區大小 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_Mode = DMA_Mode_Circular;//工作在迴圈緩存模式,數據傳輸數為0時,自動恢復配置初值 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//非常高優先順序 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被設置成記憶體到記憶體模式,與迴圈模式相對 DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化DMA DMA_Cmd(DMA2_Channel3, ENABLE); //使能DMA的channel3 TIM_Cmd(TIM2, ENABLE); //最後開啟TIM2轉換 }
然後在main()函數里,調用上面函數初始化,並判斷串口處理:
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 設置中斷優先順序分組2 uart_init(115200); delay_init(); //延時函數初始化 TIM2_Int_Init(50); //50HZ DAC_DMA_Config(); while(1) { USART_handler(); //處理串口輸入,實現頻率,峰峰值可調 delay_ms(20); } }
其中USART_handler()函數實現如下:
void USART_handler() { u8 len; u32 hz; //獲取HZ頻率 float dac_max,dac_min; //獲取DAC峰值 if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x2F; USART_RX_BUF[len]=0; sscanf((char *)USART_RX_BUF,"%d,%f,%f",&hz,&dac_max,&dac_min); printf("SET HZ = %d, MAX = %f,MIN = %f\r\n", hz,dac_max,dac_min); Set_Sine12bit(dac_max,dac_min); //更改峰值 Set_Period( hz); //更改頻率 USART_RX_STA=0; } }
3.進入串口試驗
1)設置頻率=50hz,正峰值=3.3V,負峰值=0V,串口則發送50,3.3,0.0,如下圖所示:
示波器測量:
2)設置頻率=100hz,正峰值=3V,負峰值=0V, 串口則發送100,3,0.0:
3)設置頻率=100hz,正峰值=2V,負峰值=1V, 串口則發送100,2,1:
4)設置頻率=1khz,正峰值=3.3V,負峰值=0V, 串口則發送1000,3.3,0:
5)設置頻率=20khz,正峰值=3.3V,負峰值=0V,串口則發送20000,3.3,0:
是不是很簡單~