搜索
bottom↓
回复: 36

Hi-speed software generated PWM

[复制链接]

出0入0汤圆

发表于 2010-6-17 09:49:18 | 显示全部楼层 |阅读模式
most software PWM generation methods rely on counting the cycle and then decide if a bit needs to be turned on. This approach, when implemented efficiently, can be fairly fast, but its efficiency goes down as the number of independent pwm channels go up. For example, on a 12F675 running at 4Mhz, the fastest 4-ch 256-bit pwm generation is about 3.5ms, per cycle. The issue there is that at each increment of the cycle counter, you have to compare a pwm's pre-determined duty cycle with the cycle counter to decide if a pwm channel should be turned on (or off). each test takes 3 instruction cycles so if you have 4 channels, that's 12 instruction cycles + a few for the overhead, and you are talking about ~15 instruction cycles per cycle count. for a 256-bit pwm, that's a total of 256*15=4000 instruction cycles. or about 4ms on a 4Mhz pic.

obviously, if you need to generate more channels, the cycle time goes up exponentially and making that approach unacceptible for multi-channel output.

the following is a different approach that aims to minimize the cycle time. Rather than testing each cycle count, this approach tests each channel exponentially and produces exponential delays.

so for 256-bit pwm, it makes just 8 comparison per channel, vs. the 256 comparison per channel of the old method.

the result is greatly improved speed.

出0入0汤圆

 楼主| 发表于 2010-6-17 09:49:44 | 显示全部楼层
here is the code, implemented on a 12F675.

=============code=======================

#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

void delay(unsigned char dly_shift) {        //just waste some time
        while (dly_shift--) NOP();
}
       
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x20
#define PWM3_DC                        0x4f
#define PWM4_DC                        0x2a
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu         

        while(1)
        {
                for (shift=1; shift<(1<<7); shift<<=1) {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        delay(shift);
                }
        }

}

出0入0汤圆

 楼主| 发表于 2010-6-17 09:51:59 | 显示全部楼层
the cycle time is about 1ms, vs. 4ms for the old approach.

and the cycle time degrades linearly with the number of channels, not exponentially as in the old approach.

here is the simulation in proteus.

enjoy.



(原文件名:12F675 PWM Shift.PNG)

出0入0汤圆

发表于 2010-6-17 09:54:28 | 显示全部楼层
楼主为啥不用中文呢

出0入0汤圆

 楼主| 发表于 2010-6-17 10:30:11 | 显示全部楼层
fixed a bug, refined the delay() routine (so it runs faster).

now, it finishes a cycle in 0.6ms!

===========code===================

#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6

void delay(unsigned char dly_shift) {        //just waste some time
//        while (dly_shift--) NOP();
        switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
        }
}
       
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x20
#define PWM3_DC                        0x4f
#define PWM4_DC                        0x2a
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu         

        while(1)
        {
                shift=1;
                while ((shift & (1<<7))==0) {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        shift<<=1;
                        delay(shift);
                }
        }

}

出0入0汤圆

发表于 2010-6-17 10:39:30 | 显示全部楼层
回复【3楼】fzfh1219  
楼主为啥不用中文呢
-----------------------------------------------------------------------
楼主一直用英文, 中文输入很生疏了. 很多datasheet都是英文.不乐意笑笑走开就是.

出0入0汤圆

 楼主| 发表于 2010-6-17 10:58:01 | 显示全部楼层
more optimized: now, it produces 8-bit, 4-ch pwm in 0.5ms (2Khz). 4-bit, 4-ch pwm in 0.15ms (7Khz).

this is probably the fastest pwm routine out there.

=========code============

//multi-channel pwm generation
//about 0.5ms per cycle, 8-bit, 4-ch, on a 12F675 @4Mhz
//about 0.15ms per cycle, 4-bit, 4-ch.
#include <htc.h>

__CONFIG(MCLRDIS & BORDIS & WDTDIS & PWRTEN & INTIO);

#define PWM_Resolution                (1<<3)                        //pwm resolution. (1<<3) = 4-bit / 16 steps, (1<<7)=8-bit / 256 steps
#define LED                                (1<<0)
#define PWM_PORT                GPIO
#define PWM_DDR                        TRISIO
#define PWM_SET(bits)        PWM_PORT |= (bits)        //set bits on PWM_port
#define PWM_CLR(bits)        PWM_PORT &=~(bits)        //clear bits on PWM_port
#define PWM_FLP(bits)        PWM_PORT ^= (bits)        //flip bits on PWM_port
#define PWM_STROBE(bits)        PWM_SET(bits); PWM_CLR(bits)
#define PWM1                        (1<<1)                                //pwm pin
#define PWM2                        (1<<2)                                //pwm pin
#define PWM3                        (1<<4)                                //pwm pin
#define PWM4                        (1<<5)                                //pwm pin
#define PWM1_DC                        0x01                                //pwm duty cycles
#define PWM2_DC                        0x02
#define PWM3_DC                        0x0f
#define PWM4_DC                        0x0e
//#define PWM_TMR_OFFSET        0x00                                //tmr0 offset. real cycle from offset+error -> 0xff. error is about 4-5
//#define g_pwmCounter        TMR0                                //define g_pwmCounter as timer

//unsigned char g_pwmCounter=0;

#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6

void delay(unsigned char dly_shift) {        //just waste some time
//        while (dly_shift--) NOP();
        switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
        }
}
       
void mcu_init(void) {
        ANSEL=0x00;                                        //all pins gpio
        CMCON=0x07;                                        //analog comparators off
        PWM_DDR &=~(LED | PWM1 | PWM2 | PWM3 | PWM4);        //put pwmx into output mode
}

void
main(void)
{
        unsigned char shift;

        mcu_init();                                        //initialize the mcu         

        while(1)
        {
                shift=1;
                do {
                        (PWM1_DC & shift)? PWM_SET(PWM1): PWM_CLR(PWM1);
                        (PWM2_DC & shift)? PWM_SET(PWM2): PWM_CLR(PWM2);
                        (PWM3_DC & shift)? PWM_SET(PWM3): PWM_CLR(PWM3);
                        (PWM4_DC & shift)? PWM_SET(PWM4): PWM_CLR(PWM4);
                        delay(shift);
                } while (((shift<<=1) & PWM_Resolution)==0);
        }

}

出0入0汤圆

 楼主| 发表于 2010-6-17 11:41:02 | 显示全部楼层
by inlining the delay() routine, I know get 8-bitx4 pwm in 0.4ms, and 4-bitx4 pwm in 0.12ms.

wow!
头像被屏蔽

出0入0汤圆

发表于 2010-6-17 11:47:59 | 显示全部楼层
谢谢。

好资料。
头像被屏蔽

出0入0汤圆

发表于 2010-6-17 11:50:25 | 显示全部楼层
回复【3楼】fzfh1219
楼主为啥不用中文呢
-----------------------------------------------------------------------
其实我一直希望“阿莫电子”上班时管理层能使用英文,抛弃中文。  我一直都有这个想法与计划。

很快将送3个员工到英文口语培训班。

出0入147汤圆

发表于 2010-6-17 11:52:29 | 显示全部楼层
It's great !, but we can't do anything else in the main routine :(

出0入0汤圆

发表于 2010-6-17 15:05:58 | 显示全部楼层
PWM4_DC 修改会造成信号斗动,一些应用用不了,比如有刷电机!

出0入0汤圆

发表于 2010-8-9 00:14:28 | 显示全部楼层
回复【6楼】millwood0
-----------------------------------------------------------------------

It's great!

出0入0汤圆

发表于 2010-11-16 09:38:37 | 显示全部楼层
LZ, where are you come form? chinese people welcome you!

出0入0汤圆

发表于 2010-11-16 10:14:50 | 显示全部楼层
>很快将送3个员工到英文口语培训班

wow. Nice.
Actually you may want to get direct video English training by people from North America.
I heard there are lots of English Training business target to Korea students via Skype video
(Back to the year of 2003, some company in small towns at Wisconsin hiring almost
all personal in town for the online training business).

P.s. Sooner or later the Skype will not be free anymore.

出0入0汤圆

发表于 2010-11-17 12:24:22 | 显示全部楼层
软件实现快速PWM

出0入8汤圆

发表于 2010-11-18 11:44:48 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-21 21:01:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-24 21:58:10 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-25 11:51:30 | 显示全部楼层
dddddddd

出0入0汤圆

发表于 2011-2-25 12:14:00 | 显示全部楼层
不过倾向于硬件处理

出0入0汤圆

发表于 2011-4-28 11:59:32 | 显示全部楼层
回复【13楼】Delong_z  天之蛟龙
-----------------------------------------------------------------------

你这英语说的啊。。。。。。

出0入0汤圆

发表于 2011-4-30 15:39:03 | 显示全部楼层
Hi-speed software generated PWM
你好 速度 软件 生成 PWM

出0入0汤圆

发表于 2011-5-1 00:51:34 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-1 10:29:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-28 17:03:00 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-19 17:59:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-9-2 09:20:43 | 显示全部楼层
mark soft PWM

出0入0汤圆

发表于 2011-9-2 14:16:36 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-6 21:54:56 | 显示全部楼层
mark!

出0入0汤圆

发表于 2011-12-6 22:24:18 | 显示全部楼层
hi-speed PWM mark

出0入0汤圆

发表于 2011-12-6 23:07:26 | 显示全部楼层
remarkable!

出0入0汤圆

发表于 2011-12-19 19:04:12 | 显示全部楼层
米木兄程序风格很好,马克之。

出0入0汤圆

发表于 2011-12-19 21:08:57 | 显示全部楼层
为了看懂millwood0兄台的帖子而努力学外语。。。

出0入0汤圆

发表于 2012-4-13 22:15:35 | 显示全部楼层
To type this English article is a hard work,isn't it?
By the way,i'm agree armok said quit use Chinese and use English.
I also want to type like LZ,but my English is very poor.
This reply is just a exercise,</smile~>

出0入0汤圆

发表于 2012-4-13 22:28:40 | 显示全部楼层
Hi-speed software generated PWM
你好 速度 软件 生成 PWM


Hi-speed 竟然译作“你好 速度”,吼一下!

出0入0汤圆

发表于 2012-5-13 19:06:15 | 显示全部楼层
#define delay0                NOP()
#define delay1                delay0; delay0
#define delay2                delay1; delay1
#define delay3                delay2; delay2
#define delay4                delay3; delay3
#define delay5                delay4; delay4
#define delay6                delay5; delay5
#define delay7                delay6; delay6


void delay(unsigned char dly_shift) {        //just waste some time
//        while (dly_shift--) NOP();
        switch (dly_shift) {
                case (1<<0): delay0; break;
                case (1<<1): delay1; break;
                case (1<<2): delay2; break;
                case (1<<3): delay3; break;
                case (1<<4): delay4; break;
                case (1<<5): delay5; break;
                case (1<<6): delay6; break;
                case (1<<7): delay7; break;
        }
}
      

技巧真的很强
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 08:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表