01 前言

就是这些个寄存器

发生了甚么事呢?

事情是这样的,项目需要用到PWM,很快啊,我就想到了我们厉害的STC。

打开STC-ISP开始选型,很快啊,找到手头有的STC8G1K08A符合要求。

注:《手册》为2020-11-05版STC8G说明手册

02 发展

直接复制粘贴例程,一气呵成,编译下载,PWM正常输出例程中的占空比。

使用的例程如下,位于《手册》的552与553页:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
//测试工作频率为11.0592MHz
#include "reg51.h"
#include "intrins.h"
sfr CCON = 0xd8;
sbit CF = CCON ^ 7;
sbit CR = CCON ^ 6;
sbit CCF2 = CCON ^ 2;
sbit CCF1 = CCON ^ 1;
sbit CCF0 = CCON ^ 0;
sfr CMOD = 0xd9;
sfr CL = 0xe9;
sfr CH = 0xf9;
sfr CCAPM0 = 0xda;
sfr CCAP0L = 0xea;
sfr CCAP0H = 0xfa;
sfr PCA_PWM0 = 0xf2;
sfr CCAPM1 = 0xdb;
sfr CCAP1L = 0xeb;
sfr CCAP1H = 0xfb;
sfr PCA_PWM1 = 0xf3;
sfr CCAPM2 = 0xdc;
sfr CCAP2L = 0xec;
sfr CCAP2H = 0xfc;
sfr PCA_PWM2 = 0xf4;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
void main()
{
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P3M0 = 0x00;
P3M1 = 0x00;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
CCON = 0x00;
CMOD = 0x08; //PCA时钟为系统时钟
CL = 0x00;
CH = 0x00;
//--6位PWM--
CCAPM0 = 0x42; //PCA模块0为PWM工作模式
PCA_PWM0 = 0x80; //PCA模块0输出6位PWM
CCAP0L = 0x20; //PWM占空比为50%[(40H-20H)/40H]
CCAP0H = 0x20;
//--7位PWM--
CCAPM1 = 0x42; //PCA模块1为PWM工作模式
PCA_PWM1 = 0x40; //PCA模块1输出7位PWM
CCAP1L = 0x20; //PWM占空比为75%[(80H-20H)/80H]
CCAP1H = 0x20;
//--8位PWM--
// CCAPM2 = 0x42; //PCA模块2为PWM工作模式
// PCA_PWM2 = 0x00; //PCA模块2输出8位PWM
// CCAP2L = 0x20; //PWM占空比为87.5%[(100H-20H)/100H]
// CCAP2H = 0x20;
//--10位PWM--
CCAPM2 = 0x42; //PCA模块2为PWM工作模式
PCA_PWM2 = 0xc0; //PCA模块2输出10位PWM
CCAP2L = 0x20; //PWM占空比为96.875%[(400H-20H)/400H]
CCAP2H = 0x20;
CR = 1; //启动PCA计时器
while (1)
;
}
//测试工作频率为11.0592MHz #include "reg51.h" #include "intrins.h" sfr CCON = 0xd8; sbit CF = CCON ^ 7; sbit CR = CCON ^ 6; sbit CCF2 = CCON ^ 2; sbit CCF1 = CCON ^ 1; sbit CCF0 = CCON ^ 0; sfr CMOD = 0xd9; sfr CL = 0xe9; sfr CH = 0xf9; sfr CCAPM0 = 0xda; sfr CCAP0L = 0xea; sfr CCAP0H = 0xfa; sfr PCA_PWM0 = 0xf2; sfr CCAPM1 = 0xdb; sfr CCAP1L = 0xeb; sfr CCAP1H = 0xfb; sfr PCA_PWM1 = 0xf3; sfr CCAPM2 = 0xdc; sfr CCAP2L = 0xec; sfr CCAP2H = 0xfc; sfr PCA_PWM2 = 0xf4; sfr P0M1 = 0x93; sfr P0M0 = 0x94; sfr P1M1 = 0x91; sfr P1M0 = 0x92; sfr P2M1 = 0x95; sfr P2M0 = 0x96; sfr P3M1 = 0xb1; sfr P3M0 = 0xb2; sfr P4M1 = 0xb3; sfr P4M0 = 0xb4; sfr P5M1 = 0xc9; sfr P5M0 = 0xca; void main() { P0M0 = 0x00; P0M1 = 0x00; P1M0 = 0x00; P1M1 = 0x00; P2M0 = 0x00; P2M1 = 0x00; P3M0 = 0x00; P3M1 = 0x00; P4M0 = 0x00; P4M1 = 0x00; P5M0 = 0x00; P5M1 = 0x00; CCON = 0x00; CMOD = 0x08; //PCA时钟为系统时钟 CL = 0x00; CH = 0x00; //--6位PWM-- CCAPM0 = 0x42; //PCA模块0为PWM工作模式 PCA_PWM0 = 0x80; //PCA模块0输出6位PWM CCAP0L = 0x20; //PWM占空比为50%[(40H-20H)/40H] CCAP0H = 0x20; //--7位PWM-- CCAPM1 = 0x42; //PCA模块1为PWM工作模式 PCA_PWM1 = 0x40; //PCA模块1输出7位PWM CCAP1L = 0x20; //PWM占空比为75%[(80H-20H)/80H] CCAP1H = 0x20; //--8位PWM-- // CCAPM2 = 0x42; //PCA模块2为PWM工作模式 // PCA_PWM2 = 0x00; //PCA模块2输出8位PWM // CCAP2L = 0x20; //PWM占空比为87.5%[(100H-20H)/100H] // CCAP2H = 0x20; //--10位PWM-- CCAPM2 = 0x42; //PCA模块2为PWM工作模式 PCA_PWM2 = 0xc0; //PCA模块2输出10位PWM CCAP2L = 0x20; //PWM占空比为96.875%[(400H-20H)/400H] CCAP2H = 0x20; CR = 1; //启动PCA计时器 while (1) ; }
//测试工作频率为11.0592MHz
#include "reg51.h"
#include "intrins.h"
sfr CCON = 0xd8;
sbit CF = CCON ^ 7;
sbit CR = CCON ^ 6;
sbit CCF2 = CCON ^ 2;
sbit CCF1 = CCON ^ 1;
sbit CCF0 = CCON ^ 0;
sfr CMOD = 0xd9;
sfr CL = 0xe9;
sfr CH = 0xf9;
sfr CCAPM0 = 0xda;
sfr CCAP0L = 0xea;
sfr CCAP0H = 0xfa;
sfr PCA_PWM0 = 0xf2;
sfr CCAPM1 = 0xdb;
sfr CCAP1L = 0xeb;
sfr CCAP1H = 0xfb;
sfr PCA_PWM1 = 0xf3;
sfr CCAPM2 = 0xdc;
sfr CCAP2L = 0xec;
sfr CCAP2H = 0xfc;
sfr PCA_PWM2 = 0xf4;
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P1M1 = 0x91;
sfr P1M0 = 0x92;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xb1;
sfr P3M0 = 0xb2;
sfr P4M1 = 0xb3;
sfr P4M0 = 0xb4;
sfr P5M1 = 0xc9;
sfr P5M0 = 0xca;
void main()
{
    P0M0 = 0x00;
    P0M1 = 0x00;
    P1M0 = 0x00;
    P1M1 = 0x00;
    P2M0 = 0x00;
    P2M1 = 0x00;
    P3M0 = 0x00;
    P3M1 = 0x00;
    P4M0 = 0x00;
    P4M1 = 0x00;
    P5M0 = 0x00;
    P5M1 = 0x00;
    CCON = 0x00;
    CMOD = 0x08; //PCA时钟为系统时钟
    CL = 0x00;
    CH = 0x00;
    //--6位PWM--
    CCAPM0 = 0x42;   //PCA模块0为PWM工作模式
    PCA_PWM0 = 0x80; //PCA模块0输出6位PWM
    CCAP0L = 0x20;   //PWM占空比为50%[(40H-20H)/40H]
    CCAP0H = 0x20;
    //--7位PWM--
    CCAPM1 = 0x42;   //PCA模块1为PWM工作模式
    PCA_PWM1 = 0x40; //PCA模块1输出7位PWM
    CCAP1L = 0x20;   //PWM占空比为75%[(80H-20H)/80H]
    CCAP1H = 0x20;
    //--8位PWM--
    // CCAPM2 = 0x42; //PCA模块2为PWM工作模式
    // PCA_PWM2 = 0x00; //PCA模块2输出8位PWM
    // CCAP2L = 0x20; //PWM占空比为87.5%[(100H-20H)/100H]
    // CCAP2H = 0x20;
    //--10位PWM--
    CCAPM2 = 0x42;   //PCA模块2为PWM工作模式
    PCA_PWM2 = 0xc0; //PCA模块2输出10位PWM
    CCAP2L = 0x20;   //PWM占空比为96.875%[(400H-20H)/400H]
    CCAP2H = 0x20;
    CR = 1; //启动PCA计时器
    while (1)
        ;
}

这里有一个小细节,PCA_PWMx的操作方式都是字节操作,并没有位操作。

快进到程序写到PWM操作,到了我喜欢的#define操作环节,写出了如下代码:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \
PCA_PWM##PCAn &= 0xCD; \ //设置寄存器为初始值
PCA_PWM##PCAn |= (valH & 0x03) << 4; \ //设置9,10位
PCA_PWM##PCAn |= (valH & 0x04) >> 1; \ //设置11位
CCAP##PCAn##H = valL; //设置低八位
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \ PCA_PWM##PCAn &= 0xCD; \ //设置寄存器为初始值 PCA_PWM##PCAn |= (valH & 0x03) << 4; \ //设置9,10位 PCA_PWM##PCAn |= (valH & 0x04) >> 1; \ //设置11位 CCAP##PCAn##H = valL; //设置低八位
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \
    PCA_PWM##PCAn &= 0xCD;                        \ //设置寄存器为初始值
    PCA_PWM##PCAn |= (valH & 0x03) << 4;          \ //设置9,10位
    PCA_PWM##PCAn |= (valH & 0x04) >> 1;          \ //设置11位
    CCAP##PCAn##H = valL; //设置低八位

我乖乖的按照《手册》P545的注意的顺序进行了设置,但是,无论后期怎么调用该宏定义进行更改,输出一直是设定的初始值:高。

我@#¥!@!@#¥要疯了,凭啥?

03 后语

用串口一步一步进行排查,最后将问题定位到了这个宏定义处。

经过观察发现,例程竟然没有用位操作进行PCA_PWMx的数据更新!

你设置了个甚么!

然后想起了某些特殊寄存器不能进行位操作只能进行字节操作,就写出了如下修改后的程序:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \
x = PCA_PWM##PCAn; \
x &= 0xCD; \
x |= (valH & 0x03) << 4; \
x |= (valH & 0x04) >> 1; \
PCA_PWM##PCAn = x; \
CCAP##PCAn##H = valL;
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \ x = PCA_PWM##PCAn; \ x &= 0xCD; \ x |= (valH & 0x03) << 4; \ x |= (valH & 0x04) >> 1; \ PCA_PWM##PCAn = x; \ CCAP##PCAn##H = valL;
#define _PCA_PWMSetReloadValue(PCAn, valH, valL) \
    x = PCA_PWM##PCAn;                           \
    x &= 0xCD;                                   \
    x |= (valH & 0x03) << 4;                     \
    x |= (valH & 0x04) >> 1;                     \
    PCA_PWM##PCAn = x;                           \
    CCAP##PCAn##H = valL;

对变量进行位操作后再直接字节赋值就可以正常进行调制了,,,

我无fa可说啊xdm,,

贴一个最后成功调制输出50%与75%占空比的波形:

日狗,yyds

我希望,我们强大的STC,耗子尾汁,好好反思。以后不要再犯这样的马虎,小马虎,啊,嗯… 开发者要以和为贵,要讲武德,不要搞缺印漏印。谢谢朋友们!