| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-07-11 | gingko | 初次建立 | ===== 实验三十六:DAC实验——输出直流电压 ===== ==== 一、实验目的与意义 ==== - 了解STM32的DAC结构。 - 了解STM32的DAC特征。 - 掌握DAC的使用方法。 - 掌握STM32 HAL库中DAC属性的配置方法。 - 掌握KEIL MDK 集成开发环境使用方法。 ==== 二、实验设备及平台 ==== - iCore4 双核心板。 - JLINK(或相同功能)仿真器。 - Micro USB线缆。 - Keil MDK 开发平台。 - STM32CubeMX开发平台。 - 装有WIN XP(及更高版本)系统的计算机。 ==== 三、实验原理 ==== === 1、DAC简介 === * STM32F767的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压Vref+(通ADC共用)以获得更精确的转换结果。 * STM32F767的DAC模块主要特点有: * ① 2个DAC转换器:每个转换器对应1个输出通道 * ② 8位或者12位单调输出 * ③ 12位模式下数据左对齐或者右对齐 * ④ 同步更新功能 * ⑤ 噪声波形生成 * ⑥ 三角波形生成 * ⑦ 双DAC通道同时或者分别转换 * ⑧ 每个通道都有DMA功能 * 单个DAC通道的框图如图所示: {{ :icore4:icore4_arm_hal_36_1.png?direct |}} * 图中VDDA和VSSA为DAC模块模拟部分的供电,而Vref+则是DAC模块的参考电压。DAC_OUTx就是DAC的输出通道了(对应PA4或者PA5引脚)。从图27.1.1可以看出,DAC输出是受DORx寄存器直接控制的,但是我们不能直接往DORx寄存器写入数据,而是通过DHRx间接的传给DORx寄存器,实现对DAC输出的控制。前面我们提到,STM32F767的DAC支持8/12位模式,8位模式的时候是固定的右对齐的,而12位模式又可以设置左对齐/右对齐。单DAC通道x,总共有3种情况: * 8位数据右对齐:用户将数据写入DAC_DHR8Rx[7:0]位(实际存入DHRx[11:4]位)。 * 12位数据左对齐:用户将数据写入DAC_DHR12Lx[15:4]位(实际存入DHRx[11:0]位)。 * 12位数据右对齐:用户将数据写入DAC_DHR12Rx[11:0]位(实际存入DHRx[11:0]位)。 * 本实验使用的就是单DAC通道1,采用12位右对齐格式,所以采用第3种情况。 * 如果没有选中硬件触发(寄存器DAC_CR1的TENx位置’0’),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发(寄存器DAC_CR1的TENx位置’1’),数据传输在触发发生以后3个APB1时钟周期后完成。一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。我们可以从STM32F767IGT6的数据手册查到的典型值为3us,最大是6us。所以DAC的转 * 换速度最快是333K左右。 * 本实验我们将不使用硬件触发(TEN=0),其转换的时间框图如图所示: {{ :icore4:icore4_arm_hal_36_2.png?direct |}} * DAC引脚图 {{ :icore4:icore4_arm_hal_36_3.png?direct |}} === 2、DAC输出电压 === * 经过线性转换后,数字输入会转换为0到V_(REF+)之间的输出电压。 * 各DAC通道引脚的模拟输出电压通过以下公式确定: DAC_output=V_REF×DOR/4096 === 3、原理图 === * STM32内部集成两个12位DAC,可以配置成12位或者8位,DAC具有两个独立转换通道。在双DAC模式下,DA转换可被配置成独立模式或者工作模式。iCore4中两路DAC参考电压为2.5V。本实验中我们使用DAC1通道一输出2.0V电压。原理图如下: {{ :icore4:icore4_arm_hal_36_4.png?direct |}} ==== 四、实验程序 ==== 1、主函数 int main(void) { /* MCU配置 */ /* 重置所有外设, 初始化Flash接口和Systick. */ HAL_Init(); /* 系统时钟配置 */ SystemClock_Config(); /* 初始化所有已配置的外设 */ MX_GPIO_Init(); MX_DAC_Init(); LED_GREEN_ON; HAL_DAC_Start(&hdac, DAC_CHANNEL_1); //开启DAC通道1 dac1.set_voltage(2.0); while (1) { } } 2、DAC初始化 /* DAC初始化函数*/ void MX_DAC_Init(void) { DAC_ChannelConfTypeDef sConfig; /** DAC初始化 */ hdac.Instance = DAC; if (HAL_DAC_Init(&hdac) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**DAC 通道1配置 */ sConfig.DAC_Trigger = DAC_TRIGGER_NONE; sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } * HAL库中提供了一个DAC初始化函数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; /* 初始化底层硬件 */ HAL_DAC_MspInit(hdac); } /* 初始化DAC状态*/ hdac->State = HAL_DAC_STATE_BUSY; /* 将DAC错误代码设置为none */ hdac->ErrorCode = HAL_DAC_ERROR_NONE; /* 初始化DAC状态*/ hdac->State = HAL_DAC_STATE_READY; /*返回函数状态 */ return HAL_OK; } 3、使能DAC转换通道 * 初始化DAC之后,理所当然要使能DAC转换通道,HAL库函数定义如下: HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef* hdac, uint32_t Channel)//第一个参数是DAC句柄,第二个用来设置DAC 通道 { uint32_t tmp1 = 0, tmp2 = 0; /* 检查参数 */ assert_param(IS_DAC_CHANNEL(Channel)); /* 锁定进程 */ __HAL_LOCK(hdac); /* 更改DAC状态 */ hdac->State = HAL_DAC_STATE_BUSY; /* 使能外设 */ __HAL_DAC_ENABLE(hdac, Channel); if(Channel == DAC_CHANNEL_1) { tmp1 = hdac->Instance->CR & DAC_CR_TEN1; tmp2 = hdac->Instance->CR & DAC_CR_TSEL1; /* 检查是否启用了软件触发器*/ if((tmp1 == DAC_CR_TEN1) && (tmp2 == DAC_CR_TSEL1)) { /* 启用选定的DAC软件转换 */ hdac->Instance->SWTRIGR |= (uint32_t)DAC_SWTRIGR_SWTRIG1; } } else { tmp1 = hdac->Instance->CR & DAC_CR_TEN2; tmp2 = hdac->Instance->CR & DAC_CR_TSEL2; /* 检查是否启用了软件触发器*/ if((tmp1 == DAC_CR_TEN2) && (tmp2 == DAC_CR_TSEL2)) { /* 启用选定的DAC软件转换*/ hdac->Instance->SWTRIGR |= (uint32_t)DAC_SWTRIGR_SWTRIG2; } } /* 更改DAC状态 */ hdac->State = HAL_DAC_STATE_READY; /* 进程解锁 */ __HAL_UNLOCK(hdac); /* 返回函数状态 */ return HAL_OK; } 4、设置DAC的输出值 * 通过前面的步骤设置,DAC就可以开始工作了,我们使用12位右对齐数据格式,就可以在DAC输出引脚( PA4)得到电压值了,相关的函数为: void set_voltage(double voltage) { unsigned short int temp; temp = voltage * 4095 / 2.5; HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); } /* 设置DAC通道的指定数据保持寄存器值 */ HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data) { __IO uint32_t tmp = 0; /* 检查参数 */ assert_param(IS_DAC_CHANNEL(Channel)); assert_param(IS_DAC_ALIGN(Alignment)); assert_param(IS_DAC_DATA(Data)); tmp = (uint32_t)hdac->Instance; if(Channel == DAC_CHANNEL_1) { tmp += DAC_DHR12R1_ALIGNMENT(Alignment); } else { tmp += DAC_DHR12R2_ALIGNMENT(Alignment); } /*设置DAC通道1选择的数据保持寄存器 */ *(__IO uint32_t *) tmp = Data; /* 返回函数状态 */ return HAL_OK; } ==== 五、实验步骤 ==== - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4上; - 也可以进入Debug模式,单步运行或设置断点验证程序逻辑。 ==== 六、实验现象 ==== * 用电压表测量PA4引脚有2.0V直流电压输出。