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_Fosc
11059200
#define
PWM_DUTY
255
// 定义PWM的周期,数值为PCA所选择的时钟脉冲个数
#define
PWM_HIGH_MIN
1
// 限制PWM输出的最小占空比,避免中断里重装参数时间不够
#define
PWM_HIGH_MAX
255//(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_InitTypeDef
GPIO_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); 中配置好后开始
}