NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » referencing a variable
January 11, 2012 by tchilzer2 |
|
---|---|
January 11, 2012 by tchilzer2 |
I changed the line "while (flash = 'f')" to "while (tmp_c == 'f')" otherwise any key triggers. I eliminated "uint8_t flash" as well as "flash =" from the "scanf_p" line. |
January 15, 2012 by JimFrederickson |
I know that you posted this in order to receive some help. I wasn't, and still aren't, entirely sure what you are asking. I was kind-of waiting for someone to begin to answer you to find out out of curiosity. Since no-one else has answered, it seems that maybe others don't understand what you asking either? From what I can tell these are the questions you want help with? 1 - How to read input from the serial port without causing the program to halt? 2 - How to use the information read to affect how your program runs in regards to turning LED's on/off? (The initial message heading of "referencing a variable" is not accurate. Correct?) |
January 15, 2012 by tchilzer2 |
|
January 15, 2012 by Rick_S |
One word, Interrupts. If setup properly, you can totally ignore the serial port and continue with program operation. Then when serial data comes in, the program would automatically jump to the interrupt routine, do it's thing, then return to where it left off in your program. HERE IS A LINK to the winavr tutorial site showing the basics of setting up interrupt driven serial communications. (specifially for recieve) I have not run their code nor have I set this up (at this point). I do have a project in mind for it though so I researched it a bit. Let us know if you go that route and how it works out if you do! Rick |
January 15, 2012 by tchilzer2 |
|
January 16, 2012 by JimFrederickson |
Yes, using portions of the AVR Microcontroller that cause 'Interrupts' are a solution to many issues/problems. Using 'Interrupts' do, however; have the potential to add a whole lot of additional complexities to your program. Judicial use of these though can also 'simplify' some things that you may want to do as well. These added complexities probably should be avoided until you have a better understanding of coding. Additionally learning how to accomplish what you want without interrupts is by no means a 'wasted effort'. Two things I would recommend that you use to get used to viewing programming problems. 1 - beginning-middle-end 2 - condition-response 1 - Every Program or supporting function that you create has a 'beginning-middle-end'. What I mean by that is there is 'beginning-code' that is necessary for the progrm or function to setup in order to begin doing what it is supposed to do. There is 'middle-code' which is where most of the processing in the program or function occurs. Finally there is 'end-code' which is where the program or function gracefully completes it's purpose. In the example code you uploaded I noticed a few things that seem to be incorrect... 2 - Every program is essentially a series of 'conditions and responses to those conditions'. Even when 'interrupts' are being used, the a 'condition' is the occurance of an interrupt, the 'reponse' is what is done when the interrupt service routines runs. Whether it is called 'event driven programming', 'ladder logic', 'if-then-else programming', it does all boil down to 'looking at conditions and responding appropriately to those conditions'. The Atmel AVR Microcontroller is single core and can only do 1 programming task at a time. (Note I did say 'programming task', there are other subsystems of the AVR Microcontroller that can be tending to 'other chores' while your 'code is running'. timers, serial send/receive, watchdog, etc...) Because the Microcontroller is so fast though, it can be made to appear that it is doing multiple things at a time, but still essentially it is just doing them very quickly one thing/piece at a time. Another aspect, (without getting into sleep modes, interrupts, etc...), is your processor
doesn't really 'stop'. It is going to be doing something all of the time. Often most of what it will end up doing though, is just waiting to do things that you want to have done. You have ran into this in at least part of your code. You want to turn LED's on and off,
but you want to control this affect VIA Serial Input. When you first tried to do this
you chose a routine that 'read a byte from the serial port'. The 'affect was' that the
program stopped until the data was read from the serial port. That was not what you were looking to accomplish. Changes to your Original Code:
This part is in your 'while(1)' statement. In this statement we are in what I had called the 'middle code', but the above sequence is really 'beginning code'. There is not need to continually initialize the uart, and setup a stream. So this should be moved outside o the 'while(1)' statement. (probably after where you define the "// LED as output".) For me though, I would not really be using 'streams' for your input. (I am not sure how the 'streams' would affect things, but the following would work if streams were not used and may still work if streams are used.)
You can put this wherever you want. Since the Serialport is only read after we have found that a character is available it should return as quickly as possible. (Remember when I noted that there are 'subsystems' that can tend to things while your program is running, this is an example of that.) (NOTE: the result of 'uart_char_is_waiting()' does not need to be 'explicitly compared to 1'. In 'c if statements' are executed, considered 'true', if the result if 'non-zero'.) That should get you around what you are trying to do right now. Using a timer in the AVR Microcontroller to generate 'interrupts' that you can use to create a 'timebase' would probably be the next step. That way the delay_ms() functions could go away, and you could just check a value. (your timebase, to see if some time had elapsed.) (You can look at the 'Nerdkits Libraries' as well to get an idea of what functions are available in them. Just search for 'libnerdkits' on the drive you installed to and there you should find several ".c" and ".h" files. The ".c" files are the code, and the ".h" files are the 'include files' that are used to create references for the code.) |
January 18, 2012 by tchilzer2 |
Jim, Thank you for the instruction. I have spent several hours now reading the data sheet for the microcontroller as well as flipping through the .c and .h files. Some of it gets clearer as I go on and other principles are more elusive to me. I am not exactly a biggining programer, but I am not a pro in any language either. I am new to c since the nerd kit, but I have been playing with c++ and vb for about a year. I have extensive knowledge of the old basic (TI, and commador) but those are so outdated. I learn best by using example code that I find on the internet but the problem with that in c seems to be that the libraries are different for every compiler out there. Where one command may work for boreland wont work for nerdkits. At least thats what it seems to be. I am having difficulty with what is standard. (or what commands are available and what they do). I also want to thank you for sharing the above workaround snippet. It is much more usefull for me to get one new command and know a little about what it does than to get a link to multiple lines of vaguely annotated code. Anyway, I have come to the point that I am trying to learn about interupts. The part that seems hard to me now is the clock. I dont understand (yet) how the clock should be configured (or why) given a certain kind of interrupt. I do understand that it is a cycle and every process has its turn but sifting through the workings of the bits of a microcontroller are a little daunting right now. I will learn it though especially with the help of gracious folks like yourself who take the time to help. I think I will post another thread asking some questions about the clock. Thanks so much again! |
January 18, 2012 by JimFrederickson |
One thing in your posts... The Nerdkits Forums don't seem to 'wrap lines'. If you look at your posts the lines are essentially 'paragraphs' so people, ME ;) , have to scroll across to read your posts. I find it much easier, and probably others do as well if you break up your lines into short segments. (When you 'Preview' the post you can see which ones are too long and insert 'returns' appropriately.) TI as well as Commodore? Yes there is a 'c standard', but there are differences between implementations. of course for the AVR Microcontroller alot of the difference stem from it's internal architecture and well as the fact c was designed for 'full blown computers' and while the speed of the AVR is MUCH MUCH faster than the original IBM PC, and even the IBM PC-AT, it is still not a 'full blown computer'. Another problem I have run into is that much of the information out there is referencing
'a more original form of c' and isn't entirely applicable to what I am looking for. (The 'uint8_t'
format is an example of this.) Keep in mind though that a HUGE part of the allure of 'c' is it's 'flexibility' and as with all 'flexibility' there is 'ambiguity'... Here is an 'framework' of sorts for you. NOTE: The function timer0_init() DOES WORK if you just copy it to your source file and provide the variables/constants it needs. NOTE: The structure of the ISR(TIMER0_COMPA_vect) routine is correct you just have to decide what to do. you need to remember 3 things though... 1 - The entirety of the interrupt processing routine should be kept as small as possible, and
it must complete before the next timer interrupt occurs. What does this mean? Bascially in this 'framework' there are 2 things that determines how much time you have before the TIMER0 interrupt. The TIMER0 Prescaler and the Timer0 Compare value, (TIMER_TIMER0MAX)... With the nerdkits crystal of 1,474,560 the precaler causes counts/second of: clk/1 - 1,474,560/sec clk/8 - 184,320/sec clk/64 - 23,040/sec clk/256 - 5,760/sec clk/1024- 1,440/sec So if you set the TIMER0 Prescaler to be the system clock and then set the TIMER_TIMER0MAX constant to be 10 you are going to have problems. Because TIMER0 will count at, essentailly, the maximum instruction speed and if you waiting to count to 10 then you would have only 11 instructions that could execute. BEST CASE, as many instructions are 2 clocks cycles, and a couple are longer. (you have 11 instructions because it counts from 0 to the compare value. At least I think that is right?) How many instructions that could execute per TIMER0 Interrupt = systemclockspeed / (prescaler * (TIMER0MAX + 1)) So obviously you need to create some sort of 'interrupt timing' that makes sense for what you want/need to use it for. 2 - Any value that is changed in an interrupt routine MUST HAVE the atribute of 'volatile' defined for it. If you do not do this then the compiler will not know that this value can be changed in an interrupt routine and it may 'optimize your code when it compiles' so that it stores the value in a register and the changed value in RAM is never looked at. (This is assuming that you are not letting interrupts nest, letting interrupts be interrupted, which I would recommend to ALWAYS avoid as this add more issues.) 3 - you have to make sure that you appropriately control access to the values that can be changed in an interrupt processing routine. So anytime a value that is normally changed in an in interrupt processing routine is changed outside of the interrupt processing routine you need to disable interrupts. That way while you are changing the value(s) the interrupt processing routine won't be running and use/change the value(s) until you are ready. There are a variety of ways you can accomplish this, but most likely the value(s) you will change will be small and not take much time so just disabling interrupts is likely to work without issues. Somestimes though more sophisticated mechanisms must be used.
The above is just an example. It would be much better to create a 'structure of timers' and then create the appropriate code to control them rather than discrete values. (I also think it looks better when reading the code as well.) Maybe somethings that looks like this...
Then you would have to create the appropriate code to:
Another thing, completely off the subject of 'serial ports' and/or 'interrupts'... I have found that as my program have become more sophisticated that creating a 'syserr function' is quite helpful. (Of course you could call it anything, maybe "BSD"? ;) ) Basically whenever some function I have created as an unexpected error it will call my 'syserr function' and pass a code to it. The 'syserr function' disables interrupts, and/or dumps the message to the LCD or to the Serial Port and then loops doing nothing. Ultimately I want my 'syserr function' to dump the return address from the stack, but for now I just dump the error code I pass to it. |
January 20, 2012 by Ralphxyz |
hey Jim,
The Nerdkit Guide says the crystal is 14,745,600 not 1,474,560.
Nice instructions I am getting a lot out of it. Ralph |
January 20, 2012 by JimFrederickson |
Hello Ralph, YES, I dropped a 0 and didn't even notice... (Too bad you can't 'edit' a post to correct it!) Well, hopefully the other numbers as well as most of the code is correct! Maybe that is why I have to spend so much time 'debugging'! ;) Thanks, Jim... |
January 20, 2012 by Ralphxyz |
Now the Markdown forum leaves a lot to be desired but I'd really really love to have a easy to use and setup debugger. Ralph |
January 20, 2012 by JimFrederickson |
Hello Ralph, In what context are you referring to a 'setup debugger'? I am not sure if you are referencing something to do with the forums here, or if you are talking about coding? Thanks, Jim... |
January 20, 2012 by tchilzer2 |
Ok, after some studying I want to make sure that I comprehend what is going on with these templates peice by peice. First:
Then am I to understand that the above is a variable set that can be used when defining:
|
January 20, 2012 by JimFrederickson |
Hello tchilzer2, First off, I do know my descriptions may not actually be using the 'exact c nomenclature', sorry for that in advance. I like using 'structures'. (Well at least 'simple structures'. 'structures, within structures, etc...' can easily become too convoluted for me...) For me it enables things to be grouped into meaningful, and often self-documenting, sets. In my tests, there really was not too much of a 'penalty in code size' for using 'structures' so the benefits were much more important to me. (If you have more than one 'structure' to reference in a 'function' it is helpful, for code size, to try to reference all necessary values in a structure 'by structure' but again it is not too much of a concern... Maybe that doesn't make sense? Basically if you have 'struct1', 'struct2', 'struct3' try to make changes to 'struct1 elements' in a group, then to 'struct2 elements' in a group, then to 'struct3 elements' in a group. Not always possible, but keep it in mind.) 'structures' essentially give you the ability to 'create a new/custom data type'. NOTE: There are at least 2 'formats for defining structures that work with c'. It is a matter of moving the parts of the definitions around. I only use the one I have shown, to me it makes more sense... So there are 3 things happening there... 1 - 'typedef etc...' is the actual definition of the structure. This structure has the 4 named data elements as shown. (active, currtick, resetvalue, stop...) These elements are defined to be the new data type called 'STRUCT_TIMERS'. (For me I consider 'structures' to be a 'program constant of sorts' so I capitalize them as it often done with c constants.) Everything within the braces, '{}', is part of the structure. Additional items can be added as necessary/desired. 2 - 'volatile etc...' is the part that actually allocates the 'structure' so that it can be used in your program and gives it a name. In this case the 'array mytimers' is being created that is an array of the 'STRUCT_TIMERS'. The 'array mytimers' uses a constant 'MYTIMERS_MAX' to define how many elements are in the 'array mytimers'. (Defining a constant for the array size is helpful in any part of the program where you have a support routine that needs to know the size. That way you only have to change it 1 time...) The constant 'MYTIMERS_MAX' is defined using a 'define statement' just like my constants 'TRUE', 'FALSE', and 'INVALID'... NOTE: A structure doesn't have to be an 'array', you can omit the array part. NOTE: In this case the 'volatile attribute' is used to make sure that the compiler understands that parts of this structure may be changed outside of the function within which it is used. (In this particular case an interrupt routine...) If you don't do this then the optimization that the compiler uses will give you grief. 3 - The last part are the 'support routines to control access to the structure'. Yes, getting access to data in a structure through 'support routines' that accept and/or return values, may be a little inefficient but it makes more sense to me. NOTE: The 'support routines' that I use are basically analogous to the 'methods' that are used in 'Java Objects'. (Although I have programmed in this manner LONG BEFORE JAVA... ;) ) As an example of use let's define a 'mytimers_init() function'...
NOTE: the use of the 'MYTIMERS_MAX' constant we used to define the size of our 'structure'. NOTE: if the structure was not an array then 'mytimers.active' would reference the value. NOTE: if you define an 'array within a structure', not a 'array of structures', then it is probably best to make sure it is a 'specific size'. Otherwise you get into alot of other issues that may compile but not really work. NOTE: you also have to consider how to 'control access' which I mentioned in a previous post on this thread, since you have an 'interrupt' routine that may change values... P.S. Ralph, can you 'scan this' and make sure I didn't have any other 'lapses'... ;) |
January 20, 2012 by JimFrederickson |
Sorry tchilzer2, (hmmm 'line wrap fix' doesn't seem to be working the same as before?) Hey you never did mention if the TI 99 4a you used had the extended RAM that ACTUALLY put RAM on the Processors Bus? (It may not have been called 'extended RAM' I don't really remember now, but if you 'had it' I am sure you would remember!) I didn't really ask before, but I thought you may put it out there... ;) |
January 20, 2012 by Ralphxyz |
God you cannot believe how much I wanted a TI 99. I did get a Timex Sinclair 1000. Ooops sorry I digress. Ralph |
January 20, 2012 by tchilzer2 |
Thank you Jim, I am moving along like a heard of turtles right now, but I am making some headway thanks to your help as well as yours Ralph. I have been trying to figure out this sites text editor... no conclusions yet;) as far as the TI 99 there was a few expansions that was available one of which was called extended memory. It did plug right into the bus and it added something like 2k extra bites of programmable memory. I suppose that with those pc's that memory was all ram (correct me if I am wrong) but it makes sense to me that way because it ran whatever program was loaded into memory (ie tape player lol ;) If I remember correctly the expansion had a through port as well that could use stacked memory expansions (one plugged into another) There was also another cool voice plug in that made the computer talk! I think the TI was well ahead of its time! |
January 20, 2012 by JimFrederickson |
Hello tchilzer2, It is good you are 'moving along'. I had hoped that at least some of this has been useful/helpful. There is quite a bit to wrap your head around. It is really extra difficult when everything you are programming is basically a 'system program'. You have 'nearly complete control', and 'responsibility' for what is an entire small system whenever you write code at this level. As I mentioned before the TI 99 4A was a real favorite of mine. The 9900 CPU was my draw. It was quite impressive for the time frame, and I think if TI could have 'produced' and 'marketed it better' they could have had a much greater impact on the industry. The memory expansion I was thinking of was the 32kb RAM Expansion that was added later. The main benefit of that was that it actually put RAM onto the CPU Data Bus. Originally the TI 99 4A had to 'request RAM from the Video Display Processor' a byte at a time. (Highly in-efficient, (read slow), considering the processor was word based!) I was just surprised that you mentioned that little beast, so it got me side-tracked... Ralph it is probably good that you never got one, because then you would just wonder how TI could blow it! ;) |
January 21, 2012 by Ralphxyz |
Well I was just so envious of being able to load in code from the back of magazines using a bar code reader! I had started programing setting toggle switches so to be able to load a program just by scanning a bar code, WOW that was amazing. Ralph |
Please log in to post a reply.
Did you know that a microcontroller can measure an RC time constant? Learn more...
|