完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
大家好!有人能指出一些关于如何获得正弦波调制的PWM的应用说明或示例代码(请参阅附图)。我正在尝试设置一个PWM来控制一个单相逆变器。我应该为此使用PWM发生器,还是应该结合数字输出使用定时器?我真的不知道怎样在dsPIC上得到这个结果。至于正弦波实现,我打算使用一个查找表来提高速度,因为我理解sin(x)的计算要求很高。一些技术细节:-dsPIC33EP64GS506-时钟速率:120MHz,60MIPS-PWM f频率应为20-50kHz -正弦波频率为50赫兹,谢谢!
以上来自于百度翻译 以下为原文 Hello everyone! Can someone please point out to some application notes or example codes on how to get a PWM with a sine wave modulation (please see attached figure). I'm trying to set up a PWM to control a single-phase inverter. Should I use a PWM generator for that purpose, or should I use a timer in a combination with a digital output? I really don't have a clue how to get this on a dsPIC. As for the sine wave implementation, I plan to use a look-up table for the sake of speed, as I understand that evaluation of sin(x) is computationally quite demanding. Some technical details: - dsPIC33EP64GS506 - Clock rate: 120 MHz, 60 MIPS - PWM frequency should be 20-50 kHz - Sine wave frequency is 50 Hz Thank you in advance! Attached Image(s) |
|
相关推荐
17个回答
|
|
亲爱的DarioG,谢谢你的回答!为什么我要更新一个定时IRQ内的占空比?我的意思是,我可以使用PWM IRQ来更新占空比,例如,在每个PWM周期结束时?我不明白为什么我必须使用计时器。
以上来自于百度翻译 以下为原文 Dear DarioG, Thank you for your answer! Why should I update the duty cycle inside a timed IRQ? I mean, can I update the duty cycle using the PWM IRQ, e.g., at the end of the each PWM period? I don't understand why do I have to use a timer. M. |
|
|
|
嗯,因为(除了可能的智能硬件模块)在其简单的设计中,PWM周期将比正弦波周期快得多……
以上来自于百度翻译 以下为原文 Well, because (apart from possible smart hardware modules) in its simple design, the PWM period will be much faster than the sinewave period... |
|
|
|
AHA,所以计时器只是用来减少计算工作量?例如,在20kHz PWM和50Hz正弦波时,我将有400个间隔,也许只有40个间隔就足以仿真50Hz正弦波,这也取决于输出滤波器。我做对了吗?
以上来自于百度翻译 以下为原文 Aha, so the timer is just used to reduce the computation effort? E.g., at 20 kHz PWM and 50 Hz sine wave, I would have 400 intervals, and maybe it's sufficient to have only 40 intervals to emulate a 50-Hz sine wave, which also depends on the output filter. Did I get this right? |
|
|
|
对于256微步进,我的表用了500字节存储0-90度,我用它来控制步进电机。由于cos和sin是动态的,所以计时器用来重新加载占空比。更多的间隔会使波形更平滑。irqs是最好的方法,因为你知道它会被同时调用。精确的时间加上你可以做其他事情,比如闪光灯。
以上来自于百度翻译 以下为原文 For 256 micro-stepping my table took 500 bytes storing 0-90 degrees which I use to control a stepper motor. The timer is used to re-load the duty cycle since cos and sin are dynamic. More intervals will make the wave smoother. irqs are is the best way to go since you know it will be called at the same precise time plus you can do other stuff like flashing a led. |
|
|
|
看一下:“一些处理不动点的经验
以上来自于百度翻译 以下为原文 Take a look at: "Some experience how to handle fixed point It is possible to compute true sine in fixed point format for every PWM period. For example, you have 60MIPS. It is about 1200 instruction cycles per each 50kHz PWM period. It is quite possible to brrow 69..73 instruction cycles from this amount of TCYs to compute fine, precise and true sine with minimum efforts. No coding for lookup tables, just single function Sine=_Q15sinePI(Phi). 500 fine points per half-wave! |
|
|
|
|
|
|
|
大家好,我设法得到了一个正弦波,没有任何问题。这是我的评论:-我不能使用60MIPS,而是30MIPS。如果我用7.37MHz晶体代替10MHz晶体,我就可以使用60MIPS。原因在于辅助时钟配置。-我没有使用_Q15sinePI(x),因为使用查找表(LUT)的方法快了近50%,并且我有足够的内存。Nikolay_Po-谢谢你的建议,我将考虑将来使用libq.h库来改进我的代码:)这是dsPIC33EP64GS506的完整工作代码。我希望将来能对别人有所帮助。
以上来自于百度翻译 以下为原文 Hi everyone, I managed to get a sine wave without any problems. Here are my comments: - I can't use 60 MIPS, but 30 MIPS instead. If I replace my 10-MHz crystal with a 7.37-MHz crystal, I would be able to use 60 MIPS. The reason lies in the auxiliary clock configuration. - I didn't use _Q15sinePI(x), since the approach with a lookup table (LUT) is almost 50% faster, and I have enough memory. Nikolay_Po - thank you for your suggestion, I'll consider using libq.h library in the future to improve my code :) Here is the complete working code for dsPIC33EP64GS506. I hope it might help someone in the future. // main.c #include "xc.h" #define FCY 60000000UL #include /******************************************************************************/ /***** CONFIGURATION BITS *****************************************************/ /******************************************************************************/ // FOSCSEL #pragma config FNOSC = FRC // Oscillator source: Internal fast RC (FRC) #pragma config IESO = OFF // Start up with user-selected oscillator source // FOSC #pragma config POSCMD = XT // Primary oscillator mode: XT crystal oscillator mode #pragma config OSCIOFNC = OFF // OSC2 pin function: OSC2 is clock output #pragma config FCKSM = CSECMD // Clock switching is enabled and Fail-safe Clock Monitor is disabled #pragma config PLLKEN = ON // Clock switch to PLL source will wait until the PLL lock signal is valid // FICD #pragma config ICS = PGD1 // ICD communication channel: Communicate on PGEC1 and PGED1 #pragma config JTAGEN = OFF // JTAG is disabled // FDEVOPT #pragma config PWMLOCK = OFF // PWM registers may be written without key sequence /******************************************************************************/ /***** GLOBAL VARIABLES *******************************************************/ /******************************************************************************/ short phi = 0; // Phase char quad = 1; // Quadrant // Sine wave converted in a duty cycle in 101 points // for the 1st quadrant only: [0°-90°] (limits included) const unsigned short sin100_0_90[101] = { 12000, 12188, 12377, 12565, 12753, 12942, 13129, 13317, 13504, 13691, 13877, 14063, 14249, 14433, 14618, 14801, 14984, 15166, 15348, 15528, 15708, 15887, 16065, 16242, 16417, 16592, 16766, 16938, 17109, 17279, 17448, 17615, 17781, 17946, 18108, 18270, 18430, 18588, 18745, 18900, 19053, 19205, 19355, 19503, 19649, 19793, 19936, 20076, 20215, 20351, 20485, 20618, 20748, 20876, 21001, 21125, 21246, 21365, 21482, 21596, 21708, 21818, 21925, 22030, 22132, 22232, 22329, 22424, 22516, 22605, 22692, 22776, 22858, 22937, 23013, 23087, 23157, 23225, 23291, 23353, 23413, 23470, 23524, 23575, 23623, 23668, 23711, 23751, 23787, 23821, 23852, 23880, 23905, 23928, 23947, 23963, 23976, 23987, 23994, 23999, 24000, }; int main(void) { /******************************************************************************/ /***** INITIALIZATION: OSCILLATOR *********************************************/ /******************************************************************************/ // EXTERNAL CRYSTAL FREQUENCY: 10 MHz // FCY = 60 MHz (30 MIPS) // NOTE: CPU can work faster (up to 70 MIPS), but PWM then must use (poor) FRC oscillator. // FPLLI=FIN/N1 // N1=PLLPRE+2, N1 in [2,33] short N1 = 2; CLKDIVbits.PLLPRE = N1-2; // N1=PLLPRE+2=2 // FVCO=FPLLI*M // M=PLLDIV+2, M in [2,513] short M = 24; PLLFBD = M-2; // FPLLO=FVCO/N2 (FPLLO=FOSC, FCY=FOSC/2) // N2=2*(PLLPOST+1), N2 is {2,4,8} short N2 = 2; // 2, 4 or 8 CLKDIVbits.PLLPOST = N2/2-1; /* ** Initiate clock switch ** 1. Wait for clock switch to occur ** 2. Wait for PLL to lock */ // Primary Oscillator with PLL (XTPLL, HSPLL, ECPLL) __builtin_write_OSCCONH(0x03); // 0b011 -> NOSC<2:0> (OSCCON<10:8>) // Request oscillator switch to selection specified by the NOSC<2:0> bits __builtin_write_OSCCONL(OSCCON | 0x01); // 0b1 -> OSWEN<0> (OSCCON<0>) // Wait for Clock switch to occur // Current Oscillator Selection bits (read-only): COSC<2:0> (OSCCON<15:13>) while (OSCCONbits.COSC!=0b011); // Wait for PLL to lock // PLL Lock Status bit (read-only): LOCK<0> (OSCCON<5>) while (OSCCONbits.LOCK!=1); /* ** Configure auxiliary oscillator ** 112-120 MHz for proper PWM and ADC operation */ // Configure source to fast RC with APLL ACLKCONbits.SELACLK = 0; // Use primary PLL as a source (FVCO = 120 MHz) ACLKCONbits.APSTSCLR = 0b111; // Divide-by-1 for PWM /******************************************************************************/ /***** INITIALIZATION: PORTS **************************************************/ /******************************************************************************/ // Set all ports to low LATA = 0x00; LATB = 0x00; LATC = 0x00; LATD = 0x00; // Set all ports to digital ANSELA = 0x00; ANSELB = 0x00; ANSELC = 0x00; ANSELD = 0x00; // Set all ports to digital output TRISA = 0x00; TRISB = 0x00; TRISC = 0x00; TRISD = 0x00; /******************************************************************************/ /***** INITIALIZATION: PWM ****************************************************/ /******************************************************************************/ // ACRONYMS: // PWM Pulse-Width Modulation // ITB Independent Time Base // CAM Center-Aligned Mode // CMM Complementary mode // PWM time base control register PTCONbits.PTEN = 0; // Disable high-speed PWM module PTCONbits.EIPU = 0; // Active period register updates occur on PWM cycle boundaries // PWM clock divider select register PTCON2bits.PCLKDIV = 0b000; // Divide-by-1, maximum PWM timing resolution // Configure PWM2 generator PWMCON2bits.CAM = 1; // Center-aligned mode (must use ITB) PWMCON2bits.ITB = 1; // Enable independent time base (must use for CAM) PWMCON2bits.MDCS = 0; // PDCx/SDCx registers provide duty cycle PWMCON2bits.DTC = 0b00; // Positive dead-time is actively applied for all output modes PWMCON2bits.IUE = 0; // Updates to the active PDCx/SDCx registers are synchronized to the local PWM time base PWMCON2bits.TRGIEN = 1; // A trigger event generates an IRQ // In a case of the center-aligned mode (CAM), PHASEx/SPHASEx registers provide the time base period // {PTPER,STPER,PHASEx,SPHASEx} = [(ACLK*8*PWM_PERIOD)/(PCLKDIV)]-8 // ACLK = 120 MHz (see auxiliary oscillator in the oscillator initialization routine) PHASE2 = 23992; // 40 kHz, 25 us // PWMx generator duty cycle register PDC2 = 2000; // 8 -> 0% // PWMx alternate dead-time register // In the case of the center-aligned mode configured in the complementary mode, // only ALTDTRx provides dead-time period, whereas DTRx is not used // {DTRx,ALTDTRx} = (ACLK*8*DEAD_TIME)/(PCLKDIV) ALTDTR2 = 144; // 150 ns // PWMx I/O control register IOCON2bits.PENH = 1; // PWMx module controls the PWMxH pin IOCON2bits.PENL = 1; // PWMx module controls the PWMxL pin IOCON2bits.POLH = 0; // PWMxH pin is active-high IOCON2bits.POLL = 0; // PWMxL pin is active-high IOCON2bits.PMOD = 0b00; // PWMx I/O pin pair is in the Complementary PWM output mode IOCON2bits.OVRENH = 0; // PWMx generator provides data for the PWMxH pin IOCON2bits.OVRENL = 0; // PWMx generator provides data for the PWMxL pin IOCON2bits.SWAP = 0; // PWMxH and PWMxL pins are mapped to their respective pins // Enable PWM interrupt IFS5bits.PWM2IF = 0; IEC5bits.PWM2IE = 1; IPC23bits.PWM2IP = 0b111; // Enable high-speed PWM PTCONbits.PTEN = 1; /******************************************************************************/ /***** INFINITE LOOP **********************************************************/ /******************************************************************************/ while(1); return 0; } /******************************************************************************/ /***** INTERRUPT SERVICE ROUTINE: PWM2 ****************************************/ /******************************************************************************/ // Sinewave is generated in this function void __attribute__((__interrupt__, __auto_psv__)) _PWM2Interrupt(void) { // Clear PWM2 interrupt flag IFS5bits.PWM2IF = 0; if (quad==1) { PDC2 = sin100_0_90[phi]; if (phi==100) { quad = 2; phi--; } else { phi++; } } else if (quad==2) { PDC2 = sin100_0_90[phi]; if (phi==0) { quad = 3; phi++; } else { phi--; } } else if (quad==3) { PDC2 = 24000-sin100_0_90[phi]; if (phi==100) { quad = 4; phi--; } else { phi++; } } else if (quad==4) { PDC2 = 24000-sin100_0_90[phi]; if (phi==0) { quad = 1; phi++; } else { phi--; } } else { // error: do nothing } return; } Attached Image(s) |
|
|
|
好极了!PS:不需要在中断处理程序中返回,并且…使用开关()
以上来自于百度翻译 以下为原文 nice ! ps: no need for a return in the interrupt handler, and... use a switch() |
|
|
|
你可以弹出一个指向上下的正弦表。清除所有如果…否则,它可以更快地退出IRQ。
以上来自于百度翻译 以下为原文 You could bounce a pointer up and down a sin table. Get rid of all the if..else so it can exit the irq quicker. |
|
|
|
嗯,对我来说,这看起来足够好,指针可能会加速一些,但在某些情况下
以上来自于百度翻译 以下为原文 Hmmm, to me this looks good enough pointers may speed up a little, but only in some cases |
|
|
|
这样编码比较安全:并且确保硬件在PIC管脚复位时变成三态时能安全停放。
以上来自于百度翻译 以下为原文 IMHO here } else { // error: do nothing } it's safer to code thais way: } else { // error: emergency stop & reset Reset(); } And make sure the hardware will park itself safely in case of PIC pins become tristate in reset. |
|
|
|
如果需要循环和小代码大小,则进行汇编。
以上来自于百度翻译 以下为原文 If you want the cycles and small code size then assembly. |
|
|
|
你们想得太多了,上面的“其他”永远不会发生,而C非常适合这种琐碎而缓慢的任务……
以上来自于百度翻译 以下为原文 You guys are overthinking That "else" above will never happen, and C is more than fit for such a trivial and slow task... |
|
|
|
取决于象限变量声明。如果它是全局的或易变的,编译器将实现所有情况,包括用于开关构造的“默认”。无论如何,有意地剪切异常值是良好的实践。例如,原始的OP代码可以在无效象限值上循环前行。当然,如果编译器没有优化这个情况。对于像电力逆变器这样的复杂情况,必须编写健壮的代码,以监视所有变量的合理限制。在复杂的EMI条件下的长时间运行可能导致RAM、CPU和外围操作的非零错误率。固件应该以最安全的方式对错误作出反应。
以上来自于百度翻译 以下为原文 Depends on quadrant variable declaration. If it will be global or volatile the compiler will implement all the cases, including "default" for switch construction. Anyway it's good practice to cut abnormal values intentionally. For example, original OP code may loop forewer at invalid quadrant value. Of course if the case wasn't optimized by compiler. For such complex conditions like power inverter it is mandatory to write robust code which is monitoring all the variables for theirs reasonable limints. Prolonged operation under complex EMI conditions may result nonzero error rate for RAM, CPU and peripheral operation. The firmware should react for an errors the safest way possible. |
|
|
|
|
|
|
|
这里是一个更有效的正弦波函数的实现(最多需要大约30个周期):
以上来自于百度翻译 以下为原文 Here is a much more efficient implementation of a sine wave function (it takes around 30 cycles at most): short fun_sin(short fi) { // +1 for 1st/2nd quadrants // -1 for 3rd/4th quadrants short sign = +1; // If angle is in 3rd/4th quadrant, translate it to 1st/2nd quadrant. // N2Q is total number of points in two quadrants. if (fi>N2Q) { fi = fi - N2Q; sign = -1; } // If angle is in 2nd/4th quadrant, iterate backwards. // N1Q is total number of points in a single quadrant. // Note that N2Q=2*N1Q if (fi>N1Q) { fi = N2Q - fi; } // Lookup table for sine wave contains N1Q+1 values, as follows: // lut_sin1q[0] = sin(0) // lut_sin1q[N1Q] = sin(90) - it is very important to include this point! return (sign*lut_sin1q[fi]); } |
|
|
|
谢谢大家的解释。我正在使用PIC16f1936控制器做正弦波逆变器。我做了正弦表,根据正弦表在全桥产生pwm。在pwm周期结束时或在中间用定时器中断更新pwm占空比?我正在使用16khz pwm频率.void中断isr(void){if(TMR0IF==1){count++;if(count>159){i^=1;count=0;}P1M1=i;P1M0=1;pwm(表[10]);TMR0=156;TMR0IF=0;}}
以上来自于百度翻译 以下为原文 Thanks all for giving nice explaination. I am working on sine wave inverter using PIC16f1936 controller. I made sine table , generate pwm in full bridge according to sine table . When to update pwm duty cycle using timer0 interrupt at end of pwm cycle or in middle ? i am using 16 khz pwm frequency. void interrupt isr(void) { if(TMR0IF==1) { count++; if(count>159) {i^=1; count=0; } P1M1=i; P1M0=1; pwm(table[10]); TMR0=156; TMR0IF=0; } } |
|
|
|
只有小组成员才能发言,加入小组>>
5146 浏览 9 评论
1993 浏览 8 评论
1921 浏览 10 评论
请问是否能把一个ADC值转换成两个字节用来设置PWM占空比?
3162 浏览 3 评论
请问电源和晶体值之间有什么关系吗?PIC在正常条件下运行4MHz需要多少电压?
2218 浏览 5 评论
714浏览 1评论
601浏览 1评论
有偿咨询,关于MPLAB X IPE烧录PIC32MX所遇到的问题
484浏览 1评论
PIC Kit3出现目标设备ID(00000000)与预期的设备ID(02c20000)不匹配。是什么原因
615浏览 0评论
513浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 05:25 , Processed in 1.400535 second(s), Total 111, Slave 94 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号