完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
你好!我用PIC18F45 80用20MHz晶体测量两个正方波脉冲之间的周期时间,在上升沿上设置CCP1触发,在ISR中取一个“时间戳”,然后计算MS中的时间,但用频率为10Hz的波形发生器进行测试。到200赫兹,结果有时会出错。例如,200赫兹给出5ms(完美),但有时18.107ms 100Hz 10ms,85 8962ms 50Hz 20ms,6892MS/33 MSI已经在这上面贴了几天,想知道这个错误是因为按下按钮重置值的时间是“坏的”还是别的什么?谁能引导我走向正确的方向?代码如下,配置位省略:
以上来自于百度翻译 以下为原文 Hi! I'm using PIC18F4580 with a 20Mhz crystal to measure the period time between two positive square wave pulses. I have set up CCP1 to trigger on rising edge and in the ISR I'm taking a "timestamp" and then calculating the time in ms. But when testing with a waveform generator with frequencies from 10Hz to 200Hz, the results sometimes gets wrong. E.g. 200Hz gives 5ms (perfect) but sometimes 18.107ms 100Hz 10ms 858962ms 50Hz 20ms 6.892ms/33ms I've been stuck on this for days, wondering if this error is because the timing when pressing the button to reset values is "bad" or is it something else? Anyone that can lead me to the right direction? Code below, config bits omitted: #define _XTAL_FREQ 20000000 #define RS PORTDbits.RD2 #define EN PORTDbits.RD3 #define D4 PORTDbits.RD4 #define D5 PORTDbits.RD5 #define D6 PORTDbits.RD6 #define D7 PORTDbits.RD7 #define TRUE 1 #define FALSE 0 #include #include #include #include "lcd.h" /* ******************** Variables ******************** */ unsigned long t1 = 0; unsigned long t1Count = 0; unsigned long t2 = 0; unsigned long t2Count = 0; volatile unsigned long timeBuff = 0; double elapsedTime = 0; volatile unsigned long overflowCountTMR1 = 0; volatile int pulseCount = 0; volatile int btnCount = 0; char ms[20]; // **** "Booleans" **** volatile int got2Pulses = FALSE; // 0 = false, 1 = true /* ******************** Function declarations ******************** */ void interrupts(); void noInterrupts(); void resetValues(); /* ******************** Main function ******************** */ void main() { TRISBbits.RB5 = 1; // Input push button // Set up CCP module, capture rising TRISCbits.RC2 = 1; // Set RC2/CPP1 pin as input PORTC = 0x00; // Set all pins to low CCP1CON = 0x05; // Capture rising edge PIR1bits.CCP1IF = 0; // Reset interrupt flag // Set-up timer1 for counting periodtime T1CON = 0x00; // Disable Timer1 under set-up T3CON = 0x00; // Set Timer1 as capture source for CCP1 PIR1bits.TMR1IF = 0; // Reset interrupt flag T1CON = 0x81; // Start Timer1 with 16-bits read/write // Set-up timer2 for polling push button state T2CON = 0x00; // Disable Timer1 under set-up PIR1bits.TMR2IF = 0; // Reset interrupt flag PR2 = 223; T2CON = 0x6F; // Prescaler: 16 Postscaler: 14 => Interrupt every 9,990ms (WHEN PR2 = 223) // Set up LCD CMCONbits.CM = 0x07; // Disable comperators at RB2 & RB3 TRISD = 0x00; // Set up D ports as output Lcd_Init(); Lcd_Clear(); Lcd_Set_Cursor(1,1); interrupts(); // Enable interrupts while(1) { if(btnCount == 10){ noInterrupts(); resetValues(); Lcd_Clear(); interrupts(); } // Calculate period from timestamps if (got2Pulses == TRUE){ // We got 2 pulses, calculate elapsed time // T2-T1 don't forget the overflow count variable elapsedTime = ( (t2 - t1) + ((t2Count-t1Count)*65536) )/5.0; // In us (microseconds) got2Pulses = FALSE; // Set false so we wont calculate again // Write results to LCD in ms sprintf(ms,"%4.3f",(elapsedTime/1000.0)); Lcd_Set_Cursor(1,1); Lcd_Write_String(ms); } } } /* ******************** Interrupt functions ******************** */ // Handles interrupts. Timer interrupt to keep track of nr of overflows. // Check if we got a pulse, save value if we did void interrupt ISR_handeler(){ if(PIR1bits.CCP1IF == 1){ timeBuff = CCPR1; if(PIR1bits.TMR1IF == TRUE ){ // Check if a timer1 overflow happened at the time of capture unsigned long MSBOfTimeBuff = (timeBuff & 0x8000) >> 15; // If so correct overflowCountTMR1 variable before saving if(MSBOfTimeBuff == 0){ overflowCountTMR1++; PIR1bits.TMR1IF = 0; } } pulseCount++; if(pulseCount == 1){ t1 = timeBuff; t1Count = overflowCountTMR1; } else if (pulseCount == 2){ t2 = timeBuff; t2Count = overflowCountTMR1; PIE1bits.CCP1IE = 0; // We only want to calculate between two pulses got2Pulses = TRUE; } PIR1bits.CCP1IF = 0; } if(PIR1bits.TMR1IF == 1){ overflowCountTMR1++; if(overflowCountTMR1 >= 4294967200){ overflowCountTMR1 = 0; } PIR1bits.TMR1IF = 0; } if(PIR1bits.TMR2IF == 1){ if(PORTBbits.RB5 == 0){ btnCount++; }else{ btnCount = 0; } PIR1bits.TMR2IF = 0; } } /* ******************** Functions ******************** */ void noInterrupts(){ PIE1bits.CCP1IE = 0; // Disable CPP1 interrupt PIE1bits.TMR1IE = 0; // Disable Timer1 Overflow interrupt PIE1bits.TMR2IE = 0; // Disable Timer2 Overflow interrupt // Disable global and peripheral interrupts INTCONbits.GIE = 0; INTCONbits.PEIE = 0; } void interrupts(){ PIE1bits.CCP1IE = 1; // Enable CPP1 interrupt PIE1bits.TMR1IE = 1; // Enable Timer1 Overflow interrupt PIE1bits.TMR2IE = 1; // Enable Timer2 Overflow interrupt // Enable global and peripheral interrupts INTCONbits.GIE = 1; INTCONbits.PEIE = 1; } void resetValues() { pulseCount = 0; t1 = 0; t1Count = 0; t2 = 0; t2Count = 0; btnCount = 0; } Attached Image(s) |
|
相关推荐
13个回答
|
|
TMR1和CCP1之间存在竞争状态。如果TMR1在CCP1捕获之后很快滚动,那么由于中断延迟,您的代码将看到翻转和添加65536,即使它不应该。这直接解释了200 Hz的情况=& 25000计数/ 5=5ms。(25000 + 65536)/5=18.107ms。也许在CCP1IF块中解决这个问题。如果TMR1IF=1CCPR1和阈值,然后增加翻滚。阈值取决于您的中断代码,但可能是几百个。不确定这是否解释了其余的问题。
以上来自于百度翻译 以下为原文 There's a race condition between tmr1 and ccp1. If tmr1 rolls over soon after ccp1 captures, then because of interrupt latency your code will see the rollover and add 65536 even though it shouldn't. This directly explains the 200Hz case => 25000 counts / 5 = 5ms. (25000 + 65536)/5 = 18.107ms. Maybe solve this in your CCP1IF block - if TMR1IF=1 and ccpR1 Not sure if this explains the rest of the problems. |
|
|
|
在CPP捕获中添加MSB的检查之前,我经常遇到错误的溢出计算。这个想法是检查捕获是否发生在TMIRIF之前或之后,通过查看CCP是否在附近或溢出之后。如果我正确地理解了,我应该多做一个。节俭/更严格的检查?
以上来自于百度翻译 以下为原文 I had more frequent problems with incorrect overflow calculation before adding the check of the MSB in the cpp capture. The idea is to check if the capture happend before or after TMRIIF is set, by looking if the CCP is near or after an overflow. if(PIR1bits.CCP1IF == 1){ timeBuff = CCPR1; if(PIR1bits.TMR1IF == TRUE ){ // Check if a timer1 overflow happened at the time of capture unsigned long MSBOfTimeBuff = (timeBuff & 0x8000) >> 15; // If so correct overflowCountTMR1 variable before saving if(MSBOfTimeBuff == 0){ overflowCountTMR1++; PIR1bits.TMR1IF = 0; } } If I understand you correctly the I should do a more accurate/"tighter" check? |
|
|
|
假设200 Hz,如果在第一次捕获时TMR1和lt 7768,那么TMR1将在第二次捕获时为lt;(7768+25000),或lt;0x8000。你还有一个时间窗口(7768/65536=12%)!!)你可以检测到没有发生的溢出(在捕获之前)。输入信号越慢,发生的溢出越多,竞争条件发生的可能性就越大。
以上来自于百度翻译 以下为原文 Assuming 200Hz, If tmr1<7768 on first capture, then tmr1 will be < (7768+25000), or <0x8000, on second capture. You still have a window of time (7768/65536 = 12% !!)where you could detect an overflow that didn't happen (before the capture). The slower the input signal, the more overflows happen, and the more chance for the race condition to occur. |
|
|
|
啊,我明白了。我应该做更多的阅读和计算。我试着根据你的第一个答案做出一些改变。但它没有帮助,甚至更糟。阅读问题现在更频繁发生。有没有方法来计算阈值或只是一些尝试和错误?在模拟器中,我得到一个循环计数大约170至190个周期的CCP ISR代码。
以上来自于百度翻译 以下为原文 Ah, I see. Should have done some more reading and calculations. I have tried to make some changes based on your first answer. But it didn't help, it even got worse. The reading problem happens more frequently now. Is there a way to calculate the threshold or just some trial and error? In simulator I get a cycle count around 170 - 190 cycles for CCP ISR-code. I have changed if(PIR1bits.CCP1IF == 1){ timeBuff = CCPR1; if(PIR1bits.TMR1IF == TRUE ){ // Check if a timer1 overflow happened at the time of capture unsigned long MSBOfTimeBuff = (timeBuff & 0x8000) >> 15; // If so correct overflowCountTMR1 variable before saving if(MSBOfTimeBuff == 0){ overflowCountTMR1++; PIR1bits.TMR1IF = 0; } }... to if(PIR1bits.CCP1IF == 1){ timeBuff = CCPR1; if(PIR1bits.TMR1IF == 1 ){ // Check if a timer1 overflow happened at the time of capture // If so correct overflowCountTMR1 variable before saving if(timeBuff < 200{ overflowCountTMR1++; PIR1bits.TMR1IF = 0; } }.... |
|
|
|
你所拥有的竞赛条件是固有的--计时器溢出可能在任何时候发生。但是,您可以检测到是否发生了这种情况。
以上来自于百度翻译 以下为原文 The race condition you have is inherent - timer overflow may happen at any time. However, you can detect if this has happened. // Start your interrupt from servicing the timer (instead of doing this at the and) if(PIR1bits.TMR1IF){ overflowCountTMR1++; // no need for anything else PIR1bits.TMR1IF = 0; } // here we enter the dangerous zone where timer can // still overflow. If this happens, currentTimerValue // is not synchronized with overflowCountTMR1 any // more currentTimerValue = TMR1; // Now we can detect if the de-synchronization has actually happened if(PIR1bits.TMR1IF){ // It did. bail out of the ISR and start over return; } // Here we have current time in currentTimerValue:overflowCountTMR1 // The rest is the matter of technique. if(PIR1bits.CCP1IF){ // capture has happened timeBuff = CCPR1; PIR1bits.CCP1IF = 0; overflowCountAtTheTimeOfCapure = overflowCountTMR1; // assuming interrupts are not disabled and fast enough // the timer could not roll over more than once since // the capture. Did it rolled over once? if (currentTimerValue < timeBuff) { // note, for the correct comparison both vars must be unsigned // it did. So we correct the count overflowCountAtTheTimeOfCapure--; } // At this point overflowCountAtTheTimeOfCapure:timeBuff represents the exact capture time captureTime = (overflowCountAtTheTimeOfCapure << 8) | timeBuff; // You can now use the value your calculations } |
|
|
|
谢谢,它解决了这个问题。今天我学到了一些新东西!我有一个问题:当溢出流量溢出时会发生什么?一个快速的计算在发生之前大约15分钟。溢出的比特会被丢弃还是会发生“缓冲区溢出”和“崩溃”?第一次与PIC。这将结束在一个测量箱,它肯定会被供电更长的时间,然后15分钟。你写道:但我一直保持。
以上来自于百度翻译 以下为原文 Thanks, it solved the problem. Now I have learned something new today! :) I have a question about what happens when OverflowCountTMR1 overflows? A quick calculation gives around 15 min before it happens. Does the overflowed bit get discarded or will a "buffer overflow" happen and "crash"? First time with PIC. This will end up in a box for measurement and it will surely be powered on for longer periods then 15 min. You wrote: if(PIR1bits.TMR1IF){ overflowCountTMR1++; // no need for anything else PIR1bits.TMR1IF = 0; } but I have kept if(PIR1bits.TMR1IF == 1){ overflowCountTMR1++; if(overflowCountTMR1 >= 4294967200){ overflowCountTMR1 = 0; } PIR1bits.TMR1IF = 0; } |
|
|
|
由于无符号运算的魔力,当变量翻转到零时并不重要,除非结果本身大于变量大小,否则减法仍将给出正确的结果。
以上来自于百度翻译 以下为原文 Due to the magic of unsigned arithmetic, it doesn't matter when the variable rolls over back to zero. The subtraction will still give the correct result unless the result itself would be bigger than the variable size. |
|
|
|
是的,我知道。我担心比特会被“推”到内存中的其他地方,并在运行时中断程序(缓冲区溢出)。也许我只是在过度分析。
以上来自于百度翻译 以下为原文 Yes, i know. My worries is that bits get "pushed" somewhere else in the memory and breaks the program while running (buffer overflow). Maybe I'm just over analyzing. |
|
|
|
在普通变量上没有算术可以使它“溢出”到不属于它的内存中。只有当数组索引变得太大或指针变为野生时,才会发生。
以上来自于百度翻译 以下为原文 No arithmetic on a plain variable can make it "overflow" into memory that doesn't belong to it. That only happens when you let array indices get too big, or pointers go wild. |
|
|
|
|
|
|
|
在上面的代码中可能不重要(除了在0xFFFF或0xMUN发生时可能的CPP),但是请记住,当值变成0xFFFF时,定时器中断发生,而不是当它滚动到0x000时。我在PIC18和PIC24部分进行了测试。这是1/65536早。如果用计时器中断中断扩展计时器,则可以得到0x00 000 FFFE、0x000 01FFFF、0x000 010000、0x000 010001的扩展计数。在Micro-Tick.c中有一些复杂的微芯片代码来处理这个问题。处理它的一个非常简单的方法是简单地将1的读数加在定时器读数上,我想如果你把它与CCP读数混合,那么你也需要在读数中加一个。0xFFFF包装到0x000和所有的扩展并发症消失!-)
以上来自于百度翻译 以下为原文 It probably does not matter in the code above (except maybe CPP at 0xffff or 0x0000 occur) but, Keep in mind that the timer interrupt occurs when the value becomes 0xffff and not when it rolls to 0x0000. I actaully tested this was the case on PIC18 and PIC24 parts. This is 1/65536 early. If you extend the timer with the timer interrupt interrupt you can get extended counts of 0x0000fffe, 0x0001ffff, 0x00010000, 0x00010001. There was some complicated microchip code in the MAL tick.c to deal with this issue. A really simple way to deal with it is to simply add 1 to the timer reading value and I suppose if you are mixing that with CCP readings, then you would also need to add one to those readings as well. 0xffff wraps to 0x0000 and all the extended complications go away! :-) |
|
|
|
离题到可能导致问题的编码风格:即使你只使用你的宏分配给你的“布尔”,你只应该测试它对0(或假),从来没有反对1。这样,如果有人(甚至是你在代码之外一年)分配了1以外的东西,或者一个毛刺改变了RAM中的值,你的代码将永远不会想到“哦,既不是真的也不是假的”,并因此在杂草中消失。当测试位场时,你将是安全的,但是无论如何WH都是安全的。你不使用C语言提供的更通俗的速记吗?
以上来自于百度翻译 以下为原文 Digression into coding style that can cause problems: Even if you only ever assign to your "boolean" using your macros, you should only ever test it against 0 (or FALSE), never against 1. That way, if somebody else (or even you after a year away from the code) ever assigns something other than 1, or a glitch changes the value in RAM, your code will never think "oh, neither true nor false" and go off in the weeds due to this. When testing bitfields you will be safe, but in any case why not use the more idiomatic shorthand C provides? if (got2Pulses){ // We got 2 pulses, calculate elapsed time ... if(PIR1bits.CCP1IF){ ... |
|
|
|
我认为这是定时器使用PRX寄存器的原因,因为它们产生中断PR匹配,并在下一个周期重置为0。这个定时器应该在它变成零时产生中断。然而,ITMayBeVess测试,如果(并且仅当)它在0xFF而不是0x00产生中断,那么添加1到所有的CCP和TMR读数,如克里斯建议的是必要的。
以上来自于百度翻译 以下为原文 I think this was the case with timers that use PRx registers because they produce interrupt on PR match and reset to 0 at the next cycle. This timer should produce the interrupt when it becomes zero. However, it may be worth testing, and if (and only if) it produces interrupt at 0xff instead of 0x00 then adding 1 to all CCP and TMR readings as Chris suggested is necessary. |
|
|
|
只有小组成员才能发言,加入小组>>
5248 浏览 9 评论
2036 浏览 8 评论
1956 浏览 10 评论
请问是否能把一个ADC值转换成两个字节用来设置PWM占空比?
3218 浏览 3 评论
请问电源和晶体值之间有什么关系吗?PIC在正常条件下运行4MHz需要多少电压?
2264 浏览 5 评论
787浏览 1评论
678浏览 1评论
有偿咨询,关于MPLAB X IPE烧录PIC32MX所遇到的问题
608浏览 1评论
PIC Kit3出现目标设备ID(00000000)与预期的设备ID(02c20000)不匹配。是什么原因
685浏览 0评论
582浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-27 21:38 , Processed in 1.611108 second(s), Total 101, Slave 84 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号