完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
本章节为大家讲解DAC,实际项目用到DAC的地方比较多,而且H7的DAC性能也比较给力。
59.1 初学者重要提示
对于STM32H7的DAC了解到以下几点即可:
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DAC的基本功能,然后再看手册了解细节。框图如下所示: 通过这个框图,我们可以得到如下信息:
59.2.2 DAC数据格式和输出电压 DAC的数据寄存器设计比较灵活,每个通道都有一组单独的寄存器(下面是通道1的寄存器):
除了这种单独寄存器,为了降低带宽,也支持两个通道公用一个寄存器。
由于DAC是12bit的DAC,那么范围就是0-4095,对应的输出电压如下: DAC Output = Vref *(DOR / 4095),其中Vref是参考电压,DOR是数据输出寄存器。 比如需要DAC输出0.7V,那么假设VREF+ = 3.3V, DAC_OUT1 = (3.3 * 868) / 4095 = 0.7V。 59.2.3 DAC支持的触发源 DAC支持软件触发和硬件触发,具体支持的触发源如下: #define DAC_TRIGGER_NONE ((uint32_t)0x00000000) #define DAC_TRIGGER_SOFTWARE ((uint32_t)(DAC_CR_TEN1)) #define DAC_TRIGGER_T1_TRGO ((uint32_t)(DAC_CR_TSEL1_0 | DAC_CR_TEN1)) #define DAC_TRIGGER_T2_TRGO ((uint32_t)(DAC_CR_TSEL1_1 | DAC_CR_TEN1)) #define DAC_TRIGGER_T4_TRGO ((uint32_t)(DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1) #define DAC_TRIGGER_T5_TRGO ((uint32_t)(DAC_CR_TSEL1_2 |DAC_CR_TEN1)) #define DAC_TRIGGER_T6_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) #define DAC_TRIGGER_T7_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TEN1)) #define DAC_TRIGGER_T8_TRGO ((uint32_t)(DAC_CR_TSEL1_2 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) #define DAC_TRIGGER_T15_TRGO ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TEN1)) #define DAC_TRIGGER_HR1_TRGO1 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) #define DAC_TRIGGER_HR1_TRGO2 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_1 | DAC_CR_TEN1)) #define DAC_TRIGGER_LP1_OUT ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_1 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) #define DAC_TRIGGER_LP2_OUT ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_2 | DAC_CR_TEN1)) #define DAC_TRIGGER_EXT_IT9 ((uint32_t)(DAC_CR_TSEL1_3 | DAC_CR_TSEL1_2 | DAC_CR_TSEL1_0 | DAC_CR_TEN1)) 59.2.4 DAC正常模式和采样保持模式 关于正常模式和采样保持模式,注意以下几点:
一般情况下,使用出厂校准即可,芯片上电后自动完成出厂校准。而用户校准略麻烦,暂不做研究。这里特别注意一点,校准是建立在用户使能了输出缓冲的情况下才有效。 59.3 DAC的HAL库用法 DAC的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断和DMA。下面我们逐一展开为大家做个说明。 59.3.1 DAC寄存器结构体DAC_TypeDef DAC相关的寄存器是通过HAL库中的结构体DAC_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义: typedef struct { __IO uint32_t CR; __IO uint32_t SWTRIGR; __IO uint32_t DHR12R1; __IO uint32_t DHR12L1; __IO uint32_t DHR8R1; __IO uint32_t DHR12R2; __IO uint32_t DHR12L2; __IO uint32_t DHR8R2; __IO uint32_t DHR12RD; __IO uint32_t DHR12LD; __IO uint32_t DHR8RD; __IO uint32_t DOR1; __IO uint32_t DOR2; __IO uint32_t SR; __IO uint32_t CCR; __IO uint32_t MCR; __IO uint32_t SHSR1; __IO uint32_t SHSR2; __IO uint32_t SHHR; __IO uint32_t SHRR; } DAC_TypeDef; __IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏: #define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */ 下面我们再看DAC的定义,在stm32h743xx.h文件。 #define PERIPH_BASE ((uint32_t)0x40000000) #define D2_APB1PERIPH_BASE PERIPH_BASE #define DAC1_BASE (D2_APB1PERIPH_BASE + 0x7400) #define DAC1 ((DAC_TypeDef *) DAC1_BASE) <----- 展开这个宏,(DAC_TypeDef *) 0x40007400 我们访问DAC1的CR寄存器可以采用这种形式:DAC1->CR = 0。 59.3.2 DAC的采样保持DAC_SampleAndHoldConfTypeDef 此结构体用于DAC的采样保持参数,具体定义如下: typedef struct { uint32_t DAC_SampleTime ; uint32_t DAC_HoldTime ; uint32_t DAC_RefreshTime ; } DAC_SampleAndHoldConfTypeDef; 下面将这几个参数逐一为大家做个说明: uint32_t DAC_SampleTime 此参数用于设置DAC的采样时间,范围0 - 1023。 uint32_t DAC_HoldTime 此参数用于设置DAC的保持时间,范围0 – 1023。 uint32_t DAC_RefreshTime 此参数用于设置DAC的刷新时间,范围0 – 255。 59.3.3 DAC的通道参数结构体DAC_ChannelConfTypeDef 此结构体用于DAC的通道参数配置,具体定义如下: typedef struct { uint32_t DAC_SampleAndHold; uint32_t DAC_Trigger; uint32_t DAC_OutputBuffer; uint32_t DAC_ConnectOnChipPeripheral ; uint32_t DAC_UserTrimming; uint32_t DAC_TrimmingValue; DAC_SampleAndHoldConfTypeDef DAC_SampleAndHoldConfig; }DAC_ChannelConfTypeDef; 下面将这几个参数逐一为大家做个说明: uint32_t DAC_SampleAndHold 此参数用于使能采样保持模式,具体支持的参数如下: #define DAC_SAMPLEANDHOLD_DISABLE ((uint32_t)0x00000000) #define DAC_SAMPLEANDHOLD_ENABLE ((uint32_t)DAC_MCR_MODE1_2) uint32_t DAC_Trigger 此参数用于DAC触发源的选择,具体支持的参数如下: #define DAC_TRIGGER_NONE #define DAC_TRIGGER_SOFTWARE #define DAC_TRIGGER_T1_TRGO #define DAC_TRIGGER_T2_TRGO #define DAC_TRIGGER_T5_TRGO #define DAC_TRIGGER_T6_TRGO #define DAC_TRIGGER_T7_TRGO #define DAC_TRIGGER_T8_TRGO #define DAC_TRIGGER_T15_TRGO #define DAC_TRIGGER_HR1_TRGO1 #define DAC_TRIGGER_HR1_TRGO2 #define DAC_TRIGGER_LP1_OUT #define DAC_TRIGGER_LP2_OUT #define DAC_TRIGGER_EXT_IT9 uint32_t DAC_OutputBuffer 此参数用于使能或者关闭DAC的输出缓冲,使能输出缓冲后,可以增加DAC的驱动能力,具体支持的参数如下: #define DAC_OUTPUTBUFFER_ENABLE ((uint32_t)0x00000000) #define DAC_OUTPUTBUFFER_DISABLE ((uint32_t)DAC_MCR_MODE1_1) uint32_t DAC_ConnectOnChipPeripheral 此参数用于DAC是否连接片上外设(运放,比较器等),具体支持的参数如下: #define DAC_CHIPCONNECT_DISABLE ((uint32_t)0x00000000) #define DAC_CHIPCONNECT_ENABLE ((uint32_t)DAC_MCR_MODE1_0) uint32_t DAC_UserTrimming 此参数用于设置DAC的校准方式,采用出厂模式还是用户模式,具体支持的参数如下: #define DAC_TRIMMING_FACTORY ((uint32_t)0x00000000) #define DAC_TRIMMING_USER ((uint32_t)0x00000001) uint32_t DAC_TrimmingValue 此参数用于设置用户校准模式的偏移值,参数范围1-31。 DAC_SampleAndHoldConfTypeDef DAC_SampleAndHoldConfig 此参数用于采样保持具体参数设置,详解本章3.2小节的说明。 59.3.4 DAC结构体句柄DAC_HandleTypeDef HAL库在DAC_TypeDef的基础上封装了一个结构体DAC_HandleTypeDef,定义如下: typedef struct { DAC_TypeDef *Instance; __IO HAL_DAC_StateTypeDef State; HAL_LockTypeDef Lock; DMA_HandleTypeDef *DMA_Handle1; DMA_HandleTypeDef *DMA_Handle2; __IO uint32_t ErrorCode; }DAC_HandleTypeDef; 下面将这几个参数逐一做个说明。 DAC_TypeDef *Instance 这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。 DMA_HandleTypeDef *DMA_Handle1 DMA_HandleTypeDef *DMA_Handle2 DMA句柄结构体指针变量,用于关联DAC句柄,方便调用。 HAL_LockTypeDef Lock __IO HAL_DAC_STATETypeDef State __IO uint32_t ErrorCode 这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DAC状态,而ErrorCode用于配置代码错误。 59.3.5 DAC初始化流程总结 使用方法由HAL库提供: 第1步:基本的初始化。 函数HAL_DAC_Init初始化。 配置DAC_OUT1: PA4, DAC_OUT2: PA5引脚为模拟模式。 函数HAL_DAC_ConfigChannel配置通道参数。 函数HAL_DAC_Start() or HAL_DAC_Start_DMA()使能DAC。 第2步:DAC校准。 出厂校准比较简单,芯片上电后自动完成,而用户校准需要依次调用函数HAL_DACEx_GetTrimOffset,HAL_DACEx_SelfCalibrate和HAL_DACEx_SetUserTrimming。 第3步:查询模式。 函数HAL_DAC_Start() 启动。 函数HAL_DAC_GetValue()可以读取输出值。 函数HAL_DAC_Stop可以停止DAC。 第4步:DMA方式。 函数HAL_DAC_Start_DMA()启动DMA方式转换。 DAC的数据传输一半的时候, HAL_DAC_ConvHalfCpltCallbackCh1() 或者 HAL_DACEx_ConvHalfCpltCallbackCh2() 会被调用。 DAC的数据传输完成的时候,HAL_DAC_ConvCpltCallbackCh1() 或者 HAL_DACEx_ConvHalfCpltCallbackCh2() 会被调用。 传输错误时,函数HAL_DAC_ErrorCallbackCh1会被调用。 DMA下溢错误,会调用函数HAL_DAC_DMAUnderrunCallbackCh1()或者HAL_DACEx_DMAUnderrunCallbackCh2()。 停止DAC的DMA方式,可以调用函数HAL_DAC_Stop_DMA 59.4 源文件stm32h7xx_hal_dac.c 这里把我们把如下几个常用到的函数做个说明: HAL_DAC_Init HAL_DAC_ConfigChannel HAL_DAC_Start_DMA 59.4.1 函数HAL_DAC_Init 函数原型: HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef* hdac) { /* 检测DAC句柄 */ if(hdac == NULL) { return HAL_ERROR; } assert_param(IS_DAC_ALL_INSTANCE(hdac->Instance)); if(hdac->State == HAL_DAC_STATE_RESET) { hdac->Lock = HAL_UNLOCKED; /* 初始化GPIO,NVIC等 */ HAL_DAC_MspInit(hdac); } /* 设置DAC状态忙 */ hdac->State = HAL_DAC_STATE_BUSY; /* 设置DAC无错误 */ hdac->ErrorCode = HAL_DAC_ERROR_NONE; /* 设置DAC就绪 */ hdac->State = HAL_DAC_STATE_READY; /* 返回HAL_OK */ return HAL_OK; } 函数描述: 此函数用于初始化DAC。 函数参数: 第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。 注意事项: 函数HAL_DAC_MspInit用于初始化DAC的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。 如果形参hdac的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DAC_HandleTypeDef DacHandle。 对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DAC_STATE_RESET = 0x00U。 解决办法有三 方法1:用户自己初始DAC底层。 方法2:定义DAC_HandleTypeDef DacHandle为全局变量。 方法3:下面的方法 if(HAL_DAC_DeInit(&DacHandle) != HAL_OK) { Error_Handler(); } if(HAL_DAC_Init(&DacHandle) != HAL_OK) { Error_Handler(); } 使用举例: DAC_HandleTypeDef DAC_Handle; DacHandle.Instance = DAC1; if (HAL_DAC_Init(&DacHandle) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } 59.4.2 函数HAL_DAC_ConfigChannel 函数原型: HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef* hdac, DAC_ChannelConfTypeDef* sConfig, uint32_t Channel) { uint32_t tmpreg1 = 0, tmpreg2 = 0; uint32_t tickstart = 0; /* 部分省略,未贴出 */ /* 上锁 */ __HAL_LOCK(hdac); /* 设置DAC忙 */ hdac->State = HAL_DAC_STATE_BUSY; if(sConfig->DAC_SampleAndHold == DAC_SAMPLEANDHOLD_ENABLE) { /* 通道1设置 */ if (Channel == DAC_CHANNEL_1) { } else /* 通道2设置 */ { } } if(sConfig->DAC_UserTrimming == DAC_TRIMMING_USER) /* 用户校准配置 */ { } /* 出厂模式无需配置,复位后自动设置 */ /* 获取DAC MCR数值 */ tmpreg1 = hdac->Instance->MCR; /* 清除DAC_MCR_MODE2_0, DAC_MCR_MODE2_1 和 DAC_MCR_MODE2_2 位 */ tmpreg1 &= ~(((uint32_t)(DAC_MCR_MODE1)) << Channel); /* 配置DAC通道 */ tmpreg2 = (sConfig->DAC_SampleAndHold | sConfig->DAC_OutputBuffer | sConfig->DAC_ConnectOnChipPeripheral); tmpreg1 |= tmpreg2 << Channel; /* 设置MCR数值 */ hdac->Instance->MCR = tmpreg1; /* DAC工作在正常模式 */ CLEAR_BIT (hdac->Instance->CR, DAC_CR_CEN1 << Channel); /* 获取DAC CR值 */ tmpreg1 = hdac->Instance->CR; tmpreg1 &= ~(((uint32_t)(DAC_CR_MAMP1 | DAC_CR_WAVE1 | DAC_CR_TSEL1 | DAC_CR_TEN1)) << Channel); tmpreg2 = (sConfig->DAC_Trigger); tmpreg1 |= tmpreg2 << Channel; /* 写DAC CR值 */ hdac->Instance->CR = tmpreg1; /* 禁止波形生成 */ hdac->Instance->CR &= ~(DAC_CR_WAVE1 << Channel); /* 设置DAC就绪 */ hdac->State = HAL_DAC_STATE_READY; /* 解锁 */ __HAL_UNLOCK(hdac); /* 返回HAL_OK */ return HAL_OK; } 函数描述: 此函数主要用于配置DAC的通道参数。 函数参数: 第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。 第2个参数是DAC_ChannelConfTypeDef类型结构体指针变量,用于DAC的通道参数配置,结构体变量成员的详细介绍看本章3.3小 第3个参数用于选择要配置那个通道,DAC_CHANNEL_1表示配置通道1,DAC_CHANNEL_2表示配置通道2。 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。 使用举例: static DAC_ChannelConfTypeDef sConfig; static DAC_HandleTypeDef DacHandle; sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE; /* 关闭采样保持模式,这个模式主要用于低功耗 */ sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO; /* 采用定时器6触发 */ sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; /* 使能输出缓冲 */ sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;/* 不将DAC连接到片上外设 */ sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY; /* 使用出厂校准 */ if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } 59.4.3 函数HAL_DAC_Start_DMA 函数原型: HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment) { uint32_t tmpreg = 0; /* 部分省略,未贴出 */ /* 检测参数 Check the parameters */ assert_param(IS_DAC_CHANNEL(Channel)); assert_param(IS_DAC_ALIGN(Alignment)); /* 上锁 Process locked */ __HAL_LOCK(hdac); /* 设置DAC忙 Change DAC state */ hdac->State = HAL_DAC_STATE_BUSY; /* 配置通道1 */ if(Channel == DAC_CHANNEL_1) { /* DMA传输完成回调 */ hdac->DMA_Handle1->XferCpltCallback = DAC_DMAConvCpltCh1; /* DMA半传输完成回调 */ hdac->DMA_Handle1->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh1; /* DMA传输错误回调 */ hdac->DMA_Handle1->XferErrorCallback = DAC_DMAErrorCh1; /* 使能DAC DMA */ SET_BIT(hdac->Instance->CR, DAC_CR_DMAEN1); /* 数据对齐方式设置 */ switch(Alignment) { case DAC_ALIGN_12B_R: tmpreg = (uint32_t)&hdac->Instance->DHR12R1; break; case DAC_ALIGN_12B_L: tmpreg = (uint32_t)&hdac->Instance->DHR12L1; break; case DAC_ALIGN_8B_R: tmpreg = (uint32_t)&hdac->Instance->DHR8R1; break; default: break; } } else { } } /* 使能DMA Stream */ if(Channel == DAC_CHANNEL_1) { /* 使能DAC DMA下溢中断 */ __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR1); /* 启动传输 */ HAL_DMA_Start_IT(hdac->DMA_Handle1, (uint32_t)pData, tmpreg, Length); } else { __HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR2); HAL_DMA_Start_IT(hdac->DMA_Handle2, (uint32_t)pData, tmpreg, Length); } /* 解锁 */ __HAL_UNLOCK(hdac); /* 使能DAC通道 */ __HAL_DAC_ENABLE(hdac, Channel); /* 返回HAL_OK */ return HAL_OK; } 函数描述: 此函数用于启动DAC的DMA方式 函数参数: 第1个参数是DAC_HandleTypeDef类型结构体指针变量,结构体变量成员的详细介绍看本章3.4小节。 第2个参数用于选择要配置那个通道,DAC_CHANNEL_1表示配置通道1,DAC_CHANNEL_2表示配置通道2。 第3个参数是波形数据地址。 第4个参数是传输的数据长度。 第5个参数是数据对齐方式设置。 DAC_ALIGN_8B_R 表示8bit右对齐。 DAC_ALIGN_12B_L 表示12bit左对齐。 DAC_ALIGN_12B_R 表示12bit右对齐。 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。 使用举例: static DAC_HandleTypeDef DacHandle; /* 启动DAC DMA */ if (HAL_DAC_Start_DMA(&DacHandle, DAC_CHANNEL_2, (uint32_t *)g_usWaveBuff, 64, DAC_ALIGN_12B_R) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } 59.5 总结 本章节就为大家讲解这么多,DAC功能用到的地方还是比较多的,建议熟练使用。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 03:06 , Processed in 1.548216 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号