本帖最后由 聪聪哥哥 于 2025-10-31 13:12 编辑
最近想制作一个波形发生器,手头正好有CH32的开发板,正好用来弄一下使用DAC输出不同的波形。
一:DAC的基础知识
数字/模拟转换模块(DAC),包含2个可配置 8/12 位数字输入转换2路模拟电压输出的转换器内置三角波、噪声波形发生器,支持多种事件触发转换,DMA 功能等。
二:主要特征:
2 个 DAC 转换器,每个转换器对应1个输出通道
三角波、噪声波形发生器
可配置 8 位或 12 位输出
12 位数据左对齐或右对齐
双 DAC 同时或分别转换
支持 DMA 功能
多种触发事件
三:DAC的模块结构
四:输出不同的波形
4.1 使用DMA的方式转换输出
DAC 通道具有 DMA 功能。设置 DAC_CTLR 寄存器的 DMAENx 位为1,开启对应通道的 DMA 功能。当有触发事件(不包括软件触发)发生,则产生一个 DMA 请求,然后 DAC_DORx 寄存器的数据将被更新。
4.1.1 DAC初始化:
- void Dac_Init( void )
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- DAC_InitTypeDef DAC_InitType = {0};
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
- RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init( GPIOA, &GPIO_InitStructure );
- DAC_InitType.DAC_Trigger = DAC_Trigger_T8_TRGO;
- DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None;
- DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable ;
- DAC_Init( DAC_Channel_1, &DAC_InitType );
- DAC_Cmd( DAC_Channel_1, ENABLE );
- DAC_DMACmd( DAC_Channel_1, ENABLE );
- }
4.1.2 DMA的初始化:
- void DAC1_DMA_Init( void )
- {
- DMA_InitTypeDef DMA_InitStructure = {0};
- RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA2, ENABLE );
- DMA_StructInit( &DMA_InitStructure );
- /* Note:DAC1--->DMA2.CH3 DAC2--->DMA2.CH4 */
- DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) & ( DAC->R12BDHR1 );
- DMA_InitStructure.DMA_MemoryBaseAddr = ( u32 )&dacbuff16bit;
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- DMA_InitStructure.DMA_BufferSize = 8;
- 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;
- DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init( DMA2_Channel3, &DMA_InitStructure );
- DMA_Cmd( DMA2_Channel3, ENABLE );
- }
4.1.3 定时器的初始化:
- void TIM8_Init( u16 arr, u16 psc )
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_TIM8, ENABLE );
- TIM_TimeBaseInitStructure.TIM_Period = arr;
- TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
- TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Down;
- TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
- TIM_TimeBaseInit( TIM8, &TIM_TimeBaseInitStructure );
- TIM_SelectOutputTrigger( TIM8, TIM_TRGOSource_Update );
- TIM_Cmd( TIM8, ENABLE );
- }
4.1.4 实物测试如下所示:
4.2 输出三角波形
模块内置了一个三角波生成器,可以在基准信号上加上一个小幅度的三角波。设置 WAVEx[1:0]位为'10’选择 DAC 的三角波生成功能。设置 DAC_CTLR 寄存器的 MAMPx[3:0]位来选择三角波的幅度。
系统内部包含一个从0开始的三角波计数器,在每次触发事件后3个PB1 时钟周期后累加1。计数器的值与 DAC DHRx 寄存器的数值相加并丢弃溢出位后写入 DAC DORx 寄存器。在传入 DAC DORx寄存器的数值小于 MAMPx[3:0]位定义的最大幅度时,三角波计数器逐步累加,一旦达到设置的最大幅度,则计数器开始递减,达到0后再开始累加,周而复始。将 WAVEx[1:0]位置'00’,可以复位三角波的生成。
注:1.为了产生三角波,必须使能 DAC 触发,即设 DAC CTLR寄存器的 TENx 位为 1。
2. MAMPx[3:0]位必须在使能 DAC 之前设置,否则其值不能修改。
4.2.1 DAC的初始化
- void Dac_Init( void )
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- DAC_InitTypeDef DAC_InitType = {0};
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
- RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init( GPIOA, &GPIO_InitStructure );
- DAC_InitType.DAC_Trigger = DAC_Trigger_Software;
- DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
- DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095;
- DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable ;
- DAC_Init( DAC_Channel_1, &DAC_InitType );
- /* TEN = 1 */
- DAC->CTLR |= 0x04;
- DAC_Cmd( DAC_Channel_1, ENABLE );
- DAC_SetChannel1Data( DAC_Align_12b_R, 0 );
- }
4.2.2 三角函数如下所示:
- void DAC1_Triangle_Gen_Test( void )
- {
- DAC->SWTR |= 0x01; /* Set by software, Reset by hardware */
- __asm volatile( "nop" );
- // printf("DOR1=0x%04x\r\n",DAC->DOR1);
- }
4.2.3 实物测试如下所示:
4.3 DAC 正常输出不同电压:
4.3.1 DAC初始化:
- void Dac_Init( void )
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- DAC_InitTypeDef DAC_InitType = {0};
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
- RCC_APB1PeriphClockCmd( RCC_APB1Periph_DAC, ENABLE );
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init( GPIOA, &GPIO_InitStructure );
- DAC_InitType.DAC_Trigger = DAC_Trigger_None;
- DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None;
- DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
- DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable ;
- DAC_Init( DAC_Channel_1, &DAC_InitType );
- DAC_Cmd( DAC_Channel_1, ENABLE );
- DAC_SetChannel1Data( DAC_Align_12b_R, 0 );
- }
4.3.2 主程序中调用:
- u16 DAC_Value[Num] = {64, 128, 256, 512, 1024, 2048, 4095};
- for( i = 0; i < Num; i++ ){
- DAC_SetChannel1Data( DAC_Align_12b_R, DAC_Value[i] );
- Delay_Ms(5000);
- }
可见,使用CH32的DAC功能,可以快速实现不同波形,电压的输出。
4.4 输出正弦波
- w += (PI / freq);
- if (w >= (2 * PI))
- {
- w = 0;
- }
- dac_value = (sin(w) + 1) / 2 * 4095;
这个波形看起来有点问题,看起来不是很平滑。
|