打印
[国产单片机]

求助:STC单片机PWM问题

[复制链接]
2128|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
chenjch|  楼主 | 2014-4-14 11:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
dirtwillfly| | 2014-4-14 22:02 | 只看该作者
你第二行里也说了,是大约19KHz,所以PWM频率有一点误差也是可以的

使用特权

评论回复
板凳
wh6ic| | 2014-4-15 15:42 | 只看该作者
20MHz时钟出PWM是只有几百Hz,要出19KHz,要么降低PWM有效位数为10Bit,要么提高时钟频率到一般难以承受的地步(似乎过GHz了?)

使用特权

评论回复
地板
wh6ic| | 2014-4-15 15:52 | 只看该作者
另外说一个不幸的消息,STC的PWM最高分辨率是8Bit,16Bit也好、10Bit也罢,都没有......

使用特权

评论回复
5
chenjch|  楼主 | 2014-4-15 21:03 | 只看该作者
dirtwillfly 发表于 2014-4-14 22:02
你第二行里也说了,是大约19KHz,所以PWM频率有一点误差也是可以的

但是这里达不到19KHz,按照这样子算大约只有300多Hz,感觉太少了呀

使用特权

评论回复
6
chenjch|  楼主 | 2014-4-15 21:07 | 只看该作者
wh6ic 发表于 2014-4-15 15:52
另外说一个不幸的消息,STC的PWM最高分辨率是8Bit,16Bit也好、10Bit也罢,都没有...... ...

但是数据手册上说的这个是什么意思啊?
“用CCP/PCA软硬件结合实现9~16位PWM”

使用特权

评论回复
7
chenjch|  楼主 | 2014-4-15 21:09 | 只看该作者
我把程序贴上来吧!这个好像是12位6KHz的程序,请大家帮我看看!
/*------------------------------------------------------------------*/
/* --- STC MCU International Limited -------------------------------*/
/* --- STC 1T Series MCU Programme Demo ----------------------------*/
/* --- Fax: 86-755-82944243 ----------------------------------------*/
/* --- Tel: 86-755-82948412 ----------------------------------------*/
/* If you want to use the program or the program referenced in the  */
/* article, please specify in which data and procedures from STC    */
/*------------------------------------------------------------------*/

/*      本程序经过测试完全正常, 不提供电话技术支持, 如不能理解, 请自行补充相关基础.  */

/*
功能: 使用STC内带的PCA做9~16位的PWM。在PWMn.h中选择是STC12C5201AD系列还是STC12C5A60S2系列。
                 原理说明:
本示例程序介绍在一些应用中所需要的高于8位分辨率的9~16位PWM,而8位的PWM可以直接使用STC的硬件PWM,请参考有关的的(Datasheet)。
本应用所需要资源:PCA可编程计数器阵列,捕获寄存器,匹配中断向量。
程序用到两个16位变量:
PWM_high  保存PWM输出高电平的PCA时钟数。
PWM_low   保存PWM输出低电平的PCA时钟数。
PWM的周期 = PWM_HIGH + PWM_LOW。
PCA时钟源有8种选择。
PCA模块被配置为16位高速输出方式,当PCA计数值与捕获寄存器数值匹配时,将CCP0输出取反,同时发生比较匹配中断。
比较匹配中断里判断高速输出的电平,如果是高电平,则向捕获寄存器装入高电平的PCA时钟数。如果是低电平,则装入低电平的PCA时钟数。
由于中断处理需要一点时间,所以输出的占空比不能到0%或100%,所以对PWM_high有最小和最大值,中断处理绝对时间大约为100个SYSCLK。

本示例程序的测试是基于如下假设:
PCA时基信号为系统时钟Fosc,PCA中断优先级为最高。
提示:其它中断服务开销很长时间时,有可能会影响本程序的正常运行。

本示例程序用户可以在"用户配置宏"中选择以下参数:
PCA_IDLE_DISABLE    在IDLE模式是否禁止PCA工作,选择1: MCU在IDLE模式时禁止PCA工作,  选择0:  MCU在IDLE模式时允许PCA工作。
PCA_SOURCE_SELECT   选择PCA的基准时钟源,本示例使用系统时钟Fosc做PCA时钟源。
PWM_DUTY            定义PWM的周期,数值为PCA所选择的时钟脉冲个数,用户只需要装载PWM_high,PWM_low是根据这个周期计算出来的。
PWM_HIGH_MAX        限制PWM输出的最大占空比,原因如前所述。如果装载PWM_high大于此数值,将返回错误。
PWM_HIGH_MIN        限制PWM输出的最小占空比,原因如前所述。如果装载PWM_high小于此数值,将返回错误。
*/

#include "reg51.h"

#define     MAIN_Fosc   24576000L   //定义时钟
#define     PCA_IDLE_DISABLE    0           //1: MCU在IDLE模式时禁止PCA工作。   0:  MCU在IDLE模式时允许PCA工作。
#define     PCA_SOURCE_SELECT   4           //选择PCA的基准时钟源。
                                            //0:系统时钟Fosc/12。
                                            //1:系统时钟Fosc/2。
                                            //2:定时器0的溢出。
                                            //3:ECI/P3.4脚的外部时钟输入(最大=Fosc/2)。
                                            //4:系统时钟Fosc。
                                            //5:系统时钟Fosc/4。
                                            //6:系统时钟Fosc/6。
                                            //7:系统时钟Fosc/8。
#define     PWM_DUTY        4096            //定义PWM的周期,数值为PCA所选择的时钟脉冲个数


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


sfr P_SW1       = 0xA2;                     //外设功能切换寄存器1

#define CCP_S0 0x10                         //P_SW1.4
#define CCP_S1 0x20                         //P_SW1.5

sfr CCON        =   0xD8;                   //PCA控制寄存器
sbit CCF0       =   CCON^0;                 //PCA模块0中断标志
sbit CCF1       =   CCON^1;                 //PCA模块1中断标志
sbit CR         =   CCON^6;                 //PCA定时器运行控制位
sbit CF         =   CCON^7;                 //PCA定时器溢出标志
sfr CMOD        =   0xD9;                   //PCA模式寄存器
sfr CL          =   0xE9;                   //PCA定时器低字节
sfr CH          =   0xF9;                   //PCA定时器高字节
sfr CCAPM0      =   0xDA;                   //PCA模块0模式寄存器
sfr CCAP0L      =   0xEA;                   //PCA模块0捕获寄存器 LOW
sfr CCAP0H      =   0xFA;                   //PCA模块0捕获寄存器 HIGH
sfr CCAPM1      =   0xDB;                   //PCA模块1模式寄存器
sfr CCAP1L      =   0xEB;                   //PCA模块1捕获寄存器 LOW
sfr CCAP1H      =   0xFB;                   //PCA模块1捕获寄存器 HIGH
sfr CCAPM2      =   0xDC;                   //PCA模块2模式寄存器
sfr CCAP2L      =   0xEC;                   //PCA模块2捕获寄存器 LOW
sfr CCAP2H      =   0xFC;                   //PCA模块2捕获寄存器 HIGH
sfr PCA_PWM0    =   0xf2;                   //PCA模块0的PWM寄存器
sfr PCA_PWM1    =   0xf3;                   //PCA模块1的PWM寄存器
sfr PCA_PWM2    =   0xf4;                   //PCA模块2的PWM寄存器

sfr P1M0        =   0x92;
sfr P1M1        =   0x91;

sbit  CCP0      =   P1^1;
sbit  CCP1      =   P1^0;

#define     PWM_HIGH_MAX    PWM_DUTY-32     //限制PWM输出的最大占空比。
#define     PWM_HIGH_MIN        32          //限制PWM输出的最小占空比。

/*************  本地变量声明    **************/
unsigned int    pwm;        //定义用户操作的PWM变量

/*************  本地函数声明    **************/
void  delay_ms(unsigned char ms);



/****************  外部函数声明和外部变量声明 *****************/
extern unsigned int PWM_high;               //PWM空比寄存器,即PWM输出高电平的PCA时钟脉冲个数(占空比写入变量)。
void PWMn_SetHighReg(unsigned int high);
void PWMn_init(unsigned int high);


/******************** 主函数 **************************/
//========================================================================
// 函数: void main(void)
// 描述: 不断更新PWM值,用示波器观察占空比变化。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2011-4-11
// 备注:
//========================================================================
void main(void)
{
    pwm = 1000;                             //pwm初值
    pwm = PWM_HIGH_MIN;                     //pwm初值
    PWMn_init(pwm); //初始化pwm

    while (1)
    {
        delay_ms(10);   //延时
        pwm += 10;
        if(pwm >= PWM_HIGH_MAX) pwm = PWM_HIGH_MIN;
        PWMn_SetHighReg(pwm);               //更新PWM的占空比
    }
}
/**********************************************/


//========================================================================
// 函数: void  delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数.
// 返回: none.
// 版本: VER1.0
// 日期: 2010-12-15
// 备注:
//========================================================================
void  delay_ms(unsigned char ms)
{
     unsigned int i;
     do
     {
        i = MAIN_Fosc / 14000L; //1T
        while(--i)  ;
     }while(--ms);
}

unsigned int    PWM_high;                   //定义PWM占空比寄存器,即PWM输出高电平的PCA时钟脉冲个数(占空比写入变量)。
unsigned int    PWM_low;                    //定义PWM输出低电平的PCA时钟脉冲个数。
unsigned int    CCAP0_tmp;                  //定义CCAP0重装载影射寄存器。

//========================================================================
// 函数: void PWMn_SetHighReg(unsigned int high)
// 描述: 写入占空比数据。
// 参数: high:  占空比数据,即PWM输出高电平的PCA时钟脉冲个数。
// 返回: 无
// 版本: VER1.0
// 日期: 2009-12-30
// 备注:
//========================================================================
void PWMn_SetHighReg(unsigned int high)
{
    if(high > PWM_HIGH_MAX)     high = PWM_HIGH_MAX;    //如果写入大于最大占空比数据,强制为最大占空比。
    if(high < PWM_HIGH_MIN)     high = PWM_HIGH_MIN;    //如果写入小于最小占空比数据,则返回错误代码2。
    CR = 0;                     //停止PCA。
    PWM_high = high;                        //数据在正确范围,则装入占空比寄存器。
    PWM_low = PWM_DUTY - high;              //计算并保存PWM输出低电平的PCA时钟脉冲个数。
    CR = 1;                     //启动PCA。
}

//========================================================================
// 函数: void PWMn_init(unsigned int high)
// 描述: 初始化程序。
// 参数: high:  初始化占空比数据,即PWM输出高电平的PCA时钟脉冲个数。
// 返回: 无
// 版本: VER1.0
// 日期: 2009-12-30
// 备注:
//========================================================================
void PWMn_init(unsigned int high)
{
    ACC = P_SW1;
    ACC &= ~(CCP_S0 | CCP_S1);              //CCP_S0=0 CCP_S1=0
    P_SW1 = ACC;                            //(P1.2/ECI, P1.1/CCP0, P1.0/CCP1, P3.7/CCP2)

//  ACC = P_SW1;
//  ACC &= ~(CCP_S0 | CCP_S1);              //CCP_S0=1 CCP_S1=0
//  ACC |= CCP_S0;                          //(P3.4/ECI_2, P3.5/CCP0_2, P3.6/CCP1_2, P3.7/CCP2_2)
//  P_SW1 = ACC;
//
//  ACC = P_SW1;
//  ACC &= ~(CCP_S0 | CCP_S1);              //CCP_S0=0 CCP_S1=1
//  ACC |= CCP_S1;                          //(P2.4/ECI_3, P2.5/CCP0_3, P2.6/CCP1_3, P2.7/CCP2_3)
//  P_SW1 = ACC;

    P1M1 &= ~0x02,  P1M0 |=  0x02;          //CCAP0使用PUSH-PULL输出模式
    CCON = 0;                               //清除CF、CR、CCF0、CCF1
    CMOD = (PCA_IDLE_DISABLE << 7) | (PCA_SOURCE_SELECT << 1);  //初始化PCA模式寄存器,这两项在PWMn.h中选择。
    CCAPM0 = 0x4D;                          //高速输出模式,允许比较匹配中断(ECCF0=1)。
    CL = 0;                                 //清空PCA基本计数器。
    CH = 0;
    CCAP0_tmp = 0;                          //清空CCAP0重装载影射寄存器。
    PWMn_SetHighReg(high);                  //初始化占空比数据。
    CR = 1;                                 //启动PCA。
    EA = 1;                                 //允许总中断
}

//========================================================================
// 函数: void PCA_interrupt (void) interrupt 7
// 描述: PCA中断服务程序。
// 参数: 无。
// 返回: 无。
// 版本: VER1.0
// 日期: 2009-12-30
// 备注:
//========================================================================
void PCA_interrupt (void) interrupt 7
{
    if(CCF0 == 1)       //PCA模块0中断
    {
        CCF0 = 0;       //清PCA模块0中断标志

        if(CCP0 == 1)   CCAP0_tmp += PWM_high;      //输出为高电平,则给影射寄存器装载高电平时间长度
        else            CCAP0_tmp += PWM_low;       //输出为低电平,则给影射寄存器装载低电平时间长度
        CCAP0L = (unsigned char)CCAP0_tmp;          //将影射寄存器写入捕获寄存器,先写CCAP0L
        CCAP0H = (unsigned char)(CCAP0_tmp >> 8);   //后写CCAP0H
    }
/*
    else if(CCF1 == 1)                         //PCA模块1中断
    {
        CCF1 = 0;                              //清PCA模块1中断标志
    }
    else if(CF == 1)                           //PCA溢出中断
    {
        CF = 0;                                //清PCA溢出中断标志
    }
*/
}

使用特权

评论回复
8
dirtwillfly| | 2014-4-15 23:50 | 只看该作者
chenjch 发表于 2014-4-15 21:07
但是数据手册上说的这个是什么意思啊?
“用CCP/PCA软硬件结合实现9~16位PWM” ...

鱼与熊掌不能兼得

使用特权

评论回复
9
chenjch|  楼主 | 2014-4-16 11:05 | 只看该作者
dirtwillfly 发表于 2014-4-15 23:50
鱼与熊掌不能兼得

就是说位数高,频率就不可避免地要降低,是这个意思吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

5

帖子

0

粉丝