I am currently working on a real time operating system(freertos) task,

there are 3 tasks here and the problem im having is with the 1st task. it is basically to have 2 modes, toggled by a single button "RIGHT" (keys = ~PTH & BOTH). this has got to go basically from what it is now, to a mode that just displays "RESET" on the screen. it will toggle between these two modes by pressing the "RIGHT" button. please help in anyway you can!

#define _SCI

#include <stdio.h>

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"

/*-----------------------------------------------------------
    Definitions.
-----------------------------------------------------------*/

/* Priorities assigned to demo application tasks. */
#define mainCOM_PRIORITY1			( tskIDLE_PRIORITY + 1 )
#define mainCOM_PRIORITY2			( tskIDLE_PRIORITY + 2 )

/*-----------------------------------------------------------
    Local functions prototypes.
-----------------------------------------------------------*/
static portTASK_FUNCTION_PROTO( vCOMSendTask1, pvParameters );
static portTASK_FUNCTION_PROTO( vCOMSendTask2, pvParameters );

void main( void )
{
// Set up PORTB as output and turn all LEDs off
    DDRB = 0xFF;
    PORTB = 0xFF;
// Light the top (b7) LED
    PORTB &= ~bit(7);               /* Clear appropriate bit on port */
    
/* Create two comms tasks.*/
    xTaskCreate( vCOMSendTask1, (const signed portCHAR * const)"COM1", configMINIMAL_STACK_SIZE, NULL, mainCOM_PRIORITY1, NULL );
    xTaskCreate( vCOMSendTask2, (const signed portCHAR * const)"COM2", configMINIMAL_STACK_SIZE, NULL, mainCOM_PRIORITY2, NULL );
    
    /* The tasks have been created - start the scheduler. */
    vTaskStartScheduler();
    
    /* Should not reach here! */
    for( ;; );
}
/*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCOMSendTask1, pvParameters )
{
    portTickType xLastWakeTime;
 	portTickType xFlashRate = 1000 / portTICK_RATE_MS;  // Char rate in ms

    xLastWakeTime = xTaskGetTickCount();
    
    for(;;)
    {
        putchar('1');
        vTaskDelayUntil( &xLastWakeTime, xFlashRate );
    }
}
/*-----------------------------------------------------------*/
static portTASK_FUNCTION( vCOMSendTask2, pvParameters )
{
    portTickType xLastWakeTime;
 	portTickType xFlashRate = 1500 / portTICK_RATE_MS;  // Char rate in ms

    xLastWakeTime = xTaskGetTickCount();
    
    for(;;)
    {
        putchar('2');
        vTaskDelayUntil( &xLastWakeTime, xFlashRate );
    }
}

You set your outputs, but is the default for your ports set to input? If not, no key to read!


Also you talk about inputs but I see no code for it!

im soooo sorry, i put up the wrong program, here is the actual program im working on!

#define _SCI

#include <stdio.h>

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

/*-----------------------------------------------------------
    Definitions.
-----------------------------------------------------------*/

/* Priorities assigned to application tasks. */
#define Buttons_PRIORITY	( tskIDLE_PRIORITY + 1 )
#define Clock_PRIORITY	    ( tskIDLE_PRIORITY + 2 )
#define mainLED_PRIORITY	( tskIDLE_PRIORITY + 3 )
#define Osc_PRIORITY	    ( tskIDLE_PRIORITY + 4 )

void lcd_init(void);
void lcd_clear(void);
void lcd_putstr(char *);
void lcd_putxy(char, char, char *);

// LED number to flash
#define flashLED        6

// Define bit patterns for key values and buttons
#define LEFT	0x02    /* PT1/S3 button */
#define RIGHT	0x01    /* PT0/S2 button */
#define BOTH    (LEFT | RIGHT)  /* Mask for both keys */

// Number of timer interrupts to get 1ms
#define DELAY1ms    750

/*-----------------------------------------------------------
    Local functions prototypes.
-----------------------------------------------------------*/
static portTASK_FUNCTION_PROTO( vButtonsTask, pvParameters );
static portTASK_FUNCTION_PROTO( vClockTask, pvParameters );
static portTASK_FUNCTION_PROTO( vLEDflashTask, pvParameters );
static portTASK_FUNCTION_PROTO( vOscDispTask, pvParameters );

static void vSetupTimers(void);

/* Interrupt routimes */
static void  TimerCh4_ISR(void);
static void  TimerCh3_ISR(void);

static volatile unsigned int osc_ticks;    /* oscillator speed in ms */
static volatile unsigned int count1ms;     /* Incremented by TC3 1ms interrupt */

void main( void )
{
    // Set up PORTB as output and turn all LEDs off
    DDRB = 0xFF;
    PORTB = 0xFF;
    // Light the top (b7) LED
    PORTB &= ~bit(7);               /* Clear appropriate bit on port */

    // Set up timer interrupts etc
    vSetupTimers();

    lcd_init();
	lcd_clear();
    //                    1111111111
    //          01234567890123456789
	lcd_putstr("  Oscillator demo   ");

    /* Create the three tasks.*/
    xTaskCreate( vButtonsTask, (const signed portCHAR * const)"Btns",
        configMINIMAL_STACK_SIZE*4, NULL, Buttons_PRIORITY, NULL );
    xTaskCreate( vClockTask, (const signed portCHAR * const)"RTC",
        configMINIMAL_STACK_SIZE*4, NULL, Clock_PRIORITY, NULL );
    xTaskCreate( vOscDispTask, (const signed portCHAR * const)"RTC",
        configMINIMAL_STACK_SIZE*4, NULL, Osc_PRIORITY, NULL );
    
    /* Create task to flash LED 6 */
    xTaskCreate( vLEDflashTask, (const signed portCHAR * const)"LED",
        configMINIMAL_STACK_SIZE, NULL, mainLED_PRIORITY, NULL );

    /* The tasks have been created - start the scheduler. */
    vTaskStartScheduler();
    
    /* Should not reach here! */
    for( ;; );
}
/*-----------------------------------------------------------*/
// Task to read buttons from Port T
static portTASK_FUNCTION( vButtonsTask, pvParameters )
{
    portTickType xLastWakeTime;
    portTickType xPause = 50 / portTICK_RATE_MS;  // Pause in ms

    unsigned char   keys;

    xLastWakeTime = xTaskGetTickCount();
    
    DDRT &= ~BOTH;    // LS 2 bits of Port T inputs

    for(;;)
    {
        // 50ms pause
        vTaskDelayUntil( &xLastWakeTime, xPause );

        /* Check for keypad press */
    	keys = ~PTT & BOTH;

    	if ((keys & LEFT) == LEFT)
    	{
            lcd_putxy(1, 0, "Left");
    	}
        else
        {
            lcd_putxy(1, 0, "    ");
        }
    	if ((keys & RIGHT) == RIGHT)
    	{
            lcd_putxy(1, 15, "Right");
    	}
        else
        {
            lcd_putxy(1, 15, "     ");
        }
    }
}
/*-----------------------------------------------------------*/
// Task to display clock time

static portTASK_FUNCTION( vClockTask, pvParameters )
{
    portTickType xPause = 1000 / portTICK_RATE_MS;  // Pause in ms
    portTickType xLastWakeTime;

    char    time[10];               /* Formatted to show HH:MM:SS */
    unsigned char   hrs, min, sec;  /* Current time */

    xLastWakeTime = xTaskGetTickCount();

    hrs = 0;
    min = 0;
    sec = 0;

    for(;;)
    {
        /* Send time to LCD */
        sprintf(time, "%02u:%02u:%02u", hrs, min, sec);
        lcd_putxy(1, 5, time);
        vTaskDelayUntil( &xLastWakeTime, xPause );

       /* Update count of HH:MM:SS allowing for overflow */
       if (++sec == 60)
       {
           sec = 0;
           if (++min == 60)
           {
               min = 0;
               if (++hrs == 24)
               {
            	    hrs = 0;
               }
           }
       }
    }
}
/*-----------------------------------------------------------*/
// Displays oscillator values on LCD display
/*-----------------------------------------------------------*/
static portTASK_FUNCTION( vOscDispTask, pvParameters )
{
    unsigned int  ticks
    unsigned int  tocks;
    char    clock[20];
    portTickType xLastWakeTime;
    portTickType xWait = 250 / portTICK_RATE_MS;

    xLastWakeTime = xTaskGetTickCount();

    lcd_putxy(2, 0, "osc ticks :");
    lcd_putxy(3, 0, "count1ms  :");

    for (;;)
    {
        // Send oscillator values to LCD; exclusive access to global variable
        portENTER_CRITICAL();
        ticks = osc_ticks;
        tocks = count1ms;
        portEXIT_CRITICAL();

        sprintf(clock, "%05u", ticks);
        lcd_putxy(2, 12, clock);

        sprintf(clock, "%05u", tocks);
        lcd_putxy(3, 12, clock);

        vTaskDelayUntil( &xLastWakeTime, xWait );
    }
}
/*-----------------------------------------------------------*/
// Simple LED flashing task - confirms RTOS is operating
/*-----------------------------------------------------------*/
static portTASK_FUNCTION_PROTO( vLEDflashTask, pvParameters )
{
    portTickType xLastWakeTime;
    portTickType xFlashOn = 200 / portTICK_RATE_MS;
    portTickType xFlashOff = 800 / portTICK_RATE_MS;

    xLastWakeTime = xTaskGetTickCount();

    for(;;)
    {
        // Turn LED on
        portENTER_CRITICAL();
        PORTB &= ~bit(flashLED);
        portEXIT_CRITICAL();
        vTaskDelayUntil( &xLastWakeTime, xFlashOn );
        // and off again
        portENTER_CRITICAL();
        PORTB |= bit(flashLED);
        portEXIT_CRITICAL();
        vTaskDelayUntil( &xLastWakeTime, xFlashOff );
    }
}
/*-----------------------------------------------------------*/
// Setup routine for Timers 3 and 4
/*-----------------------------------------------------------*/
static void vSetupTimers(void)
{
    /* Timer channel 3 - 1ms interrupts */
	DBug12FNP->SetUserVector(UserTimerCh3, TimerCh3_ISR);
    /* Timer channel 4 - oscillator interrupts */
	DBug12FNP->SetUserVector(UserTimerCh4, TimerCh4_ISR);

    // Set up Timers 3 and 4
    TIOS |= bit(3);     /* Make channel 3 function as an output compare */
    TC3   = TCNT + DELAY1ms;
    TIE  |= bit(3);     /* Enable interrupt for Ch 3 */
    
    DDRT  &= ~bit(4);   // Bit 4 of Port T is an input
    TCTL3 |= bit(0);    /* Rising edge for interrupt on Ch 4 */
    TIE   |= bit(4);    /* Enable interrupts on Ch4 */
}
/*-----------------------------------------------------------*/
// Interrupt routines for Timers 4 and 3
/*-----------------------------------------------------------*/
#pragma interrupt_handler TimerCh4_ISR

/* Function to handle interrupts from input compare on TC4, which
 * is the oscillator clock. It simply uses the value
 * of 1ms ticks from the TC3 interrupt routine. The oscillator can
 * give times between edges of approx 8ms to 600ms.
 */
static void TimerCh4_ISR(void)
{
   	TFLG1 = bit(4);         /* Clear the IC4 flag */
   	osc_ticks = count1ms;   /* Get new count value */
   	count1ms = 0;           /* and reset it again */
}
/*-----------------------------------------------------------*/
#pragma interrupt_handler TimerCh3_ISR

/* This timer interrupt is used to generate a count of 1ms ticks */
static void TimerCh3_ISR(void)
{
	TC3 += DELAY1ms;	/* Calculate next target count */
	TFLG1 = bit(3);		/* Clear the OC3 flag */
	count1ms++;
}
/*-----------------------------------------------------------*/

Okay so now I'm confused. You have two independent switches left and right. Built in pull-ups so when you close the switch you shunt the pin to ground, thus causing a low input.
It appears to work this way but you have to hold the switch down to keep it on.

Are you looking for latching switch logic? So it edge triggers when you press (or release) it toggles state and when you press it again it toggles again?

Either way, you need a debounce circuit, or do you have a capacitor in your circuit to debounce for you so you don't have to do it in code?

a debounce is probably what is needed, as the result should happen when the button is released. I am using a (motorola/freescale) 68HC12 processor, the two buttons being used are pre built onto the board on which the processor is mounted. the buttons left and right have been preprogrammed so other than the latching effect, nothing needs to be done with them.

i just need it to be able to scroll/toggle through 2 modes, but whatever ive tried in the past just doesnt work (it doesnt pick up the change again or it wont stay in a while loop.

anything you think would bring it closer to those goals, epecially a latch or debounce effect in the code would be hugely appreciated

Your key delay is too short 50/1000 = 20/second
Should be around 200. Use a 5

You need edge triggering.

swLast = getbits

loop:
sw = getbits
swEdge = sw ^ swLast
swLast = sw;

So now, a button JUST down, or button JUST up will have their bit in swEdge set.

So for button down

So for button down
swD = swEdge & ~sw
if (swD & 1) then 1st button just pressed

if (swD & 2) then 2nd button just pressed


So for button up
swU = swEdge & sw
if (swU & 1) then 1st button just released

if (swU & 2) then 2nd button just released


So does that help?

Comments
nice job

a little,

do u mind explaining what i need to declare and what is C code.

things like swd and swEdge, are they things you just made up or actual code. also is ~sw the port that im reading the button presses on my program.

thank you for your help, this is kind of frustrating as im thinking the code ive been taught to use is slightly different.

also the latch i had been using was:

if(~PTH & RIGHT)
{
      while(~PTH & BOTH != 0)
      {
              //wait until button is released
       }
}

Edited 3 Years Ago by Reverend Jim: Fixed formatting

It would be inappropriate to write the code in C or assembly for you.
Waiting in a while loop for input on an embedded application is not a good thing to do.
I practically gave you the code in pseudo code!
Examine what I did on paper!

static char swLast = 0xFF;
char sw, swEdge, swUp, swD;

sw = PIT;    // Get 8-bits of input from Port P

You should already know how to read the following truth table...

A   B   ~B      A^ B    (A^B)&~B      (A^B)&B
0   0     1        0          0           0
0   1     0        1          0           1
1   0     1        1          1           0
1   1     0        0          0           0

... That was more information then I should be giving you!
STUDY the logic table. Using only one switch, A is the last switch state, B is the current switch state. In the pseudo code's case, it was processing up to 8 switches simultaneously on the conditional test was only looking at the first two!

This article has been dead for over six months. Start a new discussion instead.