/*
说明:
本代码,用的是P70,P71,P72,P73四个产生PCA的PWM。
选择10位PWM模式
晶振频率22.1184Mhz,选择2分频,则PWM的频率都是10.85Khz左右
如果想用其他的端口,以及分频系数,将对应的端口宏定义的注释掉;同时认真阅读对应的函数,设置进去。
设置步骤:
1、PCAPWM_Init中切换端口代码;
2、分频系数设置。我们这里必须确定是10位PCA的PWM。
当晶振22.1184M,PCA是10位,
分频系数 时基us 周期 频率
1 0.045us 10240.045=46.3us 21.6k
2 0.09us 10240.09=92.16us 10.85khz
4 5.4khz
8 2.7k
16 0.723us 1024*0.723 =740.74us 1.35k
计算过程如下:
PCA的时钟来源是22.1184Mhz的二分频,则是11.0592Mhz,倒数就是PCA计数器的时间基准t0=1/11.0592M=0.09us
最大是10位,则PCA计时的最大值是2^10 *0.09us=92.16us,
0-1-2-…2^10—0–1,每次加1需要0.09us,则周期是92.16us;
所以频率是周期的倒数,1/92.16us=10.85khz
由于是10位的PWM,这里设置PWM的时候比较复杂,单片机将低八位之外的高两位,放在PCAPWMn的B5和B4位中;
更新占空比的时候,需要先关闭对应通道的PCAPWM,然后更新比较值,
更新比较值的时候,需要将高两位的B5和B4清0,然后将比较值的高两位提取出来赋值进去
之后,将比较值的低八位,放到对应的寄存器中。然后重新打开PCAPWM。
这里比较麻烦。
如果设置是8位的PCAPWM,就不用这么麻烦了。但是8位的PWM,最多等级是2^8=256,细分不够
变化不够光滑。既然有10位,那就用十位就好了。
*/
在这里插入图片描述
pcapwm.h
#ifndef __PCAPWM_H
#define __PCAPWM_H
#include "STC8a8k.h"
//PCA端口切换设置
//#define PCAPORTP1 0x00 //P1.7-P1.4 ECI=P1.2
//#define PCAPORTP2 0x10 //P2.3-P2.6 ECI=P2.2
#define PCAPORTP7 0x20 //P7.0-P73 ECI=P7.4
//#define PCAPORTP3 0x30 //P3.0-P3.3 ECI=P3.5
//PWM位数设置
//#define PCAPWM6Bit 0x80 //6位PWM
//#define PCAPWM7Bit 0x40
//#define PCAPWM8Bit 0x00
#define PCAPWM10Bit 0xC0
//PCA的时钟来源
//空闲模式继续PCA计数,禁止PCA计数器溢出中断
// CMOD--B7--B6--B5--B4 B3--B2--B1--B0
//CMOD--CIDL-k---k---k----CPS[2:0]----ECF
//#define PCACLK1 0x08 //系统时钟
#define PCACLK2 0x02 //系统时钟/2
//#define PCACLK4 0x0A //系统时钟/4
//#define PCACLK6 0x0C //系统时钟/6
//#define PCACLK8 0x0E //系统时钟/8
//#define PCACLK12 0x00 //系统时钟/12
//#define PCACLKTIM0 0x04 //定时器0的溢出脉冲
//#define PCACLKECI 0x06 //ECI引脚的外部输入时钟
//PCA模式
#define PCAPWMModeEnable 0x42 //PCA用作PWM模式
#define PCAPWMModeDisable 0x40 //PCA用作PWM模式
void PCAPWM_Init();
void PCAPWM_OutEnable(bit ena);//0是不是能输出,1:输出PWM
void PCA_Pwm0_10BitSet(float Duty);//Duty=0---1之间,如果等于0,输出低电平,没PWM。
void PCA_Pwm1_10BitSet(float Duty);
void PCA_Pwm2_10BitSet(float Duty);
void PCA_Pwm3_10BitSet(float Duty);
#endif
/*
说明:
本代码,用的是P70,P71,P72,P73四个产生PCA的PWM。
选择10位PWM模式
晶振频率22.1184Mhz,选择2分频,则PWM的频率都是10.85Khz左右
如果想用其他的端口,以及分频系数,将对应的端口宏定义的注释掉;同时认真阅读对应的函数,设置进去。
设置步骤:
1、PCAPWM_Init中切换端口代码;
2、分频系数设置。我们这里必须确定是10位PCA的PWM。
当晶振22.1184M,PCA是10位,
分频系数 时基us 周期 频率
1 0.045us 1024*0.045=46.3us 21.6k
2 0.09us 1024*0.09=92.16us 10.85khz
4 5.4khz
8 2.7k
16 0.723us 1024*0.723 =740.74us 1.35k
计算过程如下:
PCA的时钟来源是22.1184Mhz的二分频,则是11.0592Mhz,倒数就是PCA计数器的时间基准t0=1/11.0592M=0.09us
最大是10位,则PCA计时的最大值是2^10 *0.09us=92.16us,
0-1-2-...2^10---0--1,每次加1需要0.09us,则周期是92.16us;
所以频率是周期的倒数,1/92.16us=10.85khz
由于是10位的PWM,这里设置PWM的时候比较复杂,单片机将低八位之外的高两位,放在PCAPWMn的B5和B4位中;
更新占空比的时候,需要先关闭对应通道的PCAPWM,然后更新比较值,
更新比较值的时候,需要将高两位的B5和B4清0,然后将比较值的高两位提取出来赋值进去
之后,将比较值的低八位,放到对应的寄存器中。然后重新打开PCAPWM。
这里比较麻烦。
如果设置是8位的PCAPWM,就不用这么麻烦了。但是8位的PWM,最多等级是2^8=256,细分不够
变化不够光滑。既然有10位,那就用十位就好了。
*/
pcapwm.c
#include "pcapwm.h"
#include "delay.h"
#include <uart.h>
#include "stdio.h"
///
void PCAPWM_Init()
{
//管脚切换,参考stc官方例程
P_SW1=PCAPORTP7;//切换到P7口
CCON=0x00;
CMOD=PCACLK2;//2分频 22.1182M/2=11.0592Mhz
CL=0x00;//从0开始计数
CH=0x00;
CCAPM0=PCAPWMModeDisable;//PCA0做PWM模式
PCA_PWM0=PCAPWM10Bit;//10位模式
CCAP0L=0x20;
CCAP0H=0x20;
CCAPM1=PCAPWMModeDisable;//PCA0做PWM模式
PCA_PWM1=PCAPWM10Bit;//10位模式
CCAP1L=0x20;
CCAP1H=0x20;
CCAPM2=PCAPWMModeDisable;//PCA0做PWM模式
PCA_PWM2=PCAPWM10Bit;//10位模式
CCAP2L=0x20;
CCAP2H=0x20;
CCAPM3=PCAPWMModeDisable;//PCA0做PWM模式
PCA_PWM3=PCAPWM10Bit;//10位模式
CCAP3L=0x20;
CCAP3H=0x20;
PCAPWM_OutEnable(1);
}
void PCA_Pwm0_10BitSet(float Duty)
{
unsigned int DutyNum=0;
if(Duty==0)
{
CCAPM0= PCAPWMModeDisable;
P70=0;//这里设置输出口等于低电平,不然默认高电平
return;
}
DutyNum=1024-Duty*1024;
CCAPM0= PCAPWMModeDisable;//重新设置PWM的时候,需要先关闭PWM
PCA_PWM0 &=~(3<<4);//清0重新装高2位XCCCAPNH B5 B4
PCA_PWM0 |=(DutyNum>>4)&0x30;//设置新的高2位
CCAP0H=DutyNum;//重载低8位
CCAPM0=PCAPWMModeEnable;//设置完成之后,打开PWM
}
void PCA_Pwm1_10BitSet(float Duty)
{
unsigned int DutyNum=0;
if(Duty==0)
{
CCAPM1= PCAPWMModeDisable;
P71=0;//这里设置输出口等于低电平,不然默认高电平
return;
}
DutyNum=1024-Duty*1024;
CCAPM1= PCAPWMModeDisable;//重新设置PWM的时候,需要先关闭PWM
PCA_PWM1 &=~(3<<4);//清0重新装高2位XCCCAPNH B5 B4
PCA_PWM1 |=(DutyNum>>4)&0x30;//设置新的高2位
CCAP1H=DutyNum;//重载低8位
CCAPM1=PCAPWMModeEnable;//设置完成之后,打开PWM
}
void PCA_Pwm2_10BitSet(float Duty)
{
unsigned int DutyNum=0;
if(Duty==0)
{
CCAPM2= PCAPWMModeDisable;
P72=0;//这里设置输出口等于低电平,不然默认高电平
return;
}
DutyNum=1024-Duty*1024;
CCAPM2= PCAPWMModeDisable;//重新设置PWM的时候,需要先关闭PWM
PCA_PWM2 &=~(3<<4);//清0重新装高2位XCCCAPNH B5 B4
PCA_PWM2 |=(DutyNum>>4)&0x30;//设置新的高2位
CCAP2H=DutyNum;//重载低8位
CCAPM2=PCAPWMModeEnable;//设置完成之后,打开PWM
}
void PCA_Pwm3_10BitSet(float Duty)
{
unsigned int DutyNum=0;
if(Duty==0)
{
CCAPM3= PCAPWMModeDisable;
P73=0;//这里设置输出口等于低电平,不然默认高电平
return;
}
DutyNum=1024-Duty*1024;
CCAPM3= PCAPWMModeDisable;//重新设置PWM的时候,需要先关闭PWM
PCA_PWM3 &=~(3<<4);//清0重新装高2位XCCCAPNH B5 B4
PCA_PWM3 |=(DutyNum>>4)&0x30;//设置新的高2位
CCAP3H=DutyNum;//重载低8位
CCAPM3=PCAPWMModeEnable;//设置完成之后,打开PWM
}
//********************************************
//0是不是能输出,1:输出PWM
void PCAPWM_OutEnable(bit ena)
{
if(ena==0)//关闭PWM模块
CR=0;
else
CR=1;
}
main.c
#include "stc8a8k.h"
#include "delay.h"
#include "pcapwm.h"
#include "stdio.h"
#include <uart.h>
//*************************************************主函数
void main()
{
float aa=0.1;
int duty0;
PCAPWM_Init();
UartInit();
delay_tms(5000);//两秒后开始
printf("aaa\r\n");
delay_tms(100);//两秒后开始
duty0=10;
while(1)
{
PCA_Pwm0_10BitSet(0.1);
PCA_Pwm1_10BitSet(0.2);
PCA_Pwm2_10BitSet(0.3);
PCA_Pwm3_10BitSet(0.4);
delay_tms(100);
PCA_Pwm0_10BitSet(0);
PCA_Pwm1_10BitSet(0);
PCA_Pwm2_10BitSet(0);
PCA_Pwm3_10BitSet(0);
delay_tms(100);
PCA_Pwm0_10BitSet(0.5);
PCA_Pwm1_10BitSet(0.6);
PCA_Pwm2_10BitSet(0.7);
PCA_Pwm3_10BitSet(0.8);
delay_tms(100);
PCA_Pwm0_10BitSet(0);
PCA_Pwm1_10BitSet(0);
PCA_Pwm2_10BitSet(0);
PCA_Pwm3_10BitSet(0);
delay_tms(100);
}
}