#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++;
}
/*-----------------------------------------------------------*/