【全国电子设计竞赛电源类】SPWM波——入门教程

 

本教程针对第一次参见全国大学生电子设计竞赛并有一定嵌入式基础的同学

本教程用到的嵌入式板子的芯片型号为是STM32F103RCT(正点原子的mini板)

一.实验目的

基于STM32F103RCT输出载波频率(计数器溢出频率)为20KHz,调制波频率(400次溢出输出的整个波的频率)为50Hz的SPWM波。

二.实验准备

1.一块正点原子STM32min板子,用到高级定时器1的CH1(PA8) 与NCH1 (PB13)

2.熟练掌握STM32输出互补的PWM波的方法

3.百度自行了解什么是SPWM波SPWM等效面积法

三.实验原理

本次实验计划制造400个样本点(或者说成采400个点),即计满溢出的次数为400次。计数器每溢出一次改变一次占空比,计数周期为50us,也就是说每个样本点之间的时间间隔为50us,采样频率即为1/[50*10^(-6)] = 20KHz。因为我们需要制造400个样本点,故400个样本点总持续时间为400*50us = 20000us=20ms ,总频率为1/[20000*10^(-6)]=50Hz,最后得到周期为20ms,频率为50Hz的SPWM波。我这么说可能还会有人不明白,如下图所示:

图为等效面积法的原理,图b)为半个正弦周期的SPWM波,红色标注是为了说明我们在用软件生成的每一个样本点的样本周期都为50us,只不过不同样本点的样本周期占空比不同罢了。

越是稀疏的地方,每50us的样本周期内的占空比越大,且疏密程度以20ms为周期循环变化。

放大来看从左到右,每50us的样本周期内的占空比是逐渐变大的。

四.代码详解

1.spwm.c文件

#include"stm32f10x.h"
#include"sys.h"

extern u16 x;                   //引用main.c文件的变量x

const u32 spwm[400] = {         //正弦波样本码表
0,28,56,84,113,141,169,197,226,254,282,310,338,366,395,423,
451,479,507,535,563,591,618,646,674,702,730,757,785,812,840,867,
895,922,949,977,1004,1031,1058,1085,1112,1139,1166,1192,1219,1246,1272,1298,
1325,1351,1377,1403,1429,1455,1481,1507,1532,1558,1583,1609,1634,1659,1684,1709,
1734,1759,1783,1808,1832,1856,1880,1905,1928,1952,1976,2000,2023,2046,2070,2093,
2116,2138,2161,2184,2206,2228,2250,2272,2294,2316,2338,2359,2380,2401,2422,2443,
2464,2484,2505,2525,2545,2565,2585,2604,2624,2643,2662,2681,2700,2719,2737,2755,
2773,2791,2809,2827,2844,2861,2878,2895,2912,2928,2945,2961,2977,2993,3008,3024,
3039,3054,3069,3084,3098,3112,3127,3140,3154,3168,3181,3194,3207,3220,3232,3245,
3257,3269,3281,3292,3303,3315,3325,3336,3347,3357,3367,3377,3387,3396,3405,3414,
3423,3432,3440,3449,3457,3464,3472,3479,3486,3493,3500,3507,3513,3519,3525,3530,
3536,3541,3546,3551,3555,3559,3564,3567,3571,3575,3578,3581,3584,3586,3588,3591,
3592,3594,3596,3597,3598,3599,3599,3599,3600,3599,3599,3599,3598,3597,3596,3594,
3592,3591,3588,3586,3584,3581,3578,3575,3571,3567,3564,3559,3555,3551,3546,3541,
3536,3530,3525,3519,3513,3507,3500,3493,3486,3479,3472,3464,3457,3449,3440,3432,
3423,3414,3405,3396,3387,3377,3367,3357,3347,3336,3325,3315,3303,3292,3281,3269,
3257,3245,3232,3220,3207,3194,3181,3168,3154,3140,3127,3112,3098,3084,3069,3054,
3039,3024,3008,2993,2977,2961,2945,2928,2912,2895,2878,2861,2844,2827,2809,2791,
2773,2755,2737,2719,2700,2681,2662,2643,2624,2604,2585,2565,2545,2525,2505,2484,
2464,2443,2422,2401,2380,2359,2338,2316,2294,2272,2250,2228,2206,2184,2161,2138,
2116,2093,2070,2046,2023,2000,1976,1952,1928,1905,1880,1856,1832,1808,1783,1759,
1734,1709,1684,1659,1634,1609,1583,1558,1532,1507,1481,1455,1429,1403,1377,1351,
1325,1298,1272,1246,1219,1192,1166,1139,1112,1085,1058,1031,1004,977,949,922,
895,867,840,812,785,757,730,702,674,646,618,591,563,535,507,479,
451,423,395,366,338,310,282,254,226,197,169,141,113,84,56,28
};


void rcc_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);                         //开启//TIM1时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);   //开启
    // PA8(CH1) PB13(NCH1) 时钟
}

void gpio_init(void)                                                           //PA8,PB13配置
{
	GPIO_InitTypeDef PA8;
	GPIO_InitTypeDef PB13;
	
	PA8.GPIO_Mode=GPIO_Mode_AF_PP;                                              //复用推挽输出
	PA8.GPIO_Pin=GPIO_Pin_8;
	PA8.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&PA8);	
	
	PB13.GPIO_Mode=GPIO_Mode_AF_PP;                                             //复用推挽输出
	PB13.GPIO_Pin=GPIO_Pin_13;
	PB13.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&PB13);
}

void nvic_init(void)                                                          //中断优先级管理
{
	NVIC_InitTypeDef nvic_time1;
	nvic_time1.NVIC_IRQChannel=TIM1_UP_IRQn;	
	nvic_time1.NVIC_IRQChannelCmd=ENABLE;
	nvic_time1.NVIC_IRQChannelPreemptionPriority=3;                             
	nvic_time1.NVIC_IRQChannelSubPriority=3;
	NVIC_Init(&nvic_time1);
	
}

void spwm_init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef time1;                                //TIM1参数配置
    TIM_OCInitTypeDef time1_oc1;                                  //输出比较配置
//	TIM_BDTRInitTypeDef      TIM_BDTRInitStructure;    
	
    time1.TIM_CounterMode=TIM_CounterMode_Up;                     //向上计数模式
	time1.TIM_Period=arr;                                         //计数周期
	time1.TIM_Prescaler=psc;                                      //时钟分频 
    //CK_CNT=72MHz/psc
	time1.TIM_ClockDivision=0;
	TIM_TimeBaseInit(TIM1,&time1);

	TIM_ClearFlag(TIM1, TIM_FLAG_Update);                         //清中断标志位 
	TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);                      //开启TIM1更新中断
	
	time1_oc1.TIM_OCMode=TIM_OCMode_PWM2;                         //模式2, CNT>CCR 输出有效电平(高电平)
	time1_oc1.TIM_OCPolarity=TIM_OCPolarity_High;                 //有效电平设为高
    time1_oc1.TIM_Pulse=0;
	time1_oc1.TIM_OutputState= TIM_OutputState_Enable;            //开启通道CH1  CCER 捕获/比较使能寄存器 
	time1_oc1.TIM_OutputNState=TIM_OutputNState_Enable;           //开启通道NCH1(CH1的互补输出)
	time1_oc1.TIM_OCNPolarity=TIM_OCPolarity_High;               
	time1_oc1.TIM_OCIdleState  = TIM_OCIdleState_Reset;           //CH1 空闲状态为低电平
    time1_oc1.TIM_OCNIdleState = TIM_OCIdleState_Reset;           //NCH1空闲状态为低电平 	 
	TIM_OC1Init(TIM1,&time1_oc1);

//TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
//TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
//TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
//TIM_BDTRInitStructure.TIM_DeadTime = 0;                         //设置死区事件
//TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;            //禁止刹车输入      
//TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;
//TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
//TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

	
	TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);              //CH1预装载使能
	TIM_ARRPreloadConfig(TIM1, ENABLE);                           //使能TIMx在ARR上的预装载寄存器  允许定时器工作时像ARR缓冲器写入新值(改变计数周期),更新事件发生时载入新值覆盖ARR影子寄存器,下一次CNT要计数到ARR的新值
	TIM_CtrlPWMOutputs(TIM1,ENABLE);                              //开启BDTR MOE 控制输出总开关
	TIM_Cmd(TIM1,ENABLE);                                         //TIM1使能
	
}

void TIM1_UP_IRQHandler(void)   //50us溢出一次,进入中断,改变一次占空比
{
	static u16 i=0;
	if(TIM_GetITStatus(TIM1,TIM_IT_Update)==1)
	{
		if(i<400)               //溢出400次一个循环,也就是半个正弦波周期的SPWM波
		{
			TIM_SetCompare1(TIM1,(u16)(spwm[i])) ; 
			i++;
		}
		else i=0;
  
		TIM_ClearITPendingBit(TIM1,TIM_IT_Update); //清除中断标志位
	}
}

 

从代码里可以看到我在将刹车死区的配置给注释了, 刹车死区设置是为了防止全桥同时导通而烧坏电路而出现的,今后会讲到的,这里暂时一笔带过。

2.main.c文件 

#include "stm32f10x.h"
#include "spwm.h"
#include "sys.h"

u16 x=3600;                                         //TIM1计数上限

 int main(void)
 {	
   rcc_init();     //开启时钟
	 gpio_init();    //配置GPIO口
	 nvic_init();    //中断优先级管理
	 spwm_init(x,0);                                  //TIM1计数上限为3600;不分频;默认计数器时钟频率为72MHz
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //2位抢占优先级,2位响应优先级
	 while(1)
	 {		 
	 }
	  
 }

五.实验结果

PA8口输出

双路互补输出(PA8 PB13)

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值