STM的PWM和DAC
目录
一、STM32F103输出PWM
本部分参考自博客:(stm32f103学习总结)—stm32 PMW输出实验
PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式。
其实我们也可以这样理解,PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。
1.STM32F1 PWM介绍
STM32F1除了基本定时器TIM6和TIM7,其他定时器都可以产生PWM输出 。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出 。而通用定时器也能同时产生多达 4路的 PWM 输出,这些在定时器中断 章节中已经介绍过。 PWM的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号 ,信号频率是由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。
PWM输出比较模式总共有8种,具体由寄存器 CCMRx 的位 OCxM[2:0] 配置。我们这里只讲解最常用的两种PWM输出模式:PWM1和PWM2,其他几 种模式可以参考《STM32F10x中文参考手册》13、14、15定时器章节。
PWM1和PWM2这两种模式用法差不多,区别之处就是输出电平的极性不 同。
2.源码示例
main.c
#include "stm32f10x.h"
#include "./dac/bsp_dac.h"
int main(void)
{
/*初始化DAC,开始DAC转换*/
DAC_Mode_Init();
while(1);
}
bsp_dac.c
#include "./dac/bsp_dac.h"
//正弦波单个周期的点数
#define POINT_NUM 32
/* 波形数据 ---------------------------------------------------------*/
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
};
uint32_t DualSine12bit[POINT_NUM];
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);
/* DA的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);
}
static void DAC_TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/*使能TIMz时钟,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);
}
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);
}
void DAC_Mode_Init(void)
{
uint32_t Idx = 0;
DAC_Config();
DAC_TIM_Config();
/*填充正弦波形数据,双通道右对齐
*/
for (Idx = 0; Idx < POINT_NUM; Idx++)
{
DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);
}
DAC_DMA_Config();
}
3.进行配置
点击魔术棒
进行模拟配置 Use Simulator
进行调试
进入调试页面
点击进行波形配置
点击Setup
可以进行颜色等的设置 ↑
点击进行运行 ↓
可以看到出现波形
通过鼠标滚轮可以对疏密显示进行调节
实现PWM波形
二、STM32实现DAC输出
1.DAC的基本介绍
本部分参考自博客: 【STM32】DAC基本原理、寄存器、库函数(DAC一般步骤)
-
DAC的基本定义
Digital-to-Analog Converter的缩写。指数/模转换器或者数字/模拟转换器。是指将离散的数字信号转换为连续变量的模拟信号的器件。
典型的数字模拟转换器将表示一定比例电压值的数字信号转换为模拟信号。
STM32的DAC模块是12位数字输入,电压输出型的DAC。 -
DAC的主要特征
2个DAC转换器:每个转换器对应1个输出通道;
8位或者12位单调输出;
12位模式下数据左对齐或者右对齐;
同步更新功能;
噪声波形生成;
三角波形生成;
双DAC通道同时或者分别转换;
每个通道都有DMA功能;
外部触发转换;
输入参考电压VREF+。 -
DAC的工作框图
-
DAC转换
不能直接对寄存器DAC_DORx写入数据,任何输出到DAC通道x的数据都必须写入DAC_DHRx寄存器(数据实际写入DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD、或者DAC_DHR12RD寄存器)。
如果没有选中硬件触发(寄存器DAC_CR1的TENx位置0),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx;
如果选中硬件触发(寄存器DAC_CR1的TENx位置1),数据传输在触发发生以后3个APB1时钟周期后完成。
一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间tSETTLING之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。
2.制作一段正弦波并用示波器观看
① 使用Adobe Audition CS6制作正弦波
首先打开Adobe Audition CS6
新建音频文件
设置参数
点击效果→生成基本音色
生成正弦波
生成正弦波如图
保存为wav文件
可以看到生成了wav文件
② 使用Ultraedit与nodepad++处理音频
打开Ultraedit
点击导入wav文件
Ctrl+A全选,选择16进制复制所选视图
粘贴到另一个新建文件中
右击设置选择范围
设置一个合适的范围
将文件用nodepad++打开
设置列块编辑
将每一列都插入0x
以txt格式保存在记事本中
然后把得到的代码复制到野火的官方模板DAC输出中。删掉const uint8_t Sine12bit[]
函数括号里的参数
3.将一段数字音频歌曲数据转换为模拟音频波形输出
① 使用Au处理音频
打开Au
用Au打开音频
用鼠标拖动红线,右键点击选中区域,选择存储区域为
保存文件,设置采样频率为8000,单声道,16位
② 处理音频
此步骤与上一部分一致