5.6 DAC 使用说明
本章说明 N32H49x 标准外设库中 DAC 驱动的文件组成与 29 个公开函数,以及 5 个示例。DAC 是 12 位数字/模拟转换器,支持 8 位与 12 位数据、DMA、噪声波/三角波/锯齿波生成与缓冲器偏移校准,可独立或双通道同步转换;触发源选择、输出缓冲与波形更新规则请配合用户手册的“数字/模拟转换(DAC)”章节阅读。
5.6.1 相关文件
| 相对路径 | 作用 |
|---|---|
firmware/n32h49x_std_periph_driver/inc/n32h49x_dac.h |
定义触发源、波形、对齐方式等参数枚举,声明 29 个公开函数 |
firmware/n32h49x_std_periph_driver/src/n32h49x_dac.c |
实现上述 29 个函数:初始化与使能、输出与校准、软件触发、波形与数据、状态与中断、时钟分频与修调 |
projects/n32h49x_EVAL/examples/DAC/ |
DAC 示例根目录,含 DoubleDataDMAModeSineWave、NoiseWaveOutput、SawtoothWaveOutput、TwoDACsTriangleWave、UserBufferCalibration 5 个示例 |
projects/n32h49x_EVAL/examples/DAC/DoubleDataDMAModeSineWave/ |
该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt |
projects/n32h49x_EVAL/bsp/ |
该示例引用的公共板级文件:串口日志与微秒/毫秒延时函数 |
5.6.2 API 参考
以下 29 个公开函数按 n32h49x_dac.h 的声明顺序分为 6 组;每个条目给出功能摘要与 n32h49x_dac.c 中该函数正上方的注释原文。
初始化与使能
DAC_DeInit、DAC_StructInit、DAC_Init、DAC_Enable
输出、DMA 与校准
DAC_DmaEnable、DAC_CaliEnable、DAC_ConnetToExternalPinEnable、DAC_ConnetToOnChipEnable、DAC_HighDriveAbilityEnable、DAC_SignFormatModeEnable、DAC_DMADoubleDataModeEnable
软件触发
DAC_SoftTrgEnable、DAC_SoftTrgSawStepEnable、DAC_DualSoftwareTrgEnable、DAC_DualSoftwareTrgSawStepEnable
波形与数据
DAC_WaveGenerationConfig、DAC_SetSawtoothResetValue、DAC_SetSawtoothStepValue、DAC_SetData、DAC_SetDualChData
状态与中断
DAC_GetOutputDataVal、DAC_GetFlagSts、DAC_ClearFlag、DAC_ConfigInt、DAC_GetIntSts、DAC_ClearITPendingBit
时钟与修调
DAC_ConfigClkPrescaler、DAC_SetHighFrequencyMode、DAC_SetUserTrimming
void DAC_DeInit(DACX DACx)复位 DAC 寄存器。
name DAC_DeInit.
fun Reset the DAC registers.
param DACx :
- DAC1
- DAC2
return none
void DAC_StructInit(DAC_InitType* DAC_InitStruct)把 DAC_InitType 结构体的所有成员填为默认值。
name DAC_StructInit.
fun Fills all DAC_StructInit member with default value.
param DAC_StructInit :
- DAC_Trigger
- DAC_Trigger2
- DAC_WaveGeneration
- DAC_LFSRUnmask_TriangleAmplitude
- DAC_OutputBuffer
- DAC_TriggerEnable
- DAC_DMADoubleDataMode
- DAC_SignedFormat
- DAC_ConnectOnChipPeripheral
- DAC_ConnectExternalPin
return none
void DAC_Init(DACX DACx, DAC_InitType* DAC_InitStruct)使能或关闭指定的 DAC。
name DAC_Init.
fun Enables or disables the specified DAC.
param DACx :
- DAC1
- DAC2
param DAC_InitStruct :
- DAC_Trigger
- DAC_Trigger_Software
- DAC_Trigger_ATIM1_TRGO
- DAC_Trigger_ATIM2_TRGO
- DAC_Trigger_ATIM3_TRGO
- DAC_Trigger_GTIM1_TRGO
- DAC_Trigger_GTIM2_TRGO
- DAC_Trigger_GTIM3_TRGO
- DAC_Trigger_GTIM4_TRGO
- DAC_Trigger_GTIM5_TRGO
- DAC_Trigger_GTIM6_TRGO
- DAC_Trigger_GTIM7_TRGO
- DAC_Trigger_GTIM8_TRGO
- DAC_Trigger_GTIM9_TRGO
- DAC_Trigger_GTIM10_TRGO
- DAC_Trigger_EXTI5
- DAC_Trigger_EXTI7
- DAC_Trigger_EXTI9
- DAC_Trigger2
- DAC_Trigger2_Software
- DAC_Trigger2_ATIM1_TRGO
- DAC_Trigger2_ATIM2_TRGO
- DAC_Trigger2_ATIM3_TRGO
- DAC_Trigger2_GTIM1_TRGO
- DAC_Trigger2_GTIM2_TRGO
- DAC_Trigger2_GTIM3_TRGO
- DAC_Trigger2_GTIM4_TRGO
- DAC_Trigger2_GTIM5_TRGO
- DAC_Trigger2_GTIM6_TRGO
- DAC_Trigger2_GTIM7_TRGO
- DAC_Trigger2_GTIM8_TRGO
- DAC_Trigger2_GTIM9_TRGO
- DAC_Trigger2_GTIM10_TRGO
- DAC_Trigger2_EXTI6
- DAC_Trigger2_EXTI8
- DAC_Trigger2_EXTI10
- DAC_LFSRUnmask_TriangleAmplitude
- DAC_LFSRUnmask_Bit0
- DAC_LFSRUnmask_Bits1_0
- DAC_LFSRUnmask_Bits2_0
- DAC_LFSRUnmask_Bits3_0
- DAC_LFSRUnmask_Bits4_0
- DAC_LFSRUnmask_Bits5_0
- DAC_LFSRUnmask_Bits6_0
- DAC_LFSRUnmask_Bits7_0
- DAC_LFSRUnmask_Bits8_0
- DAC_LFSRUnmask_Bits9_0
- DAC_LFSRUnmask_Bits10_0
- DAC_LFSRUnmask_Bits11_0
- DAC_TriangleAmplitude_1
- DAC_TriangleAmplitude_3
- DAC_TriangleAmplitude_7
- DAC_TriangleAmplitude_15
- DAC_TriangleAmplitude_31
- DAC_TriangleAmplitude_63
- DAC_TriangleAmplitude_127
- DAC_TriangleAmplitude_255
- DAC_TriangleAmplitude_511
- DAC_TriangleAmplitude_1023
- DAC_TriangleAmplitude_2047
- DAC_TriangleAmplitude_4095
- DAC_WaveGeneration
- DAC_WaveGeneration_None
- DAC_WaveGeneration_Noise
- DAC_WaveGeneration_Triangle
- DAC_WaveGeneration_SAWTOOTH_INC
- DAC_WaveGeneration_SAWTOOTH_DEC
- DAC_OutputBuffer
- ENABLE
- DISABLE
- DAC_TriggerEnable
- ENABLE
- DISABLE
- DAC_DMADoubleDataMode
- ENABLE
- DISABLE
- DAC_SignedFormat
- ENABLE
- DISABLE
- DAC_ConnectOnChipPeripheral
- ENABLE
- DISABLE
- DAC_ConnectExternalPin
- ENABLE
- DISABLE
return none
void DAC_Enable(DACX DACx, FunctionalState Cmd)使能或关闭指定的 DAC。
name DAC_Enable.
fun Enables or disables the specified DAC.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_DmaEnable(DACX DACx, FunctionalState Cmd)使能或关闭指定 DAC 的 DMA 请求。
name DAC_DmaEnable.
fun Enables or disables the specified DAC DMA request.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_CaliEnable(DACX DACx, FunctionalState Cmd)使能或关闭指定 DACx 的校准功能。
name DAC_CaliEnable.
fun Enables or disables the specified DACx calibration function.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_ConnetToExternalPinEnable(DACX DACx, FunctionalState Cmd)使能或关闭 DACx 输出连接到外部引脚。
name DAC_ConnetToExternalPinEnable.
fun Enables or disables the DACx output connected to external pin.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_ConnetToOnChipEnable(DACX DACx, FunctionalState Cmd)使能或关闭 DACx 输出连接到芯片内部。
name DAC_ConnetToOnChipEnable.
fun Enables or disables the DACx output connected to on the chip.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_HighDriveAbilityEnable(DACX DACx, FunctionalState Cmd)使能或关闭 DACx 高驱动能力输出。
name DAC_HighDriveAbilityEnable.
fun Enables or disables the DACx high driver ability output.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_SignFormatModeEnable(DACX DACx, FunctionalState Cmd)使能或关闭 DACx 有符号格式模式。
name DAC_SignFormatModeEnable.
fun Enables or disables the DACx signed format mode.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_DMADoubleDataModeEnable(DACX DACx, FunctionalState Cmd)使能或关闭 DACx DMA 双数据模式。
name DAC_DMADoubleDataModeEnable.
fun Enables or disables the DACx DMA double data mode.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_SoftTrgEnable(DACX DACx, FunctionalState Cmd)使能或关闭选中 DAC 的软件触发。
name DAC_SoftTrgEnable.
fun Enables or disables software trigger of the selected DAC.
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_SoftTrgSawStepEnable(DACX DACx, FunctionalState Cmd)使能或关闭选中 DAC 锯齿波的软件触发步进信号。
name DAC_SoftTrgSawStepEnable.
fun Enables or disables software trigger step signal of the selected DAC sawtooth wave .
param DACx :
- DAC1
- DAC2
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_DualSoftwareTrgEnable(DAC_Module *Dual_DACx, FunctionalState Cmd)同时使能或关闭两个 DAC 的软件触发。
name DAC_DualSoftwareTrgEnable.
fun Enables or disables simultaneously the two DAC software triggers.
param DACx :
- DAC12
param Cmd :
- ENABLE
- DISABLE
return none
void DAC_DualSoftwareTrgSawStepEnable(DAC_Module *Dual_DACx, FunctionalState Cmd)同时使能或关闭两个 DAC 锯齿波的软件触发步进信号。
name DAC_DualSoftwareTrgEnable.
fun Enables or disables software trigger step signal of simultaneously two DACs sawtooth wave .
param DACx :
- DAC12
param Cmd :
- ENABLE
- DISABLE
return none
使用提示: 源码注释的 name 字段写作 DAC_DualSoftwareTrgEnable.,与函数名 DAC_DualSoftwareTrgSawStepEnable 不一致,按函数名调用即可。
void DAC_WaveGenerationConfig(DACX DACx, uint32_t DAC_Wave)配置选中 DAC 的波形生成。
name DAC_WaveGenerationConfig.
fun Configure the selected DAC wave generation. .
param DACx :
- DAC1
- DAC2
param DAC_Wave :
- DAC_WaveGeneration_None
- DAC_WaveGeneration_Noise
- DAC_WaveGeneration_Triangle
- DAC_WaveGeneration_SAWTOOTH_INC
- DAC_WaveGeneration_SAWTOOTH_DEC
return none
void DAC_SetSawtoothResetValue(DACX DACx, uint16_t ResetValue)设置锯齿波生成的复位数据。
name DAC_SetSawtoothResetValue.
fun Set the swatooth waveform generation reset data.
param DACx :
- DAC1
- DAC2
param ResetValue:
- the value is range from 0- 0xfff;
return none
void DAC_SetSawtoothStepValue(DACX DACx, uint16_t StepData)设置锯齿波生成的步进数据。
name DAC_SetSawtoothStepValue.
fun Set the swatooth waveform generation step data.
param DACx :
- DAC1
- DAC2
param StepData:
- the value is range from 0- 0xfff;
return none
void DAC_SetData(DACX DACx, uint32_t DAC_Align, uint16_t Data)设置指定 DAC 的数据保持寄存器值。
name DAC_SetData.
fun Set the data holding register value for the specified DAC.
param DACx :
- DAC1
- DAC2
param DAC_Align :
- DAC_ALIGN_R_8BIT
- DAC_ALIGN_L_12BIT
- DAC_ALIGN_R_12BIT
param Data : Data to be loaded in the selected data holding register.
return none
void DAC_SetDualChData(DAC_Module *Dual_DACx, uint32_t DAC_Align, uint16_t Data2, uint16_t Data1)设置指定双 DAC 的数据保持寄存器值。
name DAC_SetDualChData.
fun Set the data holding register value for the specified dual-DAC.
param DACx :
- DAC12
param DAC_Align :
- DAC_ALIGN_R_8BIT
- DAC_ALIGN_L_12BIT
- DAC_ALIGN_R_12BIT
param Data2 : Data to be loaded in the selected DACy data holding register.
param Data1 : Data to be loaded in the selected DACx data holding register.
return none
uint16_t DAC_GetOutputDataVal(DACX DACx)获取选中 DAC 最后一次的数据输出值。
name DAC_GetOutputDataVal.
fun Get the last data output value of the selected DAC .
param DACx :
- DAC1
- DAC2
return The selected DAC data output value.
FlagStatus DAC_GetFlagSts(DACX DACx, uint32_t DAC_FLAG)获取指定 DAC 的状态标志。
name DAC_GetFlagSts.
fun Get the specified DAC status flag.
param DACx :
- DAC1
- DAC2
param DAC_FLAG:
- DAC_FLAG_DMAUDR
- DAC_FLAG_CALCOMPLETE
- DAC_FLAG_DORSTAT
- DAC_FLAG_TROVC
return FlagStatus :
- SET
- RESET
void DAC_ClearFlag(DACX DACx, uint32_t DAC_FLAG)清除指定 DAC 的状态标志。
name DAC_ClearFlag.
fun Clear the specified DAC status flag.
param DACx :
- DAC1
- DAC2
param DAC_FLAG:
- DAC_FLAG_DMAUDR
- DAC_FLAG_TROVC
return none
void DAC_ConfigInt(DACX DACx, uint32_t DAC_IT, FunctionalState Cmd)使能或关闭指定 DAC 的中断。
name DAC_ConfigInt.
fun Enables or disables the specified DAC interrupts.
param DACx :
- DAC1
- DAC2
param DAC_IT:
- DAC_INT_DMAUDRIEN
- DAC_INT_TROVIEN
param Cmd :
- ENABLE
- DISABLE
return none
FlagStatus DAC_GetIntSts(DACX DACx, uint32_t DAC_IT)获取指定 DAC 的中断标志。
name DAC_GetIntSts.
fun Get the specified DAC interrupts flag.
param DACx :
- DAC1
- DAC2
param DAC_IT:
- DAC_INTFLAG_DMAUDR
- DAC_INTFLAG_TROVC
return FlagStatus :
- SET
- RESET
void DAC_ClearITPendingBit(DACX DACx, uint32_t DAC_IT)清除 DACx 中断挂起位。
name DAC_ClearITPendingBit.
fun Clears the DACx interrupt pending bit.
param DACx :
- DAC1
- DAC2
param DAC_IT:
- DAC_INTFLAG_DMAUDR
- DAC_INTFLAG_TROVC
return FlagStatus :
- SET
- RESET
void DAC_ConfigClkPrescaler(DAC_Module* DACx, uint8_t Prescaler)配置 DAC_CLK 预分频。
name DAC_ConfigClkPrescaler.
fun Configures the DAC_CLK prescaler.
param DACx :
- DAC12
param Prescaler:
- the value range from 1 - 0xff
return none
void DAC_SetHighFrequencyMode(DAC_Module* DACx, uint32_t mode)配置选中 DAC 的高频接口模式。
name DAC_SetHighFrequencyMode.
fun Configures the high frequency interface mode for the selected DAC.
param DACx :
- DAC12
param mode:
- DAC_HIGH_FREQ_MODE_DISABLE
- DAC_HIGH_FREQ_MODE_BELOW_80M
- DAC_HIGH_FREQ_MODE_BELOW_160M
- DAC_HIGH_FREQ_MODE_ABOVE_160M
return none
void DAC_SetUserTrimming(DACX DACx, uint8_t TrimmingValue)配置选中 DAC 的偏移修调值。
name DAC_SetUserTrimming.
fun Config the offset trimming value for the selected DAC .
param DACx :
- DAC1
- DAC2
param TrimmingValue: DAC new trimming value
- the data is range from 0 - 31
return none
5.6.3 Demo 示例说明
本节说明 DAC 的 5 个示例:DoubleDataDMAModeSineWave 用 GTIM1 触发配合 DMA 双数据模式输出正弦波,NoiseWaveOutput 用软件触发输出伪噪声波,SawtoothWaveOutput 输出递增锯齿波并由软件触发步进,TwoDACsTriangleWave 由 ATIM1 同步触发 DAC1 与 DAC2 输出两路三角波,UserBufferCalibration 演示缓冲器偏移校准并给出用户修调值。DAC1_OUT 固定为 PA4,DAC2_OUT 为 PA5。
5.6.3.1 DoubleDataDMAModeSineWave 双数据模式 DMA 正弦波输出
工程目录: projects/n32h49x_EVAL/examples/DAC/DoubleDataDMAModeSineWave/
配置系统时钟与 DAC 时钟分频→将 PA4 配置为模拟输出→配置 DMA1 通道 1 循环搬运正弦表→配置 DAC1 使用 GTIM1 触发与 DMA 双数据模式→启动 DMA 与 GTIM1 由更新事件持续触发转换
| 项目 | 源码解读 |
|---|---|
| 功能 | GTIM1 更新事件经 TRGO 触发 DAC1,DMA1 通道 1 以循环方式把 Sine32bit 表搬运到 DAC 双数据保持寄存器;PA4 输出 16 点正弦波,每两点打包进一个 32 位字,双数据模式在一次触发中依次转换低 16 位与高 16 位。 |
| 源码组成 | src/main.c:main、RCC_Configuration、GPIO_Configuration、DMA_Config、DAC_Configuratoin、GTIM1_Init;inc/main.h:包含 n32h49x_dac.h、n32h49x_dma.h、n32h49x_tim.h、n32h49x_gpio.h、n32h49x_rcc.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务程序(仅异常处理);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:RCC_ConfigPclk1(RCC_HCLK_DIV4),DAC_ConfigClkPrescaler(DAC12,120) 使 DAC_CLK 约 1 MHz,DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);引脚:PA4 模拟模式作为 DAC1_OUT; DAC: DAC_Trigger_GTIM1_TRGO、DAC_DMADoubleDataMode=ENABLE、DAC_OutputBuffer=DISABLE、DAC_ConnectExternalPin=ENABLE;DMA: DMA1_CH1 外设地址 DAC12->DR12CH1,缓冲区 16 字,循环模式,并调用 DMA_RequestRemap(DMA_REMAP_DAC1,DMA1_CH1,ENABLE)。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration、GPIO_Configuration、DMA_Config、DAC_Configuratoin、GTIM1_Init;随后把 Sine12bit 相邻两点拼成 Sine32bit[16],使能 DMA1 通道 1 并启动 GTIM1;GTIM1 每次更新事件输出 TRGO,DAC 触发一次读取一个 32 位字并依次转换两个采样点。 |
| 主要 API | DAC_StructInit, DAC_Init, DAC_DmaEnable, DAC_Enable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode |
| 验证方法 | 下载运行后用示波器观察 PA4,可得到 16 点正弦波; GTIM1 触发频率为 16 MHz / 16 = 1 MHz,每触发一次转换两点,故正弦波频率约为 1 MHz / 16 = 62.5 kHz。 |
| 使用提示 | 硬件平台为 N32H497ZGL7_EVB; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; GTIM1-7/BTIM1-2 最高 120 MHz,PCLK1 不能为 1 或 2 分频,示例使用 4 分频。 |
核心代码解读与移植
示例先配置时钟、模拟输出引脚、DMA 与 DAC,再把正弦表两两合并为 32 位数据并启动 DMA 与定时器,由 GTIM1 更新事件持续触发转换。
数据路径: RCC_Configuration 配置 GPIO、DMA 与 DAC 时钟 → GPIO_Configuration 把 PA4 设为模拟输出 → DMA_Config 建立循环搬运 → DAC_Configuratoin 选择 GTIM1 触发与双数据模式 → GTIM1_Init 输出更新 TRGO → main 填充 Sine32bit 并启动 DMA 与 GTIM1
1. 配置系统时钟与 DAC 时钟分频。 RCC_Configuration 先把 PCLK1 设为 HCLK 的 1/4,使能 DMA1 与 GPIO 时钟,再使能 DAC12 与 GTIM1 时钟并把 DAC_CLK 分频到约 1 MHz。
void RCC_Configuration(void)
{
/* Enable peripheral clocks ------------------------------------------------*/
RCC_ConfigPclk1(RCC_HCLK_DIV4);/* The maximum operating clock of GTIM1-7/BTIM1-2 is 120MHz,the division frequency of PCLK1 cannot be 1 or 2 divisions */
/* Enable DMA1 clocks */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_DMA1, ENABLE);
/* Enable GPIOA, GPIOB, GPIOC clocks */
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
/* Enable DAC1 DAC2 GTIM1 clocks */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 | RCC_APB1_PERIPHEN_GTIM1 ,ENABLE);
/* Config DAC12 prescaler factor,DAC_CLK = 1M*/
DAC_ConfigClkPrescaler(DAC12,120);
DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
移植到其他型号时可精简未使用的 GPIO 时钟,但 DMA1 与 DAC12、GTIM1 的时钟以及 DAC_CLK 分频必须保留。
2. 配置模拟输出引脚。 GPIO_Configuration 把 PA4 配置为模拟模式作为 DAC1_OUT。
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
/* DAC1_OUT */
GPIO_InitStructure.Pin = GPIO_PIN_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
更换评估板时只需修改引脚号,模拟模式与 DAC1_OUT 的对应关系由芯片引脚复用决定。
3. 配置 DAC。 DAC_Configuratoin 选择 GTIM1 触发、关闭输出缓冲、连接外部引脚,并使能双数据模式、DMA、触发与 DAC1 本体。
void DAC_Configuratoin(void)
{
DAC_InitType DAC_InitStructure;
DAC_StructInit(&DAC_InitStructure);
/* DAC1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_GTIM1_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_DMADoubleDataMode = ENABLE;
DAC_InitStructure.DAC_OutputBuffer = DISABLE;
DAC_InitStructure.DAC_ConnectOnChipPeripheral = DISABLE;
DAC_InitStructure.DAC_ConnectExternalPin = ENABLE;
DAC_InitStructure.DAC_TriggerEnable = ENABLE;
DAC_Init(DAC1, &DAC_InitStructure);
/* Enable DAC1 DMA function */
DAC_DmaEnable(DAC1, ENABLE);
/* Enable DAC1 */
DAC_Enable(DAC1, ENABLE);
}
双数据模式要求 DMA 每次搬运一个 32 位字;关闭输出缓冲可提高刷新率,但需根据负载评估建立时间。
4. 配置 DMA 通道。 DMA_Config 让 DMA1_CH1 从 Sine32bit 循环搬运 16 个字到 DAC12->DR12CH1,并把 DMA 请求映射到 DAC1。
void DMA_Config(void)
{
DMA_InitType DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.PeriphAddr = (uint32_t)&DAC12->DR12CH1;
DMA_InitStructure.MemAddr = (uint32_t)Sine32bit;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
DMA_InitStructure.BufSize = 16;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
DMA_InitStructure.MemoryInc = DMA_MEM_INC_ENABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_WORD;
DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_WORD;
DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR;
DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(DMA1_CH1, &DMA_InitStructure);
DMA_RequestRemap(DMA_REMAP_DAC1, DMA1_CH1,ENABLE);
}
搬运用字宽(WORD)与双数据模式匹配,循环模式保证正弦表自动重复;DMA_RequestRemap 必须把 DAC1 请求接到通道 1。
5. 配置触发并启动。 GTIM1_Init 把 GTIM1 更新事件输出为 TRGO 作为 DAC 触发源,main 在填充正弦表后使能 DMA 并启动定时器。
void GTIM1_Init(void)
{
TIM_TimeBaseInitType TIM_TimeBaseStructure;
uint16_t PrescalerValue ;
PrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
/* GTIM1 Configuration */
/* Time base configuration */
TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.Period = 16-1;
TIM_TimeBaseStructure.Prescaler = PrescalerValue;
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;
TIM_TimeBaseStructure.CounterMode = TIM_CNT_MODE_UP;
TIM_InitTimeBase(GTIM1, &TIM_TimeBaseStructure);
/* GTIM1 TRGO selection */
TIM_SelectOutputTrig(GTIM1, TIM_TRGO_SRC_UPDATE);
}
/* Fill Sine32bit table */
for (index = 0; index < 16; index++ )
{
Sine32bit[index] = (Sine12bit[2*index+1] << 16) + (Sine12bit[2*index]);
}
/* Enable DMA1 channel1 */
DMA_EnableChannel(DMA1_CH1, ENABLE);
TIM_Enable(GTIM1, ENABLE);
触发频率由 GTIM1 周期与预分频共同决定;更换波形表时保持 Sine32bit 元素个数与 DMA BufSize 一致。
对应源码: src/main.c
5.6.3.2 NoiseWaveOutput 噪声波输出
工程目录: projects/n32h49x_EVAL/examples/DAC/NoiseWaveOutput/
配置系统与 DAC 时钟→将 PA4 配置为模拟输出→配置 DAC1 产生噪声波并写入初始数据→主循环软件触发产生噪声
| 项目 | 源码解读 |
|---|---|
| 功能 | DAC1 以软件触发方式输出伪噪声波,LFSR 掩码为 DAC_LFSRUnmask_Bit0;主循环反复触发转换,PA4 输出随 LFSR 变化的噪声电压。 |
| 源码组成 | src/main.c:main、RCC_Configuration、GPIO_Configuration、DAC_Configuratoin;inc/main.h:包含 n32h49x_dac.h、n32h49x_gpio.h、n32h49x_rcc.h、delay.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务程序(仅异常处理);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:DAC_ConfigClkPrescaler(DAC12,120) 使 DAC_CLK 约 1 MHz,DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);引脚:PA4 模拟模式作为 DAC1_OUT; DAC: DAC_Trigger_Software、DAC_WaveGeneration_Noise、DAC_LFSRUnmask_Bit0、DAC_OutputBuffer=DISABLE、DAC_TriggerEnable=ENABLE;初始数据: DAC_SetData(DAC1,DAC_ALIGN_R_12BIT,4094)。 |
| 程序与数据路径 | main 先调用 RCC_Configuration 与 GPIO_Configuration,再调用 DAC_Configuratoin 配置并使能 DAC1;while(1) 中反复 DAC_SoftTrgEnable 触发一次转换并延时 1 us,LFSR 在两次触发之间推进,产生伪随机噪声序列。 |
| 主要 API | DAC_StructInit, DAC_Init, DAC_Enable, DAC_SetData, DAC_SoftTrgEnable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode |
| 验证方法 | 下载运行后用示波器观察 PA4,可看到随机变化的噪声波形; 改变 DAC_LFSRUnmask_Bit0 或主循环延时,可调整噪声的频率与形态。 |
| 使用提示 | 硬件平台为 N32H497ZGL7_EVB; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; 软件触发前必须使能触发,否则 DAC_SWTRGx 不产生效果。 |
核心代码解读与移植
示例配置 DAC1 产生噪声波,主循环通过软件触发让 LFSR 推进并更新输出。
数据路径: RCC_Configuration 配置 GPIO 与 DAC 时钟 → GPIO_Configuration 把 PA4 设为模拟输出 → DAC_Configuratoin 选择噪声波与软件触发 → main 主循环 DAC_SoftTrgEnable 触发转换
1. 配置系统与 DAC 时钟。 RCC_Configuration 使能 GPIO 与 DAC12 时钟,并把 DAC_CLK 分频到约 1 MHz。
void RCC_Configuration(void)
{
/* Enable GPIOA, GPIOB, GPIOC clocks */
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
/* Enable DAC1 clocks */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
/* Config DAC12 prescaler factor,DAC_CLK = 1M*/
DAC_ConfigClkPrescaler(DAC12,120);
DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
移植时保留 DAC12 时钟与分频设置即可,GPIO 时钟按实际使用的端口裁剪。
2. 配置模拟输出引脚。 GPIO_Configuration 把 PA4 配置为模拟模式作为 DAC1_OUT。
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
// DAC1_OUT
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
更换评估板时只需修改引脚号;噪声波只经 PA4 输出,不占用其他外设。
3. 配置 DAC 噪声波。 DAC_Configuratoin 选择软件触发与噪声波,关闭输出缓冲并使能触发,然后写入初始数据。
void DAC_Configuratoin(void)
{
DAC_InitType DAC_InitStructure;
DAC_StructInit(&DAC_InitStructure);
/* DAC1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_Software;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Noise;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
DAC_InitStructure.DAC_OutputBuffer = DISABLE;
DAC_InitStructure.DAC_ConnectOnChipPeripheral = DISABLE;
DAC_InitStructure.DAC_ConnectExternalPin = ENABLE;
DAC_InitStructure.DAC_TriggerEnable = ENABLE;
DAC_Init(DAC1, &DAC_InitStructure);
/* Enable DAC1 */
DAC_Enable(DAC1, ENABLE);
/* Set DAC1 DHR12R register */
DAC_SetData(DAC1,DAC_ALIGN_R_12BIT, 4094);
}
LFSR 掩码决定噪声幅度,DAC_SetData 设定 LFSR 的基准值;噪声模式下数值由硬件在每次触发时更新。
4. 主循环软件触发。 初始化完成后,while(1) 反复触发一次转换并延时 1 us。
while (1)
{
DAC_SoftTrgEnable(DAC1, ENABLE);
systick_delay_us(1);
}
触发间隔决定噪声更新速率;缩短延时可以提高噪声的等效带宽。
对应源码: src/main.c
5.6.3.3 SawtoothWaveOutput 锯齿波输出
工程目录: projects/n32h49x_EVAL/examples/DAC/SawtoothWaveOutput/
配置时钟→配置 PA4 模拟输出与 PA5 推挽输出→配置 DAC1 递增锯齿波与软件步进触发→配置 ATIM1 更新中断与 TRGO→主循环每 2 ms 推进一次锯齿波台阶
| 项目 | 源码解读 |
|---|---|
| 功能 | DAC1 输出递增锯齿波,复位值 0x100、步进值 60; ATIM1 更新中断置位 DAC_Reset_Flag,主循环连续调用 150 次 DAC_SoftTrgSawStepEnable,锯齿波从复位值逐步上升并在达到满量程后回卷。 |
| 源码组成 | src/main.c:main、RCC_Configuration、GPIO_Configuration、DAC_Configuratoin、NVIC_Configuration、TIM_Configuration;inc/main.h:包含 n32h49x_dac.h、n32h49x_tim.h、n32h49x_gpio.h、n32h49x_rcc.h、delay.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务程序(含置位 DAC_Reset_Flag 的 ATIM1_IRQHandler);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:DAC_ConfigClkPrescaler(DAC12,120)、DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M),并使能 ATIM1 总线时钟;引脚:PA4 模拟输出,PA5 推挽输出用于观察触发; DAC: DAC_WaveGeneration_SAWTOOTH_INC、DAC_Trigger_ATIM1_TRGO、DAC_Trigger2_Software、DAC_SetSawtoothResetValue(DAC1,0x100)、DAC_SetSawtoothStepValue(DAC1,60);定时器:ATIM1 周期 1500、TRGO 为更新事件并开启更新中断。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration、GPIO_Configuration、DAC_Configuratoin、NVIC_Configuration、TIM_Configuration;ATIM1_IRQHandler 在更新中断里置位 DAC_Reset_Flag;while(1) 中当标志为 1 且步进计数小于 150 时触发一次锯齿波步进并延时 2 ms,达到 150 次后清零重新开始。 |
| 主要 API | DAC_Init, DAC_SetSawtoothResetValue, DAC_SetSawtoothStepValue, DAC_Enable, DAC_SoftTrgSawStepEnable |
| 验证方法 | 下载运行后用示波器观察 PA4,可看到由 150 级台阶组成的递增锯齿波; 修改 DAC_SetSawtoothStepValue 的步长或复位值可改变波形幅度与台阶高度。 |
| 使用提示 | 硬件平台为 N32H497ZGL7_EVB; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; 锯齿波的台阶推进由软件步进触发控制,需配合 DAC_SoftTrgSawStepEnable;PA5 作为辅助输出便于用示波器同步观察。 |
核心代码解读与移植
示例配置 DAC1 输出递增锯齿波,由 ATIM1 更新事件周期置位标志,主循环按标志逐级推进锯齿波台阶。
数据路径: RCC_Configuration 配置 GPIO、ATIM1 与 DAC 时钟 → GPIO_Configuration 设置 PA4 模拟输出与 PA5 推挽输出 → DAC_Configuratoin 选择递增锯齿波与软件步进触发 → TIM_Configuration 令 ATIM1 更新事件输出 TRGO 并开中断 → main 主循环按标志调用 DAC_SoftTrgSawStepEnable 步进
1. 配置系统时钟。 RCC_Configuration 使能 GPIO、ATIM1 与 DAC12 时钟,并把 DAC_CLK 分频到约 1 MHz。
void RCC_Configuration(void)
{
/* Enable GPIOA, GPIOB, GPIOC clocks */
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_ATIM1,ENABLE);
/* Enable DAC1 DAC2 clocks */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
/* Config DAC12 prescaler factor,DAC_CLK = 1M*/
DAC_ConfigClkPrescaler(DAC12,120);
DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
移植时保留 ATIM1、DAC12 时钟与分频设置;ATIM1 是高级定时器,其总线时钟需与触发频率目标匹配。
2. 配置输出引脚。 GPIO_Configuration 把 PA4 设为模拟输出用于锯齿波,PA5 设为推挽输出用于辅助观察。
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
/* DAC1_OUT */
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_5 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
PA4 必须为模拟模式,PA5 为推挽输出;更换引脚时保持模式与用途对应。
3. 配置 DAC 锯齿波。 DAC_Configuratoin 选择 ATIM1 触发与递增锯齿波,并设置复位值与步进值。
void DAC_Configuratoin(void)
{
DAC_InitType DAC_InitStructure;
DAC_StructInit(&DAC_InitStructure);
/* DAC1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_ATIM1_TRGO;
DAC_InitStructure.DAC_Trigger2 = DAC_Trigger2_Software;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_SAWTOOTH_INC;
DAC_InitStructure.DAC_OutputBuffer = DISABLE;
DAC_InitStructure.DAC_ConnectOnChipPeripheral = DISABLE;
DAC_InitStructure.DAC_ConnectExternalPin = ENABLE;
DAC_InitStructure.DAC_TriggerEnable = ENABLE;
DAC_Init(DAC1, &DAC_InitStructure);
DAC_SetSawtoothResetValue(DAC1,0x100);
DAC_SetSawtoothStepValue(DAC1,60);
/* Enable DAC1 */
DAC_Enable(DAC1, ENABLE);
}
DAC_Trigger2 为步进触发;锯齿波从复位值开始,每次步进增加 DAC_SetSawtoothStepValue 设定的量,回卷到复位值后重新递增。
4. 配置 ATIM1 触发与中断。 TIM_Configuration 设置 ATIM1 周期并把更新事件输出为 TRGO,同时开启更新中断。
void TIM_Configuration(void)
{
/* Compute the prescaler value */
uint16_t PrescalerValue = 0;
TIM_TimeBaseInitType TIM_TimeBaseStructure;
PrescalerValue = (uint32_t)(SystemCoreClock / 5000) - 1;
/* Time base configuration */
TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.Period = 1500; //300ms Trigger DAC
TIM_TimeBaseStructure.Prescaler = PrescalerValue;
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;
TIM_TimeBaseStructure.CounterMode = TIM_CNT_MODE_UP;
TIM_InitTimeBase(ATIM1, &TIM_TimeBaseStructure);
/* Prescaler configuration */
TIM_ConfigPrescaler(ATIM1, PrescalerValue, TIM_PSC_RELOAD_MODE_IMMEDIATE);
TIM_SelectOutputTrig(ATIM1,TIM_TRGO_SRC_UPDATE);
/* ATIM1 enable update irq */
TIM_ConfigInt(ATIM1, TIM_INT_UPDATE, ENABLE);
/* ATIM1 enable counter */
TIM_Enable(ATIM1, ENABLE);
}
周期与预分频共同决定触发间隔;移植时按目标刷新周期重新计算 Period 与 Prescaler。
5. 主循环推进锯齿波台阶。 main 在检测到更新中断标志后,连续触发 150 次步进,每次延时 2 ms。
while (1)
{
if(DAC_Reset_Flag == 1)
{
if(DAC_Step_Index < DAC_Step_Num )
{
DAC_SoftTrgSawStepEnable(DAC1,ENABLE);
systick_delay_ms(2);
DAC_Step_Index++;
}
else
{
DAC_Step_Index = 0;
DAC_Reset_Flag = 0;
}
}
}
}
DAC_Step_Num 为 150,对应 150 级台阶;改变步长或台阶数会改变锯齿波的上升斜率。
对应源码: src/main.c
5.6.3.4 TwoDACsTriangleWave 双 DAC 三角波输出
工程目录: projects/n32h49x_EVAL/examples/DAC/TwoDACsTriangleWave/
配置时钟→将 PA4 与 PA5 配置为模拟输出→配置 DAC1 与 DAC2 三角波并写入双通道数据→配置 ATIM1 更新事件触发→使能 ATIM1 计数持续触发
| 项目 | 源码解读 |
|---|---|
| 功能 | DAC1、DAC2 由同一 ATIM1 更新事件同步触发输出三角波,DAC1 幅度为 2047、DAC2 幅度为 1023; PA4 与 PA5 分别输出两路三角波,初始数据通过 DAC_SetDualChData 一次写入。 |
| 源码组成 | src/main.c:main、RCC_Configuration、GPIO_Configuration、DAC_Configuratoin、ATIM1_Init;inc/main.h:包含 n32h49x_dac.h、n32h49x_tim.h、n32h49x_gpio.h、n32h49x_rcc.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务程序(仅异常处理);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:使能 ATIM1 与 DAC12 总线时钟,DAC_ConfigClkPrescaler(DAC12,120) 使 DAC_CLK 约 1 MHz,DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);引脚:PA4、PA5 均配置为模拟模式; DAC: DAC_Trigger_ATIM1_TRGO、DAC_WaveGeneration_Triangle,DAC1 幅度 DAC_TriangleAmplitude_2047、DAC2 幅度 DAC_TriangleAmplitude_1023,并用 DAC_SetDualChData(DAC12,DAC_ALIGN_R_12BIT,0x100,0x100) 写初始数据;定时器:ATIM1 周期 16、TRGO 为更新事件。 |
| 程序与数据路径 | main 依次调用 RCC_Configuration、GPIO_Configuration、DAC_Configuratoin、ATIM1_Init;DAC_Configuratoin 先配置 DAC1,再复用同一结构体修改幅度后配置 DAC2,然后写入双通道数据并分别使能两路;最后 TIM_Enable(ATIM1,ENABLE) 启动定时器,两路 DAC 在每次更新事件同步转换。 |
| 主要 API | DAC_Init, DAC_SetDualChData, DAC_Enable, DAC_ConfigClkPrescaler, DAC_SetHighFrequencyMode |
| 验证方法 | 下载运行后用示波器同时观察 PA4 与 PA5,可看到两路频率相同、幅度不同的三角波; 两路由同一触发同步,相位一致。 |
| 使用提示 | 硬件平台为 N32H497ZGL7_EVB; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; 两路共用 DAC_InitType 结构体,配置 DAC2 时只改需要不同的字段,其余沿用 DAC1 的设置。 |
核心代码解读与移植
示例用同一 ATIM1 更新事件同步触发 DAC1、DAC2,两路各自产生不同幅度的三角波。
数据路径: RCC_Configuration 配置 GPIO、ATIM1 与 DAC 时钟 → GPIO_Configuration 把 PA4 与 PA5 设为模拟输出 → DAC_Configuratoin 配置两路三角波并用 DAC_SetDualChData 写初始数据 → ATIM1_Init 令更新事件输出 TRGO → main 使能 ATIM1 持续触发
1. 配置系统时钟。 RCC_Configuration 使能 GPIO、ATIM1 与 DAC12 时钟,并把 DAC_CLK 分频到约 1 MHz。
void RCC_Configuration(void)
{
/* Enable GPIOA, GPIOB, GPIOC clocks */
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
/* Enable ATIM1 clocks */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_ATIM1, ENABLE);
/* Enable DAC1 DAC2 clocks */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
DAC_ConfigClkPrescaler(DAC12,120);
DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
}
移植时保留 ATIM1 与 DAC12 时钟;DAC_CLK 分频影响转换刷新率与缓冲建立时间。
2. 配置输出引脚。 GPIO_Configuration 把 PA4、PA5 都配置为模拟模式,分别对应 DAC1_OUT 与 DAC2_OUT。
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
// DAC1_OUT DAC2_OUT
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
两路输出引脚可一次配置;更换引脚时保持模拟模式与 DAC 通道的对应关系。
3. 配置两路 DAC。 DAC_Configuratoin 先配置 DAC1 的三角波幅度,再改幅度配置 DAC2,然后用 DAC_SetDualChData 写双通道数据并分别使能。
void DAC_Configuratoin(void)
{
DAC_InitType DAC_InitStructure;
DAC_StructInit(&DAC_InitStructure);
/* DAC1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_ATIM1_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle;
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_2047;
DAC_InitStructure.DAC_OutputBuffer = DISABLE;
DAC_InitStructure.DAC_ConnectOnChipPeripheral = DISABLE;
DAC_InitStructure.DAC_ConnectExternalPin = ENABLE;
DAC_InitStructure.DAC_TriggerEnable = ENABLE;
DAC_Init(DAC1, &DAC_InitStructure);
/* DAC2 Configuration */
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_1023;
DAC_Init(DAC2, &DAC_InitStructure);
/* Set DAC1 DAC2 DHR12R register */
DAC_SetDualChData(DAC12,DAC_ALIGN_R_12BIT, 0x100, 0x100);
/* Enable DAC1 */
DAC_Enable(DAC1, ENABLE);
/* Enable DAC2 */
DAC_Enable(DAC2, ENABLE);
}
两个 DAC 共用触发源与波形设置,仅三角波幅度不同;DAC_SetDualChData(DAC12,...) 一次写入两路的初始数据。
4. 配置 ATIM1 触发。 ATIM1_Init 设置 ATIM1 周期并把更新事件输出为 TRGO。
void ATIM1_Init(void)
{
TIM_TimeBaseInitType TIM_TimeBaseStructure;
uint16_t PrescalerValue ;
PrescalerValue = (uint32_t)(SystemCoreClock / 16000000) - 1;
/* ATIM1 Configuration */
TIM_InitTimBaseStruct(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.Period = 16-1;
TIM_TimeBaseStructure.Prescaler = PrescalerValue;
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;
TIM_TimeBaseStructure.CounterMode = TIM_CNT_MODE_UP;
TIM_InitTimeBase(ATIM1, &TIM_TimeBaseStructure);
/* ATIM1 TRGO selection */
TIM_SelectOutputTrig(ATIM1, TIM_TRGO_SRC_UPDATE);
}
ATIM1 的触发频率决定三角波的台阶速率;移植时按目标波形频率重新计算周期。
5. 启动触发。 main 在初始化完成后使能 ATIM1 计数,两路 DAC 在每次更新事件同步转换。
/* ATIM1 enable counter */
TIM_Enable(ATIM1, ENABLE);
只要 ATIM1 持续计数,两路三角波就会自动刷新,无需主循环干预。
对应源码: src/main.c
5.6.3.5 UserBufferCalibration 缓冲器偏移校准
工程目录: projects/n32h49x_EVAL/examples/DAC/UserBufferCalibration/
配置时钟与 PA4 模拟输出→初始化串口日志→使能 DAC1 校准并启动→逐一写修调值直到校准完成→打印修调值或失败信息
| 项目 | 源码解读 |
|---|---|
| 功能 | 对 DAC1 的缓冲器做偏移校准:先使能校准与 DAC1,再循环写入候选修调值并检查 DAC_FLAG_CALCOMPLETE;校准成功后把修调值通过串口打印,失败则提示修调无效。 |
| 源码组成 | src/main.c:main、RCC_Configuration、GPIO_Configuration、Start_UserTrimming;inc/main.h:包含 n32h49x_dac.h、n32h49x_gpio.h、n32h49x_rcc.h、delay.h、log.h;src/n32h49x_it.c、inc/n32h49x_it.h:中断服务程序(仅异常处理);readme.txt:功能、环境与使用说明;MDK-ARM/、EWARM/:Keil 与 IAR 工程。 |
| 关键配置 | 时钟:DAC_ConfigClkPrescaler(DAC12,120) 使 DAC_CLK 约 1 MHz,DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);引脚:PA4 模拟模式作为 DAC1_OUT; DAC:软件触发、 DAC_WaveGeneration_None、DAC_OutputBuffer=ENABLE(校准要求缓冲器使能)、DAC_CaliEnable(DAC1,ENABLE);校准:循环 32 次 DAC_SetUserTrimming(DAC1,index),每次延时 100 us 并检查 DAC_FLAG_CALCOMPLETE。 |
| 程序与数据路径 | main 调用 RCC_Configuration、log_init、GPIO_Configuration,然后调用 Start_UserTrimming(&Trim_Value);Start_UserTrimming 内部配置并使能 DAC1、开启校准,随后在循环里逐个尝试修调值;一旦 DAC_GetFlagSts(DAC1,DAC_FLAG_CALCOMPLETE) 置位就返回 SUCCESS 并回写修调值,否则循环结束后返回 ERROR。 |
| 主要 API | DAC_StructInit, DAC_Init, DAC_CaliEnable, DAC_Enable, DAC_SetUserTrimming, DAC_GetFlagSts |
| 验证方法 | 下载运行后通过串口日志查看结果:成功时打印修调值,失败时打印修调无效信息,可据此判断校准是否完成。 |
| 使用提示 | 硬件平台为 N32H497ZGL7_EVB; 开发环境为 KEIL MDK-ARM 5.34 或 IAR EWARM 8.50.1; 校准必须在输出缓冲器使能的条件下进行; 实测得到的修调值可在正式应用启动时用 DAC_SetUserTrimming 写入。 |
核心代码解读与移植
示例对 DAC1 的缓冲器做一次偏移校准,并返回可用的用户修调值。
数据路径: RCC_Configuration 配置 GPIO 与 DAC 时钟 → GPIO_Configuration 把 PA4 设为模拟输出 → Start_UserTrimming 使能缓冲器与校准并循环尝试修调值 → main 打印校准结果
1. 配置系统时钟。 RCC_Configuration 使能 GPIO 与 DAC12 时钟,并把 DAC_CLK 分频到约 1 MHz。
void RCC_Configuration(void)
{
/* Enable GPIOA, GPIOB, GPIOC clocks */
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA | RCC_AHB_PERIPHEN_GPIOB | RCC_AHB_PERIPHEN_GPIOC, ENABLE);
/* Enable DAC1 DAC2 clocks */
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPHEN_DAC12 ,ENABLE);
/* Config DAC12 prescaler factor,DAC_CLK = 1M*/
DAC_ConfigClkPrescaler(DAC12,120);
DAC_SetHighFrequencyMode(DAC12,DAC_HIGH_FREQ_MODE_BELOW_160M);
}
校准只用到 DAC12 与 GPIO 时钟,移植时可裁剪未使用的端口时钟。
2. 配置模拟输出引脚。 GPIO_Configuration 把 PA4 配置为模拟模式作为 DAC1_OUT。
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
// DAC1_OUT
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
校准过程不产生外部输出,PA4 的模拟配置只是保持与其他示例一致。
3. 配置 DAC 并启动校准。 Start_UserTrimming 使能输出缓冲、开启校准与 DAC1,然后逐个尝试修调值直到校准完成。
ErrorStatus Start_UserTrimming(uint8_t *NewTrimValue)
{
uint8_t index =0;
DAC_InitType DAC_InitStructure;
DAC_StructInit(&DAC_InitStructure);
/* DAC1 Configuration */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_Software;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = ENABLE;
DAC_InitStructure.DAC_ConnectOnChipPeripheral = DISABLE;
DAC_InitStructure.DAC_ConnectExternalPin = ENABLE;
DAC_InitStructure.DAC_TriggerEnable = ENABLE;
DAC_Init(DAC1, &DAC_InitStructure);
/* Enable DAC1 Calibration */
DAC_CaliEnable(DAC1,ENABLE) ;
/* Enable DAC1 */
DAC_Enable(DAC1, ENABLE);
for(index = 0;index<32;index++)
{
DAC_SetUserTrimming(DAC1,index) ;
systick_delay_us(100);
if(DAC_GetFlagSts(DAC1,DAC_FLAG_CALCOMPLETE) != RESET)
{
*NewTrimValue = index;
return SUCCESS;
}
}
return ERROR;
}
校准要求输出缓冲使能;DAC_SetUserTrimming 写入候选值后需等待约 100 us 再查 CALCOMPLETE,命中即返回对应修调值。
4. 打印校准结果。 main 调用 Start_UserTrimming 后按返回值通过串口打印成功或失败信息。
/*Start User Trimming ------------------------------------------------------*/
status = Start_UserTrimming(&Trim_Value);
if(status == SUCCESS)
{
log_info("User trimming passed, the triming value = 0x%x\r\n",Trim_Value);
}
else
{
log_info("User trimming failed,the triming invalid\r\n");
}
量产时可把得到的修调值固化到应用里,开机后用 DAC_SetUserTrimming 直接写入,省去每次上电的校准循环。
对应源码: src/main.c
5.6.4 注意与排障
| 场景 | 检查与建议 | 来源 |
|---|---|---|
| 触发源选择 | DAC 使能状态下禁止修改 Tx(y)SEL[4:0];需要切换触发源时应先关闭对应 DAC,改好后再重新使能。 |
用户手册 |
| 高频接口模式 | 总线时钟高于 80 MHz 时必须配置 DACxy_HFSEL[1:0],否则接口时序不满足要求。 |
用户手册 |
| 同时内外输出 | 同时使能内部输出(INOUTxEN)与外部引脚输出(EXOUTxEN)时,必须同时使能输出缓冲器(Bx(y)EN = 1)。 |
用户手册 |
| 使能等待 | 使能 DAC 后需等待唤醒时间 tWAKEUP 再使用输出,否则转换结果不稳定。 | 用户手册 |
| DMA 下溢 | DMA 下溢错误标志 DMAUDR 通过写 1 清除。 |
用户手册 |
| 缓冲器校准 | 校准前先置 CALxEN 并保持缓冲器使能(BxEN = 1),等待约 100 us 后检查 CALFLAGx;校准得到的修调码通过 OTRIMx[4:0] 写入。 |
用户手册 |
| 输出与参考电压 | DAC 输出电压为 VREF+ 乘以 DATO/4095,参考电压来自 VREF+ 引脚或内置 VREFBUF;满量程精度直接取决于该参考电压。 |
用户手册 |