【问天Block】STC15单片机PWM输出讲解

【问天Block】STC15单片机PWM输出讲解


  • 示波器捕捉到的实时波形

  • 采用的是自制开发板
    【问天Block】STC15单片机PWM输出讲解_第1张图片
    【问天Block】STC15单片机PWM输出讲解_第2张图片

  • 我的开发板已经开源《【开源分享】自制STC15W408AS开发板》

  • 开发工具:问天Block

  • 采用的是字符编程方式,如果使用图像块编程频率是固定的11.0592MHz,我自制的STC15W408AS使用的是外部16MHz的晶振。

  • 以PCA三路PWM输出范例参考
    【问天Block】STC15单片机PWM输出讲解_第3张图片

PWM频率调节

  • 下面的函数是对时钟的分频,决定PWM的工作频率。PCA_Clock_1T频率最高,PCA_Clock_12T频率最低。
PCA_InitStructure.PCA_Clock    = PCA_Clock_1T; //PCA_Clock_1T, PCA_Clock_2T, PCA_Clock_4T, PCA_Clock_6T, PCA_Clock_8T, PCA_Clock_12T, PCA_Clock_Timer0_OF, PCA_Clock_ECI
  • PCA_Clock_1T的频率:16MHz/256=62.5KHz;(时钟频率采用的是外部晶振16MHz,)

  • PCA_Clock_12T = 16MHz/256/12=5208Hz

固定频率下的占空比调节

  • 下面是关于占空比调整的函数,原函数调节的占空比是0~100占空比调整映射到0-254之间不断变化的占空比值。注意:0对应的是最高占空比值,接近100%,254是最小占空比差不多为0.
void loop()
{
  for (i = 0; i < 255; i = i + 1) {
    UpdatePwm(PCA0, i);
    UpdatePwm(PCA1, i);
    UpdatePwm(PCA2, i);
    delay(50);
  }
}

主程序代码

#define SYS_CLK 16000000L//设置时钟频率16MHz

#include 
#include "lib/STC15_PCA.h"
#include "lib/STC15_delay.h"

uint8 i;

void setup()
{
  PCA_InitTypeDef	PCA_InitStructure;

  PCA_InitStructure.PCA_Clock    = PCA_Clock_12T; //PCA_Clock_1T, PCA_Clock_2T, PCA_Clock_4T, PCA_Clock_6T, PCA_Clock_8T, PCA_Clock_12T, PCA_Clock_Timer0_OF, PCA_Clock_ECI
  PCA_InitStructure.PCA_IoUse    = PCA_P11_P10_P37; //PCA_P12_P11_P10_P37, PCA_P34_P35_P36_P37, PCA_P24_P25_P26_P27
  PCA_InitStructure.PCA_Interrupt_Mode = DISABLE;	//ENABLE, DISABLE
  PCA_InitStructure.PCA_Polity   = PolityHigh;	//优先级设置	PolityHigh,PolityLow
  PCA_InitStructure.PCA_RUN      = DISABLE;	//ENABLE, DISABLE
  PCA_Init(PCA_Counter,&PCA_InitStructure);

  PCA_InitStructure.PCA_Mode     = PCA_Mode_PWM; //PCA_Mode_PWM, PCA_Mode_Capture, PCA_Mode_SoftTimer, PCA_Mode_HighPulseOutput
  PCA_InitStructure.PCA_PWM_Wide = PCA_PWM_8bit;	//PCA_PWM_8bit, PCA_PWM_7bit, PCA_PWM_6bit
  PCA_InitStructure.PCA_Interrupt_Mode = DISABLE;	//PCA_Rise_Active, PCA_Fall_Active, ENABLE, DISABLE
  PCA_InitStructure.PCA_Value    = 100 << 8;	//对于PWM,高8位为PWM占空比
  PCA_Init(PCA0,&PCA_InitStructure);

  PCA_InitStructure.PCA_Mode     = PCA_Mode_PWM; //PCA_Mode_PWM, PCA_Mode_Capture, PCA_Mode_SoftTimer, PCA_Mode_HighPulseOutput
  PCA_InitStructure.PCA_PWM_Wide = PCA_PWM_8bit;	//PCA_PWM_8bit, PCA_PWM_7bit, PCA_PWM_6bit
  PCA_InitStructure.PCA_Interrupt_Mode = DISABLE;	//PCA_Rise_Active, PCA_Fall_Active, ENABLE, DISABLE
  PCA_InitStructure.PCA_Value    = 100 << 8;	//对于PWM,高8位为PWM占空比
  PCA_Init(PCA1,&PCA_InitStructure);

  PCA_InitStructure.PCA_Mode     = PCA_Mode_PWM; //PCA_Mode_PWM, PCA_Mode_Capture, PCA_Mode_SoftTimer, PCA_Mode_HighPulseOutput
  PCA_InitStructure.PCA_PWM_Wide = PCA_PWM_8bit;	//PCA_PWM_8bit, PCA_PWM_7bit, PCA_PWM_6bit
  PCA_InitStructure.PCA_Interrupt_Mode = DISABLE;	//PCA_Rise_Active, PCA_Fall_Active, ENABLE, DISABLE
  PCA_InitStructure.PCA_Value    = 100 << 8;	//对于PWM,高8位为PWM占空比
  PCA_Init(PCA2,&PCA_InitStructure);

  CR = 1; //1: 允许PCA计数器计数,必须由软件清0。

  //PCA三路输出PWM
}

void loop()
{
  for (i = 0; i < 250; i = i + 1) {
    UpdatePwm(PCA0, i);
    UpdatePwm(PCA1, i);
    UpdatePwm(PCA2, i);
    delay(50);
  }
}

void main(void)
{
  setup();
  while(1){
    loop();
  }
}

  • STC15_PCA.h文件

#ifndef	__STC15_PCA_H
#define	__STC15_PCA_H

#include 

#define	TRUE	1
#define	FALSE	0

//=============================================================

//========================================

#define	PolityLow			0	//低优先级中断
#define	PolityHigh			1	//高优先级中断

#define		ENABLE		1
#define		DISABLE		0

#define	PCA0			0
#define	PCA1			1
#define	PCA2			2
#define	PCA_Counter		3
#define	PCA_P11_P10_P37	(0<<4)
#define	PCA_P35_P36_P37	(1<<4)
#define	PCA_P25_P26_P27	(2<<4)
#define	PCA_Mode_PWM				0x42	//B0100_0010
#define	PCA_Mode_Capture			0
#define	PCA_Mode_SoftTimer			0x48	//B0100_1000
#define	PCA_Mode_HighPulseOutput	0x4c	//B0100_1100
#define	PCA_Clock_1T	(4<<1)
#define	PCA_Clock_2T	(1<<1)
#define	PCA_Clock_4T	(5<<1)
#define	PCA_Clock_6T	(6<<1)
#define	PCA_Clock_8T	(7<<1)
#define	PCA_Clock_12T	(0<<1)
#define	PCA_Clock_Timer0_OF	(2<<1)
#define	PCA_Clock_ECI	(3<<1)
#define	PCA_Rise_Active	(1<<5)
#define	PCA_Fall_Active	(1<<4)
#define	PCA_PWM_8bit	(0<<6)
#define	PCA_PWM_7bit	(1<<6)
#define	PCA_PWM_6bit	(2<<6)


typedef struct
{
	uint8	PCA_IoUse;	//PCA_P12_P11_P10_P37, PCA_P34_P35_P36_P37, PCA_P24_P25_P26_P27
	uint8	PCA_Clock;	//PCA_Clock_1T, PCA_Clock_2T, PCA_Clock_4T, PCA_Clock_6T, PCA_Clock_8T, PCA_Clock_12T, PCA_Clock_Timer0_OF, PCA_Clock_ECI
	uint8	PCA_Mode;	//PCA_Mode_PWM, PCA_Mode_Capture, PCA_Mode_SoftTimer, PCA_Mode_HighPulseOutput
	uint8	PCA_PWM_Wide;	//PCA_PWM_8bit, PCA_PWM_7bit, PCA_PWM_6bit
	uint8	PCA_Interrupt_Mode;	//PCA_Rise_Active, PCA_Fall_Active, ENABLE, DISABLE
	uint8	PCA_Polity;	//优先级设置	PolityHigh,PolityLow
	uint16	PCA_Value;
	uint8	PCA_RUN;	//ENABLE, DISABLE
} PCA_InitTypeDef;

bit		B_Capture0,B_Capture1,B_Capture2;
uint8		PCA0_mode,PCA1_mode,PCA2_mode;
uint16		CCAP0_tmp,PCA_Timer0;
uint16		CCAP1_tmp,PCA_Timer1;
uint16		CCAP2_tmp,PCA_Timer2;

/*************	功能说明	**************


******************************************/




//========================================================================
// 函数: UpdatePwm(uint8 PCA_id, uint8 pwm_value)
// 描述: 更新PWM值. 
// 参数: PCA_id: PCA序号. 取值 PCA0,PCA1,PCA2,PCA_Counter
//		 pwm_value: pwm值, 这个值是输出低电平的时间.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void	UpdatePwm(uint8 PCA_id, uint8 pwm_value)
{
	if(PCA_id == PCA0)		CCAP0H = pwm_value;
	else if(PCA_id == PCA1)	CCAP1H = pwm_value;
	else if(PCA_id == PCA2)	CCAP2H = pwm_value;
}

//========================================================================
// 函数: void	PCA_Init(PCA_id, PCA_InitTypeDef *PCAx)
// 描述: PCA初始化程序.
// 参数: PCA_id: PCA序号. 取值 PCA0,PCA1,PCA2,PCA_Counter
//		 PCAx: 结构参数,请参考PCA.h里的定义.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void	PCA_Init(uint8 PCA_id, PCA_InitTypeDef *PCAx)
{
	if(PCA_id > PCA_Counter)	return;		//id错误

	if(PCA_id == PCA_Counter)			//设置公用Counter
	{
		CR = 0;
		CH = 0;
		CL = 0;
		AUXR1 = (AUXR1 & ~(3<<4)) | PCAx->PCA_IoUse;			//切换IO口
		CMOD  = (CMOD  & ~(7<<1)) | PCAx->PCA_Clock;			//选择时钟源
		CMOD  = (CMOD  & ~1) | (PCAx->PCA_Interrupt_Mode & 1);	//ECF
		if(PCAx->PCA_Polity == PolityHigh)		PPCA = 1;	//高优先级中断
		else									PPCA = 0;	//低优先级中断
		if(PCAx->PCA_RUN == ENABLE)	CR = 1;
		return;
	}

	PCAx->PCA_Interrupt_Mode &= (3<<4) + 1;
	if(PCAx->PCA_Mode >= PCA_Mode_SoftTimer)	PCAx->PCA_Interrupt_Mode &= ~(3<<4);

	if(PCA_id == PCA0)
	{
		CCAPM0    = PCAx->PCA_Mode | PCAx->PCA_Interrupt_Mode;	//工作模式, 中断模式
		PCA_PWM0  = (PCA_PWM0 & ~(3<<6)) | PCAx->PCA_PWM_Wide;	//PWM宽度

		PCA_Timer0 = PCAx->PCA_Value;
		B_Capture0 = 0;
		PCA0_mode = PCAx->PCA_Mode;
		CCAP0_tmp = PCA_Timer0;
		CCAP0L = (uint8)CCAP0_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
		CCAP0H = (uint8)(CCAP0_tmp >> 8);	//后写CCAP0H
	}
	if(PCA_id == PCA1)
	{
		CCAPM1    = PCAx->PCA_Mode | PCAx->PCA_Interrupt_Mode;
		PCA_PWM1  = (PCA_PWM1 & ~(3<<6)) | PCAx->PCA_PWM_Wide;

		PCA_Timer1 = PCAx->PCA_Value;
		B_Capture1 = 0;
		PCA1_mode = PCAx->PCA_Mode;
		CCAP1_tmp = PCA_Timer1;
		CCAP1L = (uint8)CCAP1_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
		CCAP1H = (uint8)(CCAP1_tmp >> 8);	//后写CCAP0H
	}
	if(PCA_id == PCA2)
	{
		CCAPM2    = PCAx->PCA_Mode | PCAx->PCA_Interrupt_Mode;
		PCA_PWM2  = (PCA_PWM2 & ~(3<<6)) | PCAx->PCA_PWM_Wide;

		PCA_Timer2 = PCAx->PCA_Value;
		B_Capture2 = 0;
		PCA2_mode = PCAx->PCA_Mode;
		CCAP2_tmp = PCA_Timer2;
		CCAP2L = (uint8)CCAP2_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
		CCAP2H = (uint8)(CCAP2_tmp >> 8);	//后写CCAP0H
	}
}


//========================================================================
// 函数: void	PCA_Handler (void) interrupt PCA_VECTOR
// 描述: PCA中断处理程序.
// 参数: None
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void	PCA_Handler (void) interrupt 7
{
	if(CCF0)		//PCA模块0中断
	{
		CCF0 = 0;		//清PCA模块0中断标志
		if(PCA0_mode >= PCA_Mode_SoftTimer)		//PCA_Mode_SoftTimer and PCA_Mode_HighPulseOutput
		{
			CCAP0_tmp += PCA_Timer0;
			CCAP0L = (uint8)CCAP0_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
			CCAP0H = (uint8)(CCAP0_tmp >> 8);	//后写CCAP0H
		}
		else if(PCA0_mode == PCA_Mode_Capture)
		{
			CCAP0_tmp = CCAP0H;	//读CCAP0H
			CCAP0_tmp = (CCAP0_tmp << 8) + CCAP0L;
			B_Capture0 = 1;
		}
	}

	if(CCF1)	//PCA模块1中断
	{
		CCF1 = 0;		//清PCA模块1中断标志
		if(PCA1_mode >= PCA_Mode_SoftTimer)		//PCA_Mode_SoftTimer and PCA_Mode_HighPulseOutput
		{
			CCAP1_tmp += PCA_Timer1;
			CCAP1L = (uint8)CCAP1_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
			CCAP1H = (uint8)(CCAP1_tmp >> 8);	//后写CCAP0H
		}
		else if(PCA1_mode == PCA_Mode_Capture)
		{
			CCAP1_tmp = CCAP1H;	//读CCAP1H
			CCAP1_tmp = (CCAP1_tmp << 8) + CCAP1L;
			B_Capture1 = 1;
		}
	}

	if(CCF2)	//PCA模块2中断
	{
		CCF2 = 0;		//清PCA模块1中断标志
		if(PCA2_mode >= PCA_Mode_SoftTimer)		//PCA_Mode_SoftTimer and PCA_Mode_HighPulseOutput
		{
			CCAP2_tmp += PCA_Timer2;
			CCAP2L = (uint8)CCAP2_tmp;			//将影射寄存器写入捕获寄存器,先写CCAP0L
			CCAP2H = (uint8)(CCAP2_tmp >> 8);	//后写CCAP0H
		}
		else if(PCA2_mode == PCA_Mode_Capture)
		{
			CCAP2_tmp = CCAP2H;	//读CCAP2H
			CCAP2_tmp = (CCAP2_tmp << 8) + CCAP2L;
			B_Capture2 = 1;
		}
	}

	if(CF)	//PCA溢出中断
	{
		CF = 0;			//清PCA溢出中断标志
	}

}

#endif


  • STC15_delay.h文件
#ifndef __STC15_DELAY_H
#define __STC15_DELAY_H	

#include 

#ifndef SYS_CLK 
#define SYS_CLK 11059200L
#endif

void delay1ms();			//延迟1毫秒
void delay(uint16 time);	//延迟time毫秒

#if (SYS_CLK == 24000000)
void delay1us();			//延迟1微秒
void delay5us();			//延迟5微秒
void delay10us();			//延迟10微秒
void delay50us();			//延迟50微秒
void delay100us();			//延迟100微秒



//========================================================================
// 描述: 延迟1微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay1us()		//@24.000MHz
{
	uint8 i;
	_nop_();
	_nop_();
	i = 3;
	while (--i);
}

//========================================================================
// 描述: 延迟5微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay5us()		//@24.000MHz
{
	uint8 i;
	_nop_();
	_nop_();
	i = 27;
	while (--i);
}

//========================================================================
// 描述: 延迟10微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay10us()		//@24.000MHz
{
	uint8 i;
	_nop_();
	_nop_();
	i = 57;
	while (--i);
}

//========================================================================
// 描述: 延迟50微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay50us()		//@24.000MHz
{
	uint8 i, j;

	i = 2;
	j = 39;
	do
	{
		while (--j);
	} while (--i);
}

//========================================================================
// 描述: 延迟100微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay100us()		//@24.000MHz
{
	uint8 i, j;

	i = 3;
	j = 82;
	do
	{
		while (--j);
	} while (--i);
}



#elif (SYS_CLK == 12000000)
    
void delay1us();			//延迟1微秒
void delay5us();			//延迟5微秒
void delay10us();			//延迟10微秒
void delay50us();			//延迟50微秒
void delay100us();			//延迟100微秒

//========================================================================
// 描述: 延迟1微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay1us()		//@12.000
{
	_nop_();
    _nop_();
    _nop_();
    _nop_();
}

//========================================================================
// 描述: 延迟5微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay5us()		//@12.000
{
	uint8 i;
    _nop_();
    _nop_();
	i = 12;
	while (--i);
}

//========================================================================
// 描述: 延迟10微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay10us()		//@12.000
{
	uint8 i;
    _nop_();
    _nop_();
	i = 27;
	while (--i);
}

//========================================================================
// 描述: 延迟50微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay50us()		//@12.000
{
	uint8 i, j;

	i = 1;
	j = 146;
	do
	{
		while (--j);
	} while (--i);
}

//========================================================================
// 描述: 延迟100微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay100us()		//@12.000
{
	uint8 i, j;

	i = 2;
	j = 39;
	do
	{
		while (--j);
	} while (--i);
}

#elif (SYS_CLK == 5529600)
    
void delay1us();			//延迟1微秒
void delay5us();			//延迟5微秒
void delay10us();			//延迟10微秒
void delay50us();			//延迟50微秒
void delay100us();			//延迟100微秒

//========================================================================
// 描述: 延迟1微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay1us()		//@5.5296
{
	_nop_();
}

//========================================================================
// 描述: 延迟5微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay5us()		//@5.5296
{
	uint8 i;
    _nop_();
    _nop_();
	i = 4;
	while (--i);
}

//========================================================================
// 描述: 延迟10微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay10us()		//@5.5296
{
	uint8 i;
	_nop_();
	i = 11;
	while (--i);
}

//========================================================================
// 描述: 延迟50微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay50us()		//@5.5296
{
	uint8 i;
    _nop_();
    _nop_();
	i = 66;
	while (--i);
}

//========================================================================
// 描述: 延迟100微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay100us()		//@5.5296
{
	uint8 i, j;
    _nop_();
	i = 1;
	j = 134;
	do
	{
		while (--j);
	} while (--i);
}

#else //11059200

void delay1us();			//延迟1微秒
void delay5us();			//延迟5微秒
void delay10us();			//延迟10微秒
void delay50us();			//延迟50微秒
void delay100us();			//延迟100微秒

//========================================================================
// 描述: 延迟1微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay1us()		//@11.0592
{
	_nop_();
    _nop_();
    _nop_();
}

//========================================================================
// 描述: 延迟5微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay5us()		//@11.0592
{
	uint8 i;
	_nop_();
	i = 11;
	while (--i);
}

//========================================================================
// 描述: 延迟10微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay10us()		//@11.0592
{
	uint8 i;
	_nop_();
	i = 25;
	while (--i);
}

//========================================================================
// 描述: 延迟50微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay50us()		//@11.0592
{
	uint8 i, j;
    _nop_();
	i = 1;
	j = 134;
	do
	{
		while (--j);
	} while (--i);
}

//========================================================================
// 描述: 延迟100微秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay100us()		//@11.0592
{
	uint8 i, j;
    _nop_();
    _nop_();
	i = 2;
	j = 15;
	do
	{
		while (--j);
	} while (--i);
}

#endif

//========================================================================
// 描述: 延迟1毫秒.
// 参数: none.
// 返回: none.
//========================================================================
void delay1ms()	//1毫秒@sys_clk
{
   uint8 ms = 1;
   uint16 i;
	 do{
	      i = SYS_CLK / 13000;
		  while(--i)	;   //14T per loop
     }while(--ms);
}

//========================================================================
// 描述: 延迟指定毫秒.
// 参数: 延迟时间(1-65535).
// 返回: none.
//========================================================================
void delay(uint16 time)
{
  if(time < 1)
  {
	  time = 1;
  }	
  do { delay1ms();} while (--time);
}

#endif		//delay.h

你可能感兴趣的:(单片机,STC15,PWM输出)