完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电子发烧友论坛|
我正在使用PWM5(最终)控制太阳能控制器中的MOSFET。我希望在PWM开关开启后的不同时间使用ADC读取电压。我的方法是TOA)使用TMR2(它输入PWM)在PWM被触发并设置为高的时候产生中断。注意:我在定时器上使用一个4X后标量,这意味着中断只会每4个PWM周期产生一次,将中断频率保持在一个合理的速率。B)在TMR0中断中,使用TMR2中断启动TMR0,它将在指定的时间段内产生中断。关闭TMR0并启动ADC读取。D)在不同的TMR0延迟下重复在PWM循环中的不同偏移的ADC采样。什么工作:A)PWM及其TMR2中断。我知道这是因为我可以看到一个范围内的PWM信号,并且我使用一个数字输出引脚在中断中高达几微秒,以产生在范围内可以看到的第二个输出信号。我在中断中也有一个计数器,我在一个主()循环中打印,以确认中断正在被触发。什么不起作用:B)TMR0生成的延迟在主()中从循环开始时起作用(用计数器和范围表示)。但不是在TMR2中断时启动的。我假设计时器/标志之间存在某种交互作用,并且在一个中断中,阻止计时器0从计时器2中断,但是我可以在这些论坛或其他地方找到任何东西。我非常感激。或者如果有另一种方式来做这件事,我们也会理解。我的主要C代码如下所示。PWM和定时器控制功能是由MCC在MPLAB X IDE V4.05中生成的。我附加了MCC生成的文件(以及相关的文件)和我的Me.c也作为单独的文件。注意,IFDelay-time0SyStand(59, 0);Delay-Time0SistActer();从TMR2YMyIdHealthHythLe()移动到Trime:TMR0的while循环似乎正常运行。它不在TMR2yMyIdHealthDand()内操作,如下所示。
PWM5.C(2.50 KB)-下载5次TMR0.C(4.05 KB)-下载8次TMR2.C(3.38 KB)-下载7次 以上来自于百度翻译 以下为原文 I'm using a PWM5 to (eventually) control a mosfet in solar power controller. I would like to use the ADC read voltages at various times after the pwm switches on. My approach to doing this is to a) use TMR2 (which feeds into the PWM) to generate an interrupt at the time the PWM is triggered and set to high. Note: I'm using a 4x postscalar on the timer which means the interrupt only gets generated every 4 PWM cycles to keep the interrupt frequency to a reasonable rate. b) Use the TMR2 interrupt to start TMR0 which will generate its own interrupt after a specified period of time c) In the TMR0 interrupt, turn off TMR0 and start the ADC read. d) Repeat this at different TMR0 delays to ADC sample at different offsets in the PWM cycle. What works: a) The pwm and its TMR2 interrupt. I know this because I can see the PWM signal on a scope, and I use a digital out pin to go high in the interrupt for a few microseconds to generate a second output signal I can see on the scope. I also have a counter in the interrupt which I print out in a main() loop to also confirm the interrupt is being triggered. What doesn't work: b) The TMR0 generated delay works (shown with a counter and on a scope) when started from a loop in main(). But NOT when started within the TMR2 interrupt. I'm assuming there is some interaction between timers/flags/and being within an interrupt that prevents the timer 0 being started from the timer 2 interrupt, but I can find anything in these forums or elsewhere. Any thoughts as to whats going wrong would be much appreciated. Or if there is an alternate way of doing this that would also be appreciated. My main.c code is shown below. The pwm and timer control functions are generated by MCC in MPLAB X IDE v4.05. I attached the MCC generated files (well the relevant ones) and my main.c also as separate files. Note that if delay_timer0_setup(59, 0); delay_timer0_start(); is moved from the TMR2_my_InterruptHandler() to the while loop in main() TMR0 seems to operate properly. It does not operate from within TMR2_my_InterruptHandler() as shown below. #include "mcc_generated_files/mcc.h" int TMR0_interrupt_counter = 0; void TMR0_my_interrupt_handler() { TMR0_StopTimer(); TMR0_interrupt_counter++; Power_Pulse_for_Counter_SetHigh(); __delay_us(5); Power_Pulse_for_Counter_SetLow(); } void delay_timer0_setup(int us, int ns) { int delay_in_125ns_chunks = (us*8) + (ns /125); TMR0_StopTimer(); TMR0_Initialize(); TMR0_Write16bitTimer(delay_in_125ns_chunks ); TMR0_SetInterruptHandler(TMR0_my_interrupt_handler); } void delay_timer0_start() { TMR0_StartTimer(); } int TNR2_interrupt_counter = 0; void TMR2_my_InterruptHandler(void) { Power_Pulse_for_Counter_SetHigh(); TNR2_interrupt_counter++; __delay_us(5); Power_Pulse_for_Counter_SetLow(); delay_timer0_setup(59, 0); delay_timer0_start(); } /* Main application */ void main(void) { // initialize the device SYSTEM_Initialize(); //32 MHz //tmr2 has postscalar = 4 which means only 1 every 4 counts an interrupt is issued. The PWM ignores the postscalar //pwm duty cycle is from 0 to 68 (0 to 100%) TMR2_LoadPeriodRegister(16); TMR2_SetInterruptHandler(TMR2_my_InterruptHandler); PWM5_LoadDutyValue(16); //25% duty cycle INTERRUPT_GlobalInterruptEnable(); // Enable the Global Interrupts INTERRUPT_PeripheralInterruptEnable(); // Enable the Peripheral Interrupts int counter = 0; while (1) { counter++; Led_General_Purpose_SetHigh(); __delay_ms(500); printf("%d) tmr2_interrupt_counter=%d tmr0_interrupt_counter=%dn",counter, TNR2_interrupt_counter, TMR0_interrupt_counter); Led_General_Purpose_SetLow(); __delay_ms(500); } } Attachment(s) main.c (3.71 KB) - downloaded 6 times pwm5.c (2.50 KB) - downloaded 5 times tmr0.c (4.05 KB) - downloaded 8 times tmr2.c (3.38 KB) - downloaded 7 times |
|
相关推荐
9个回答
|
|
|
|
|
|
|
|
|
“TNR2YBASTHOTY计数器”应该有一个“易失性”限定符添加到它的定义中。
以上来自于百度翻译 以下为原文 "TNR2_interrupt_counter" should have a "volatile" qualifier added to its definition. |
|
|
|
|
|
|
|
|
|
|
|
很好的关于“挥发性”-谢谢。但是…只是尝试添加“挥发性”-没有效果。因此,仍然没有调用TMR0YMyOractTypHANDLE()。
以上来自于百度翻译 以下为原文 Good point about "volatile" - thanks. But ... Just tried adding "volatile" - no effect. So it still appears that TMR0_my_interrupt_handler() is not being called. |
|
|
|
|
|
嗨,在中断中使用基于SW的延迟例程从来都不是一个好的解决方案。当优化代码时,只有易失性才会发挥作用。如果你不介意的话,你能不能演示一下MCC生成的主中断程序?当做
以上来自于百度翻译 以下为原文 Hi, Using SW based delay routines from within an interrupt is never a good solution... Volatile will only come into play when you optimize code. If you don't it does not matter. Can you please show the main interrupt routine generated by MCC ? Regards |
|
|
|
|
|
完全同意“基于中断的基于SW的延迟例程从来都不是一个好的解决方案”。实际上,我可以在TMR2中断中使用Y-Y-DelaysMs-()函数来引起延迟,但当然,它占用了显著的CPU长度以用于任何显著的延迟长度,这就是为什么我试图使用TMR0来创建延迟。F实现我所要做的事情:即,在PWM周期开始后,采取ADC采样和可调延迟时间?感谢您的反馈RISC!这里是来自MCC的TMR0代码(所有功能用于完整性):这里是TMR2的MCC代码:
以上来自于百度翻译 以下为原文 Completely agree with "SW based delay routines from within an interrupt is never a good solution". I was actually able to use the __delay_ms() function within the TMR2 interrupt to cause the delay I needed, but of course it uses up significant CPU % for any significant delay length, which is why I am trying to use TMR0 to create the delay instead. Do you have any recommendations on a better way of achieving what I am trying to do: that is, take an ADC sample at and adjustable delay time after the PWM cycle starts? Thanks for you feedback RISC! Here is the TMR0 code (all functions for completeness) from MCC: #include #include "tmr0.h" /** Section: Global Variables Definitions */ volatile uint16_t timer0ReloadVal16bit; /** Section: TMR0 APIs */ void (*TMR0_InterruptHandler)(void); void TMR0_Initialize(void) { // Set TMR0 to the options selected in the User Interface // T0CS FOSC/4; T0CKPS 1:1; T0ASYNC synchronised; T0CON1 = 0x40; // TMR0H 255; TMR0H = 0xFF; // TMR0L 252; TMR0L = 0xFC; // Load TMR0 value to the 16-bit reload variable timer0ReloadVal16bit = (TMR0H << 8) | TMR0L; // Clear Interrupt flag before enabling the interrupt PIR0bits.TMR0IF = 0; // Enabling TMR0 interrupt. PIE0bits.TMR0IE = 1; // Set Default Interrupt Handler TMR0_SetInterruptHandler(TMR0_DefaultInterruptHandler); // T0OUTPS 1:1; T0EN disabled; T016BIT 16-bit; T0CON0 = 0x10; } void TMR0_StartTimer(void) { // Start the Timer by writing to TMR0ON bit T0CON0bits.T0EN = 1; } void TMR0_StopTimer(void) { // Stop the Timer by writing to TMR0ON bit T0CON0bits.T0EN = 0; } uint16_t TMR0_Read16bitTimer(void) { uint16_t readVal; uint8_t readValLow; uint8_t readValHigh; readValLow = TMR0L; readValHigh = TMR0H; readVal = ((uint16_t)readValHigh << 8) + readValLow; return readVal; } void TMR0_Write16bitTimer(uint16_t timerVal) { // Write to the Timer0 register TMR0H = timerVal >> 8; TMR0L = (uint8_t) timerVal; } void TMR0_Reload16bit(void) { // Write to the Timer0 register TMR0H = timer0ReloadVal16bit >> 8; TMR0L = (uint8_t) timer0ReloadVal16bit; } void TMR0_ISR(void) { // clear the TMR0 interrupt flag PIR0bits.TMR0IF = 0; // Write to the Timer0 register TMR0H = timer0ReloadVal16bit >> 8; TMR0L = (uint8_t) timer0ReloadVal16bit; if(TMR0_InterruptHandler) { TMR0_InterruptHandler(); } // add your TMR0 interrupt custom code } void TMR0_SetInterruptHandler(void (* InterruptHandler)(void)){ TMR0_InterruptHandler = InterruptHandler; } void TMR0_DefaultInterruptHandler(void){ // add your TMR0 interrupt custom code // or set custom function using TMR0_SetInterruptHandler() } And here is the MCC code for TMR2: #include #include "tmr2.h" /** Section: Global Variables Definitions */ void (*TMR2_InterruptHandler)(void); /** Section: TMR2 APIs */ void TMR2_Initialize(void) { // Set TMR2 to the options selected in the User Interface // PR2 4; PR2 = 0x04; // TMR2 0; TMR2 = 0x00; // Clearing IF flag before enabling the interrupt. PIR1bits.TMR2IF = 0; // Enabling TMR2 interrupt. PIE1bits.TMR2IE = 1; // Set Default Interrupt Handler TMR2_SetInterruptHandler(TMR2_DefaultInterruptHandler); // T2CKPS 1:16; T2OUTPS 1:4; TMR2ON on; T2CON = 0x1E; } void TMR2_StartTimer(void) { // Start the Timer by writing to TMRxON bit T2CONbits.TMR2ON = 1; } void TMR2_StopTimer(void) { // Stop the Timer by writing to TMRxON bit T2CONbits.TMR2ON = 0; } uint8_t TMR2_ReadTimer(void) { uint8_t readVal; readVal = TMR2; return readVal; } void TMR2_WriteTimer(uint8_t timerVal) { // Write to the Timer2 register TMR2 = timerVal; } void TMR2_LoadPeriodRegister(uint8_t periodVal) { PR2 = periodVal; } void TMR2_ISR(void) { // clear the TMR2 interrupt flag PIR1bits.TMR2IF = 0; if(TMR2_InterruptHandler) { TMR2_InterruptHandler(); } } void TMR2_SetInterruptHandler(void (* InterruptHandler)(void)){ TMR2_InterruptHandler = InterruptHandler; } void TMR2_DefaultInterruptHandler(void){ // add your TMR2 interrupt custom code // or set custom function using TMR2_SetInterruptHandler() } |
|
|
|
|
|
我还有一条信息:在我的1秒状态打印循环中,我把打印TMR0L添加到我的Primff()语句中。TMRO0L每次打印一个不同的数字,这大概是它正在计数的证据。因为它是从一个中断开始的。我尝试添加Py0BITS.TMR0IE=1;在TMR2中断程序中,但没有帮助。IE:
以上来自于百度翻译 以下为原文 I have one more piece of information: I added printing TMR0L to my printf() statement in my 1 second status print loop in main(). TMRO0L prints a different number each time so that presumably is evidence that it is counting. My guess is the interrupt from that timer is is not being properly enabled because it is being started from within an interrupt. I tried adding PIE0bits.TMR0IE = 1; in the TMR2 interrupt routine but that didn't help. ie: void TMR2_my_InterruptHandler(void) { Power_Pulse_for_Counter_SetHigh(); TNR2_interrupt_counter++; __delay_us(5); Power_Pulse_for_Counter_SetLow(); delay_timer0_setup(59, 0); delay_timer0_start(); PIE0bits.TMR0IE = 1; } |
|
|
|
|
|
使用32 MHz系统频率和定时器2周期16,预分频器1 16,PWM频率(不使用定时器2后标器)由fPWM=(32 e6/4)/16/16=32.350 kHz(32μs)的tMR2中断频率,使用后缩放器1:4 ift2tIn=(32 e6/4)/16/16 /4=7.8124 kHz(7.8124 US,或γin)。在32 MHz的结构周期中,注意到TMR0在指令周期速率上被计时,因此…闪耀的错误:如果加载16位TMR0值为59×8,则在它溢出之前的指令周期的数量由65636-(59×8)=65064给出。因此,在下一个定时器2中断之前它将没有时间溢出。因此,代替(59×8),可以使该参数成为59×8的两个补码。在程序中,可以简单地使用(UTI1616T)(-59×8)=0xFE28,这将使定时器0在以后溢出472个指令周期。(接近定时器2中断间隔的中心。)现在,另一个真正的问题是:我不认为人们对函数调用所产生的开销有感觉。特别是,ISR的函数调用更昂贵(时间和代码),因为需要保存更多的东西。因此,我不需要MCC使程序为我工作。主要是消除了MCC生成的ISR中的所有函数调用。其次,在ISR动作本身中,我删除了所有函数CA。注意,在定时器2 ISR中重新初始化定时器0没有任何价值。只要重新加载TMR0与所需的值,并重新启动它。这是我的ISR:请注意,TimeVar是一个全球性的16位变量。这里是全局文件,我在主文件中定义:我改变了计时器2初始化,将PR2设置为15。(注意,PR2=15在定时器2溢出频率计算中给出了16的除法。)我还消除了定时器0初始化中所有不需要的东西。我略微改变了输出打印语句,以确保我正在查看程序的输出而不是提交的文件。这是我的PIC16F18325(插入好奇心板)的结果:8月5日2018编译在17:50:35 PDT由XC8版本2000 1:TMR2YEXTROTY计数器=4316,TMR0Y中断计数器=4316 2:TMR2YEXTROTY计数器=12906,TMR0Y中断计数器=12905 3:TMR2Y中断计数器=21496,TMR0IN间TrMRTA计数器=21496:4:TMR2YEXTROTTY计数器=30087,TMR0Y中断器计数器=30087 5:TMR2A中断器计数器=38678,TMR0Y中断器计数器=38677 6:TMR2A中断计数器=47269,TMR0Y中断计数器=47268 7:TMR2Y中断计数器计数器=55859,TMR0Y中断计数器=55859:TMR2YEXTROTY计数器=γ,TMR0Y中断计数器=64450。在“范围”上观察到的脉冲与上面所表达的期望一致。
以上来自于百度翻译 以下为原文 With 32 MHz system frequency and timer 2 period of 16, prescaler 1:16, the PWM frequency (does not use Timer 2 postscaler) is given by Fpwm = (32e6 / 4) / 16 / 16 = 32.350 kHz (32 us) The TMR2 interrupt frequency, using postscaler 1:4 is Ft2int = (32e6/4) / 16 / 16 / 4 = 7.8124 kHz (128 us, or 1024 instruction cycles at 32 MHz) Note that TMR0 is being clocked at the instruction cycle rate so... Glaring error: If you load the 16-bit TMR0 with a value of 59*8, the number of instruction cycles before it overflows is given by 65536 - (59*8) = 65064. So it won't have time to overflow before the next Timer 2 interrupt. So, instead of (59*8) you can make the argument to be the two's complement of 59*8. In the program you could simply use (uint16_t)(-59*8) = 0xFE28 This would make Timer 0 overflow 472 instruction cycles later. (Kind of close to the center of the interval between Timer 2 interrupts.) Now, here's the other real problem: I don't think people have a feel for the amount of overhead created by function calls. In particular, function calls from an ISR are more expensive (time and code) since more stuff has to be saved. So, I un-MCC-ified your program to make it work for me. Mainly I eliminated all function calls from the MCC-generated ISR. Secondly, within the ISR action itself, I eliminated all function calls. Note, that I see no value in re-initializing Timer 0 in the Timer 2 ISR. Just reload TMR0 with the required value and start it up again. Here'a my ISR: void interrupt service_interrupt() { // Don't call other functions to service the individual // interrupts! // Do everything from the "real" interrupt function. if (PIE1bits.TMR2IE && PIR1bits.TMR2IF) { // Reset the interrupt flag PIR1bits.TMR2IF = 0; LED1 = 1; // Do NOT call delay function! // The number of instructions for incrementing the 16-bit // variable will give a pulse that is wide enough to trigger // on (and to see) on the 'scope. //__delay_us(5); ++TMR2_interrupt_counter; LED1 = 0; // Don't call a function! Just do it. //TMR0_StopTimer(); T0CON0bits.T0EN = 0; // Don't call a function! Just do it. //TMR0_Write16bitTimer(timerVal); TMR0H = timerVal >> 8; TMR0L = (uint8_t) timerVal; // Don't call a function! Just do it. //TMR0_StartTimer(); T0CON0bits.T0EN = 1; } if (PIE0bits.TMR0IE && PIR0bits.TMR0IF) { // Clear the interrupt flag PIR0bits.TMR0IF = 0; // Stop the timer! T0CON0bits.T0EN = 0; // Don't call a delay routine! The number of instructions to increment // the 16-bit counter is sufficient to trigger and display on the 'scope LED2 = 1; ++TMR0_interrupt_counter; LED2 = 0; } } // End of service_interrupt() Note that timerVal is a global 16-bit variable. Here are the globals, which I defined in the Main file: volatile uint16_t TMR0_interrupt_counter; // Guaranteed to initialize to zero volatile uint16_t TMR2_interrupt_counter; // Guaranteed to initialize to zero // With PR2 = 15, Prescaler 1:16, Postscaler 1:4, the number of // instructions in a Timer2 interrupt period is 1024. // // Heuristically, the value 59*8 = 472 gives something "pretty close" to the middle // of the 1024-instruction TMR2 interrupt period. // If it weren't for overhead, the value 64*8 = 512 would be the middle //volatile uint16_t timerVal = (uint16_t)(-59*8); // Heck. I'll just give the number of instructions. The tweaked value -465 gives just // about as close to the middle as I can see on my 'scope with my PIC16F18345. volatile uint16_t timerVal = (uint16_t)(-465); // In the "real" program, the value of timerVal would be settable from main() // or from some other function (not within the ISR). // The Timer 2 ISR simply reloads TMR0 with this value. I changed the Timer 2 initialization to set PR2 to 15. (Note that PR2 = 15 gives a division of 16 in Timer 2 overflow frequency calculations.) I also eliminated all of the unneeded stuff in Timer 0 initialization. I changed the output print statement a little, just to make sure I'm looking at my program's output rather than that of the files you submitted. Here's the result from my PIC16F18325 (plugged into a Curiosity board): Compiled on Aug 5 2018 at 17:50:35 PDT by XC8 version 2000 1: tmr2_interrupt_counter= 4316, tmr0_interrupt_counter= 4316 2: tmr2_interrupt_counter=12906, tmr0_interrupt_counter=12905 3: tmr2_interrupt_counter=21496, tmr0_interrupt_counter=21496 4: tmr2_interrupt_counter=30087, tmr0_interrupt_counter=30087 5: tmr2_interrupt_counter=38678, tmr0_interrupt_counter=38677 6: tmr2_interrupt_counter=47269, tmr0_interrupt_counter=47268 7: tmr2_interrupt_counter=55859, tmr0_interrupt_counter=55859 8: tmr2_interrupt_counter=64450, tmr0_interrupt_counter=64450 . . . Pulses observed on the 'scope are consistent with the expectations I expressed above. Regards, Dave |
|
|
|
|
|
戴夫,谢谢你一千次!你牢牢抓住了这一点:这确实是核心问题。我非常感谢你的帮助!-彼得
以上来自于百度翻译 以下为原文 Dave, A thousand times thank you! You nailed it with: That was indeed the core problem. I really appreciate your help! -Peter |
|
|
|
|
只有小组成员才能发言,加入小组>>
MPLAB X IDE V6.25版本怎么对bootloader和应用程序进行烧录
473 浏览 0 评论
5793 浏览 9 评论
2334 浏览 8 评论
2224 浏览 10 评论
请问是否能把一个ADC值转换成两个字节用来设置PWM占空比?
3530 浏览 3 评论
1124浏览 1评论
有偿咨询,关于MPLAB X IPE烧录PIC32MX所遇到的问题
1095浏览 1评论
我是Microchip 的代理商,有PIC16F1829T-I/SS 技术问题可以咨询我,微信:A-chip-Ti
873浏览 1评论
MPLAB X IDE V6.25版本怎么对bootloader和应用程序进行烧录
475浏览 0评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 04:56 , Processed in 0.776119 second(s), Total 60, Slave 53 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
1574