STM32的PWM和DAC练习

相关简介

PWM是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调 制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控 制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成 为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信, 功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些 音频放大器,因此学习PWM具有十分重要的现实意义。 其实我们也可以这样理解,PWM是一种对模拟信号电平进行数字编码 的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个 具体模拟信号的电平进行编码。PWM 信号仍然是数字的,因为在给定的 任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压 或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去 的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被 断开的时候。只要带宽足够,任何模拟值都可以使用 PWM 进行编码。

一、用STM32F103输出一路PWM波形

1.找到野火提供的官方资料,并且打开。
在这里插入图片描述
2.主函数代码:

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_AdvanceTim.h"  
int main(void)
{	
	ADVANCE_TIM_Init();
  while(1)
  {      
  }
}

3.通过主函数查看相关函数代码。
在这里插入图片描述
4.相关函数代码:

static void ADVANCE_TIM_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

  // Êä³ö±È½ÏͨµÀ GPIO ³õʼ»¯
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

  // Êä³ö±È½ÏͨµÀ»¥²¹Í¨µÀ GPIO ³õʼ»¯
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1N_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

  // Êä³ö±È½ÏͨµÀɲ³µÍ¨µÀ GPIO ³õʼ»¯
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_BKIN_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
	// BKINÒý½ÅĬÈÏÏÈÊä³öµÍµçƽ
	GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);	
}
static void ADVANCE_TIM_Mode_Config(void)
{
  // ¿ªÆô¶¨Ê±Æ÷ʱÖÓ,¼´ÄÚ²¿Ê±ÖÓCK_INT=72M
	ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);

/*--------------------ʱ»ù½á¹¹Ìå³õʼ»¯-------------------------*/
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	// ×Ô¶¯ÖØ×°ÔؼĴæÆ÷µÄÖµ£¬ÀÛ¼ÆTIM_Period+1¸öƵÂʺó²úÉúÒ»¸ö¸üлòÕßÖжÏ
	TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;	
	// Çý¶¯CNT¼ÆÊýÆ÷µÄʱÖÓ = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;	
	// ʱÖÓ·ÖƵÒò×Ó £¬ÅäÖÃËÀÇøʱ¼äʱÐèÒªÓõ½
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	// ¼ÆÊýÆ÷¼ÆÊýģʽ£¬ÉèÖÃΪÏòÉϼÆÊý
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	// Öظ´¼ÆÊýÆ÷µÄÖµ£¬Ã»Óõ½²»ÓùÜ
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	// ³õʼ»¯¶¨Ê±Æ÷
	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

	/*--------------------Êä³ö±È½Ï½á¹¹Ìå³õʼ»¯-------------------*/		
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	// ÅäÖÃΪPWMģʽ1
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	// Êä³öʹÄÜ
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	// »¥²¹Êä³öʹÄÜ
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 
	// ÉèÖÃÕ¼¿Õ±È´óС
	TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;
	// Êä³öͨµÀµçƽ¼«ÐÔÅäÖÃ
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	// »¥²¹Êä³öͨµÀµçƽ¼«ÐÔÅäÖÃ
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
	// Êä³öͨµÀ¿ÕÏеçƽ¼«ÐÔÅäÖÃ
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	// »¥²¹Êä³öͨµÀ¿ÕÏеçƽ¼«ÐÔÅäÖÃ
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
	TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);

	TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
  TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
  TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
  TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
  
  TIM_BDTRInitStructure.TIM_DeadTime = 11;
  TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

  TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
  TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
  TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);
	
	// ʹÄܼÆÊýÆ÷
	TIM_Cmd(ADVANCE_TIM, ENABLE);	
	// Ö÷Êä³öʹÄÜ£¬µ±Ê¹ÓõÄÊÇͨÓö¨Ê±Æ÷ʱ£¬Õâ¾ä²»ÐèÒª
	TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
}

主函数主要通过调用上述两个函数代码实现
下图是采用调试功能进行波形的查看。
在这里插入图片描述

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

(一)DAC简介

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

(二)输出一个周期2khz的正弦波

1.根据提供资料,找到相应的程序代码。
在这里插入图片描述
2.找到sinWave.m文件,使用MATLAB打开。
在这里插入图片描述
3.具体代码,注意这里是进行修改过后的代码,主要是将采样点扩展到3600个。

%用于产生正弦数据表,输出到文件dac_sinWave.c 文件中,复制到c语言数组即可

n = 2*pi/3600 : 2*pi/3600 : 2*pi      %分成3600等份

a = sin(n)+1;                     %求取sin函数值并向上平移一个单位,消除负数值
a = a * 3.3/2;                    %调整幅值,使范围限制为0~3.3   
r = a* (2.^12) /3.3               %求取dac数值,12位dac LSB = 3.3/2.^12 
r = uint16(r);                     %把double型数据转化成16位整型数据 

for i = 1:32                        
if r(i) > 4095                      %限制数据最大不超过4095
    r(i) = 4095
end
end 

dlmwrite('dac_sinWave.c',r);      %把数据写入到文件,方便添加到stm32工程中
plot(n,r,'.')                     %把这些点画出来 

4.运行过后,可以看到如下的图形,是由3600个采样点构成。
在这里插入图片描述
5.运行过后,可以查看如下图所示的文件,这是通过MATLAB生成的采样点。
在这里插入图片描述
6.打开之后,可以看到如下代码,将这些采样点进行复制。
在这里插入图片描述
7.找到const uint16_t Sine12bit[POINT_NUM]数组,将上一步中代码复制到该数组中。
在这里插入图片描述
注意调整格式,不然会报错

8.主函数代码:

#include "stm32f10x.h"
#include "./dac/bsp_dac.h"
int main(void)
{
			DAC_Mode_Init();
  	  while(1);	 
}

9.将程序代码烧录进开发板,同时,示波器接PA4接口,观察波形,下图的波形有一定误差,同时连接蜂鸣器,可以听到“嘀”的声音。
在这里插入图片描述

(三)将一段数字音频歌曲数据转换为模拟音频波形输出

1.将自己喜欢的歌曲或者音频用AU软件打开,如下两张图所示。
在这里插入图片描述
在这里插入图片描述
2.用鼠标拖动红色线选中一块区域,点击右键选择存储选区为。
在这里插入图片描述
3.按照下图进行设置,同时要设置为16位。
在这里插入图片描述
4.使用Ultraedit打开刚刚保存的音频资料。
在这里插入图片描述
5.用键盘Ctrl+A全选,鼠标右键,点击十六进制复制所选视图,如下图所示。
在这里插入图片描述
6.新建一个文件,将刚刚选中的编码复制进去,并点击右键,选择范围进行设置。
在这里插入图片描述
7.再次复制,新建一个文件,保存,用notepad文件,点击编辑,列块编辑第一列插入0x,剩下的插入0x和,最后插入。
在这里插入图片描述
8.打开野火提供的程序代码,将编码复制进去,然后将程序烧录进入开发板即可,步骤同上,最后结果如下图所示。
在这里插入图片描述

三、总结

本次我们了解了PWM和DAC,通过STM32,了解到数字信号、模拟信号相关的操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值