• HC32_HC32F072FAUA_DAC的使用


    1 首先你得有一个工程

    参考前面介绍的:

    HC32_HC32F072FAUA_从零开始搭建空工程模板_江湖上都叫我秋博的博客-CSDN博客

    HC32_keil工程的复制_重命名_以及函数、变量定义的正常跳转问题_江湖上都叫我秋博的博客-CSDN博客

    复制一个新工程,重命名为DAC, 开启美妙的DAC通信之旅

    2 原理图

    PA04 是DAC输出端口

    3 看参考样例的核心代码

    官网提供的样例中,有两个关于DAC的代码,一个是正弦波,一个是三角波。都测试过,能够正常运行。

     

     而我们需要实现,我想要它输出多少V它就输出多是V的效果。

    路径:官网提供的驱动库及样例的压缩包解压后

    xxx\hc32f072_ddl_Rev1.1.1\example\dac\sv_dac_dma\MDK\sv_dac_dma.uvprojx

    这个代码是正弦波的

    1. #include "sysctrl.h"
    2. #include "dac.h"
    3. #include "flash.h"
    4. #include "gpio.h"
    5. #include "math.h"
    6. #include "dmac.h"
    7. uint16_t SendBuf[128];
    8. #define PI 3.14159265358979 //圆周率
    9. static void App_SysClkInit(void); ///< 系统时钟初始化
    10. static void App_GpioInit(void); ///< GPIO初始化
    11. static void App_DACInit(void); ///< DAC初始化
    12. static void App_DMAInit(void); ///< DMA初始化
    13. int32_t main(void)
    14. {
    15. App_SysClkInit(); ///< 系统时钟初始化
    16. App_GpioInit(); ///< GPIO初始化
    17. App_DACInit(); ///< DAC初始化
    18. App_DMAInit(); ///< DMA初始化
    19. while(1)
    20. {
    21. // SendBuf[0]=1024;
    22. Dac0_SoftwareTriggerCmd(); ///< 软件触发
    23. delay10us(12);
    24. }
    25. }
    26. static void App_SysClkInit(void)
    27. {
    28. stc_sysctrl_clk_cfg_t stcCfg;
    29. stc_sysctrl_pll_cfg_t stcPLLCfg;
    30. Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE); ///< 使能FLASH模块的外设时钟
    31. Flash_WaitCycle(FlashWaitCycle1);
    32. Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); ///< PLL使用RCH作为时钟源,因此需要先设置RCH
    33. stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; ///< RCH 4MHz
    34. stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; ///< PLL 输出48MHz
    35. stcPLLCfg.enPllClkSrc = SysctrlPllRch; ///< 输入时钟源选择RCH
    36. stcPLLCfg.enPllMul = SysctrlPllMul12; ///< 4MHz x 12 = 48MHz
    37. Sysctrl_SetPLLFreq(&stcPLLCfg);
    38. ///< 选择PLL作为HCLK时钟源;
    39. stcCfg.enClkSrc = SysctrlClkPLL;
    40. ///< HCLK SYSCLK/2
    41. stcCfg.enHClkDiv = SysctrlHclkDiv1;
    42. ///< PCLK 为HCLK/8
    43. stcCfg.enPClkDiv = SysctrlPclkDiv1;
    44. ///< 系统时钟初始化
    45. Sysctrl_ClkInit(&stcCfg);
    46. }
    47. static void App_GpioInit(void)
    48. {
    49. ///< 开启GPIO外设时钟
    50. Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 使能GPIO模块的外设时钟
    51. Gpio_SetAnalogMode(GpioPortA, GpioPin4); //PA04作为DAC的模拟输出
    52. }
    53. static void _BufProduce(uint16_t* buf)
    54. {
    55. uint8_t tmp;
    56. double tmp1;
    57. tmp1=PI/64;
    58. for(tmp=0; tmp<128; tmp++)
    59. {
    60. buf[tmp] =(uint16_t)(((sin(tmp1*tmp))*2047)+2048);
    61. // buf[tmp] = 4095;
    62. }
    63. }
    64. static void App_DACInit(void)
    65. {
    66. stc_dac_cfg_t dac_initstruct;
    67. Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE); ///< 使能DAC模块的时钟
    68. dac_initstruct.boff_t = DacBoffDisable;
    69. dac_initstruct.ten_t = DacTenEnable;
    70. dac_initstruct.sref_t = DacVoltageAvcc;
    71. dac_initstruct.mamp_t = DacMenp4095;
    72. dac_initstruct.tsel_t = DacSwTriger; ///< 软件触发方式
    73. dac_initstruct.align = DacRightAlign; ///< 右对齐
    74. Dac0_Init(&dac_initstruct);
    75. Dac0_Cmd(TRUE);
    76. Dac0_DmaCmd(TRUE); ///< DAC通道DMA使能
    77. _BufProduce(SendBuf); ///< 产生正弦波的采样点
    78. }
    79. static void App_DMAInit(void)
    80. {
    81. stc_dma_cfg_t DmaInitStruct;
    82. Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE); ///< 使能DMA模块的外设时钟
    83. DmaInitStruct.enMode = DmaMskBlock; ///< 选择块传输
    84. DmaInitStruct.u16BlockSize = 1; ///< 块传输个数
    85. DmaInitStruct.u16TransferCnt = 128; ///< 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
    86. DmaInitStruct.enTransferWidth = DmaMsk16Bit; ///< 传输数据的宽度,此处选择字(16Bit)宽度
    87. DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc; ///< 源地址自增
    88. DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix; ///< 目的地址自增
    89. DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; ///< 禁止重新加载传输目的地址
    90. DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; ///< 使能重新加载传输源地址
    91. DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; ///< 使能重新加载BC/TC值
    92. DmaInitStruct.u32SrcAddress = (uint32_t)SendBuf; ///< 源地址
    93. DmaInitStruct.u32DstAddress = 0x40002508; ///< 目标地址:DAC_DHR12R0
    94. DmaInitStruct.enRequestNum = DmaDAC0Trig; ///< 设置DAC0触发
    95. DmaInitStruct.enTransferMode = DmaMskContinuousTransfer; ///< 连续传输
    96. DmaInitStruct.enPriority = DmaMskPriorityFix; ///< 各通道固定优先级,CH0优先级 > CH1优先级
    97. Dma_InitChannel(DmaCh0,&DmaInitStruct); ///< 初始化dma通道0
    98. Dma_Enable(); ///< 使能DMA
    99. Dma_EnableChannel(DmaCh0); ///< 使能DMA通道0
    100. Dma_ClrStat(DmaCh0); ///< 清零:STAT[2:0]
    101. }

    4 我们自己的代码

    我们将样例代码稍加修改,移植到我们的框架当中。

    本代码同时拥有 LED闪烁 UART通信以及DAC指定输出的功能。

    main.c

    注意:系统时钟初始化代码,它需要放在串口初始化之前,否则串口通信会出问题。

    1. #include "ddl.h"
    2. #include "uart.h"
    3. #include "gpio.h"
    4. #include "dac.h"
    5. #include "user_gpio.h"
    6. #include "user_uart.h"
    7. #include "user_dac.h"
    8. int32_t main(void)
    9. {
    10. // sys_clk_init(); // 系统的时钟初始化 应该放在串口初始化之前 否则系统会出问题
    11. user_led_init();
    12. user_uart_init();
    13. user_dac_init();
    14. while(1)
    15. {
    16. if(fpgaRxFlag == 1){ // 当我收到fpga发来的固定长度为8的8个字节以后,我把它发过来的数据,给它回传回去
    17. send_data_to_fpga(fpgaRx, 8);
    18. fpgaRxFlag = 0;
    19. }
    20. if(pcRxFlag ==1 ){
    21. send_data_to_pc(pcRx, 8);
    22. pcRxFlag = 0;
    23. }
    24. DAC_OUT = 4095; // 0~4095表示0~3.3V
    25. Dac0_SoftwareTriggerCmd(); // 触发DAC转换
    26. Gpio_SetIO(LED1_PORT, LED1_PIN);
    27. Gpio_SetIO(LED2_PORT, LED2_PIN);
    28. delay1ms(500); // while 里面必须有个延迟,不然while(1)把cpu占用了,进不了中断。
    29. Gpio_ClrIO(LED1_PORT, LED1_PIN);
    30. Gpio_ClrIO(LED2_PORT, LED2_PIN);
    31. delay1ms(500);
    32. }
    33. }

    user_dac.c 我们专门添加一个文件,来写我们自己对dac的配置,以便于后续其他功能的添加

    1. #include "user_dac.h"
    2. #include "sysctrl.h"
    3. #include "dac.h"
    4. #include "flash.h"
    5. #include "gpio.h"
    6. #include "math.h"
    7. #include "dmac.h"
    8. uint16_t DAC_OUT = 0;
    9. void sys_clk_init(void)
    10. {
    11. stc_sysctrl_clk_cfg_t stcCfg;
    12. stc_sysctrl_pll_cfg_t stcPLLCfg;
    13. Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE); // 使能FLASH模块的外设时钟
    14. Flash_WaitCycle(FlashWaitCycle1);
    15. Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); // PLL使用RCH作为时钟源,因此需要先设置RCH
    16. stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; // RCH 4MHz
    17. stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; // PLL 输出48MHz
    18. stcPLLCfg.enPllClkSrc = SysctrlPllRch; // 输入时钟源选择RCH
    19. stcPLLCfg.enPllMul = SysctrlPllMul12; // 4MHz x 12 = 48MHz
    20. Sysctrl_SetPLLFreq(&stcPLLCfg);
    21. // 选择PLL作为HCLK时钟源;
    22. stcCfg.enClkSrc = SysctrlClkPLL;
    23. // HCLK SYSCLK/2
    24. stcCfg.enHClkDiv = SysctrlHclkDiv1;
    25. // PCLK 为HCLK/8
    26. stcCfg.enPClkDiv = SysctrlPclkDiv1;
    27. // 系统时钟初始化
    28. Sysctrl_ClkInit(&stcCfg);
    29. }
    30. void dac_gpio_config(void)
    31. {
    32. Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 使能GPIO模块的外设时钟
    33. Gpio_SetAnalogMode(GpioPortA, GpioPin4); // PA04作为DAC的模拟输出
    34. }
    35. void dac_config(void)
    36. {
    37. stc_dac_cfg_t dac_initstruct;
    38. Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE); // 使能DAC模块的时钟
    39. dac_initstruct.boff_t = DacBoffDisable;
    40. dac_initstruct.ten_t = DacTenEnable;
    41. dac_initstruct.sref_t = DacVoltageAvcc;
    42. dac_initstruct.mamp_t = DacMenp4095;
    43. dac_initstruct.tsel_t = DacSwTriger; // 软件触发方式
    44. dac_initstruct.align = DacRightAlign; // 右对齐
    45. Dac0_Init(&dac_initstruct);
    46. Dac0_Cmd(TRUE);
    47. Dac0_DmaCmd(TRUE); // DAC通道DMA使能
    48. }
    49. void dac_dma_config(void)
    50. {
    51. stc_dma_cfg_t DmaInitStruct;
    52. Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE); // 使能DMA模块的外设时钟
    53. DmaInitStruct.enMode = DmaMskBlock; // 选择块传输
    54. DmaInitStruct.u16BlockSize = 1; // 块传输个数
    55. DmaInitStruct.u16TransferCnt = 1; // 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
    56. DmaInitStruct.enTransferWidth = DmaMsk16Bit; // 传输数据的宽度,此处选择字(16Bit)宽度
    57. DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc; // 源地址自增
    58. DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix; // 目的地址自增
    59. DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; // 禁止重新加载传输目的地址
    60. DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; // 使能重新加载传输源地址
    61. DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; // 使能重新加载BC/TC值
    62. DmaInitStruct.u32SrcAddress = (uint32_t)&DAC_OUT; // 源地址
    63. DmaInitStruct.u32DstAddress = 0x40002508; // 目标地址:DAC_DHR12R0
    64. DmaInitStruct.enRequestNum = DmaDAC0Trig; // 设置DAC0触发
    65. DmaInitStruct.enTransferMode = DmaMskOneTransfer; // 连续传输
    66. DmaInitStruct.enPriority = DmaMskPriorityFix; // 各通道固定优先级,CH0优先级 > CH1优先级
    67. Dma_InitChannel(DmaCh0,&DmaInitStruct); // 初始化dma通道0
    68. Dma_Enable(); // 使能DMA
    69. Dma_EnableChannel(DmaCh0); // 使能DMA通道0
    70. Dma_ClrStat(DmaCh0); // 清零:STAT[2:0]
    71. }
    72. void user_dac_init(void){
    73. // sys_clk_init();
    74. dac_gpio_config();
    75. dac_config();
    76. dac_dma_config();
    77. }

    user_dac.h

    1. #ifndef _USER_DAC_H_
    2. #define _USER_DAC_H_
    3. #include "ddl.h"
    4. extern uint16_t DAC_OUT;
    5. void sys_clk_init(void);
    6. void dac_gpio_config(void);
    7. void dac_config(void);
    8. void dac_dma_config(void);
    9. void user_dac_init(void);
    10. #endif

    我们的实验结果如下:

    当DAC_OUT = 4095时

    当DAC_OUT = 2048时

    4095应该对应3.3V,2048应该对应1.65V,实验值与理论值基本吻合。🙂

    感谢您的阅读,欢迎留言讨论、收藏、点赞。

  • 相关阅读:
    企业为什么要选择通配符SSL证书使用?
    LVGL 之 windows 上 lvgl 模拟器基于 Visual Studio 搭建方法的简单整理
    Java面试记录
    点云从入门到精通技术详解100篇-基于尺度统一的三维激光点云与高清影像配准
    【Go语言如何用 interface 实现多态】
    基于quartz的定时任务动态启停实现分析(人人平台为例)
    Spring注解驱动之了解Servlet3.0
    【图解HTTP】返回结果的HTTP状态码
    如何解决WIN11系统在安装HyperV虚拟机,网络桥接后网络上传慢的问题
    GitHub-使用 Git工具 创建密钥id_rsa.pub
  • 原文地址:https://blog.csdn.net/heqiunong/article/details/125989068