大锤子 发表于 2025-4-18 11:02:10

8G1K08 10位PWM疑问

<p>使用8G1K08 20pin的单片机,使用PCA0 模块的 PWM模式产生PWM方波;</p>
<p>PWM 初始化及占空比设置代码如下。其中 adc_value 为10位adc采样值,范围为0 ~1023;</p>
<p>`#include &quot;pwm.h&quot;</p>
<p>void PWM_Init(void)<br />
{<br />
P3M0 &amp;= ~0x20;<br />
P3M1 &amp;= ~0x20;</p>
<pre><code>P_SW1 &amp;= ~(0X20);
P_SW1 |= (0X10);                // 切换PCA0 的引脚为P35
CCON = 0X00;
CMOD = 0X0A;
CCAPM0 = 0X42;
PCA_PWM0 |= 0xc0;

CL = 0;
CH = 0;

// 下边的三个值共同绝顶初始占空比
PWM_Duty(1024/2);

CCON |= 0X40;
</code></pre>
<p>}</p>
<p>void PWM_Duty(unsigned int adc_value)<br />
{<br />
// 首先将 PCA_PWM0 的 EPC0H 初始化为0,然后或上adc_value的最高位;<br />
PCA_PWM0 &amp;= ~(0X02);<br />
PCA_PWM0 |= ((adc_value &gt;&gt; 9) &amp; 0x02);<br />
// 然后设置 PCA_PWM0 的 XCCAP0H (5:4)<br />
PCA_PWM0 &amp;= ~(0X30);<br />
PCA_PWM0 |= ((adc_value &gt;&gt; 5) &amp; 0x30);</p>
<pre><code>CCAP0H = (adc_value &amp; 0xff);
</code></pre>
<p>}</p>
<p>`</p>
<p>现象:</p>
<p>频率符合预期;</p>
<p>占空比看上去不太对。 求大神帮忙看下占空比设置是否正确。</p>
<p>另外有个小疑问, 这个PCA的计数器是16位的, 如果将CH,CL 设置为0, 等计数器溢出后是从多少开始计数, 需不需要软件设置 CH = 1111 1100 CL = 0000 0000</p>

DebugLab 发表于 2025-4-18 11:17:05

传入参数0000H~03FFH设置占空比

void PWM_Out(unsigned int pwm_0,pwm_1,pwm_2)
{
        unsigned char temp_l,temp_h,temp;
       
        temp_l=pwm_0&0x00ff;                //读pwm_0低8位赋值给temp_l
        temp_h=(pwm_0&0x0300)>>4;        //读pwm_0高2位,移动到XCCAP0H(PCA_PWM0)位置,赋值给temp_h
        temp=PCA_PWM0&0xcd;                        //读PCA_PWM0,XCCAP2H(PCA_PWM0)、EPC0H(PCA_PWM0)清零后赋值给temp
        temp_h|=temp;                                //写其他位到temph
        if(pwm_0==0x03ff)                        //如果pwm_0最大
                temp_h|=0x02;                        //设置EPC0H(PCA_PWM0)为1
        PCA_PWM0=temp_h;                        //写PCA_PWM0(先写高2位)
        CCAP0H=temp_l;                                //写CCAP0H(再写低8位)
       
        temp_l=pwm_1&0x00ff;                //读pwm_1低8位赋值给temp_l
        temp_h=(pwm_1&0x0300)>>4;        //读pwm_1高2位,移动到XCCAP1H(PCA_PWM1)位置,赋值给temp_h
        temp=PCA_PWM1&0xcd;                        //读PCA_PWM1,XCCAP1H(PCA_PWM2)、EPC1H(PCA_PWM1)清零后赋值给temp
        temp_h|=temp;                                //写其他位到temph
        if(pwm_1==0x03ff)                        //如果pwm_1最大
                temp_h|=0x02;                        //设置EPC1H(PCA_PWM1)为1
        PCA_PWM1=temp_h;                        //写PCA_PWM1(先写高2位)
        CCAP1H=temp_l;                                //写CCAP1H(再写低8位)
       
        temp_l=pwm_2&0x00ff;                //读pwm_2低8位赋值给temp_l
        temp_h=(pwm_2&0x0300)>>4;        //读pwm_2高2位,移动到XCCAP2H(PCA_PWM2)位置,赋值给temp_h
        temp=PCA_PWM2&0xcd;                        //读PCA_PWM2,XCCAP2H(PCA_PWM2)、EPC2H(PCA_PWM2)清零后赋值给temp
        temp_h|=temp;                                //写其他位到temph
        if(pwm_2==0x03ff)                        //如果pwm_2最大
                temp_h|=0x02;                        //设置EPC2H(PCA_PWM2)为1
        PCA_PWM2=temp_h;                        //写PCA_PWM2(先写高2位)
        CCAP2H=temp_l;                                //写CCAP2H(再写低8位)
}

梁工 发表于 2025-4-18 11:35:54

PCA计数器溢出后是从0开始计数的。
装载占空比是分开装载的,最好在PCA中断中及时装载,避免同步的问题。
外部程序装载占空比,有可能更改了高2位数据,低8位还未更改时,
刚好出现新周期的开始,会将新的高2位和旧的低8位组合在一起,出现错误,
但错误只在一个周期,没有再次更新占空比之前,随后的PWM都会正确。

大锤子 发表于 2025-4-18 13:41:15

梁工 发表于 2025-4-18 11:35
PCA计数器溢出后是从0开始计数的。
装载占空比是分开装载的,最好在PCA中断中及时装载,避免同步的问题。
...

就是CH和CL计数溢出后会从0000 0000 开始? 那10位的PWM 在 CH = 0000 0011 后还会继续计数? 直到 1111 1111 ?

梁工 发表于 2025-4-18 14:03:49

大锤子 发表于 2025-4-18 13:41
就是CH和CL计数溢出后会从0000 0000 开始? 那10位的PWM 在 CH = 0000 0011 后还会继续计数? 直到 1111...


手册里有详细的说明,你可以仔细看一下。
10位PWM模式是拿10位占空比数据跟CH、CL低10位做比较,高6位无意义,对于PWM来说,计数器是10位的,从0计到1023,再+1就是0,发出自动装载信号。

8位PWM模式是拿8位占空比数据跟CL低10位做比较,高6位无意义,对于PWM来说,计数器是10位的,从0计到1023,再+1就是0,发出自动装载信号。7位、6位类似。


大锤子 发表于 2025-4-18 16:01:54

梁工 发表于 2025-4-18 14:03
手册里有详细的说明,你可以仔细看一下。
10位PWM模式是拿10位占空比数据跟CH、CL低10位做比较,高6位无 ...

哦哦, 那就是说不需要考虑CH的高6位。 修改占空比之需要修改EPCnH CCAPnH XCCPnH 就好了,需要注意的是占空比这几个寄存器的修改不是原子操作。可能在相邻的两个周期之间有误差。
我这个LED调光的程序还好。 对这个要求不高。 只要大致波形对就可以了。 以后可以进一步优化。
页: [1]
查看完整版本: 8G1K08 10位PWM疑问