STM32F407寄存器操作(定时器触发DAC+DMA)

目录

  • 背景
  • 配置流程
    • DAC
    • DMA
  • 寄存器
    • TIM4
      • TIM4->CR2
    • DAC
      • DAC->CR
    • DMA
      • DMA1_Stream5 ->CR
  • 程序
    • TIM4
    • DAC
    • DMA
  • 结尾

背景

让单片机生成各种波可以说是非常常见的情况,从基础的PWM到SVPWM,SIN。可以说DAC也是非常重要的一环。
假设我需要一个500K的sin函数怎么办呢?于是就需要用到一个东西就是定时器触发DAC,我们也可以用DMA将大量的数据搬到DAC的寄存器里面,实现非常流畅的效果。
好了,废话少说下面我们开始吧

配置流程

DAC

首先我们看一下那些定时器可以触发DAC
STM32F407寄存器操作(定时器触发DAC+DMA)_第1张图片
大家看到TRGO就蒙了,这啥玩意?怎么听都没听过?
别怕,其实这个事件是专门用于STM32用于触发内部东西的一个事件,

大家也不要慌,这个事件配置起来非常简单,比PWM配置的还简单,这里我就以TIM4的TRGO举例了。

DMA

STM32F407寄存器操作(定时器触发DAC+DMA)_第2张图片
STM32F407寄存器操作(定时器触发DAC+DMA)_第3张图片
这里大家可以看一看,没有什么特别重要的东西

STM32F407寄存器操作(定时器触发DAC+DMA)_第4张图片
可以看到的是DAC全都在DMA1上面而ADC全都在DMA2上,也就是说我们可以做到ADC一边读,DAC一边写,而我经过实践也确实证明了这个方案可行。

寄存器

TIM4

TIM4->CR2

STM32F407寄存器操作(定时器触发DAC+DMA)_第5张图片
主要是第4位
STM32F407寄存器操作(定时器触发DAC+DMA)_第6张图片
这里将模式写成2——更新模式

对就这么简单,配置好模式,设置好分频和重装值就能触发DAC了

DAC

DAC->CR

STM32F407寄存器操作(定时器触发DAC+DMA)_第7张图片

主要是第4位
STM32F407寄存器操作(定时器触发DAC+DMA)_第8张图片
配置好相关事件,看好注意事项。

第12位
在这里插入图片描述

第0,1位
STM32F407寄存器操作(定时器触发DAC+DMA)_第9张图片
第3位
STM32F407寄存器操作(定时器触发DAC+DMA)_第10张图片

DMA

DMA1_Stream5 ->CR

STM32F407寄存器操作(定时器触发DAC+DMA)_第11张图片
第6-14位
STM32F407寄存器操作(定时器触发DAC+DMA)_第12张图片
相信用到这个的盆友都非常了解DMA了,我就不过多解释了。我配置的是存储器到外设模式,禁止循环模式,外设指针固定,存储器指针递增,一次传输半个字节。
这里注意一下,DAC一共有四个数据寄存器分别是12位的两个,8位的两个。大家注意指定好放在哪个寄存器里面,否则输出电压和理论值是不一样的。

程序

TIM4

void tim4_pwm(unsigned int arr4,unsigned int psc4)
{
	RCC->APB1ENR|=1<<2;		//TIM4时钟使能
	
	TIM4->ARR=arr4;		//设定计数器自动重装值 
	TIM4->PSC=psc4;		//设定计数器分频
	
	TIM4->CR2|=2<<4;		//触发TRGO
	TIM4->CR1|=0x01;    	//使能定时器4
}

DAC

void init_alladc(void)
{
	RCC->APB1ENR|=1<<29;//开启DAC时钟
	RCC->AHB1ENR|=1<<0;//开启GPIOA时钟
}

void init_dac1(void)
{
	GPIOA->MODER|=3<<8;//PA4模拟输入
	GPIOA->PUPDR|=2<<8;//PA4下拉模式
	
	DAC->CR|=1<<0;//使能DAC1通道
	DAC->CR|=(1<<1);//使能DAC1输出通道缓冲器
	
	DAC->CR|=1<<2;//DAC1通道触发使能
	DAC->CR|=5<<3;//TIM4 TRGO事件触发DAC1
	
	DAC->CR|=1<<12;//DAC1通道DMA使能
}

DMA

//初始化DMA1 组5 通道7
//DAC1
void init_DMA1_S5C7(unsigned short DACWEI)
{	
	DMA1_Stream5 ->CR   = 0;//禁止数据流 ,才能写寄存器 
	
	//外设地址寄存器
	//将所需寄存器的地址放入PAR寄存器
	DMA1_Stream5 ->PAR  = (unsigned int)(&DAC->DHR12R1);
	
	//数据流地址寄存器
	//M1AR仅在双通道模式下有用
	//将数据所在地址给M0AR寄存器
	DMA1_Stream5 ->M0AR = (unsigned int)(&(FMSin));
	
	DMA1_Stream5 ->NDTR = DACWEI;			// 一次传输数量
	DMA1_Stream5 ->FCR  = 0x21;		//FIFO所有配置失效
	DMA1_Stream5 ->CR |= 1<< 6;		//储存器到外设模式
	
	//循环模式:
	//当NDTR寄存器减到0时自动重装
	//单次模式(普通模式):
	//NDTR减到0后停止DMA
	DMA1_Stream5 ->CR |= 1<< 8;   //循环模式
	DMA1_Stream5 ->CR |= 0<< 9;   //外设非增量模式
	DMA1_Stream5 ->CR |= 1<<10;   //存储器增量模式,指针增加,可用于传输数组
	DMA1_Stream5 ->CR |= 1<<11;		//外设数据长度:16位
	DMA1_Stream5 ->CR |= 1<<13;		//存储器数据长度:16位
	DMA1_Stream5 ->CR |= 1<<16;   //中等优先级
	
	//突发传输
	//DMA占用CPU总线时间,此时CPU无法工作
	//一个节拍:传输多少次32位变量
	//应用场景:从ram里读出字节
	DMA1_Stream5 ->CR |= 0<<21;   //外设突发单次传输
	DMA1_Stream5 ->CR |= 0<<23;   //存储器突发单次传输
	
	DMA1_Stream5 ->CR |= 7<<25;   //通道7
	DMA1_Stream5 ->CR |= 1<<0;    //使能数据流
}

结尾

还是那句话,程序上不可能无脑搬的,希望大家能汇总各家所长,理解后写出属于自己风格的驱动程序,若还有不懂的,可以评论区留言,祝愿大家学有所成。

你可能感兴趣的:(stm32,单片机,arm)