| **银杏科技有限公司旗下技术文档发布平台** ||||
|技术支持电话|**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直流电压输出。