之前想写个程序能够控制STM32F103VET6的DAC双通道输出不同的电压值,并且能够通过串口控制两个通道电压实时可变化,但是在网上一直没找到资源,就反复的查看野火给的范例和数据手册DAC那块输出的讲解,最后整明白了分享给大家。
跟着我进行对比(野火的范例——双通道输出正弦波)的学习。
1、bsp_dac.h文件的修改
首先看一下野火在bsp_dac.h文件中如何定义的如下图

在这里野火定义了一个双DAC的 12 位右对齐数据保持寄存器(DAC_DHR12RD) ,我的理解是“双”字应该是说明这个寄存器是被双通道(PA4、PA5共用的),所以要想让两个通道输出不同的电压值,就必须重新定义这两个通道(PA4、PA5)的地址——定义成能一对一的模式,即一个单独的寄存器控制单独的一个。查看STM32官方中文参考手册的P194-P197页就会发现这两个通道(PA4、PA5)的确各自有控制自己的寄存器。下图为例。

#ifndef __DAC_H
#define __DAC_H
#include "stm32f10x.h"
//DAC 两个通道的寄存器地址,12位、右对齐、双通道
#define DAC_DHR12R1_ADDRESS          (DAC_BASE+0x08)
#define DAC_DHR12R2_ADDRESS          (DAC_BASE+0x14)
void DAC_OutVoltage(uint16_t VoltageLeft,uint16_t VoltageRight);
void DAC_Channel2_Config(void);
void DAC_Channel2_TIM_Config(void);
void DAC_Channel1_Config(void);
void DAC_Channel1_TIM_Config(void);
#endif /* __DAC_H */

请主要看我的两个地址的重新定义,其他是功能函数没什么好看的

2、bsp_dac.c文件的修改
在修改这块之前一定要看好这张图,当我们采用软件定时触发的方式更新寄存器内的值和DAC的输出(范例和我的过程都是通过刷新DAC的DMA来更新输出的)时,不是所有的定时触发都可用,仅限一下

接着我们来看一下DMA配置是几个比较重要的参数,先看野火范例

这里面我觉得一般使用时需要修改的,部分就是
①DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS; //外设数据地址
②DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit ; //内存数据地址 DualSine12bit
③DMA_InitStructure.DMA_BufferSize = POINT_NUM; //缓存大小为POINT_NUM字节
④DMA_Init(DMA2_Channel4, &DMA_InitStructure);
/* 使能DMA2-14通道 */
DMA_Cmd(DMA2_Channel4, ENABLE);
这四个部分,第一个就是我们在头文件中修改的重新定义的地址
第二个是要更新的数据,就是我们DAC要转换的那个数字
第三个是DMA要缓存更新的数据的数量(在野火范例中是要不断更新输出32的正弦波不同时候的值大小,所以范例中采用宏定义的方式数量写成32,如果要实时更新,宏定义把这里数量改成1进行)。
第四个是DMA的通道,DAC的两个输出通道(PA4、PA5)都有属于自己的DMA通道,因此要想实时控制双通道输出不同的值就要使能他们各自的DMA。如下图(这里就需要到手册的DMA那章去看了)

然后定时器配置那块不讲了,你可以照葫芦画瓢在写一个定时器,一个定时器触发一个DAC通道,一对一的触发,我就是这么干的,至于只用一个定时器触发行不行我没尝试。注意的是用两个定时触发两个通道(一对一的方式)的话,定时扫描设置的时间一定要不同,相同的话会出bug。

下面我把我写的,准确说修改的bsp_dac.c文件分享如下

#include "bsp_dac.h"
//正弦波单个周期的点数
#define POINT_NUM_Channel2 1
#define POINT_NUM_Channel1 1
uint32_t DualSine12bit_Channel2[POINT_NUM_Channel2];
uint32_t DualSine12bit_Channel1[POINT_NUM_Channel1];
/*** @brief  使能DAC的时钟,初始化GPIO,初始化DAC的两个通道DAC_Channel_1、DAC_Channel_2* @param  无* @retval 无*/
void DAC_Channel2_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;DAC_InitTypeDef  DAC_InitStructure;/* 使能GPIOA时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        /* 使能DAC时钟 */   RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); /* DAC的GPIO配置,模拟输入 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 配置DAC 通道2 */DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;                      //使用TIM2作为触发源DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;   //不使用波形发生器DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Enable;/* 配置DAC 通道2 */DAC_Init(DAC_Channel_2, &DAC_InitStructure);/* 使能通道2 由PA5输出 */DAC_Cmd(DAC_Channel_2, ENABLE);/* 使能DAC通道2的DMA请求 */DAC_DMACmd(DAC_Channel_2, ENABLE);
}
/*** @brief  配置TIM2* @param  无* @retval 无*/
void DAC_Channel2_TIM_Config(void)
{TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;/* 使能TIM2时钟,TIM2CLK 为72M */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    /* TIM2基本定时器配置 */// TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = (2-1);                                          //定时周期 20  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                                  //预分频,不分频 72M / (0+1) = 72MTIM_TimeBaseStructure.TIM_ClockDivision = 0x0;                         //时钟分频系数TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    //向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);/* 配置TIM2触发源 */TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);/* 使能TIM2 */TIM_Cmd(TIM2, ENABLE);
}
/*** @brief  配置DMA* @param  无* @retval 无*/
static void DAC_Channel2_DMA_Config(void)
{   DMA_InitTypeDef  DMA_InitStructure;/* 使能DMA2时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);/* 配置DMA2 */DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2_ADDRESS;                 //外设数据地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit_Channel2 ;             //内存数据地址 DualSine12bitDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                           //数据传输方向内存至外设DMA_InitStructure.DMA_BufferSize = POINT_NUM_Channel2;                                                                    //缓存大小为POINT_NUM字节  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;               //外设数据地址固定  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                    //内存数据地址自增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;  //外设数据以字为单位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;                 //内存数据以字为单位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                    //循环模式DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                          //高DMA通道优先级DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                        //非内存至内存模式  DMA_Init(DMA2_Channel4, &DMA_InitStructure);    /* 使能DMA2-14通道 */DMA_Cmd(DMA2_Channel4, ENABLE);
}
/***************************************************************通道1*********************************************/
void DAC_Channel1_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;DAC_InitTypeDef  DAC_InitStructure;/* 使能GPIOA时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        /* 使能DAC时钟 */   RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); /* DAC的GPIO配置,模拟输入 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 配置DAC 通道2 */DAC_InitStructure.DAC_Trigger = DAC_Trigger_T4_TRGO;                      //使用TIM2作为触发源DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;   //不使用波形发生器DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Enable;/* 配置DAC 通道1 */DAC_Init(DAC_Channel_1, &DAC_InitStructure);/* 使能通道2 由PA5输出 */DAC_Cmd(DAC_Channel_1, ENABLE);/* 使能DAC通道1的DMA请求 */DAC_DMACmd(DAC_Channel_1, ENABLE);
}
/*** @brief  配置TIM4* @param  无* @retval 无*/
void DAC_Channel1_TIM_Config(void)
{   TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;   /* 使能TIM2时钟,TIM2CLK 为72M */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  /* TIM2基本定时器配置 */// TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = (10-1);                                         //定时周期 20  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                                  //预分频,不分频 72M / (0+1) = 72MTIM_TimeBaseStructure.TIM_ClockDivision = 0x0;                         //时钟分频系数TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;    //向上计数模式TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);/* 配置TIM4触发源 */TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Update);/* 使能TIM4 */TIM_Cmd(TIM4, ENABLE);
}
/*** @brief  配置DMA* @param  无* @retval 无*/
static void DAC_Channel1_DMA_Config(void)
{   DMA_InitTypeDef  DMA_InitStructure;/* 使能DMA2时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);/* 配置DMA2 */DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1_ADDRESS;                 //外设数据地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit_Channel1 ;             //内存数据地址 DualSine12bitDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                                           //数据传输方向内存至外设DMA_InitStructure.DMA_BufferSize = POINT_NUM_Channel1;                                                                    //缓存大小为POINT_NUM字节  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;               //外设数据地址固定  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                    //内存数据地址自增DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;  //外设数据以字为单位DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;                 //内存数据以字为单位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                    //循环模式DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                          //高DMA通道优先级DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                        //非内存至内存模式  DMA_Init(DMA2_Channel3, &DMA_InitStructure);    /* 使能DMA2-13通道 */DMA_Cmd(DMA2_Channel3, ENABLE);
}
/*************************************************************电压输出函数********************************/
/*** @brief  DAC电压输出函数* @param  Voltage* @retval 无*/
void DAC_OutVoltage(uint16_t VoltageLeft,uint16_t VoltageRight)
{uint32_t Idx = 0,Idy=0; DualSine12bit_Channel1[Idy] = (VoltageRight << 16) + (VoltageRight);DualSine12bit_Channel2[Idx] = (VoltageLeft << 16) + (VoltageLeft);DAC_Channel2_DMA_Config();DAC_Channel1_DMA_Config();
}

这个.C文件总结来说就是每一个DAC输出通道配一个DMA通道和一个软件定时触发。

至于怎么通过串口实时修改输出的值,代码如下,虽然只是串口接收.C文件的一部分,但我想看过野火WIFI那章节的人一看就明白了,不多说。

else if( ( pCh = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "Speed_" ) ) != 0 ) {SpeedTemp1 = * ( pCh + 6 )-0x30;SpeedTemp2 = * ( pCh + 7 )-0x30;SpeedTemp3 = * ( pCh + 8 )-0x30;SpeedTemp4 = * ( pCh + 9 )-0x30;SpeedTemp5 = * ( pCh + 10 )-0x30;SpeedTemp6 = * ( pCh + 11 )-0x30;SpeedTemp7 = * ( pCh + 12 )-0x30;SpeedTemp8 = * ( pCh + 13 )-0x30;SpeedLeft = SpeedTemp1*1000+SpeedTemp2*100+SpeedTemp3*10+SpeedTemp4;SpeedRight = SpeedTemp5*1000+SpeedTemp6*100*SpeedTemp7*10+SpeedTemp8;DAC_OutVoltage(SpeedLeft,SpeedRight);            }

这样就能通过串口改变STM32F103VET6的两个DAC输出通道的电压输出大小(0-3.3V之间变化),实现实时变化。

个人学习心得,有什么讲的不对的地方请指出。

STM32F103VET6——DAC双通道(PA4、PA5)输出不同电压值,串口可控电压输出的大小相关推荐

  1. STM32配置DAC输出固定电压和方波

    STM32F103VCT6自带两个12位DAC,DAC的转换速度一直没有查到,网上有人说是1MHZ的频率,那就是1us了.ADC的转换时间在56MHZ工作频率下为1us,在72MHZ工作频率下为1.1 ...

  2. STM32F103VET6基于HAL库和标准库下DAC 心形波形输出

    STM32F103VET6基于HAL库和标准库下DAC 心形波形输出

  3. DAC双通道输出电压实验

    更多交流欢迎关注作者抖音号:81849645041 目的 了解DAC数模转换工作原理,利用DAC两个通道输出电压,结合ADC读取引脚电压. 原理 DAC 为数字/模拟转换模块,它的作用就是把输入的数字 ...

  4. STM32CubeMX学习笔记(20)——DAC接口使用(输出正弦波)

    一.DAC简介 DAC(Digital-to-Analog Converter),即数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与 ADC 相反.在常 ...

  5. 嵌入式实验(四):用STM32输出PWM波形/DAC功能完成波形输出

    0 实验目标 用STM32F103输出一路PWM波形,建议采用定时器方法.野火和网上大多数资源采用此方法,有完整源码.用示波器观察输出波形. 用STM32F103的DAC功能完成以下波形输出,用示波器 ...

  6. T46 Keithley 2612如何输出高电压?

    Keithley 2612如何输出高电压? Error Code: 802 OUTPUT blocked by interlock 硬件 软件 Voltage compliance Source> ...

  7. STM32F103的DAC功能实现音频输出

    本次实验主要内容:用Adobe audition或goldwave等音频编辑软件录制"您好欢迎光临!"的几秒钟的声音(8khz采样.8bit量化编码的单声道wav格式),确保音频数 ...

  8. 【硬件】如何使用直流稳压源输出负电压?

    创作时间:2020-11-07 如何使用直流稳压源输出负电压? 1)先看看三脚插头 经过测量这个地和稳压源的三脚供电插头的EARTH通 2)看看直流稳压源的输出. 稳压源上有3个接线柱 红色 : + ...

  9. 手机常用的快充QC2.0/3.0协议,你都了解吗?设备(比如支持快充的手机)通过USB数据通讯口D+/D-输出电压信号给充电器,充电器内置USB输入解码芯片,然后充电器会输出目标电压。

    手机常用的快充QC2.0/3.0协议,你都了解吗? 零是起源 资料共享- 公众号:零是起源 15 人赞同了该文章 何谓快充QC2.0/3.0协议? 1.QC2.0协议 QC2.0就是Quick Cha ...

最新文章

  1. 中one_气场不比BBA差,续航里程远、加速快的理想ONE值得买吗?
  2. php 小数末尾进1,PHP处理浮点数进一、去尾(不进行四舍五入) | 剑花烟雨江南...
  3. 2021年3月12日 北京格灵深瞳Java开发实习面试(一面)
  4. Eclipse将android 类编译为jar类库
  5. 华为“燃料”助力荣耀向上,全力冲击高端市场
  6. Programming WCF Services 学习笔记四、Instance Management
  7. 10.1 分别通过函数和重载运算符来实现复数相加
  8. python3.6 django部署_Centos7 django+uwsgi+nginx+python3.6.8部署
  9. matlab红外图像温度提取,一种基于红外热图的温度提取方法.pdf
  10. 组合式应用新利器?SaaS新时代事件网格如何解决集成标准化问题
  11. 2017.6.6 数表 思考记录
  12. mysql 5.6 没死_MySQL 5.6不删空用户的影响
  13. 带宽和下载速率的关系
  14. 付出与收获对等的自然法则,执行力离开去做马上去做
  15. 关于单页面应用一些随想
  16. Git Your branch is ahead of ‘origin/master‘ by X commits解决方法
  17. stosb, stosw, stosd 汇编指令
  18. 2021年苹果手机绕ID解锁教程-附使用工具
  19. 在 Word 中插入 Latex 公式
  20. 2023年天津天狮学院专升本市场营销专业《管理学》考试大纲

热门文章

  1. C/C++内存管理器
  2. 计算机的基础配置,教你认知电脑基本配置
  3. pyqt5中利用搜索框和按钮,搜索表中内容
  4. 系统时不变性与因果性的判断总结
  5. 微信引流推广:美拍视频简单的引流方法分享
  6. 产品:“嘘,这事千万别让开发知道”
  7. python字符串与十六进制互相转换
  8. 财经小知识:美国国债
  9. Android安全检测之加固的坑
  10. echarts图表的自适应处理,包含同页面单个图表和多个图表两种情况