STC15W4K48S4 它有6通道高精度PWM发生器

来源:互联网 发布:淘宝店铺手机发布宝贝 编辑:程序博客网 时间:2024/05/16 13:00

STC15W4K48S4  的 PCA_PWM 只有两路 PWM0 和 PWM1 已经用来控制了两个风机,因为项目需要要控制3个风机所以又添加了一个PWM来控制风机,查看电路板发现只有一个 PWM7的引脚是空起来的,所以就用这个引脚进行第3路的PWM输出,

程序如下:红色部分是添加的 PWM7的程序,其他是STC芯片资料里的程序

void PWM7_Init(void) 函数里面有详细说明

// --------------------------------------------------------- PCA_PWM.h----------------------------------------------------------------------------


#ifndef __PCA_PWM_H_

#define __PCA_PWM_H_


#include "config.h"
#include "main.h"



/***********************************用户宏定义**********************************/
//#define MAIN_Fosc11059200  
#define   PWM_DUTY255 // 定义PWM的周期,数值为PCA所选择的时钟脉冲个数
#define PWM_HIGH_MIN1 // 限制PWM输出的最小占空比,避免中断里重装参数时间不够
#define PWM_HIGH_MAX255//(PWM_DUTY - PWM_HIGH_MIN) // 限制PWM输出最大占空比


/*********************************************************************************/
#define PCA0 0
#define PCA1 1
#define PWM7 2





//-------------------------------------------------------------------------
//       Add   B7    B6     B5    B4     B3      B2   B1  B0  
// AUXR1 A2H  S1_S1 S1_S0 CCP_S1 CCP_S0 SPI_S1 SPI_S0  -  DSP


// CCP_S1 CCP_S0
//   0      0       PCA_P12_P11_P10_P37
//   0      1       PCA_P34_P35_P36_P37
//   1      0       PCA_P24_P25_P26_P27


//#define PCA_P12_P11_P10_P37 (0<<4)
#define PCA_P34_P35_P36_P37 (1<<4)
#define PCA_P24_P25_P26_P27 (2<<4)


//------------------------------------------------------------------------
//          Address  B7   B6    B5     B4    B3    B2    B1    B0
// CCAPM0     DAH    -   ECOM0 CAPP0  CAPN0 MAT0  TOG0  PWM0  ECCF0


// ECOM0: 当 ECOM0 = 1,允许比较功能
// CAPP0: 当 CAPP0 = 1,允许上升沿捕获
// CAPN0: 当 CAPN0 = 1,允许下降沿捕获
// MAT0:  当 MAT0 = 1 时,PCA计数值与模块的比较/捕获寄存器的值的匹配价格置位CCON寄存器中的中断标志位 CCF0
// TOG0:  当 TOG0 = 1 时,工作在PCA高速脉冲输出模式,PCA计数值与模块的比较/捕获寄存器的值的匹配将使CCP0脚翻转
//        (CCP0/PCA0/PWM0/P1.1 或 CCP0_2/PCA0/PWM0/P3.5 或 CCP0_3/PCA0/PWM0/P2.5)
// PWM0:  当PWM0 = 1时,允许CCP0脚输出PWM波
// ECCF0: 使能CCF0中断。使能寄存器CCON的比较/捕获标志CCF0,用来产生中断


// CCAPM1 和 CCAPM2 和 CCAPM0 一样


#define PCA_Mode_PWM 0x42  //  ECOM0 = 1  PWM0 = 1
//#define PCA_Mode_Capture 0
//#define PCA_Mode_SoftTimwe 0x48  //  ECOM0 = 1  MAT0 = 1
//#define PCA_Mode_HighPluseOutput 0x4C  //  ECOM0 = 1  MAT0 = 1 TOG0 = 1


//#define PCA_Rise_Active (1<<5)  // 上升沿捕获 CAPP0 = 1
//#define PCA_Fall_Active (1<<4)  // 上升沿捕获 CAPN0 = 1




//---------------------------------------------------------------------------
//       Address   B7     B6   B5  B4   B3    B2    B1    B0
// CMOD  D9H       CIDL   -    -    -   CPS2  CPS1  CPS0  ECF


// CIDL: CIDL = 0, 空闲模式下PCA计数器继续工作
// CIDL = 1, 空闲模式下PCA计数器停止工作
// 
// CPS2  CPS1  CPS0   选择CCP/PCA/PWM时钟源输入
//   0     0     0     (0,系统时钟,SYSclk/12
//   0     0     1      (1, 系统时钟,SYSclk/2
//   0     1    0      (2, 定时器0溢出脉冲。由于定时器0可以工作在1T模式,所以
// 可以达到一个时钟就溢出,从而达到最高频率CPU工作时钟SYSclk
// 通过改变T0的溢出率,可以实现可调频率的PWM输出
//   0     1     1      (3, ECI/P1.2(或P3.4或P2.4)引脚输入外部时钟,(最大速率= SYSclk/2)
//   1     0     0      (4, 系统时钟,SYSclk
//   1     0     1      (5, 系统时钟/4, SYSclk/4
//   1     1     0      (6, 系统时钟/6, SYSclk/6
//   1     1     1      (6, 系统时钟/8, SYSclk/8
/* 
例如,CPS2/CPS1/CPS0 = 1/0/0 时,CCP/PCA/PWM时钟源是SYSclk,不用定时器0,PWM的频率为
SYSclk/256
如果要用系统时钟/3来作为PCA的时钟源,应选择T0的溢出作为CCP/PCA/PWM时钟源,此时
应让T0工作在1T模式,计数3个脉冲即将产生溢出。用T0的溢出可对系统进行1~65536级分频,
(T0工作在16位重装载模式)
*/


// ECF: PCA计数溢出中断使能位
//       ECF = 0 ,禁止CCON中的CF位中断
//       ECF = 1,  允许CCON中的CF位中断


#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 (8<<1)
#define PCA_Clock_12T (0<<1)
//#define PCA_Clock_Timer0_OF (2<<1)
//#define PCA_Clock_ECI (3<<1)


//----------------------------------------------------------------------------
// PCA 模块PWM寄存器PCA_PWM0、PCA_PWM1、PCA_PWM2


//           Address   B7      B6      B5  B4  B3  B2  B1     B0
// PCA_PWM0   F2H      EBS0_1  EBS0_0  -   -   -   -   EPC0H  EPC0L


//  EBS0_1 EBS0_0 当PCA模块0工作于PWM模式时的功能选择位
//    0      0    : PCA 模块0,工作于8位PWM功能
//    0      1    : PCA 模块0,工作于7位PWM功能
//    1      0    : PCA 模块0,工作于6位PWM功能
//    1      1    : 无效 PCA 模块0,工作于8位PWM功能


//  EPC0H 在PWM模式下,与CCAP0H组成9位数
//  EPC0L 在PWM模式下,与CCAP0L组成9位数


// PCA_PWM1 PCA_PWM2 一样


//#define PCA_PWM_8bit   (0<<6)
//#define PCA_PWM_7bit   (1<<6)
//#define PCA_PWM_6bit   (2<<6)


//sbit PPCA = IP^7;// PCA 中断优先级设定位


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












#define PwmClk_1T 0








// --------------------------------------------------------------
#define EAXSFR() P_SW2 |= (1 << 7)// 指令操作对象为扩展SFR (XSFR)
#define EAXRAM() P_SW2 &= ~(1 << 7)// 指令操作对象为扩展SFR (XSFR)
// --------------------------------------------------------------


//sfr P_SW2 = 0xBA;










// --------------------------------------------------------------
// #define PWM2_INIT_OUT_LOW (0 << 0)
// #define PWM2_INIT_OUT_HIGH (1 << 0)


// #define PWM3_INIT_OUT_LOW (0 << 1)
// #define PWM3_INIT_OUT_HIGH (1 << 1)


// #define PWM4_INIT_OUT_LOW (0 << 2)
// #define PWM4_INIT_OUT_HIGH (1 << 2)


// #define PWM5_INIT_OUT_LOW (0 << 3)
// #define PWM5_INIT_OUT_HIGH (1 << 3)


// #define PWM6_INIT_OUT_LOW (0 << 4)
// #define PWM6_INIT_OUT_HIGH (1 << 4)


#define PWM7_INIT_OUT_LOW (0 << 5)
#define PWM7_INIT_OUT_HIGH (1 << 5)


sfr PWMCFG = 0xF1;
// --------------------------------------------------------------
















// --------------------------------------------------------------
#define ENHANCE_PWM_ENABLE (1 << 7)// 使能增强型PWM波形发送器
#define ZERO_INT_DISABLE (0 << 6)// 关闭PWM计时器归零使能中断
#define ZERO_INT_ENABLE (1 << 6)// 关闭PWM计时器归零使能中断


// #define PWM2_OUT_ENABLE (1 << 0)// PWM2 输出使能
// #define PWM3_OUT_ENABLE (1 << 1)// PWM3 输出使能
// #define PWM4_OUT_ENABLE (1 << 2)// PWM4 输出使能
// #define PWM5_OUT_ENABLE (1 << 3)// PWM5 输出使能
// #define PWM6_OUT_ENABLE (1 << 4)// PWM6 输出使能
#define PWM7_OUT_ENABLE (1 << 5)// PWM7 输出使能


sfr PWMCR = 0xF5;


// --------------------------------------------------------------


/*
PWM计数器为一个15位的寄存器,可设置1~32767之间的任意值作为PWM的周期。
*/
#define PWMCH   *((u8 volatile xdata *)0xFFF0)// PWM计时器高字节,PWMCH高7位
#define PWMCL   *((u8 volatile xdata *)0xFFF1)// PWM计时器低字节,PWMCH低8位




/*
PWM时钟选择寄存器
*/
#define PWM_CLK_SOURCE_SYS_CLK (0 << 4)// PWM时钟源使用系统时钟经分频后的时钟
#define PWM_CLK_SOURCE_TIM2 (1 << 4)// PWM时钟源使用定时器2溢出脉冲


// n = 1,2,3,4,5,6,7,...15 ;n = 1 表示1分频 n = 2 表示2分频
#define PWM_CLK_DEV(n) (((n) & 0x0F)-1)// PWM时钟源使用定时器2溢出脉冲


#define PWMCKS  *((u8 volatile xdata *)0xFFF2)








// PWM2翻转计数器
#define PWM2T1H *((u8 volatile xdata *)0xFF00) // PWM7的第一次翻转计时器的高字节
#define PWM2T1L *((u8 volatile xdata *)0xFF01) // PWM7的第一次翻转计时器的低字节
#define PWM2T2H *((u8 volatile xdata *)0xFF02) // PWM7的第二次翻转计时器的高字节
#define PWM2T2L *((u8 volatile xdata *)0xFF03) // PWM7的第二次翻转计时器的低字节




// --------------- PWM2CR -------------------------------


#define PWM2_T1_INT_INVERT_DISENABLE (0 << 0)// PWM7 T1 关闭T1翻转时中断
#define PWM2_T1_INT_INVERT_ENABLE (1 << 0)// PWM7 T1 使能T1翻转时中断


#define PWM2_T2_INT_INVERT_DISENABLE (0 << 1)// PWM7 T2 关闭T2翻转时中断
#define PWM2_T2_INT_INVERT_ENABLE (1 << 1)// PWM7 T2 使能T2翻转时中断


#define PWM2_INT_DISABLE (0 << 2)
#define PWM2_INT_ENABLE (1 << 2)


#define PWM2_P3_7 (0 << 3)
#define PWM2_P2_6 (1 << 3)


#define PWM2CR  *((u8 volatile xdata *)0xFF04)


// --------------------------------------------------------------




#define PWM7T1H *((u8 volatile xdata *)0xFF50) // PWM7的第一次翻转计时器的高字节
#define PWM7T1L *((u8 volatile xdata *)0xFF51) // PWM7的第一次翻转计时器的低字节
#define PWM7T2H *((u8 volatile xdata *)0xFF52) // PWM7的第二次翻转计时器的高字节
#define PWM7T2L *((u8 volatile xdata *)0xFF53) // PWM7的第二次翻转计时器的低字节
// --------------- PWM7CR -------------------------------


#define PWM7_T1_INT_INVERT_DISENABLE (0 << 0)// PWM7 T1 关闭T1翻转时中断
#define PWM7_T1_INT_INVERT_ENABLE (1 << 0)// PWM7 T1 使能T1翻转时中断


#define PWM7_T2_INT_INVERT_DISENABLE (0 << 1)// PWM7 T2 关闭T2翻转时中断
#define PWM7_T2_INT_INVERT_ENABLE (1 << 1)// PWM7 T2 使能T2翻转时中断


#define PWM7_INT_DISABLE (0 << 2)
#define PWM7_INT_ENABLE (1 << 2)


#define PWM7_P1_7 (0 << 3)
#define PWM7_P0_6 (1 << 3)


#define PWM7CR  *((u8 volatile xdata *)0xFF54)


// --------------------------------------------------------------









//sbit CCP0 = P2^5;
//sbit CCP1 = P2^6;


extern int xdata pwm0,pwm1,pwm2;




//extern char wind_in_size_id;
//extern char wind_out_size_id;


// extern u8 idata WinSize_In[6];
// extern u8 idata WinSize_Out[6];


void PWMn_Updata(u8 PCA_id, int pwm);
void PCA_PWM_Init(void);
void delay_ms_pwm(u8 ms);
void PWM7_Init(void);
#endif





// ---------------------------------------PCA_PWM.c--------------------------------------------------------- 


#include "PCA_PWM.h"
#include "GPIO.h"


int xdata pwm0,pwm1,pwm2;






//========================================================================
// 函数: void  delay_ms(u8 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注: 
//========================================================================


void delay_ms_pwm(u8 ms)
{
unsigned int i;
do{
i = MAIN_Fosc / 13000;
while(--i);
}while(--ms);
}


//========================================================================
// 函数: void PWMn_Updata(u8 PCA_id, u8 pwm)
// 描述: 更新占空比数据。
// 参数: PCA_id: 那个通道的PWM,pwm 即PWM输出高电平的PCA时钟脉冲个数。
// 返回: 无
// 版本: VER1.0
// 日期: 2014-6-21
// 备注: 
//========================================================================
void PWMn_Updata(u8 PCA_id, int pwm)
{
u8 SW2_tmp = 0;// SW2

if (pwm > PWM_HIGH_MAX) pwm = PWM_HIGH_MAX; //如果写入大于最大占空比数据,强制为最大占空比。
if (pwm < PWM_HIGH_MIN) pwm = PWM_HIGH_MIN;//如果写入小于最小占空比数据,强制为最小占空比。

if (PCA_id == PCA0)
{
CR = 0;
CCAP0L = (u8)pwm;// 将映射寄存器写入不好寄存器,先写CCAP0L
CCAP0H = CCAP0L;   // 后写CCAP0H // 启动PCA
CR = 1;
}
else if (PCA_id == PCA1)
{
CR = 0; // 停止PCA一会,一般不会影响PWM
CCAP1L = (u8)pwm;// 将映射寄存器写入不好寄存器,先写CCAP1L
CCAP1H = CCAP1L;   // 后写CCAP1H // 启动PCA
CR = 1; // 启动PCA
}
else if (PCA_id == PWM7)
{

SW2_tmp = P_SW2;// 保存SW2设置
EAXSFR(); // 访问 XFR 
PWM7T1L = 0xFF - (u8)pwm;// PWM7 第一个翻转计数器的低字节
P_SW2 = SW2_tmp;// EAXRAM(); 恢复访问 XRAM

PWMCR |= ENHANCE_PWM_ENABLE;// 使能PWM波形发生器, PWM计时器开始
}



}


//========================================================================
// 函数: void PCA_PWM_Init(void)
// 描述: PCA初始化程序.
// 参数: none
// 返回: none.
// 版本: V1.0, 2014-06-21
//========================================================================
void PCA_PWM_Init(void)
{

GPIO_InitTypeDefGPIO_InitStructure; //结构定义

// P3.5、 P3.6设置 推挽输出 PWM输出
GPIO_InitStructure.Pin  = GPIO_Pin_5 | GPIO_Pin_6;//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp;//推挽输出
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);//初始化

// P1.7设置 推挽输出 PWM输出
GPIO_InitStructure.Pin  = GPIO_Pin_7;//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_OUT_PP;//推挽输出
GPIO_Inilize(GPIO_P1 ,&GPIO_InitStructure);//初始化


PWM7_Init();

CR = 0;
AUXR1 = (AUXR1 & ~(3<<4)) | PCA_P34_P35_P36_P37;// 引脚配置
CCAPM0 = (PCA_Mode_PWM | DISABLE); // CCAPM0 PWM模式 不中断
CCAPM1 = (PCA_Mode_PWM | DISABLE); // CCAPM1 PWM模式 不中断


CH = 0;
CL = 0;
CMOD = (CMOD & ~(7<<1)) | PCA_Clock_4T;// 选择时钟  SYSclk/12

// pwm0 = (PWM_DUTY / 4 * 1);// 给PWM一个初始值
// pwm1 = (PWM_DUTY / 4 * 2);


pwm0 = PWM_HIGH_MAX;// 给PWM一个初始值 关闭
pwm1 = PWM_HIGH_MAX;
pwm2 = PWM_HIGH_MAX;

PWMn_Updata(PCA0, pwm0);
PWMn_Updata(PCA1, pwm1);
PWMn_Updata(PWM7, pwm2);

//CR = 1; // 运行PCA定时器
}








//========================================================================
// 函数: void PWM7_Init(void)
// 描述: PWM7 初始化函数.
// 参数: none
// 返回: none.
// 版本: 
// STC15W4K48S4 的 PWM7 是这个芯片新增的功能,它有6通道高精度PWM发生器,带死区控制的
// 增强型波形发生器,从PWM2 到 PWM8, 而 PCA_PWM 只有两路 PWM0 和 PWM1 
// 因为本程序要控制3个风机所以又添加了一个PWM7来控制风机
//========================================================================
void PWM7_Init(void)
{

EAXSFR(); // 访问 XFR 

PWMCFG |= PWM7_INIT_OUT_LOW;// PWM7 输出端口初始化为低电平

// PMW7 的时钟为 系统时钟的4分频和 PCA_PWM 即PWM0 和 PWM2 的时钟一样
PWMCKS |= PWM_CLK_SOURCE_SYS_CLK | PWM_CLK_DEV(4);

PWMCH = 0x00;
PWMCL = 0xFF; // PWM周期255



// ------------------ PWM7 ---------------------

// 这里设置PWM7的初始电平为低电平 ,
// 因为本程序用的是 PWM脉冲周期为255,所以 这里只用了 PWM7T1L 这个变量,PWM7T1H 永远为 0x00;
// PWM7 的驱动和 PWM0 和 PWM1 不同,它在一个周期内要设置两次翻转,这两次翻转的寄存器为 

// 第一次翻转寄存器 [PWM7T1H PWM7T1L]
// PWM计数器和 [PWM7T1H PWM7T1L] 进行比较,
// 如果 PWM计数器值 < [PWM7T1H PWM7T1L]  PWM7输出低电平 初始化设置为低电平,
// 如果 PWM计数器值 >= [PWM7T2H PWM7T2L]  PWM7输出高电平 ,


// 第二次翻转寄存器 [PWM7T1H PWM7T1L]
//  当 PWM7T1L 赋值为 0xFF时(在本程序里 0xFF 表示风机风量为关,这个值越小表示风量越大),
// 如果PWM 在来一个 CLK PWM跳变为高电平, 这时从 PWM计数器和 [PWM7T2H PWM7T2L] 
//  进行比较, 如果 PWM计数器值 < [PWM7T2H PWM7T2L]   则为高电平 ,
//    如果 PWM计数器值 >= [PWM7T2H PWM7T2L]  则为低电平 ,
// 因为 PWM7T2H = 0x00 , PWM7T2L = 0x01, 所以这个高电平持续时间只有一个CLK的时间 
// 所以达到输出高脉冲时间最短的设置,表示风量为关



// 在 PWM更新函数 PWMn_Updata(PWM7, pwm2); 里只改变 PWM7T1L 的值,其他值不变,则 就得到了 
// 通过 PWM7T1L 来控制 PWM的占空比. 当 PWM7T1L 越大 高电平持续的时间越短,PWM7T1L 越小 ,
// 高电平持续的时间越长,和 PCA_PWM 产生的效果一样


PWM7T1H = 0x00;
PWM7T1L = 0x00;// 

PWM7T2H = 0x00;
PWM7T2L = 0x01;

// PWM7 输出为默认值,关闭中断
PWM7CR = 0x00;

// --------------------------------------------------
EAXRAM(); // 恢复访问 XRAM


PWMCR |= PWM7_OUT_ENABLE;// PWM7 输出使能  PWM计时器没有开始 ,在PWMn_Updata(PWM7, pwm2); 中配置好后开始
}






0 0