This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to divide the timer into three events.



I been working on a project based on replicating a red light traffic system by using the Tiva C series, I am new into programming and microcontrollers so i am having a lot of issues. The main idea is to have 4 traffic lights, each having 3 LEDS for a total of 12. Then i want to add a temperature sensor and a light sensor to modify the sequence of the leds accordingly to the values gotten from the sensors.   

What i am here for, is to understand how to generate a three event sequence by using a single timer. 

I want to use the timer to divide the process into three different events, at each event I want to be able to light up an LED of an external circuit. First Event would light up the first LED (Green), second event would light up the second LED(YELLOW) and the third event to light up a third LED (RED). 

The following code is what I been working on, also I want to use only one timer to do this implementation. 

// function prototypes
void init_timer(void);
void Timer0_ISR(void);
void init_output(void);

uint32_t timer=0;
uint32_t sys_clock;

int main(void)
{
// Configure system clock at 40 MHz.
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
sys_clock = SysCtlClockGet();


init_timer();
init_output();
// Enable the processor to respond to interrupts.
IntMasterEnable();
// Start the timer by enabling operation of the timer module.
TimerEnable(TIMER0_BASE, TIMER_A);

while(1){

}
}

void init_output(void) //Enabling the different ports
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Enable GPIO Port F.
GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

}
void init_timer(void)
{
// Enable and configure Timer0 peripheral.
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
// Configure as a 32-bit timer in periodic mode.
TimerConfigure(TIMER0_BASE, TIMER_CFG_A_CAP_COUNT);
// Initialize timer load register.
TimerLoadSet(TIMER0_BASE, TIMER_A, sys_clock -1);

// Registers a function to be called when the interrupt occurs.
IntRegister(INT_TIMER0A, Timer0_ISR);
//IntRegister(INT_TIMER0A, Timer1_ISR);
// The specified interrupt is enabled in the interrupt controller.
IntEnable(INT_TIMER0A);
// Enable the indicated timer interrupt source.
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);


}


void Timer0_ISR(void)
{
// Clear the timer interrupt.
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

timer = TimerValueGet(TIMER0_BASE, TIMER_A);

//setting the timer = to the value of the timer at that moment, then divide the timer into 3, in order to have three different events. At each event I used the GPIOS to send a high or low output. I am sure I can not divide the timer like this but that is the way I thought of the timer, please help find another way to do such sequence.
if (timer = 13333333) {
//GPIOPinRead(GPIO_PORTA_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 15);
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);

}
else if (timer = 26666666)
{
//GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 15);


}
else if (timer = 39999999){
//GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 15);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);
}
else {
timer=0;
}
}

  • Hello user3949854,

    It would be simpler to do it with a time base. Consider a simple sequence that at any given time only one side has to Green and all other's Red. Let's also say that the time it remains Green is X. When changing to Yellow it could be X/10. Thus you need the timer to work once with X as the Time Count and X/10 as the Next time count in one-shot mode so that you can arm the timer for the next cycle.

    Initially make one light as Green and others as Red and load the timer with X.

    When a timeout occurs, reload the counter with X/10 and change the one that is green to yellow

    When the next timeout occurs, reload the counter with X and change the one that is yellow to red and the next one as Green. The next one can be a variable in memory that counts 0-1-2-3-0-1-2-3...

    There is no hysteresis between yellow and red, so you can factor another X/10. The algo can then evolve from there for sensors.

    Regards

    Amit

  • Basically what you need is a 'state machine' variable, which is used in a switch statement running in the main function(you could run it in the timer ISR, but it's always better to keep the ISR as short as possible).

    So the different states could be for example, STATE_INIT, STATE_GREEN, STATE_YELLOW, STATE_RED, STATE_ETC... (You can use the 'enum' type to declare the state variable, but it's not needed, you can define them each with a different value)

    Let the timer run in ONE_SHOT mode, and in the timer ISR, set a flag(volatile global variable).

    In the main loop you wait for that flag, if it's set it will then loop through the switch statement(when you declare that flag, set it to 1, so it switches to the STATE_INIT when the programs goes through the loop for the first time).

    In the first case in your switch (case STATE_INIT:), you could set the outputs to a predefined state, reload the timer to a specific delay, set your state variable to the next state, reset the flag and start the timer.

    Then the next time the flag is set from the ISR, the switch statement will switch the next case(STATE_GREEN), here again you set the outputs, reload the timer to a specific delay, set your state variable to the next state, reset the flag and start the timer.

    And so on, when you reach the last state, set the state variable to the first state(well, second in this case, STATE_GREEN).

    Meanwhile, in your main loop, while checking the flag, you can check the inputs(temp, light), and change the state variable to a specific state, set the flag, stop the timer, well just do what you need to do.

    Hope this helps.

  • And - to positively prevent death/destruction - your code must POSITIVELY/FORCEFULLY PREVENT any possible occurrence of MULTIPLE (near simultaneous) GREEN LIGHTS!  That's rather important - is it not?

    What happens should the MCU fail?  Or should it fail on Green?  Or should the Led driver (for Green) latch on?  What then? 

    Clearly responders have "assumed" all is well.   Yet - in the real world - these questions must be anticipated - and successfully answered!  Needed methinks is a robust Led "feedback" mechanism - this problem is NOT just a, "Program a State Machine" exercise.  Positive confirmation of Led operation is usually mandated (thus reads of each/every Led is normal/customary)

    Should not the illumination of ANY GREEN demand the, "jumping thru very high hoops?"  Not just a switch statement!

    "Surgeon - Do NO Harm" has an MCU-Programmer implication too - deserves mention...  Most always there's a, "Big Picture" - and micro-focus (too often) misses...

  • I doubt this is for a 'real world' application, more like for a 'model world' application.

    Would you ask a 'novice' to program a critical system to be used in a 'real world', with a microcontroller which is not designed for it?

    He can easily add different states, depending on inputs, to account for critical situations, if he needs to, but as he is a novice, I wanted him to grab the basic's first.

  • Your points are all valid - I acknowledge.

    Yet - this (uninspired) programming task given by "lock step" (educators) is the real issue - is it not?  Of course you don't assign this (or other critical designs) to beginners.  (I was assigned this in a college Fortran class - and (nearly) got kicked out for identifying TWO (or more) GREEN possibilities...{motivated me later to go to law-school})

    I'm not so sure that he can "easily add different states" - my belief is that any such critical design should be deeply & critically designed/considered "up front" - not with "after the fact" additions.  This IS a Control system - is it not?  And you/I must have observed that any decent control system demands (often - real time) feedback.  (i.e. Green is not "stuck" on - via any fault - perhaps even redundancy must be employed...)

    Indeed you guided him (quite nicely) through the basics.  Yet my "real world points" remain critical (despite defensive posturing) - and bear (some) consideration.  And are too often "missed" by MCU-centric focus - which was my key thrust...

    (and - if the teacher is any good - poster will get "extra credit" for his "Big Picture get" - likely missed by compliant others!)

  • I agree with your point, any safety critical system will need a fail safe function, and many considerations for the 'what if' cases.

    But you'll need more than just a microcontroller and a program then, most likely redundant hardware which checks the main hardware, for like 'is the main microcontroller still running?', and if it's not the case, this hardware takes it over and let all orange lights blink for example. And a lot more like checking for power, shorts, blown lamps, etc.

    Although I don't see a problem using a state machine concept(you'll have to have some kind of it anyway, or are you referring to a RTOS), how would it have two green possibilities?

    If it's due to a hardware malfunction(say output locking), then you need to have the hardware to 'read' or trigger that situation, and if you do have it, then you could go to a 'fail safe' state(function)...

    If the microcontroller locks up, you can have the watchdog timer jump to the 'fail safe' state.

    Well probably I'm missing something, but anyway, it's a starting point.

      

  • We are (now) more in agreement than not.

    My ire targets the professors/course instructors - and the "work ethic" which enables unthinking - lock-step - repetition of "same old traffic light."  In their defense - that "repetition" now shifts to a "current" MCU.  Yet - on whole - it's effort light/uninspired - and "lures" students into "limited picture" thinking...

    Indeed other hardware is required - we sometimes design "mission critical" systems - multiple - tightly coupled MCUs work in concert - and often must "vote" to take a decision.  In such systems unique, back-up batteries/supplies route independently to each/every MCU board. (in some airframe applications - there are rules dictating how close, "fly by wire" cables may come.  This in the attempt to avoid an in-flight - localized catastrophe - severing both main & redundant signal cables - this modeling past, hydraulic plumbing.)  

    As small, tech biz owner - such "Big Picture" thinking must be "pounded" into the heads of even the most talented hires.  Should our o.p. have read this far - your & my "shift" to, "management of the unexpected" will either be welcomed (poster recognizes the import "outside the box") or rejected (marc & cb1 have added to his thinking/workload).

    I know which response I'd choose in hiring!   Missing such critical piece (early) - rarely (i.e. never) ends well...