• 【嵌入式】HC32F07X DAC模拟输出 + DMA传输


    目录

    一 背景说明

    二 原理分析

    三 模拟电压输出


    一 背景说明

            使用小华(华大)的MCU HC32F07X实现两个通道的 0-5V 电压模拟输出。

    二 原理分析

    【1】DAC原理说明

            所谓DAC,就是Digital-Analog-Converter,数字模拟转换器。在模拟电路中,电流电压变化是连续的,而数字电路处理的数据都是离散的数据,输出高电平或者低电平,比如5V单片机,引脚输出的电压要么5V要么0V。DAC做的就是输出一个“任意“的电压,当然这个”任意“是有限制的。

    【2】HC32F07X的DAC外设

            HC32F07X 集成了两个 DAC 转换器,各具有一个输出通道: DAC0_OUT 和 DAC1_OUT。

    DAC 主要特性如下:
    ■ 一个数据保持寄存器
    ■ 12 位模式下数据采用左对齐或右对齐
    ■ 同步更新功能
    ■ 生成噪声波
    ■ 生成三角波
    ■ 双 DAC 通道,支持单独或同时转换
    ■ DMA 功能(包括下溢检测)
    ■ 通过外部触发信号进行转换
    ■ 4 种参考源: AVCC 电压、 ExRef 引脚、内置 1.5v 参考电压、内置 2.5v 参考电压;

            DAC框图如下:

            更多详细的内容可以参考HC32F07X芯片的DATASHEET。

    三 模拟电压输出

            选用引脚 PA04(DAC0)、PA05(DAC1)进行两路电压模拟输出,参考电压为AVCC(5V),并使用DMA传输数据

    【1】系统时钟初始化

    1. static void App_SysClkInit(void)
    2. {
    3. stc_sysctrl_clk_cfg_t stcCfg;
    4. stc_sysctrl_pll_cfg_t stcPLLCfg;
    5. Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE); ///< 使能FLASH模块的外设时钟
    6. Flash_WaitCycle(FlashWaitCycle1);
    7. Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); ///< PLL使用RCH作为时钟源,因此需要先设置RCH
    8. stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; ///< RCH 4MHz
    9. stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; ///< PLL 输出48MHz
    10. stcPLLCfg.enPllClkSrc = SysctrlPllRch; ///< 输入时钟源选择RCH
    11. stcPLLCfg.enPllMul = SysctrlPllMul12; ///< 4MHz x 12 = 48MHz
    12. Sysctrl_SetPLLFreq(&stcPLLCfg);
    13. ///< 选择PLL作为HCLK时钟源;
    14. stcCfg.enClkSrc = SysctrlClkPLL;
    15. ///< HCLK SYSCLK/2
    16. stcCfg.enHClkDiv = SysctrlHclkDiv1;
    17. ///< PCLK 为HCLK/8
    18. stcCfg.enPClkDiv = SysctrlPclkDiv1;
    19. ///< 系统时钟初始化
    20. Sysctrl_ClkInit(&stcCfg);
    21. }

    【2】DAC初始化GPIO

    1. //模拟量输出引脚定义
    2. #define OUT_DAC0_PORT (GpioPortA)
    3. #define OUT_DAC0_PIN (GpioPin4)
    4. #define OUT_DAC1_PORT (GpioPortA)
    5. #define OUT_DAC1_PIN (GpioPin5)
    6. /**************************************************************************
    7. * 函数名称: DAC_Init
    8. * 功能描述: DAC初始化GPIO
    9. **************************************************************************/
    10. void DAC_Init(void)
    11. {
    12. Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); //使能GPIO模块的外设时钟
    13. Gpio_SetAnalogMode(OUT_DAC0_PORT, OUT_DAC0_PIN); //PA04作为DAC0的模拟输出
    14. Gpio_SetAnalogMode(OUT_DAC1_PORT, OUT_DAC1_PIN); //PA05作为DAC1的模拟输出
    15. }

    【3】DAC初始化配置

    1. /**************************************************************************
    2. * 函数名称: DAC_Cfg
    3. * 功能描述: DAC初始化配置
    4. **************************************************************************/
    5. void DAC_Cfg(void)
    6. {
    7. stc_dac_cfg_t dac_initstruct;
    8. Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE); ///< 使能DAC模块的时钟
    9. dac_initstruct.boff_t = DacBoffDisable; //禁止缓冲器
    10. dac_initstruct.ten_t = DacTenEnable; //使能通道触发
    11. dac_initstruct.sref_t = DacVoltageAvcc; //参考电压选择AVCC电压
    12. dac_initstruct.mamp_t = DacMenp4095; //振幅选择
    13. dac_initstruct.tsel_t = DacSwTriger; //软件触发方式
    14. dac_initstruct.align = DacRightAlign; //右对齐
    15. Dac0_Init(&dac_initstruct); //DAC0初始化
    16. Dac1_Init(&dac_initstruct); //DAC1初始化
    17. Dac0_Cmd(TRUE);
    18. Dac0_DmaCmd(TRUE);
    19. Dac1_Cmd(TRUE);
    20. Dac1_DmaCmd(TRUE);
    21. }

    【4】DAC直接存储器存取配置

    1. uint16_t out_buff[2];
    2. /**************************************************************************
    3. * 函数名称: DAC_DmaCfg
    4. * 功能描述: DAC直接存储器存取配置
    5. * 其他说明: 两个DAC需用两个DMA通道
    6. **************************************************************************/
    7. void DAC_DmaCfg(void)
    8. {
    9. stc_dma_cfg_t DmaInitStruct;
    10. Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE); ///< 使能DMA模块的外设时钟
    11. DmaInitStruct.enMode = DmaMskBlock; ///< 选择块传输
    12. DmaInitStruct.u16BlockSize = 1; ///< 块传输个数
    13. DmaInitStruct.u16TransferCnt = 1; ///< 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
    14. DmaInitStruct.enTransferWidth = DmaMsk16Bit; ///< 传输数据的宽度,此处选择字(16Bit)宽度
    15. DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc; ///< 源地址自增
    16. DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix; ///< 目的地址自增
    17. DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; ///< 禁止重新加载传输目的地址
    18. DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; ///< 使能重新加载传输源地址
    19. DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; ///< 使能重新加载BC/TC值
    20. DmaInitStruct.u32SrcAddress = (uint32_t)&out_buff[0]; ///< 源地址
    21. DmaInitStruct.u32DstAddress = 0x40002508; ///< 目标地址: DAC_DHR12R0
    22. DmaInitStruct.enRequestNum = DmaDAC0Trig; ///< 设置DAC0触发
    23. DmaInitStruct.enTransferMode = DmaMskOneTransfer; ///< 传输一次
    24. DmaInitStruct.enPriority = DmaMskPriorityFix; ///< 各通道固定优先级,CH0优先级 > CH1优先级
    25. Dma_InitChannel(DmaCh0,&DmaInitStruct); ///< 初始化dma通道0
    26. DmaInitStruct.u32SrcAddress = (uint32_t)&out_buff[1]; ///< 源地址
    27. DmaInitStruct.u32DstAddress = 0x40002514; ///< 目标地址: DAC_DHR12R1
    28. DmaInitStruct.enRequestNum = DmaDAC1Trig; ///< 设置DAC1触发
    29. Dma_InitChannel(DmaCh1,&DmaInitStruct); ///< 初始化dma通道1
    30. Dma_Enable(); ///< 使能DMA
    31. Dma_EnableChannel(DmaCh0); ///< 使能DMA通道0
    32. Dma_ClrStat(DmaCh0); ///< 清零:STAT[2:0]
    33. Dma_EnableChannel(DmaCh1); ///< 使能DMA通道1
    34. Dma_ClrStat(DmaCh1); ///< 清零:STAT[2:0]
    35. }

    【5】DAC通道0/1触发接口

    1. /**************************************************************************
    2. * 函数名称: DAC0_Trig/DAC1_Trig
    3. * 功能描述: DAC通道0/1触发
    4. **************************************************************************/
    5. void DAC0_Trig(uint16_t p_out)
    6. {
    7. out_buff[0] = p_out;
    8. Dac0_SoftwareTriggerCmd();
    9. }
    10. void DAC1_Trig(uint16_t p_out)
    11. {
    12. out_buff[1] = p_out;
    13. Dac1_SoftwareTriggerCmd();
    14. }

    【6】主函数调用

    1. int32_t main(void)
    2. {
    3. //系统时钟
    4. App_SysClkInit();
    5. //输出模块
    6. DAC_Init();
    7. DAC_Cfg();
    8. DAC_DmaCfg();
    9. while(1)
    10. {
    11. //输出
    12. DAC0_Trig(4095);
    13. DAC1_Trig(2048);
    14. delay1ms(10);
    15. }
    16. }

    【6】实测结果

            示波器测量PA04(DAC0)、PA05(DAC1)的输出电压如下,根据参考电压5V计算得到DAC0 输出应该为 5V * 4095 / 4095 = 5V;DAC1 输出应该为 5V * 2048 / 4095 = 2.5V。实测符合预期:

  • 相关阅读:
    python从入门到毕业,我用了两个月,你呢?
    【计算机网络微课堂】5.9 TCP报文段的首部格式
    基于springboot供应链管理系统毕业设计源码121518
    经典双指针算法试题(一)
    物联网通信技术课程作业资料(TPUNB技术)
    矩阵消元-MIT
    李彦宏回顾大模型重构百度这一年
    BI报表与数据开发
    transformer不同的包加载模型的结构不一样
    缓存学习总结3(服务器内存缓存)推荐使用
  • 原文地址:https://blog.csdn.net/sinat_33408502/article/details/134072180