NerdKits - electronics education for a digital generation

You are not logged in. [log in]

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
tchilzer2's Avatar
    Hello,

    I am very new to the c programming language. I have altered the flashing an led program (from the nerdkits guide) to flash two led's alternately (will be used in top police flashers.) I want to control them with my computer keyboard. My problem is that I need to reference a variable during a while loop that is not contained in the while loop. Here is my code:

    / led_blink.c
    // for NerdKits with ATmega168
    // hevans@nerdkits.edu

    #define F_CPU 14745600

    #include <avr/io.h>
    #include <inttypes.h>

    #include "../libnerdkits/delay.h"
    #include "../libnerdkits/lcd.h"

    #include <stdio.h>

    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>

    #include "../libnerdkits/uart.h"

    // PIN DEFINITIONS:
    //
    // PC4 -- LED anode

    int main() {

      // LED as output
      DDRC |= (1<<PC4);
      DDRC |= (1<<PC3);
      // loop keeps looking forever
      while(1) {

       // init serial port
      uart_init();
      FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
      stdin = stdout = &uart_stream;

       // listen for command
       char tmp_c;

       unit8_t flash
        flash = scanf_P(PSTR("%c"), &tmp_c);

        while (flash = 'f') {

          printf_P(PSTR("Got command '%c'\r\n"), tmp_c);

        // turn on LED 1/ turn off led 2
        PORTC |= (1<<PC4);
        PORTC &= ~(1<<PC3);
        //delay for 500 milliseconds to let the light stay on
        delay_ms(500);

        // turn off LED 1/ turn off led 2
        PORTC &= ~(1<<PC4);
        PORTC |= (1<<PC3);
        //delay for 500 milliseconds to let the light stay off
        delay_ms(500);

      }
      while (flash = 'o'){
      PORTC &= ~(1<<PC4);
      PORTC &= ~(1<<PC3);
      }
      }
      return 0;
    }

    What I need is a command line whithin each "while" loop to jump out and check the "flash" variable to see if it has changed. I cannot put the flash input in the while loop because it stops to listen after the first cycle and that is an undesireable effect. does anyone have any suggestions?
    Thank you in advance!
January 11, 2012
by tchilzer2
tchilzer2's Avatar

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
JimFrederickson's Avatar

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
tchilzer2's Avatar
Hello Jim,

first I want to say thanks for responding. Next I want to let you know that I have moved on considerably since this post. My questions still have not been aswered, but I have re designed my program to run differently. Yes I would very much like to know how to have a program read input from serial and not wait for the input. I want it to periodically scan to see if the input has changed. I want the program to run until a key stroke occurs and on the next loop the program picks up the new variable. for example:

void flash(){                                                     |  if I scanf hear 
while (keystroke != "s"){                                         | the lights stop flashing
// flash LED 1/ turn off led 2 (and viseversa) back and forth     | to wait for a keystroke
   }                                                              |
}
initmain(void){
while (1){
char keystroke
scanf("%d"(keystroke));    |
while (keystroke != "f"){  |  this all works,        flashing the lights
//output pins are off      |  however once f is     without any chance of 
}                          |  pressed scanf is      accepting a new keystroke
flash();                   | completely bypassed    "s" to stop them.
 }
}

Am I making sense?
Also yes I suppose the head is misleading... when I first posted, I wasnt sure how to go
about asking my question the right way. I looked at it a few times and saw was to trim it up,
but I couldnt find a way to edit. Sorry everything was such a mess. I hope this ex. explains my delema a little better.
January 15, 2012
by Rick_S
Rick_S's Avatar

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
tchilzer2's Avatar
Thank you Rick,

I must admit that after viewing the code in this link I am a bit lost.
It is however something new to learn to work with so I will take the time to 
learn the code. I will post when I get it to work.
January 16, 2012
by JimFrederickson
JimFrederickson's Avatar

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:

    // init serial port
        uart_init();
        FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
        stdin = stdout = &uart_stream;

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.)

    if (uart_char_is_waiting() == 1) {
        flash = uart_read();
        }

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
tchilzer2's Avatar

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
JimFrederickson's Avatar

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?
The 99 4a? ONE of my 2 Favorite Processors of all time... (I do hope you at the very least had the extended RAM that ACTUALLY put RAM on the Processors Bus instead of having to get request RAM from the Video Processor!)

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.

    #define INVALID     255
    #define TRUE        1
    #define FALSE       0

    void timer0_init() {

    //  This is called with interrupt disabled

    //  TCCR0A  -  Timer 0 Counter Control Register A
    //  TCCR0B  -  Timer 0 Counter Control Register B
    //                          CS0     CS1     CS2
    //  No Clock                0       0       0
    //  clk (no prescale)       1       0       0
    //  clk/8                   0       1       0
    //  clk/64                  1       1       0
    //  clk/256                 0       0       1
    //  clk/1024                1       0       1
    //  clk on TO Falling Edge  0       1       1
    //  clk on T0 Rising Edge   1       1       1

    //  Timer 0 Prescaler

    //  Timer 0 Counter
    //  TCNTO

    //  TIMSK0  -  Timer Mask Register
    //  OCIE0  Timer 0 Comparison Interrupt
    //  TOIE0  Timer 0 Overflow Interrupt

    //  Timer0 is setup to do:
    //  clk/8 
    //  count up to TIMER_TIMER0MAX constant
    //  automatically clear the timer and restart counting

    // CTC (Clear Timer on Compare Match mode)
    // Match Value set by OCR0A register
        TCCR0A |= (1<<WGM01);

    // clocked from System Clock clk/8
        TCCR0B = 0;
        TCCR0B |= (1<<CS01);

    // clock comparator value
    //  TIMER_TIMER0MAX is an uint16_t
        OCR0A = TIMER_TIMER0MAX;

        TIMSK0 |= (1<<OCIE0A);

    //  This routine clears any timers that are setup
        mytimers_clear();
    }

    ISR(TIMER0_COMPA_vect) {
        uint8_t local_i;

    //  Timer0 Interrupt Overflow Service Routine

    //  One tick

    //  process any timer that is 'active and not currently stopped'    
    //  only count it not already 0
        if (myledofftimer_counter > 0) {
            myledofftimer_counter--;
    //  when 0 then set timer to stopped                
            if (myledofftimer_counter == 0) {
                myledofftimer_stopped = TRUE;
                }
            }

        if (myledontimer_counter > 0) {
            myledontimer_counter--;
    //  when 0 then set timer to stopped                
            if (myledontimer_counter == 0) {
                myledontimer_stopped = TRUE;
                }
            }
        }

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...

    typedef struct {
        uint8_t     active;         //  Timer is actively in use and should be processed
        uint16_t    currtick;       //  current count down value in the timer
        uint16_t    resetvalue;     //  value the timer to be 'set to' when reset
        uint8_t     stopped;        //  Timer is currently stopped and needs
                                    //  processing, or was never started
    } STRUCT_TIMERS;

    volatile STRUCT_TIMERS mytimers[MYTIMERS_MAX];

Then you would have to create the appropriate code to:

mytimers_init(); // Initialize the mytimers structure

mytimers_set(itimerid, itimervalue);  // set a timer to be used, making it active.

mytimers_stop(itimerid);  //  stop a timer from counting

mytimers_reset(itimerid);  //  reset a timer so it can be resused later, making in inactive

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
Ralphxyz's Avatar

hey Jim,

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

The Nerdkit Guide says the crystal is 14,745,600 not 1,474,560.

The crystal oscillator for your NerdKit is a 14.7456 Megahertz crystal. That means that there are 14,745,600 instructions executed every second!

Nice instructions I am getting a lot out of it.

Ralph

January 20, 2012
by JimFrederickson
JimFrederickson's Avatar

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
Ralphxyz's Avatar

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
JimFrederickson's Avatar

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
tchilzer2's Avatar

Ok,

after some studying I want to make sure that I comprehend what is going on with these templates peice by peice. First:

typedef struct {                                                        | Is this defining a variable type
uint8_t active; // Timer is actively in use and should be processed     | (like char) named STRUCT_TIMERS  
uint16_t currtick; // current count down value in the timer             | where active, currtick,  
uint16_t resetvalue; // value the timer to be 'set to' when reset       | resetvalue, and stopped are 8 or
uint8_t stopped; // Timer is currently stopped and needs                | 16 bit variable type members?
// processing, or was never started                                       is mytimers the variable of 
} STRUCT_TIMERS;                                                        | type STRUCT_TIMERS?
volatile STRUCT_TIMERS mytimers[MYTIMERS_MAX];                          | What is volatile & MYTIMERS_MAX?

Then am I to understand that the above is a variable set that can be used when defining:

mytimers_init(); // Initialize the mytimers structure                                       | Is each line here
mytimers_set(itimerid, itimervalue); // set a timer to be used, making it active.           | a function def.
mytimers_stop(itimerid); // stop a timer from counting                                      | to be called 
mytimers_reset(itimerid); // reset a timer so it can be resused later, making in inactive   | later like a 
                                                                                              command?
January 20, 2012
by JimFrederickson
JimFrederickson's Avatar

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'...

    void mytimers_clear() {
        uint8_t i;

    //  NOTE:  Depending how this example is implemented we may only need
    //  to clear the '.active' value since we probably don't care about 
    //  the rest, and when the timer is set the other values are initialized.
    //  for me though, of usually use the '_init function' that i create
    //  as the place I look for what's in my structure.

        for (i = 0; i++ ; i < MYTIMERS_MAX) {
            mytimers[i].active = FALSE;
            mytimers[i].currtick = 0;
            mytimers[i].resetvalue = 0;
            mytimers[i].stopped = FALSE;
            }
        }

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
JimFrederickson's Avatar

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
Ralphxyz's Avatar

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
tchilzer2's Avatar

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
JimFrederickson's Avatar

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
Ralphxyz's Avatar

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

Post a Reply

Please log in to post a reply.

Did you know that a microcontroller can measure an RC time constant? Learn more...