参考前面介绍的:
HC32_HC32F072FAUA_从零开始搭建空工程模板_江湖上都叫我秋博的博客-CSDN博客
HC32_keil工程的复制_重命名_以及函数、变量定义的正常跳转问题_江湖上都叫我秋博的博客-CSDN博客
复制一个新工程,重命名为DAC, 开启美妙的DAC通信之旅

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


而我们需要实现,我想要它输出多少V它就输出多是V的效果。
路径:官网提供的驱动库及样例的压缩包解压后
xxx\hc32f072_ddl_Rev1.1.1\example\dac\sv_dac_dma\MDK\sv_dac_dma.uvprojx
这个代码是正弦波的
- #include "sysctrl.h"
- #include "dac.h"
- #include "flash.h"
- #include "gpio.h"
- #include "math.h"
- #include "dmac.h"
-
- uint16_t SendBuf[128];
-
- #define PI 3.14159265358979 //圆周率
-
- static void App_SysClkInit(void); ///< 系统时钟初始化
- static void App_GpioInit(void); ///< GPIO初始化
- static void App_DACInit(void); ///< DAC初始化
- static void App_DMAInit(void); ///< DMA初始化
-
- int32_t main(void)
- {
- App_SysClkInit(); ///< 系统时钟初始化
- App_GpioInit(); ///< GPIO初始化
- App_DACInit(); ///< DAC初始化
- App_DMAInit(); ///< DMA初始化
-
- while(1)
- {
- // SendBuf[0]=1024;
- Dac0_SoftwareTriggerCmd(); ///< 软件触发
- delay10us(12);
- }
- }
-
- static void App_SysClkInit(void)
- {
- stc_sysctrl_clk_cfg_t stcCfg;
- stc_sysctrl_pll_cfg_t stcPLLCfg;
-
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE); ///< 使能FLASH模块的外设时钟
- Flash_WaitCycle(FlashWaitCycle1);
- Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); ///< PLL使用RCH作为时钟源,因此需要先设置RCH
-
- stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; ///< RCH 4MHz
- stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; ///< PLL 输出48MHz
- stcPLLCfg.enPllClkSrc = SysctrlPllRch; ///< 输入时钟源选择RCH
- stcPLLCfg.enPllMul = SysctrlPllMul12; ///< 4MHz x 12 = 48MHz
- Sysctrl_SetPLLFreq(&stcPLLCfg);
-
- ///< 选择PLL作为HCLK时钟源;
- stcCfg.enClkSrc = SysctrlClkPLL;
- ///< HCLK SYSCLK/2
- stcCfg.enHClkDiv = SysctrlHclkDiv1;
- ///< PCLK 为HCLK/8
- stcCfg.enPClkDiv = SysctrlPclkDiv1;
- ///< 系统时钟初始化
- Sysctrl_ClkInit(&stcCfg);
- }
-
- static void App_GpioInit(void)
- {
- ///< 开启GPIO外设时钟
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 使能GPIO模块的外设时钟
-
- Gpio_SetAnalogMode(GpioPortA, GpioPin4); //PA04作为DAC的模拟输出
- }
-
- static void _BufProduce(uint16_t* buf)
- {
- uint8_t tmp;
- double tmp1;
- tmp1=PI/64;
- for(tmp=0; tmp<128; tmp++)
- {
- buf[tmp] =(uint16_t)(((sin(tmp1*tmp))*2047)+2048);
- // buf[tmp] = 4095;
- }
- }
-
- static void App_DACInit(void)
- {
- stc_dac_cfg_t dac_initstruct;
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE); ///< 使能DAC模块的时钟
-
- dac_initstruct.boff_t = DacBoffDisable;
- dac_initstruct.ten_t = DacTenEnable;
- dac_initstruct.sref_t = DacVoltageAvcc;
- dac_initstruct.mamp_t = DacMenp4095;
- dac_initstruct.tsel_t = DacSwTriger; ///< 软件触发方式
- dac_initstruct.align = DacRightAlign; ///< 右对齐
- Dac0_Init(&dac_initstruct);
- Dac0_Cmd(TRUE);
- Dac0_DmaCmd(TRUE); ///< DAC通道DMA使能
-
- _BufProduce(SendBuf); ///< 产生正弦波的采样点
-
- }
-
- static void App_DMAInit(void)
- {
- stc_dma_cfg_t DmaInitStruct;
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE); ///< 使能DMA模块的外设时钟
-
- DmaInitStruct.enMode = DmaMskBlock; ///< 选择块传输
- DmaInitStruct.u16BlockSize = 1; ///< 块传输个数
- DmaInitStruct.u16TransferCnt = 128; ///< 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
- DmaInitStruct.enTransferWidth = DmaMsk16Bit; ///< 传输数据的宽度,此处选择字(16Bit)宽度
- DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc; ///< 源地址自增
- DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix; ///< 目的地址自增
- DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; ///< 禁止重新加载传输目的地址
- DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; ///< 使能重新加载传输源地址
- DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; ///< 使能重新加载BC/TC值
- DmaInitStruct.u32SrcAddress = (uint32_t)SendBuf; ///< 源地址
- DmaInitStruct.u32DstAddress = 0x40002508; ///< 目标地址:DAC_DHR12R0
- DmaInitStruct.enRequestNum = DmaDAC0Trig; ///< 设置DAC0触发
- DmaInitStruct.enTransferMode = DmaMskContinuousTransfer; ///< 连续传输
- DmaInitStruct.enPriority = DmaMskPriorityFix; ///< 各通道固定优先级,CH0优先级 > CH1优先级
- Dma_InitChannel(DmaCh0,&DmaInitStruct); ///< 初始化dma通道0
-
- Dma_Enable(); ///< 使能DMA
- Dma_EnableChannel(DmaCh0); ///< 使能DMA通道0
- Dma_ClrStat(DmaCh0); ///< 清零:STAT[2:0]
- }
我们将样例代码稍加修改,移植到我们的框架当中。
本代码同时拥有 LED闪烁 UART通信以及DAC指定输出的功能。
main.c
注意:系统时钟初始化代码,它需要放在串口初始化之前,否则串口通信会出问题。
- #include "ddl.h"
- #include "uart.h"
- #include "gpio.h"
- #include "dac.h"
-
- #include "user_gpio.h"
- #include "user_uart.h"
- #include "user_dac.h"
-
-
- int32_t main(void)
- {
- // sys_clk_init(); // 系统的时钟初始化 应该放在串口初始化之前 否则系统会出问题
- user_led_init();
- user_uart_init();
- user_dac_init();
-
- while(1)
- {
- if(fpgaRxFlag == 1){ // 当我收到fpga发来的固定长度为8的8个字节以后,我把它发过来的数据,给它回传回去
- send_data_to_fpga(fpgaRx, 8);
- fpgaRxFlag = 0;
- }
-
- if(pcRxFlag ==1 ){
- send_data_to_pc(pcRx, 8);
- pcRxFlag = 0;
- }
-
- DAC_OUT = 4095; // 0~4095表示0~3.3V
- Dac0_SoftwareTriggerCmd(); // 触发DAC转换
-
- Gpio_SetIO(LED1_PORT, LED1_PIN);
- Gpio_SetIO(LED2_PORT, LED2_PIN);
-
- delay1ms(500); // while 里面必须有个延迟,不然while(1)把cpu占用了,进不了中断。
-
- Gpio_ClrIO(LED1_PORT, LED1_PIN);
- Gpio_ClrIO(LED2_PORT, LED2_PIN);
-
- delay1ms(500);
- }
- }
user_dac.c 我们专门添加一个文件,来写我们自己对dac的配置,以便于后续其他功能的添加

- #include "user_dac.h"
- #include "sysctrl.h"
- #include "dac.h"
- #include "flash.h"
- #include "gpio.h"
- #include "math.h"
- #include "dmac.h"
-
-
- uint16_t DAC_OUT = 0;
-
- void sys_clk_init(void)
- {
- stc_sysctrl_clk_cfg_t stcCfg;
- stc_sysctrl_pll_cfg_t stcPLLCfg;
-
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralFlash, TRUE); // 使能FLASH模块的外设时钟
- Flash_WaitCycle(FlashWaitCycle1);
- Sysctrl_SetRCHTrim(SysctrlRchFreq4MHz); // PLL使用RCH作为时钟源,因此需要先设置RCH
-
- stcPLLCfg.enInFreq = SysctrlPllInFreq4_6MHz; // RCH 4MHz
- stcPLLCfg.enOutFreq = SysctrlPllOutFreq36_48MHz; // PLL 输出48MHz
- stcPLLCfg.enPllClkSrc = SysctrlPllRch; // 输入时钟源选择RCH
- stcPLLCfg.enPllMul = SysctrlPllMul12; // 4MHz x 12 = 48MHz
- Sysctrl_SetPLLFreq(&stcPLLCfg);
-
- // 选择PLL作为HCLK时钟源;
- stcCfg.enClkSrc = SysctrlClkPLL;
- // HCLK SYSCLK/2
- stcCfg.enHClkDiv = SysctrlHclkDiv1;
- // PCLK 为HCLK/8
- stcCfg.enPClkDiv = SysctrlPclkDiv1;
- // 系统时钟初始化
- Sysctrl_ClkInit(&stcCfg);
- }
-
-
- void dac_gpio_config(void)
- {
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 使能GPIO模块的外设时钟
- Gpio_SetAnalogMode(GpioPortA, GpioPin4); // PA04作为DAC的模拟输出
- }
-
- void dac_config(void)
- {
- stc_dac_cfg_t dac_initstruct;
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralDac, TRUE); // 使能DAC模块的时钟
-
- dac_initstruct.boff_t = DacBoffDisable;
- dac_initstruct.ten_t = DacTenEnable;
- dac_initstruct.sref_t = DacVoltageAvcc;
- dac_initstruct.mamp_t = DacMenp4095;
- dac_initstruct.tsel_t = DacSwTriger; // 软件触发方式
- dac_initstruct.align = DacRightAlign; // 右对齐
- Dac0_Init(&dac_initstruct);
- Dac0_Cmd(TRUE);
- Dac0_DmaCmd(TRUE); // DAC通道DMA使能
-
- }
-
- void dac_dma_config(void)
- {
- stc_dma_cfg_t DmaInitStruct;
-
- Sysctrl_SetPeripheralGate(SysctrlPeripheralDma, TRUE); // 使能DMA模块的外设时钟
-
- DmaInitStruct.enMode = DmaMskBlock; // 选择块传输
- DmaInitStruct.u16BlockSize = 1; // 块传输个数
- DmaInitStruct.u16TransferCnt = 1; // 块传输次数,一次传输数据大小为 块传输个数*BUFFER_SIZE
- DmaInitStruct.enTransferWidth = DmaMsk16Bit; // 传输数据的宽度,此处选择字(16Bit)宽度
- DmaInitStruct.enSrcAddrMode = DmaMskSrcAddrInc; // 源地址自增
- DmaInitStruct.enDstAddrMode = DmaMskDstAddrFix; // 目的地址自增
- DmaInitStruct.enDestAddrReloadCtl = DmaMskDstAddrReloadDisable; // 禁止重新加载传输目的地址
- DmaInitStruct.enSrcAddrReloadCtl = DmaMskSrcAddrReloadEnable; // 使能重新加载传输源地址
- DmaInitStruct.enSrcBcTcReloadCtl = DmaMskBcTcReloadEnable; // 使能重新加载BC/TC值
- DmaInitStruct.u32SrcAddress = (uint32_t)&DAC_OUT; // 源地址
- DmaInitStruct.u32DstAddress = 0x40002508; // 目标地址:DAC_DHR12R0
- DmaInitStruct.enRequestNum = DmaDAC0Trig; // 设置DAC0触发
- DmaInitStruct.enTransferMode = DmaMskOneTransfer; // 连续传输
- DmaInitStruct.enPriority = DmaMskPriorityFix; // 各通道固定优先级,CH0优先级 > CH1优先级
- Dma_InitChannel(DmaCh0,&DmaInitStruct); // 初始化dma通道0
-
- Dma_Enable(); // 使能DMA
- Dma_EnableChannel(DmaCh0); // 使能DMA通道0
- Dma_ClrStat(DmaCh0); // 清零:STAT[2:0]
- }
-
- void user_dac_init(void){
- // sys_clk_init();
- dac_gpio_config();
- dac_config();
- dac_dma_config();
- }
user_dac.h

- #ifndef _USER_DAC_H_
- #define _USER_DAC_H_
-
- #include "ddl.h"
-
- extern uint16_t DAC_OUT;
-
- void sys_clk_init(void);
- void dac_gpio_config(void);
- void dac_config(void);
- void dac_dma_config(void);
- void user_dac_init(void);
-
- #endif
-
我们的实验结果如下:
当DAC_OUT = 4095时

当DAC_OUT = 2048时

4095应该对应3.3V,2048应该对应1.65V,实验值与理论值基本吻合。🙂
感谢您的阅读,欢迎留言讨论、收藏、点赞。