打印

单片机本身的硬件PWM输出是8位的,如何实现16位PWM输出?

[复制链接]
11413|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
any_014|  楼主 | 2015-6-2 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 any_014 于 2015-6-6 11:34 编辑

用的STC12单片机,选的还是个20脚的...
本来用的PCA功能里的PWM输出功能,可惜是8位的,不过倒是方便,给CH和CL写个数,PCA计时器计时后,如果小于这个值相应管教输出低电平,大于这个值输出高电平。挺省心的。
可现在发现8位有点不够用了,想弄成16位的。

看了下STC官网的例子,用一个定时器生成多路PWM输出。是用一个定时器,每次中断,有个计数值自动加一,增到一定值时,归零,算是周期吧。中间用这个计数值做比较来控制IO口输出高或低。
就是定时器中断太频繁,给其它任务的时间少了。

其他想到的,就是用PCA的16位定时器功能,因为四路PCA公用一个定时器,把其中两路设为16位计时器模式,一路设的值为低电平时间,另一路设成最大值,为整个周期的时间,这样两路引起的中断,分别将单片机IO口拉高和拉低。
就是觉得有点麻烦。

STC的PCA还有个高速输出功能,是计时器到了设定值引发IO口电平反转。
给的例子是,PCA中断后将CH和CL的值自动增加一固定值,这样总是经过固定的时间触发IO口反转。
有没有可能用这个模式产生占空比可调并且周期固定的PWM?

-----------------------------------------------------------------------------------------
现在按自己想的改了下,结果用定时器模式,PCA输出管脚没有变化,不知道哪里设置错了...
void PCAInit()
{
        CCON = 0;                       //Initial PCA control register
                                    //PCA timer stop running
                                    //Clear CF flag
                                    //Clear all module interrupt flag
    CL = 0;                         //Reset PCA base timer
    CH = 0;
    CMOD = 0x00;                    //Set PCA timer clock source as Fosc/12


    CCAP0H = 0x80;               //第一路用来产生固定占空比的方波,想每中断一次,IO管脚翻转一次;
        CCAP0L = 0x00;
        CCAPM0 = 0x49;                  //PCA module-0 work in 8-bit PWM mode and no PCA interrupt

    CCAP1H = CCAP1L = 0x00;         //设为16位定时器模式,到预定值后,PWM管脚输出高电平;CCAP1H,CCAP1L值在主程序里根据测量值改变;
    CCAPM1 = 0x49;
        
        CCAP2H = CCAP2L = 0xFF;         //设为16位定时器模式,到预定值后,PWM管脚输出低电平;设为0xFFFF,为PWM波一周期计数值;
    CCAPM2 = 0x49;

    CR = 1;                         //PCA timer start run
    EPCAI = 1;

}
void PCA_isr() interrupt 6 using 1
{
    if(CCF0)
        {
                CCF0 = 0;
                VEE = !VEE;
        }
        if(CCF1)
        {
                CCF1 = 0;
                DAPWM = !DAPWM;
        }
        if(CCF2)
        {
                CCF2 = 0;
        }
}

-----------------------------------------------------------------------------------------------

发现PCA定时器有个溢出中断,这样应该只用一个PCA模组做16位定时器就可以了。

-------------------------------------------------------------------------------------------------

当模组0计时器引发中断,将IO管脚拉低高;PCA计时器溢出引发中断,将IO管脚拉低。这样试着没问题。
看了下波形,占空比略有变化,估计是其他中断占用时间了。

------------------------------------------------------------------------------------------------------

PCA中断影响主程序时间采样了...
也许该放弃这个了,下次改板时换成STC15系列的吧...

--------------------------------------------------------------------------------------------------

按默认中断优先级来的话,外部中断>定时器中断>串口中断,现在外部中断和计数器中断是轮流开着的,应该没有影响到定时器计数的吧,还是不知道为什么会定时器测量数会跳,难道是硬件问题?

相关帖子

沙发
any_014|  楼主 | 2015-6-2 17:31 | 只看该作者
还有选用的是20脚的STC12,只有两路PCA输出管脚,不知道另两路PCA模块是不是也给省掉了?

使用特权

评论回复
板凳
hjh2008303| | 2015-6-3 09:45 | 只看该作者
用16BIT 定时器外加一个输出引脚,在定时器里改变引脚状态,可行

使用特权

评论回复
地板
any_014|  楼主 | 2015-6-3 11:16 | 只看该作者
hjh2008303 发表于 2015-6-3 09:45
用16BIT 定时器外加一个输出引脚,在定时器里改变引脚状态,可行

我现在想的是用两个定时器控制。

看了STC官网的例子,用1个定时器实现的,但是中断的太频繁了。

使用特权

评论回复
5
ayb_ice| | 2015-6-3 11:21 | 只看该作者
any_014 发表于 2015-6-3 11:16
我现在想的是用两个定时器控制。

看了STC官网的例子,用1个定时器实现的,但是中断的太频繁了。 ...

软件是不可能真正实现16位的精度的

中断处理的时间会对精度造成影响

使用特权

评论回复
6
any_014|  楼主 | 2015-6-3 16:12 | 只看该作者
ayb_ice 发表于 2015-6-3 11:21
软件是不可能真正实现16位的精度的

中断处理的时间会对精度造成影响

额,其实用不了16位那么高。
只是现在做个温度变送器,0-400度的范围,如果是8位PWM输出的话,估计就等2度2度的变化了。
所以想高一点。

使用特权

评论回复
7
any_014|  楼主 | 2015-6-3 16:34 | 只看该作者
现在按自己想的改了下,结果用定时器模式,PCA输出管脚没有变化,不知道哪里设置错了...
相关程序在主楼更新,请各位帮忙看看。

使用特权

评论回复
8
coody| | 2015-6-3 17:40 | 只看该作者
ayb_ice 发表于 2015-6-3 11:21
软件是不可能真正实现16位的精度的

中断处理的时间会对精度造成影响

16位自动重装或PCA就不会影响精度。

使用特权

评论回复
9
ayb_ice| | 2015-6-4 08:52 | 只看该作者
coody 发表于 2015-6-3 17:40
16位自动重装或PCA就不会影响精度。

重装载也做不到

软件要控制输出,进入中断都会有抖动,中断是有延迟的,而且不是个定值

使用特权

评论回复
10
any_014|  楼主 | 2015-6-4 09:00 | 只看该作者
caosix 发表于 2015-6-3 17:33
硬件 都做不到的 ,最好 别用软件去做,

那样 扩展 分辨率,,其实 可靠性 很低。。

F4XX系列的太贵了吧。
也用不到32位的...
可能的话,以后会考虑用STM32F1XX的。

使用特权

评论回复
11
hjh2008303| | 2015-6-4 19:53 | 只看该作者
any_014 发表于 2015-6-3 11:16
我现在想的是用两个定时器控制。

看了STC官网的例子,用1个定时器实现的,但是中断的太频繁了。 ...

中断太频繁也不好,所以你还是考虑换平台吧,话说要那么高精度干什么呢?

使用特权

评论回复
12
any_014|  楼主 | 2015-6-5 10:06 | 只看该作者
hjh2008303 发表于 2015-6-4 19:53
中断太频繁也不好,所以你还是考虑换平台吧,话说要那么高精度干什么呢? ...

额,要不了那么高精度,估计10位就足够了。

使用特权

评论回复
13
hjh2008303| | 2015-6-6 18:47 | 只看该作者
any_014 发表于 2015-6-5 10:06
额,要不了那么高精度,估计10位就足够了。

10位都1024了,什么系统需要1024可级别呢

使用特权

评论回复
14
any_014|  楼主 | 2015-6-8 09:23 | 只看该作者
hjh2008303 发表于 2015-6-6 18:47
10位都1024了,什么系统需要1024可级别呢

现在在做个PT100变送器,0-400度输入范围,4-20mA输出。如果用8位定时器的话,估计就是2度一跳了。

使用特权

评论回复
15
gx_huang| | 2015-6-8 13:20 | 只看该作者
这个容易呀,还得看你自己系统的软件架构,自己用定时器输出PWM也是可以的,只是周期长一些,外部的RC滤波时间常数大一些就可以了。假设定时器周期25US,2000等级就是50毫秒。如果软件算法好一些,波动会很小的。
以下是一个软件PWM输出算法:
PWM输出加低通滤波,PWM输出的大周期是0.512秒(20个小周期),小周期是25.6毫秒。
比如IV输出为131时,分成20份,每份6,余数是11,则前11个小周期内输出7,后9个小周期内输出6。
总输出还是131,但是前11小周期和后9小周期的输出不一样。
经过这样处理后,滤波输出的波动会小很多,但是一个大周期内还是有1的波动。

如果你有PWM硬件输出,在前一次PWM输出周期内计算下一个输出值,比如10个PWM周期组成一个大的周期。
总的最大值是2560,如果输出1001,1001=100*10+1,前面9个PWM=100,最后一个PWM=101。

使用特权

评论回复
16
any_014|  楼主 | 2015-6-8 14:09 | 只看该作者
gx_huang 发表于 2015-6-8 13:20
这个容易呀,还得看你自己系统的软件架构,自己用定时器输出PWM也是可以的,只是周期长一些,外部的RC滤波 ...

比较独特的想法...
没那么想过,谢谢你了。

现在是放弃了用定时器做PWM输出的想法,因为前边AD转换用的双积分的,现在感觉AD采样不稳,每次上电测量结果和上次不一致,怀疑是其他中断影响了测量。

使用特权

评论回复
17
gx_huang| | 2015-6-8 14:30 | 只看该作者
any_014 发表于 2015-6-8 14:09
比较独特的想法...
没那么想过,谢谢你了。

你如果是软件方式实现ADC的,没有人比我更清楚了。
你的采样有抖动,是因为你负责ADC的定时中断优先级和中断模式不对。
ADC和PWM,可以在一个定时器里实现的。

使用特权

评论回复
18
any_014|  楼主 | 2015-6-9 09:11 | 只看该作者
|--------20ms定时------|----切换通道,等待外部中断---|
|------反向积分---------|----正向积分------------------------|

正向积分时间是我需要的,如果ADC和PWM用同一个定时器,不可能吧?得需要定时器中断触发IO引脚电平改变吧。

使用特权

评论回复
19
gx_huang| | 2015-6-9 09:23 | 只看该作者
改变电路,改变思路,不要一棵树吊死。

使用特权

评论回复
20
hjh2008303| | 2015-6-13 21:38 | 只看该作者
any_014 发表于 2015-6-8 09:23
现在在做个PT100变送器,0-400度输入范围,4-20mA输出。如果用8位定时器的话,估计就是2度一跳了。 ...

如果精度真的很高的话,还是升级硬件,用定时器实现的,如果中间多了一两条指令,pwm也就不标准了

使用特权

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

本版积分规则

17

主题

132

帖子

3

粉丝