DAC简介:
stm32只有2个DAC,每个DAC有1个独立的通道,这和ADC有区别(有3个ADC,每个ADC有16个通道),特征如下:
DAC 功能框图
功能说明:
1 参考电压:
2 数模转换 输出通道:
注意,在使用DAC时,GPIO引脚一定要配置成模拟输入,不然没有输出,中文参考手册的描述:
3 触发源及DHRx寄存器:
双DAC 模式:
DAC 的寄存器描述:
1 控制寄存器DAC_CR
2 DAC 软件触发寄存器:
3 输入数据对齐寄存器:
4 双DAC输入数据寄存器:
5 输出数据寄存器(由软件写入):
定时器触发设置
1 定时器时基初始化,并配置触发源:
/**
* @brief 配置TIM
* @param 无
* @retval 无
*/
static void DAC_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 = (20-1); //定时周期 20
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //预分频,不分频 72M / (0+1) = 72M
TIM_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);
}
这里面使用到了TIM_SelectOutputTrigger函数,这个在之前 TIM 定时器章节几乎没有使用,来看一下源码实现:
/**
* @brief Selects the TIMx Trigger Output Mode.
* @param TIMx: where x can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 12 or 15 to select the TIM peripheral.
* @param TIM_TRGOSource: specifies the Trigger Output source.
* This paramter can be one of the following values:
*
* - For all TIMx
* @arg TIM_TRGOSource_Reset: The UG bit in the TIM_EGR register is used as the trigger output (TRGO).
* @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output (TRGO).
* @arg TIM_TRGOSource_Update: The update event is selected as the trigger output (TRGO).
*
* - For all TIMx except TIM6 and TIM7
* @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag
* is to be set, as soon as a capture or compare match occurs (TRGO).
* @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output (TRGO).
* @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output (TRGO).
* @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output (TRGO).
* @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output (TRGO).
*
* @retval None
*/
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource)
{
/* Check the parameters */
assert_param(IS_TIM_LIST7_PERIPH(TIMx));
assert_param(IS_TIM_TRGO_SOURCE(TIM_TRGOSource));
/* Reset the MMS Bits */
TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_MMS);
/* Select the TRGO source */
TIMx->CR2 |= TIM_TRGOSource;
}
可以看到,其实就是配置TIMx_CR2寄存器的对应位,寄存器描述如下:
我们希望给定时器一个计数值,当定时器溢出(更新中断)时,产生一个更新事件,正好作为DAC的定时器触发。
DAC配置(产生两路DAC模拟信号)
1 生成正弦波数据
/* 波形数据 ---------------------------------------------------------*/
const uint16_t Sine12bit[POINT_NUM] = {
2048 , 2460 , 2856 , 3218 , 3532 , 3786 , 3969 , 4072 ,
4093 , 4031 , 3887 , 3668 , 3382 , 3042 , 2661 , 2255 ,
1841 , 1435 , 1054 , 714 , 428 , 209 , 65 , 3 ,
24 , 127 , 310 , 564 , 878 , 1240 , 1636 , 2048
};
2 DMA配置:
/**
* @brief 配置DMA
* @param 无
* @retval 无
*/
static void DAC_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* 使能DMA2时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
/* 配置DMA2 */
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_ADDRESS; //外设数据地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit ; //内存数据地址 DualSine12bit
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向内存至外设
DMA_InitStructure.DMA_BufferSize = POINT_NUM; //缓存大小为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);
}
3 GPIO初始化:
/**
* @brief 使能DAC的时钟,初始化GPIO
* @param 无
* @retval 无
*/
static void DAC_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_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 配置DAC 通道1 */
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; //使用TIM2作为触发源
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不使用波形发生器
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //不使用DAC输出缓冲
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
/* 配置DAC 通道2 */
DAC_Init(DAC_Channel_2, &DAC_InitStructure);
/* 使能通道1 由PA4输出 */
DAC_Cmd(DAC_Channel_1, ENABLE);
/* 使能通道2 由PA5输出 */
DAC_Cmd(DAC_Channel_2, ENABLE);
/* 使能DAC的DMA请求 */
DAC_DMACmd(DAC_Channel_2, ENABLE);
}
4 定时器时基初始化和触发配置
/**
* @brief 配置TIM
* @param 无
* @retval 无
*/
static void DAC_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 = (20-1); //定时周期 20
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //预分频,不分频 72M / (0+1) = 72M
TIM_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);
}
5 生成双DAC数据(频率相同,幅值1/2),然后初始化双DAC:
/**
* @brief DAC初始化函数
* @param 无
* @retval 无
*/
void DAC_Mode_Init(void)
{
uint32_t Idx = 0;
DAC_Config();
DAC_TIM_Config();
/* 填充正弦波形数据(两路DAC幅值相差1/2),双通道右对齐*/
for (Idx = 0; Idx < POINT_NUM; Idx++)
{
DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx] / 2);
}
DAC_DMA_Config();
}
在主函数中进行测试:
main.c
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
*初始化DAC,开始DAC转换*/
DAC_Mode_Init();
while(1);
}
测试效果如图所示,波形生成正确。
上一篇:stm32专题三十四:独立看门狗 IWDG
下一篇:stm32专题三十六:MDK编译过程和文件类型(一)
推荐阅读
史海拾趣
进入XXXX年代,康龙公司意识到技术创新是企业持续发展的关键。于是,公司投入大量资金引进先进的生产设备和技术人才,加强研发力量。经过几年的努力,康龙在精密模具设计和开发方面取得了重大突破,大大提高了生产效率和产品精度。同时,公司还注重产品质量的提升,通过严格的质量控制和检验流程,确保每一件产品都符合客户的高标准要求。
CSR plc的创始人们怀揣着对音频技术的热情与追求,在剑桥这个科技创新的摇篮中开始了他们的征程。初创时期,公司的主要业务集中在音频领域,他们研发出了一系列创新的音频技术,为当时的移动设备市场带来了前所未有的听觉体验。这些技术的成功应用,不仅让CSR plc在行业内崭露头角,也为公司的后续发展奠定了坚实的基础。
随着技术的不断进步和产品的日益成熟,AVG开始积极寻求市场扩张的机会。公司先后进入多个国家和地区,通过设立分支机构和与当地企业建立合作关系,逐步扩大了市场份额。同时,AVG还注重品牌建设和提升,通过参加国际电子展会、举办技术研讨会等活动,提高了品牌知名度和影响力。这些举措使得AVG在全球电子行业中的地位逐渐提升。
进入21世纪后,汽车电子市场蓬勃发展,为Eris Tech提供了新的发展机遇。公司凭借在半导体技术方面的积累,成功开发出多款适用于汽车电子系统的半导体产品,如功率管理芯片、传感器等。这些产品不仅提高了汽车电子系统的性能,还降低了成本,赢得了汽车厂商的广泛认可。随着汽车电子市场的不断扩大,Eris Tech的营收也实现了快速增长。
为了更好地满足客户需求和推动业务发展,Crystek公司设立了专门负责频率控制的部门——Crystek Crystals和Crystek Microwave。这两个部门分别致力于开发和制造使用石英谐振器的频率产品以及为微波行业开发频率控制和支持产品。这种专业化的分工不仅提高了公司的运营效率,也使得Crystek公司能够更好地为客户提供定制化的解决方案和优质的服务。
Capax Technologies Inc的成功还得益于与各大企业的紧密合作。公司与多家知名的电子设备制造商建立了长期稳定的合作关系,为其提供高品质的组件和技术支持。通过与合作伙伴的共同努力,Capax Technologies Inc的产品得以广泛应用在各类电子设备中,进一步提升了公司的知名度和市场份额。
目的是向USB设备传输图像并显示 USB设备已经做好了 驱动正常 而且有测试程序 只要选择一个文件 点发送 最终设备就可以显示图像了 现在我要做的就是在另一个复杂点的程序中也实现这个功能 但是目前总是不成功 因为是第一次接触USB传输的领域 请大 ...… 查看全部问答∨ |
|
本人用 IAR 夹ST LINK 调试,用了几天都正常,今天突然出故障了,就是程序跑几秒钟之后,会跑到汇编行(Disassembly)的__DebugBreak的地方,找了好久的原因都不知所措,烦请学长指点。 1XH0NNOW2OM%_TLHW9I@P`A.jpg (8.86 KB) ...… 查看全部问答∨ |
|
ADC输入较大时,输出的数字值正确,但当输入较小时,输出就不对了,越接近零,错误越大。 芯片应该没问题,可能是layout的影响,哪些情况会出现这种干扰呢?… 查看全部问答∨ |
#define ONEWIRE_DQ 27 //OneWire 引脚int OneWire_Reset(int);int OneWire_ReadByte(int, int);int OneWire_ReadBit(int, int);void OneWire_WriteByte(int, int);void OneWire_WriteBit(int, int);int OneWire_DS18B20_ConvertTemperature( ...… 查看全部问答∨ |
刚刚玩这种板子,为什么9B96的历程在ARM 软件跑的时候都要修改PC,SP指针?不修改就不能正确运行程序 还有就是自己建的工程好像都不能正常运行。 历程里的map文件哪里来的? 有没有高手指点一二,谢谢了~… 查看全部问答∨ |