本帖最后由 正点原子运营 于 2024-4-30 09:32 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
6)正点原子STM32技术交流QQ群:725095144
本章介绍使用STM32F103的DAC输出指定的电压值。通过本章的学习。读者将学习到DAC的使用。 本章分为如下几个小节: 37.1 硬件设计 37.2 程序设计 37.3 下载验证
37.1 硬件设计 37.1.1 例程功能 1. LCD上不断刷新显示PA4引脚输出电压的数字量、模拟量和PA1引脚输入电压的模拟量 2. 按下WKUP按键可以加大PA4引脚输出的电压,按下KEY0按键可以减小PA4引脚输出的电压 3. LED0闪烁,提示程序正在运行
37.1.2 硬件资源 1. LED LED0 - PB5 2. 正点原子2.8/3.5/4.3/7/10寸TFTLCD模块 3. 按键 WKUP - PA0 KEY0 - PE4 4. ADC2 Channel1 - PA1 5. DAC Channel1 - PA4
37.1.3 原理图 本章实验使用的DAC为STM32F103的片上资源,因此没有对应的连接原理图。
37.2 程序设计 37.2.1 HAL库的DAC驱动 本章实验主要使用DAC的Channel1(PA4引脚)输出指定的电压值(0V~3.3V),其具体的步骤如下: ①:初始化DAC ②:配置DAC通道 ③:开启DAC转换 ④:设置DAC输出值 在HAL库中对应的驱动函数如下: ①:初始化DAC 该函数用于初始化DAC的相关参数,其函数原型如下所示: - HAL_StatusTypeDef HAL_DAC_Init(DAC_HandleTypeDef *hdac);
复制代码该函数的形参描述,如下表所示: 表37.2.1.1 函数HAL_DAC_Init()形参描述 该函数的返回值描述,如下表所示: 表37.2.1.2 函数HAL_DAC_Init()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- DAC_HandleTypeDef dac_handle = {0};
-
- /* 初始化DAC */
- dac_handle.Instance = DAC;
- HAL_DAC_Init(&dac_handle);
- }
复制代码②:配置DAC通道 该函数用于配置DAC通道,其函数原型如下所示: - HAL_StatusTypeDef HAL_DAC_ConfigChannel( DAC_HandleTypeDef *hdac,
- DAC_ChannelConfTypeDef*sConfig,
- uint32_t Channel);
复制代码该函数的形参描述,如下表所示: 表37.2.1.3 函数HAL_DAC_ConfigChannel()形参描述 该函数的返回值描述,如下表所示: 表37.2.1.4 函数HAL_DAC_ConfigChannel()返回值描述 该函数使用DAC_ChannelConfTypeDef类型结构体指针传入了DAC通道的配置参数,该结构体的定义如下所示: - typedef struct
- {
- uint32_t DAC_Trigger; /* 外部触发源 */
- uint32_t DAC_OutputBuffer; /* 输出缓冲 */
- }DAC_ChannelConfTypeDef;
复制代码该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- DAC_ChannelConfTypeDef config = {0};
-
- /* 配置DAC通道 */
- config.DAC_Trigger =DAC_TRIGGER_SOFTWARE;
- config.DAC_OutputBuffer=DAC_OUTPUTBUFFER_DISABLE;
- HAL_DAC_ConfigChannel(&dac_handle, &config);
- }
复制代码③:开启DAC转换 该函数用于开启DAC转换,其函数原型如下所示: - HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel);
复制代码该函数的形参描述,如下表所示: 表37.2.1.5 函数HAL_DAC_Start()形参描述 该函数的返回值描述,如下表所示: 表37.2.1.6 函数HAL_DAC_Start()返回值描述 该函数的使用示例,如下所示: - #include"stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 开启DAC转换 */
- HAL_DAC_Start(&dac_handle, DAC_CHANNEL_1);
- }
复制代码④:设置DAC输出值 该函数用于设置DAC输出值,其函数原型如下所示: - HAL_StatusTypeDef HAL_DAC_SetValue( DAC_HandleTypeDef *hdac,
- uint32_t Channel,
- uint32_t Alignment,
- uint32_t Data);
复制代码该函数的形参描述,如下表所示: 表37.2.1.7 函数HAL_DAC_SetValue()形参描述 该函数的返回值描述,如下表所示: 表37.2.1.8 函数HAL_DAC_SetValue()返回值描述 该函数的使用示例,如下所示: - #include "stm32f1xx_hal.h"
- void example_fun(void)
- {
- /* 设置DAC输出值 */
- HAL_DAC_SetValue(&dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 1000);
- }
复制代码37.2.2DAC驱动 本章实验的DAC驱动主要负责向应用层提供DAC的初始化和配置其输出指定电压的函数。本章实验中,DAC的驱动代码包括dac.c和dac.h两个文件。 DAC驱动中,DAC的初始化函数,如下所示: - /**
- *@brief 初始化DAC
- *@param 无
- *@retval 无
- */
- void dac_init(void)
- {
- /* 配置DAC */
- g_dac_handle.Instance = DAC_DACX;
- HAL_DAC_Init(&g_dac_handle);
- HAL_DAC_Start(&g_dac_handle, DAC_DACX_CHY);
- }
- /**
- *@brief HAL库DAC初始化MSP函数
- *@param hdac: DAC句柄
- *@retval 无
- */
- voidHAL_DAC_MspInit(DAC_HandleTypeDef*hdac)
- {
- GPIO_InitTypeDef gpio_init_struct = {0};
- DAC_ChannelConfTypeDef dac_channel_conf_struct = {0};
-
- if (hdac->Instance == DAC_DACX)
- {
- DAC_DACX_CLK_ENABLE();
- DAC_DACX_CHY_GPIO_CLK_ENABLE();
-
- /* 配置DAC输出引脚 */
- gpio_init_struct.Pin = DAC_DACX_CHY_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_ANALOG;
- gpio_init_struct.Pull = GPIO_NOPULL;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(DAC_DACX_CHY_GPIO_PORT, &gpio_init_struct);
-
- /* 配置DAC通道 */
- dac_channel_conf_struct.DAC_Trigger = DAC_TRIGGER_NONE;
- dac_channel_conf_struct.DAC_OutputBuffer =DAC_OUTPUTBUFFER_DISABLE;
- HAL_DAC_ConfigChannel( &g_dac_handle,
- &dac_channel_conf_struct,
- DAC_DACX_CHY);
- }
- }
复制代码从上面的代码中可以看出,DAC的初始化函数会初始化DAC、配置DAC通道并开启DAC转换。 DAC驱动中,配置DAC通道输出指定电压的函数,如下所示: - /**
- *@brief 设置DAC输出电压
- *@param voltage: DAC输出电压(扩大1000倍)
- *@retval 无
- */
- voiddac_set_voltage(uint16_t voltage)
- {
- uint16_t value;
-
- value = (voltage * 4095) / 3300;
- value &= 0xFFF;
- HAL_DAC_SetValue(&g_dac_handle, DAC_DACX_CHY, DAC_ALIGN_12B_R, value);
- }
复制代码该函数将输入的电压模拟量转换为DAC输出的数字量后,将该值写入指定DAC通道的数据保持寄存器。
37.2.3 实验应用代码 本章实验的应用代码,如下所示: - extern DAC_HandleTypeDef g_dac_handle;
- int main(void)
- {
- uint8_t t = 0;
- uint8_t key;
- uint16_t dac_value;
- uint16_t dac_voltage = 100;
- uint16_t adc_value;
- uint16_t adc_voltage;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置时钟,72MHz */
- delay_init(72); /* 初始化延时 */
- usart_init(115200); /* 初始化串口 */
- led_init(); /* 初始化LED */
- key_init(); /* 初始化按键 */
- lcd_init(); /* 初始化LCD */
- adc_init(); /* 初始化ADC */
- dac_init(); /* 初始化DAC */
-
- lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
- lcd_show_string(30, 70, 200, 16, 16, "DACTEST", RED);
- lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
-
- lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+KEY0:-", RED);
-
- lcd_show_string(30, 130, 200, 16, 16, "DAC_CH1VAL:", BLUE);
- lcd_show_string(30, 150, 200, 16, 16, "DAC_CH1_VOL:0.000V", BLUE);
- lcd_show_string(30, 170, 200, 16, 16, "ADC2_CH1_VOL:0.000V", BLUE);
-
- /* 设置DAC输出电压 */
- dac_set_voltage(dac_voltage);
-
- while (1)
- {
- key = key_scan(0);
- if (key == WKUP_PRES)
- {
- /* 加大DAC输出 */
- if (dac_voltage < 3300)
- {
- dac_voltage += 100;
- dac_set_voltage(dac_voltage);
- }
- }
- else if (key == KEY0_PRES)
- {
- /* 减小DAC输出 */
- if (dac_voltage > 100)
- {
- dac_voltage -= 100;
- dac_set_voltage(dac_voltage);
- }
- }
-
- if (++t == 20)
- {
- t = 0;
-
- /* 显示DAC输出数字量 */
- dac_value = HAL_DAC_GetValue(&g_dac_handle, DAC_DACX_CHY);
- lcd_show_xnum(126, 130, dac_value, 4, 16, 0, BLUE);
-
- /* 显示DAC输出模拟量 */
- lcd_show_xnum(126, 150, dac_voltage / 1000, 1, 16, 0, BLUE);
- lcd_show_xnum(142, 150, dac_voltage % 1000, 3, 16, 0x80, BLUE);
-
- /* 显示ADC采集模拟量 */
- adc_value = adc_get_result_average(ADC_ADCX_CHY, 10);
- adc_voltage = (adc_value * 3300) / 4095;
- lcd_show_xnum(134, 170, adc_voltage / 1000, 1, 16, 0, BLUE);
- lcd_show_xnum(150, 170, adc_voltage % 1000, 3, 16, 0x80, BLUE);
-
- LED0_TOGGLE();
- }
-
- delay_ms(10);
- }
- }
复制代码可以看到,应用代码中不仅初始化了DAC的Channel1(PA4引脚)同时还使能了ADC2的Channel1(PA1引脚)用于采集DAC Channel1的输出电压。在完成初始化后,便不断地扫描按键并将DAC输出电压的模拟量和数字量以及ADC采集到电压的模拟量在LCD上进行显示,此时若扫描到KEY0按键,则减少DAC输出电压的数字量,若扫描到WKUP按键,则增加DAC输出电压的数字量。
37.3 下载验证 在完成编译和烧录操作后,可以看到LCD上实时刷新显示着DAC输出电压的模拟量和数字量以及ADC采集到电压的模拟量,此时可以将PA4引脚(DAC Channel1输出引脚)和PA4引脚(ADC Channel1采集引脚)通过杜邦线相连,在按下KEY0或WKUP按键来调整DAC通道1的输出电压,可以看到LCD上显示的DAC输出电压的模拟量和数字量以及ADC采集到电压的模拟量也随之变化,并且ADC采集到电压的模拟量也十分接近DAC输出电压的模拟量。 |