NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » How to create a loop timer while checking 2 pin inputs
March 22, 2012 by Blackbird |
1st time posting. I have done a lot of searching and playing with code and can't figure out how to get this to do what I want. I've got the if && to check for high on both pins and count using a delay, but it is not what I need. What I need:
Loop and monitor, no problem. Monitor inputs and turn on outputs, no problem. Figuring out what statement to use to monitor and time the input pin so it will go to the next 'if' if the time is held for only 2 seconds--problem. I don't want a 3 second delay, I need a 3 second counter. It is probably a no brainer for someone on here and I just can't seem to put it together. Thanks for looking. Love the kit. I have burned many hours. Too much on this last part though. |
---|---|
March 22, 2012 by JimFrederickson |
It is easiest to use interrupts to do what you want. In your case, it seems that you have only 'a single event at a time' to measure so it it will be pretty straight forward. (If you have more than 'a single event to time' then this approach would still work, but you would have to us this basic skeleton to configure multiple 'software timers'.)
So basically this should allow system_timertick to count up to 6 seconds. (In 1/10,000 of a second intervals). NOTE: As mentioned in the code I am using a 16mhz crystal NOT the standard Nerdkits Crystal. This should help you to 'get started'. NOTE: The 'volatile' keyboard must be used on the system_timertick. What 'volatile' does is to tell the compiler that the program will ALWAYS need to load the system_timertick value from memory and avoid optimizations on teh value. The reason for this is because the Interrupt routine can change this value, and the compiler cannot predict when this will occur, so if the compiler decided to optimize that value by keeping in an AVR Register then the program will never see the change in the value. So use this you could simply clear the system_timertick, and then do what you need to do. After you have an event that you wanted to time then check the value. NOTES: 1 - When you check the value you will need to either 'disable interrupts' or 'write the value to a temporary variable. The reason for this is because the Interrupts will continue to fire, and the value could change if you reference more than once in your inline code. It is MUCH BETTER to just write it to a temporary variable in your mainline code that way the interrupt can continue along it's merry way. WHICH YOU WOULD NEED TO ALLOW TO HAPPEN if you needed to have multiple/software timers. 2 - If there is a possibility that your timed value can exceed the 6 seconds, or timeout at a certain point, you will need to check the system_timertick in your main loop to determine if a timeout has occurred. |
March 22, 2012 by pcbolt |
Blackbird - If you don't need 1/10,000 sec resolution, you could use the NK code from the "realtime_clock" project (in tutorial section). This will only give you 1/100 sec resolution but will not "reset" until more than 200 days has elapsed. You'll also benefit by using Pin Change Interrupts. This will trigger each time PC1 or PB1 changes state. Fortunately for you, by using PC1 and PB1, you can actually use two separate interrupt service routines (ISR) to monitor the pins. You can initialize the interrupts using:
As Jim stated above, the ISR's work best by simply updating global (and volatile) variables. So the following "pseudocode" can be used:
Then in your monitoring loop you just test all the possibilities:
You'll most likely need more flag variables and tests but it's a start. Sounds like you're making an interesting project. |
March 23, 2012 by Blackbird |
Wow. Thanks for the quick responses. I see now that I have bit off a bit more than I can chew at the moment since some of the coding and terms are over my head, but I will dig into the examples and learn about each term. I read a bit on the interrupts and it seemed like what I needed, but could not figure out how to integrate the timer, so thanks again for getting me going. I little more backgound for the curious. I have already made the 2 LED displays, 4" digits, (both scores pointing towards each pit) and decided to make the reset cooler and add reverse (the source of my current issues), oh and add speach and sound. The scoring is done via laser diodes and IR receivers (already working) at each pit that you just wave your hand/finger through. (had to use a debounce chip for that (i love that chip,works great)). To keep things simple (for me, and to keep pins open on the 168) I decided to use chips to drive the displays and use the 168 as the brains. That is where the current code comes into play. Since it is so easy to increment a score, people love to blast past the mark (it will score as fast as you can wave your fingers through, even 4 at a time), so I thought reverse would be cool, by holding your hand in one beam for 3 seconds it would start slowly counting backwards and by blocking both beams for 3 seconds it would reset. The speech/sound is (hopefully) going to come from a RC Systems Doubletalk RC8660 voice chip. Already have that and can program via the development board. It says it communicates via Standard serial (UART) and 8-bit bus interfaces, so it will be my next learing phase once the scoring is working. Thanks again for the help and I am more than willing to accept any helpful advice or suggestions. I have found it much easier for me to learn new stuff when I want a result, rather than being force fed, and since there are so many distractions in life, it is good to have a goal, even if it is just a hobby. Great community. Glad I decided on the NerdKit. |
May 21, 2012 by Blackbird |
I have a large portion of the scoreboard working, including the sound interface (UART code, not all the variables) but I am having a problem with the score not responding after some time. I changed the code a bit to spit the output back to the computer and it appears that at some point the time starts counting backwards back to 0 then back up. After this occurs, the scoring wont work. It will still recognize the input (blocking the laser) but does not change score or count blue or green 'hold' time. It happens right around the 5 minute mark. The timer code is from the 'real time clock'. Time=system time, Green score, Green input y/n, green 'Y' time, Blue score, blue input, blue 'y' time Here is the screen shot when it changes. Time:32766 Gnscr: 4 Gnhg: 0 Gntm: 0 bluscr: 9 bluhg: 0 blutm: 0 Time:32767 Gnscr: 4 Gnhg: 0 Gntm: 0 bluscr: 9 bluhg: 0 blutm: 0 Time:-32768 Gnscr: 4 Gnhg: 0 Gntm: 0 bluscr: 9 bluhg: 0 blutm: 0 Time:-32768 Gnscr: 4 Gnhg: 0 Gntm: 0 bluscr: 9 bluhg: 0 blutm: 0 Time:-32767 Gnscr: 4 Gnhg: 0 Gntm: 0 bluscr: 9 bluhg: 0 blutm: 0 Because I am still testing and modifing the code, I have a lot of lines that are just // so I don't have to retype them if I use them later. When I use the LCD display, the same freeze happens. The time continues to count (down) so I know the chip is not locking up, but the negative numbers are messing with my If/Then statements. Any thoughts would be appreciated. // Scoreboard.c
|
May 21, 2012 by pcbolt |
Blackbird - Great project. Glad to see you've progressed so far. I think what is happening is when you declared your time variables (bluetime, greentime etc) you declared them as "int". In AVR programming, an "int" is a signed 16-bit variable. This means it can only hold values from -32,768 to 32,767. In hex representation -32768 is 0x8000 and 32767 is 0x7FFF, so it "kind of" makes sense that after 0x7FFF the timer will go to 0x8000. The easiest way to change this is to make any time variable 32-bits (signed or unsigned...won't really matter here), by declaring them int32_t (just like "the_time"). I'm surprised the compiler didn't holler at you. BTW, did you start programming in assembly? I only ask because the way you use the "goto" routines reminds me of assembly. Some "C" programmers don't like to use "goto" but I say if it works, more power to you. |
May 22, 2012 by Blackbird |
Thanks. I will make those changes tonight and try it again. As far as programming, this is my first time. BASIC was as close as I got back in the 80's. I am learning C as I go, on an 'as-needed' basis. I seem to get more from reading in the forums and reverse engineering then from the numerous 'quick starts' I have found online, although I pick up a tidbit each time I read one. I am more into elecrtonics, led's, and gadgets, but this microcontroller has so many possibilities. I am trying to get a better grasp of C, but with it being a hobby it is hard to dedicate the time to learn it the way I should. If you think of a book or guide that may be helpful to me, let me know. Thanks again for your help. |
May 22, 2012 by Blackbird |
One more question as I am sitting here thinking, this all occurs with me not providing any input to the controller. The 'time' value that is counting up to 32767 then going to -32768 and counting backwards is 'the_time' which is already set at 32-bits. I am missing how the variables I created are causing 'the_time' to change and count backwards. I could see it locking up or something, but I thought the timer was part of the chip hardware. Thanks for your insight. |
May 22, 2012 by pcbolt |
Blackbird - You're right, the timer is part of the chip hardware and actually operates independently of the main code. The timer you're using (Timer0) is actually only 8-bits, it only counts from 0 to 255 (max), then either counts down or restarts at zero. The way it is set up now, it stops at 143 then restarts at 0. Whenever it hits 143 (once every 1/100th of a second) the interrupt is triggered and "the_time" is incremented. When you assign one of your 16-bit time variables to the 32-bit "the_time" value, the upper 16-bits are lost. If a variable is "signed" the processor looks at the left-most bit to see if the number is positive or negative (0 is positive, 1 is negative). So when you count up "the_time" goes from 0x00007FFF to 0x00008000 and the left-most bit is 0 in both cases. When you copy those numbers into a 16-bit variable, you lose the left-most 16-bits and get 0x7FFF and 0x8000 (rememeber each hex digit is 4-bits). 0x7FFF in binary is 0111 1111 1111 1111 and positive. 0x8000 is 1000 0000 0000 0000 and therefore negative. I know it's odd but it actually saves time in the processor. |
May 22, 2012 by Blackbird |
That makes sense to me for the variables that I assign to equal 'the_time' but not for 'the_time' itself. I thought this statment, volatile int32_t the_time; made 'the_time' a 32 bit variable and would therefore not run out of space for a couple hundred days? Are you saying that my assigning a variable like 'bluetime' to equal the variable 'the_time' is causing an issue with 'the_time'? The explaination may be beyond me at the moment, so feel free to use a bigger hammer. :) I will try the modifications to my assigned variables and try it out. I just hope I am not misunderstanding your direction. Just out of curiosity, how would you redirect multiple subroutines to the same point without 'goto'? Seems to make the logic flow much easier for me, but I also did not know another way. Thanks again. |
May 22, 2012 by pcbolt |
Blackbird - Ah...I see now where the confusion is. "the_time" should NOT change when another variable is assigned to it, it will have enough space to last a couple of hundred days. When you use the 16-bit variables in the "if" tests, you will run into trouble. So the question is "why does 'the_time', a 32-bit variable, start to count backwards?" The answer is "it doesn't". It's just getting displayed wrong by the "printf_P" statement on line 161 above. The "%.d" assumes a 16-bit variable. To get it to display correctly, try using "%ld" (that's a lower "L" not 1). You won't need the decimal point in it. As for the "multiple subroutines to one point" question, just format it a little differently. Take your "bluereverse" block, and format it like this:
Now anytime you want to execute it place this in your main loop:
When "bluereverse()" is finished, it jumps to the line after the code that called the subroutine. But like I said before....if it is easier for you just stick to what's comfortable. |
May 22, 2012 by Blackbird |
I made the changes to only the time variables as you suggested.
It appears to work still @ 14 minutes, so I am feeling better thanks to your help. The PC output still goes up to 32k and then starts counting down to 0, then goes back up. I am thinking that it is my print string causing the display issue,
I am still curious as to what was happening with the assigned variables if you feel like trying to explain it again. Thanks again for getting me past this road block. By the way, I also make decals as a hobby and would be HAPPY to send you some if you would like. I know you do this stuff to help others, but I really appreciate your efforts and sharing your knowledge. Still working at 22 min. :) |
May 22, 2012 by pcbolt |
Correction - Line 1 should read:
Can't forget the braces :-) |
May 22, 2012 by Blackbird |
I posted while you were responding. Thanks. |
Please log in to post a reply.
Did you know that a motor is harder to turn when its terminals are shorted together? Learn more...
|