STM32 阶梯波输出

发布者:Meshulun最新更新时间:2016-10-11 来源: eefocus关键字:STM32  阶梯波输出 手机看文章 扫描二维码
随时随地手机看文章
STM32其实可以弄出很多花样的。上次讲过怎么输出正弦波,这次就讲讲怎么输出阶梯波。阶梯波的输出与正弦波的输出思路大同小异,都是采用DAC+DMA描点的方法实现,不过相比起来阶梯波的输出稍微简单些。
下面就讲讲怎么生成阶梯波,还是基于我自己的规范工程。
1、工程的改动
1)代码中需要用到定时器,所以添加stm32f10x_tim.c到STM32F10x_StdPeriod_Driver工作组中。
2)除了定时器,还需要用到DAC,故添加stm32f10x_dac.c到STM32F10x_StdPeriod_Driver工作组中。
3)最后还需要添加stm32f10x_dma.c到STM32F10x_StdPeriod_Driver工作组中
4)打开stm32f10x_conf.h文件,把stm32f10x_tim.h、stm32f10x_dac.h、stm32f10x_dma.h包含进来,也就是将原先屏蔽的包含这些文件的语句去掉屏蔽。
5)新建Escalatar.c与Escalatar.h这两个文件分别保存在BSP文件夹中的src与inc中,并将Escalatar.c添加进工程的BSP中。
 
2、Escalatar.c与Escalatar.h的程序编写
在代码中,我设置两路正弦波输出,一路输出频率为800Hz的阶梯波,另一路输出频率为1600Hz的阶梯波,他们分别对应的DAC通道1的PA4引脚,与DAC通道2的PA5引脚。所以代码中首先初始化这两个引脚:

/*************************************************************
Function : Escalatar_GPIO_Init
Description: 阶梯波相关引脚配置
Input : none
return : none
*************************************************************/
static void Escalatar_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //初始化引脚时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; //DAC CH1与CH2对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

接下去要配置定时器了,定时器的作用就是设置阶梯波的频率,由于要输出两路频率不相同的定时器,所以这里需要配置两路的定时器,一路设置频率为800Hz,另一路设置频率为1600Hz,代码如下:

#define _800Hz 72000000/6/800 //频率值为800Hz
#define _1600Hz 72000000/6/1600 //频率值为1600Hz

/*************************************************************
Function : Escalatar_TIM_Init
Description: 阶梯波定时器初始化
Input : none
return : none
*************************************************************/
static void Escalatar_TIM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM6, ENABLE);//初始化定时器2与6的时钟

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = _800Hz;//正弦波1频率设置
TIM_TimeBaseStructure.TIM_Prescaler = 0x0;//没有预分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;//时钟不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//增计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Period = _1600Hz;//正弦波2频率设置
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);//更新TIM2输出触发
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);//更新TIM6输出触发

TIM_Cmd(TIM2, ENABLE);//打开TIM2
TIM_Cmd(TIM6, ENABLE);//打开TIM6
}

在这段代码中分别设置TIM2输出800Hz频率与TIM6输出1600Hz频率,设置TIM2与TIM6为更新触发。
接下去配置DAC,DAC总共2路通道,由于要输出正弦波,所以这两个通道都需要配置。代码如下:

/*************************************************************
Function : Escalatar_DAC_Init
Description: 阶梯波DAC初始化
Input : none
return : none
*************************************************************/
static void Escalatar_DAC_Init(void)
{
DAC_InitTypeDef DAC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//初始化DAC的时钟

DAC_StructInit(&DAC_InitStructure);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//指定DAC1的触发定时器TIM2
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//无波形产生
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;//不是能DAC输出缓冲
DAC_Init(DAC_Channel_1, &DAC_InitStructure);//初始化DAC channel1

DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;//指定DAC2的触发定时器TIM6
DAC_Init(DAC_Channel_2, &DAC_InitStructure);//初始化DAC channel2

DAC_Cmd(DAC_Channel_1, ENABLE);//使能DAC channel1
DAC_Cmd(DAC_Channel_2, ENABLE);//使能DAC channel2

DAC_DMACmd(DAC_Channel_1, ENABLE);//使能DAC Channel1的DMA
DAC_DMACmd(DAC_Channel_2, ENABLE);//使能DAC Channel2的DMA
}

配置了两个DAC通道CH1与CH2,分别设置为T2触发与T6触发,除此之外还要打开DAC的DMA功能,以便被DMA控制输出想要的波形。
讲到DMA,就要讲讲DMA的配置,它的代码如下:

#define DAC_DHR8R1_Address 0x40007410//DAC通道1的8位右对齐数据保持寄存器地址
#define DAC_DHR8R2_Address 0x4000741C//DAC童道2的8位有对齐数据保持寄存器地址

const uint8_t Escalator8bit[6] = {0x0, 0x33, 0x66, 0x99, 0xCC, 0xFF};//阶梯形描点

/*************************************************************
Function : Escalatar_DMA_Init
Description: 阶梯波DAM初始化
Input : none
return : none
*************************************************************/
static void Escalatar_DMA_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//初始化DMA2的时钟

DMA_DeInit(DMA2_Channel3);//将DMA配置成默认值
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_Address;//指定DMA2通道3的目标地址为DAC1_DHR12R1
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Escalator8bit;//指定DMA的源地址为数组Escalator8bit
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设作为数据传输的目的地
DMA_InitStructure.DMA_BufferSize = 6;//DMA缓冲区大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设机地址存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度为半字
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度为半字
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作在循环缓存模式,数据传输数为0时,自动恢复配置初值
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;//非常高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//通道未被设置成内存到内存模式,与循环模式相对
DMA_Init(DMA2_Channel3, &DMA_InitStructure);//初始化DMA

DMA_DeInit(DMA2_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R2_Address;//指定DMA2通道3的目标地址为DAC2_DHR12R2
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_Init(DMA2_Channel4, &DMA_InitStructure);

DMA_Cmd(DMA2_Channel3, ENABLE);//使能DMA的channel3
DMA_Cmd(DMA2_Channel4, ENABLE);//使能DMA的channel4
}

在《STM32正弦波输出》一文中,已经讲过,DAC的CH1与CH2分别对应着是DMA2的CH3与CH4,所以上面配置的是DMA2的CH3与CH4。配置DMA的外设基地址为DAC的数据寄存器,这里因为阶梯波只需用8位DAC就够了,所以数据寄存器分别选择DAC_DHR8R1_Address(DAC通道1的8位右对齐数据保持寄存器地址)与DAC_DHR8R2_Address(DAC童道2的8位有对齐数据保持寄存器地址)就可以了。而DMA的缓冲选择我们上面的定义的数组Escalator8bit,用来让DMA的自动描阶梯波的波形。Escalator8bit[]只有6个元素,用于描阶梯波,输出有6个阶梯的波形。所以这里设置DMA的缓冲大小为6,外设数据宽度与内存的数据宽度设置字节。这样的话,DMA就差不多配置好了。
还要编写一个总函数:Escalatar_Init()来初始化上面的配置,代码如下:

/*************************************************************
Function : Escalatar_Init
Description: 阶梯波初始化
Input : none
return : none
*************************************************************/
void Escalatar_Init(void)
{
Escalatar_GPIO_Init();
Escalatar_TIM_Init();
Escalatar_DAC_Init();
Escalatar_DMA_Init();
}

下面是Escalator.h函数,代码如下:

#ifndef __ESCALATOR_H__
#define __ESCALATOR_H__
#include "stm32f10x.h"

void Escalatar_Init(void);

#endif

3、main函数的编写
main函数很简单,代码如下:

/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
BSP_Init();
Escalatar_Init();
PRINTF("\nmain() is running!\r\n");
while(1)
{
LED1_Toggle();
Delay_ms(1000);
}
}

4、测试
用示波器的探头分别连接PA4与PA5两个引脚,然后在示波器中就可以看到阶梯波了.
PA4,也就是DAC的CH1对应的引脚会输出频率为800Hz的阶梯波,如下图所示:
STM32 阶梯波输出 - ziye334 - ziye334的博客
PA5,也就是DAC的CH2对应的引脚会输出频率为1600Hz的阶梯波,如下图所示:
                STM32 阶梯波输出 - ziye334 - ziye334的博客
关键字:STM32  阶梯波输出 引用地址:STM32 阶梯波输出

上一篇:STM32 三角波输出
下一篇:STM32 六步PWM输出

推荐阅读最新更新时间:2024-03-16 15:14

STM32的定时器有两种捕获模式——PWM输入模式和普通输入模式
一个定时器最多能同时捕获几路PWM波? 我只需要得到PWM的高电平宽度,PWM的频率是50HZ STM32的定时器有两种捕获模式 PWM输入模式和普通输入模式 在PWM输入模式下,一个定时器只能同时捕获一路PWM波 在普通输入模式下,理论上是可以同时捕获4路PWM波 即,在定时器中断中改变触发模式(上升沿、下降沿) 然后寄存器两次的差值即近似为高电平长度
[单片机]
嵌入式开发之STM32开发之EXTI中断使用及踩坑
关键点 中断配置,中断触发 中断配置 中断必然要绑定一个触发中断的外部I/O口,这里我选PA0,对应EXIT0,因为PA0正好对应我板子上的K3键,我需要K3键去触发这个中断 GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; /* config the extiline(PB0) clock and AFIO clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);//GPIOA根据你自己板子设定
[单片机]
STM32定时器中TIM_RepetitionCounter作用详解
在STM32中 有一个这个TIM_RepetitionCounter参数。如下,定时了0.001s,然后在中断中计数1000次,点亮熄灭LED,正常情况来说,led会亮1s,然后灭1s,不断重复。 当 TIM_RepetitionCounter 参数设置为0 时,确实是1s。 当 TIM_RepetitionCounter 参数设置为1 时,明显感觉到亮灭的时间被延长了一倍。 所以 TIM_RepetitionCounter 应该是在本次定时结束后,再重装载定时 1次,进入中断,所以 当TIM_RepetitionCounter =1时,相当于定时0.001s 2次进入中断,那么led的亮灭时间就变成了2s。 当TIM_R
[单片机]
<font color='red'>STM32</font>定时器中TIM_RepetitionCounter作用详解
深入解析STM32_USB-FS-Device_Lib库V0.2
图1 展示了一个典型的USB应用与USB-FS-Device library的关系图。我们可以看出图中由3个层构成分别是:外围硬件(hardware)、STM32_USB-FS_Device_Lib和用户层(User application)。我们从下到上来分析: 图1 典型的USB应用与USB-FS-Device library的关系图 1.外围硬件(hardware) 就是我们的购买的芯片STM32F10XXX和开发板 2 STM32_USB-FS_Device_Lib 就是STM提供给我们的The USB-FS-Device library固件库,它由STM32_USB FS_Device_ Driver和A
[单片机]
深入解析STM32_USB-FS-Device_Lib库V0.2
STM32模拟串口输出偶有乱码
因为芯片串口不够用,只好用IO口模拟串口,在网上下载了个模拟串口的程序,可运行,但发现串口输出隔几个字符就会出现乱码,主要部分代码如下: #define OI_TXD PAout(12) #define OI_RXD PAin(11) #define BuadRate_9600 100 u8 len = 0; //接收计数 u8 USART_buf ; //接收缓冲区 u8 recvStat = COM_STOP_BIT; u8 recvData = 0; void IO_TXD(u8 Data) { u8 i = 0; OI_TXD = 0;
[单片机]
STM32与SHT1X温湿度传感器通讯
在这次项目开发中应用到了SHT1X温湿度传感器,该系列有SHT10、SHT11和SHT15,属于Sersirion温湿度传感器家族中的贴片封装系列。包括一个电容性聚合体测湿敏感元件、一个用能隙材料制成的测温元件,传感器内部有一个精度高达14为位的A/D转换器。更详细资料请参考说明书。 1、硬件介绍 现在对本次使用的SHT15作简要介绍。其引脚定义如下: SHT1X温湿度传感器使用的2线通讯,类是于I2C总线,但并不相同,使用普通的GPIO就可实现通讯。此次采用STM32F103VET6来操作SHT15,具体的连接方式如下: SCK 用于微处理器与SHT1x 之间的通讯同步。由于接口包含了完全静态逻辑,因而不存在最小S
[单片机]
<font color='red'>STM32</font>与SHT1X温湿度传感器通讯
STM32的IO配置点灯
1、led.c的具体的代码: /*----------------------------------------------------------*/ #include led.h /* ------------------------------------------------------------------------- 文件名:led.c 描述 :根据硬件连接配置LED端口,打开对应的寄存器 ---------------------------------------------------------------------------*/ void LED_Init(void) { GPIO_I
[单片机]
RyanMqtt移植指南
测试环境:stm32F401RCT6、RT-Thread版本: v4.1.0、RT-Thread Studio版本: 2.2.6、网络硬件使用ec800m移植at_socket使用sal框架。 1、移植介绍 RyanMqtt 库希望应用程序为以下接口提供实现: system 接口 RyanMqtt 需要 RTOS 支持,必须实现如下接口才可以保证 mqtt 客户端的正常运行 network 接口 RyanMqtt 依赖于底层传输接口 API,必须实现该接口 API 才能在网络上发送和接收数据包 MQTT 协议要求基础传输层能够提供有序的、可靠的、双向传输(从客户端到服务端 和从服务端到客户端)的字节流 time 接口
[单片机]
RyanMqtt移植指南
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved