初识STM32的PWM和DAC

一、PWM

1、PWM介绍

PWM是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调 制,简称脉宽调制。STM32F1除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出 。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出 。而通用定时器也能同时产生多达 4路的 PWM 输出,这些在定时器中断 章节中已经介绍过。 PWM的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号 ,信号频率是由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。
在这里插入图片描述
PWM输出比较模式总共有8种,具体由寄存器 CCMRx 的位 OCxM[2:0] 配置。最常用的两种PWM输出模式:PWM1和PWM2:
在这里插入图片描述

PWM输出配置:

  • 使能定时器及端口时钟,并设置引脚复用器映射
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE); //可选的参数在 stm32f10x_gpio.h 都已经列出来非常详细
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
  • 初始化定时器参数,包含自动重装值,分频系数,计数方式等
void TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
  • 初始化PWM输出参数,包含PWM模式、输出极性,使能等
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
  • 开启定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); TIM_Cmd(TIM3,ENABLE); //开启定时器
  • 修改TIMx_CCRx的值控制占空比
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1);
  • 使能TIMx在CCRx上的预装载寄存器 使能输出比较预装载库函数是:
void  TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

第一个参数用于选择定时器,第二个参数用于选择使能还是失能输出比较预装载寄存器,可选择为TIM_OCPreload_Enable、TIM_OCPreload_Disable。

  • 使能 TIMx 在 ARR 上的预装载寄存器允许位 使能 TIMx 在 ARR 上的预装载寄存器允许位库函数是:
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);  //第一个参数用于选择定时器,第二个参数用于选择使能还是失能。

高级定时器要想输出PWM波形,必须要设置一个 MOE 位(TIMx_BDTR 的第 15 位),以使能主输出,否则不会输出 PWM。库函数设置的函数为:

   void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
2、用STM32F103输出一路PWM波形

实验代码可参考野火官方给的资料。
部分代码:

void LED_GPIO_Config(void)
{		
		/*定义一个GPIO_InitTypeDef类型的结构体*/
		GPIO_InitTypeDef GPIO_InitStructure;

		/*开启LED相关的GPIO外设时钟*/
		RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE);
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;	

		/*设置引脚模式为通用推挽输出*/
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

		/*设置引脚速率为50MHz */   
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

		/*调用库函数,初始化GPIO*/
		GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);	
		
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;

		/*调用库函数,初始化GPIO*/
		GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
		
		/*选择要控制的GPIO引脚*/
		GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;

		/*调用库函数,初始化GPIOF*/
		GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);

		/* 关闭所有led灯	*/
		GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
		
		/* 关闭所有led灯	*/
		GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);	 
    
    /* 关闭所有led灯	*/
		GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
}

main.c函数:

int main(void)
{
	/* led 端口配置 */ 
	LED_GPIO_Config();
	
	/* 定时器初始化 */
	GENERAL_TIM_Init();
	
  while(1)
  {      
  }
}

点击Options For Target进行如下配置:
在这里插入图片描述
然后点击OK。
接下来点击仿真按钮:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最后点击运行仿真:
在这里插入图片描述
在这里插入图片描述
结果如下:
在这里插入图片描述

将程序下载到指南针开发板上,用示波器观察如下:

在这里插入图片描述
在这里插入图片描述

二、用STM32F103的DAC功能完成波形输出

1、DAC简介

       DAC 为数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对应的模拟电压输出,它的功能与 ADC 相反。在常见的数字信号系统中,大部分传感器信号被化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码,由计算机处理完成后,再由 DAC 输出电压模拟信号,该电压模拟信号常常用来驱动某些执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。
       STM32 具有片上 DAC 外设,它的分辨率可配置为 8 位或 12 位的数字输入信号,具有两个 DAC 输出通道,这两个通道互不影响,每个通道都可以使用 DMA 功能,都具有出错检测能力,可外部触发。

2、输出一个周期2khz的正弦波

打开野火官方的的DAC例程,在此例程上进行操作。
根据定时器的配置,可推算出正弦波频率的计算方式:
在这里插入图片描述
可根据上述公式计算出周期为2KHz的正弦波的定时周期为1125。

  */
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 = (1125-1);       									//定时周期 1125
  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);

}

在这里插入图片描述

3、将一段数字音频歌曲数据转换为模拟音频波形输出

首先下载一首自己喜欢的歌曲,用Adobe Audition CS6打开;
然后截取歌曲的一部分:
在这里插入图片描述

在这里插入图片描述
保存为.wav文件,且频率为8kHz,量化16bit;
在这里插入图片描述

然后用UltraEdit打开刚刚我们保存的文件;
在这里插入图片描述
点击Ctrl+A全选,右键选择“十六进制复制选定视图”;
在这里插入图片描述
然后新建文件,粘贴;
在这里插入图片描述
右键“选择范围”;
在这里插入图片描述
在这里插入图片描述
将选中的内容复制下来,放在一个新文件里面,然后用notepad++打开,点击编辑→列块编辑→插入文本,生成结果如下:

在这里插入图片描述
在这里插入图片描述
将上面得到的十六进制文本复制(由于太长,我只选择了一部分);

0x52 ,0x49 ,0x46 ,0x46 ,0xCC ,0x51 ,0x01 ,0x00 ,0x57 ,0x41 ,0x56 ,0x45 ,0x66 ,0x6D ,0x74 ,0x20 ,
0x12 ,0x00 ,0x00 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00 ,0x40 ,0x1F ,0x00 ,0x00 ,0x80 ,0x3E ,0x00 ,0x00 ,
0x02 ,0x00 ,0x10 ,0x00 ,0x00 ,0x00 ,0x64 ,0x61 ,0x74 ,0x61 ,0x8E ,0x37 ,0x01 ,0x00 ,0x5E ,0xFF ,
0x85 ,0x00 ,0xA7 ,0x01 ,0x90 ,0x00 ,0xBE ,0xFF ,0x08 ,0x00 ,0xFE ,0x00 ,0xC5 ,0xFC ,0x79 ,0x00 ,
0xCD ,0xFE ,0xEA ,0xFF ,0x3B ,0xFF ,0xC7 ,0x00 ,0xE6 ,0x00 ,0xA4 ,0xFF ,0x8D ,0xFF ,0x82 ,0x01 ,
0xDD ,0xFF ,0x7A ,0x00 ,0x6B ,0x00 ,0xFF ,0xFF ,0xEE ,0xFF ,0x5F ,0x00 ,0x4D ,0xFF ,0x94 ,0xFF ,
0x15 ,0x00 ,0xD4 ,0xFE ,0xD5 ,0x00 ,0xB2 ,0xFF ,0xAE ,0x00 ,0xBA ,0x00 ,0x38 ,0x01 ,0x4D ,0xFF ,
0x65 ,0x00 ,0x83 ,0xFE ,0x21 ,0xFF ,0xF5 ,0xFF ,0x0A ,0x00 ,0x20 ,0xFF ,0xBA ,0x00 ,0xA1 ,0x00 ,
0x5A ,0x00 ,0x07 ,0x00 ,0x27 ,0x00 ,0xA2 ,0x00 ,0x96 ,0xFF ,0xB7 ,0x00 ,0x6F ,0x00 ,0xA0 ,0xFF ,
0x4F ,0x00 ,0x29 ,0xFF ,0xCE ,0xFF ,0x77 ,0x00 ,0x3A ,0xFE ,0x46 ,0x01 ,0xF7 ,0xFE ,0x08 ,0x02 ,
0x5F ,0x00 ,0x4B ,0x00 ,0x98 ,0x00 ,0x69 ,0xFF ,0x9E ,0xFE ,0x61 ,0xFE ,0xE4 ,0xFF ,0x4C ,0x00 ,
0xBB ,0xFF ,0xE6 ,0x00 ,0x62 ,0x00 ,0x48 ,0xFF ,0xF6 ,0xFF ,0xE6 ,0xFF ,0xB3 ,0x00 ,0x89 ,0xFF ,

然后复制到代码当中:
在这里插入图片描述

然后连接硬件,下载程序,运行仿真:
在这里插入图片描述

三、总结

PWM和DAC有些难,作为初学者还需要慢慢理解和实践。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值