一、简介
本文将基于STM32F407VET6介绍,如何使用RT-Thread Studio开发环境下使用DAC设备。并且DAC的相关介绍在另外一篇博客中介绍到,如果想对DAC有一个更加深刻的了解,可以参考下面这篇文章。
二、RTT时钟配置
由于使用RTT生成的工程默认使用的是系统内部时钟,便于我们对时间的控制,所以通常会使用外部时钟,因此需要对工程中的时钟进行更改,更改内容如下:
- 打开RT-Thread Studio软件新建基于芯片的项目,并使用外部时钟系统。
- 在drv_clk.c文件中添加时钟配置函数,并且注释内部时钟的调用。
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
void clk_init(char *clk_source, int source_freq, int target_freq)
{
// system_clock_config(target_freq);
SystemClock_Config();
}
三、DAC初始化配置
1.打开DAC驱动框架
在RT-Thread Setting
中借助图形化配置工具打开软件DAC的驱动框架,如下图所示:
2.定义DAC宏定义
在board.h文件中添加DAC的宏定义,从而保证能够使用DAC的相关驱动函数。
/*-------------------------- DAC CONFIG BEGIN --------------------------*/
/** if you want to use DAC you can use the following instructions.
*
* STEP 1, open DAC driver framework support in the RT-Thread Settings file
*
* STEP 2, define macro related to the DAC
* such as #define BSP_USING_DAC1
*
* STEP 3, copy your DAC init function from stm32xxxx_hal_msp.c generated by stm32cubemx to the end of board.c file
* such as void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
*
* STEP 4, modify your stm32xxxx_hal_config.h file to support DAC peripherals. define macro related to the peripherals
* such as #define HAL_DAC_MODULE_ENABLED
*
*/
#define BSP_USING_DAC1
/*-------------------------- DAC CONFIG END --------------------------*/
3.编写DAC初始化代码
可以使用STM32CubeMx自动生成代码,也可以自己编写初始化代码,使能DAC1和DAC2。然后将生成的函数HAL_DAC_MspInit(DAC_HandleTypeDef* dacHandle)
复制到board.c文件中进行初始化。
void HAL_DAC_MspInit(DAC_HandleTypeDef* dacHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(dacHandle->Instance==DAC)
{
/* DAC clock enable */
__HAL_RCC_DAC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**DAC GPIO Configuration
PA4 ------> DAC_OUT1
PA5 ------> DAC_OUT2
*/
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
4.打开STM32宏定义
在driver中的stm32f4xx_hal_conf.h
中DAC宏定义打开。
四、驱动代码编写
1.dac.c
主要包含两个函数,int set_dac_output(uint32_t dac_value, uint8_t channel)
和void close_dac_output(uint8_t channel)
,设置通道和输出电压,以及关闭通道的输出函数。参考电压:2.5V
为参考,最大输出2.5V。
#include "dac.h"
/**
* @brief 设置DAC输出电压
* @param dac_value DAC值
* @param channel 通道
* @return
*/
int set_dac_output(uint32_t dac_value, uint8_t channel)
{
rt_dac_device_t dac_dev;
rt_uint32_t value, vol;
rt_err_t ret = RT_EOK;
/* 查找设备 */
dac_dev = (rt_dac_device_t)rt_device_find(DAC_DEV_NAME);
if (dac_dev == RT_NULL)
{
rt_kprintf("dac sample run failed! can't find %s device!\n", DAC_DEV_NAME);
return RT_ERROR;
}
/* 打开通道 */
ret = rt_dac_enable(dac_dev, channel);
/* 设置输出值 */
value = dac_value;
if (value > 4095)
{
value = 4095;
}
rt_dac_write(dac_dev, channel, value);
rt_kprintf("the value is :%d \n", value);
/* 转换为对应电压值 */
vol = value * REFER_VOLTAGE / CONVERT_BITS;
rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
return ret;
}
/**
* @brief 关闭DAC输出
* @param channel 通道
*/
void close_dac_output(uint8_t channel)
{
rt_dac_device_t dac_dev;
/* 查找设备 */
dac_dev = (rt_dac_device_t)rt_device_find(DAC_DEV_NAME);
if (dac_dev == RT_NULL)
{
rt_kprintf("dac sample run failed! can't find %s device!\n", DAC_DEV_NAME);
return RT_ERROR;
}
rt_dac_disable(dac_dev, channel);
}
2.dac.h
#ifndef APPLICATIONS_DAC_H_
#define APPLICATIONS_DAC_H_
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#include <stdlib.h>
#define DAC_PORT GPIOA
#define DAC_PIN GPIO_PIN_5 // dac引脚号 -- DAC1_OUT2
#define DAC_DEV_NAME "dac1" // DAC 设备名称
#define DAC_DEV_CHANNEL_1 1 // DAC 通道1
#define DAC_DEV_CHANNEL_2 2 // DAC 通道2
#define REFER_VOLTAGE 250 // 参考电压 2.5V,数据精度乘以100保留2位小数
#define CONVERT_BITS (1 << 12) // 转换位数为12位
extern int set_dac_output(uint32_t dac_value, uint8_t channel);
extern void close_dac_output(uint8_t channel);
#endif /* APPLICATIONS_DAC_H_ */
3.main.c
主要是设置DAC的输出值和通道,然后进行DAC的输出。
#include <rtthread.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "dac.h"
int main(void)
{
int count = 1;
while (count)
{
set_dac_output(2048, 1);
set_dac_output(4095, 2);
rt_thread_mdelay(3000);
}
return RT_EOK;
}
五、测试验证
通过示波器可以观察到输出的波形,两个通道的电压分别是2.52V和1.3V
,和我们设置的参数基本上一直,设置的4095为输出电压2.5V,2048则是1.25V
,测试的会存在一定的电压误差,所以两者不是完全相等。测试波形如下: