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()函數里,調用USART_handler()
其中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:
是不是很簡單~