Hi-speed software generated PWM
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. 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);
}
}
} 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.
http://cache.amobbs.com/bbs_upload782111/files_30/ourdev_562178.PNG
(原文件名:12F675 PWM Shift.PNG) 楼主为啥不用中文呢 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);
}
}
} 回复【3楼】fzfh1219
楼主为啥不用中文呢
-----------------------------------------------------------------------
楼主一直用英文, 中文输入很生疏了. 很多datasheet都是英文.不乐意笑笑走开就是. 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);
}
} by inlining the delay() routine, I know get 8-bitx4 pwm in 0.4ms, and 4-bitx4 pwm in 0.12ms.
wow! 谢谢。
好资料。 回复【3楼】fzfh1219
楼主为啥不用中文呢
-----------------------------------------------------------------------
其实我一直希望“阿莫电子”上班时管理层能使用英文,抛弃中文。我一直都有这个想法与计划。
很快将送3个员工到英文口语培训班。 It's great !, but we can't do anything else in the main routine :( PWM4_DC 修改会造成信号斗动,一些应用用不了,比如有刷电机! 回复【6楼】millwood0
-----------------------------------------------------------------------
It's great! LZ, where are you come form? chinese people welcome you! >很快将送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. 软件实现快速PWM mark mark mark dddddddd 不过倾向于硬件处理 回复【13楼】Delong_z天之蛟龙
-----------------------------------------------------------------------
你这英语说的啊。。。。。。 Hi-speed software generated PWM
你好 速度 软件 生成 PWM mark mark mark mark mark soft PWM mark mark! hi-speed PWM mark remarkable! 米木兄程序风格很好,马克之。 为了看懂millwood0兄台的帖子而努力学外语。。。 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~> Hi-speed software generated PWM
你好 速度 软件 生成 PWM
Hi-speed 竟然译作“你好 速度”,吼一下!
#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;
}
}
技巧真的很强
页:
[1]