说明:文档记录基于RT-Thread的STM32F103外设DAC操作。
1.DAC的GPIO配置
函数位于 drivers\stm32f1xx_hal_msp.c
//DAC底层驱动,时钟配置,引脚 配置
//此函数会被HAL_DAC_Init()调用
//hdac:DAC句柄
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_DAC_CLK_ENABLE(); //使能DAC时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Pin=GPIO_PIN_4; //PA4
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
//新增DAC2
GPIO_Initure.Pin=GPIO_PIN_5; //PA4
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hdac->Instance==DAC)
{
/* USER CODE BEGIN DAC_MspInit 0 */
/* USER CODE END DAC_MspInit 0 */
/* Peripheral 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;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN DAC_MspInit 1 */
/* USER CODE END DAC_MspInit 1 */
}
}
2.调试代码
以下是成功调试的代码,开发板是野火的 霸道STM32,这个开发板只有DAC2 ;PA5能用,所以代码是在 原子的 DAC1,PAC4的基础上增加了DAC2, 关于RT Thread 线程部分也只做了 DAC2部分的。
备注:关于DAC1,DAC2 的引脚配置的函数位于 drivers \ stm32f1xx_hal_msp.c 的
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac) 函数,里面对DAC1,DAC2的IO进行了配置,如果只用到其中一个,需要到这个函数里面把其一关闭。
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;//这段代码同时配置了DAC1,DAC2即 PA4,PA5,如果只需其一,删掉其一即可。
2.1 DAC_DRIVERS.h
#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
extern DAC_HandleTypeDef DAC1_Handler;//DAC句柄
extern DAC_HandleTypeDef DAC2_Handler;//DAC句柄
void DAC2_test(void);
2.2 DAC_DRIVERS.c
#include "DAC_DRIVERS.h"
DAC_HandleTypeDef DAC1_Handler; //DAC句柄
DAC_HandleTypeDef DAC2_Handler; //DAC句柄
//初始化DAC1
void DAC1_Init(void)
{
DAC_ChannelConfTypeDef DACCH1_Config;
DAC1_Handler.Instance = DAC;
HAL_DAC_Init(&DAC1_Handler); //初始化DAC
DACCH1_Config.DAC_Trigger = DAC_TRIGGER_NONE; //不使用触发功能
DACCH1_Config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; //DAC1输出缓冲关闭
HAL_DAC_ConfigChannel(&DAC1_Handler, &DACCH1_Config, DAC_CHANNEL_1); //DAC通道1配置
HAL_DAC_Start(&DAC1_Handler, DAC_CHANNEL_1); //开启DAC通道1
}
//初始化DAC2
void DAC2_Init(void)
{
DAC_ChannelConfTypeDef DACCH2_Config;
DAC2_Handler.Instance = DAC;
HAL_DAC_Init(&DAC2_Handler); //初始化DAC
DACCH2_Config.DAC_Trigger = DAC_TRIGGER_NONE; //不使用触发功能
DACCH2_Config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE; //DAC1输出缓冲关闭
HAL_DAC_ConfigChannel(&DAC2_Handler, &DACCH2_Config, DAC_CHANNEL_2); //DAC通道1配置
HAL_DAC_Start(&DAC2_Handler, DAC_CHANNEL_2); //开启DAC通道1
}
//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void DAC1_Set_Vol(rt_uint16_t vol)
{
double temp = vol;
temp /= 1000;
temp = temp * 4096 / 3.3;
HAL_DAC_SetValue(&DAC1_Handler, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp); //12位右对齐数据格式设置DAC值
}
//设置通道2输出电压
//vol:0~3300,代表0~3.3V
void DAC2_Set_Vol(rt_uint16_t vol)
{
double temp=vol;
temp /= 1000;
temp = temp * 4096 / 3.3;
HAL_DAC_SetValue(&DAC2_Handler, DAC_CHANNEL_2, DAC_ALIGN_12B_R, temp); //12位右对齐数据格式设置DAC值
}
/* 线程 DAC2_entry 的入口函数 */
static void DAC2_entry(void *param)
{
DAC2_Init();
rt_uint16_t vout = 1300;
while (1)
{
DAC2_Set_Vol(vout);
rt_kprintf("DAC2, PA5= %d mV \n", 1300);
rt_thread_mdelay(2000); //以ms为单位延时,函数自动去算出设置的时间需要多少时钟节拍。
}
}
//线程创建函数
void DAC2_test(void)
{
rt_thread_t tid1; //创建线程控制块指针来接收线程创建函数的返回值,目的是通过返回值判断线程是否创建ok
/* 创建线程 1,名称是 DAC2,入口是 DAC2_entry*/
tid1 = rt_thread_create("DAC2", DAC2_entry, RT_NULL, 5000, //设置内存堆栈大小
10, 10); //设置优先级,时间片参数,时间片是在有多个相同优先级线程时,这个线程每次被执行多少个时间片
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
}
//INIT_APP_EXPORT(DAC2_test);