Skip to content

Instantly share code, notes, and snippets.

@furkantektas
Last active August 29, 2015 14:01
Show Gist options
  • Save furkantektas/e1ed65ffd13d6d74bdaa to your computer and use it in GitHub Desktop.
Save furkantektas/e1ed65ffd13d6d74bdaa to your computer and use it in GitHub Desktop.
HCS12 Garage Simulation Project
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include <stdio.h> /* derivative-specific definitions */
#include <stdlib.h>
#include "lcd.h"
#pragma CODE_SEG __NEAR_SEG NON_BANKED
// ASM
#define enable_intr() __asm(cli)
#define disable_intr() __asm(sei)
// INTERRUPTS
#define INTERRUPT_RTI interrupt(((0x10000-Vrti)/2)-1)
#define INTERRUPT_TIMOVF interrupt(((0x10000-Vtimovf)/2)-1)
#define INTERRUPT_TIMCH1 interrupt (((0x10000 - Vtimch1)/2)-1)
#define INTERRUPT_TIMCH2 interrupt (((0x10000 - Vtimch2)/2)-1)
#define INTERRUPT_TIMCH4 interrupt (((0x10000 - Vtimch4)/2)-1)
// #define INTERRUPT_BUZ interrupt (((0x10000 - Vtimch5)/2)-1)
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
#define KEYA 10
#define KEYB 11
#define KEYC 12
#define KEYD 13
#define KEYASTERISK 14
#define KEYSHARP 15
// KEYPAD
#define ROW_NUM 4
#define COL_NUM 4
#define TRUE 1
#define FALSE 0
#define MIN 1
#define SEC 0
#define NOTAKEY -1
#define BUZZERSEC 1
#define TIMOVFPERSEC 11
#define RTIOVFPERSEC 25
#define TIMERRESOLUTION 40
#define SENSORDISTANCE 143500
#define MAXSPEED 60
#define NOTINITIALIZED -1
#define MSGHIGHSPEED "HIGH SPEED!"
#define MSGGARAGEFULLERROR "GARAGE FULL!"
#define MSGGARAGEEMPTYERROR "GARAGE EMPTY!"
#define GARAGECAPACITY 5
#define LCDWIDTH 16
#define MAINMENUCOUNT 2
volatile const char menu[MAINMENUCOUNT][LCDWIDTH] = {
"GARAGE",
"CLOCK & AVG"
};
typedef enum direction_e{
IN,
OUT,
NODIRECTION
} direction;
typedef enum screenModes_e{
MODEGARAGE,
MODECLOCK,
MODEHIGHSPEED,
MODEMAINMENU,
MODEGARAGEFULL,
MODEGARAGEEMPTY,
} screenModes;
const int MAXINT = (unsigned int) -1;
// Global Variables
// Time variables
volatile unsigned int rtiCount = 0,
timerCount = 0,
timer1Val = NOTINITIALIZED,
timer2Val = NOTINITIALIZED;
volatile int remainingTime = -1;
volatile short gMenuSelection = 0,
gGaraceCount = 0,
gTotalGaraceInCount = 0,
gTotalGaraceOutCount = 0;
short gLastSpeed = 0.0;
direction gLastDirection = '-';
screenModes gMode = MODEMAINMENU, oldGMode = MODEMAINMENU;
// boolean variables
volatile short refreshLCD = TRUE,
autoRefreshLCD = FALSE,
wasHighSpeed = FALSE;
direction getDirection();
char getLastDirectionChar();
// Speed Functions
short getSpeed() {
int timeInterval = abs(timer1Val-timer2Val);
if(timer1Val == NOTINITIALIZED || timer2Val == NOTINITIALIZED)
return NOTINITIALIZED;
if(timeInterval < 0)
timeInterval *= -1;
else if(timeInterval == 0)
return MAXINT;
return (SENSORDISTANCE/(timeInterval* RTIOVFPERSEC * TIMERRESOLUTION));
}
short isHighSpeed() {
short speed = getSpeed();
if(speed == NOTINITIALIZED)
return FALSE;
if(speed == MAXINT)
return TRUE;
return (speed > MAXSPEED);
}
void resetTimers() {
gLastSpeed = getSpeed();
wasHighSpeed = isHighSpeed();
gLastDirection = getLastDirectionChar();
timer1Val = NOTINITIALIZED;
timer2Val = NOTINITIALIZED;
}
direction getDirection() {
// if timer1 and timer2 does not initialized or equal, no direction is captured
if(timer1Val == timer2Val || timer1Val == NOTINITIALIZED || timer2Val == NOTINITIALIZED)
return NODIRECTION;
return (timer1Val > timer2Val);
}
void PlaySound(void);
// Keypad Functions
int ReadKey(void);
void disableTimerIntr(void) {
TIOS = TIOS | BIT5; /* Configure PT5 as Output */
/* Compare */
TCTL2 = (TCTL2 | BIT2) & ~BIT3; /* Set up PT5 */
/* to toggle on compare */
TFLG1 = 0x00; /* Clear Channel 5 flag */
TSCR2 = TSCR2 | BIT7;
}
//Interrupts
INTERRUPT_RTI void intrRti(void);
INTERRUPT_TIMCH1 void intrTimCh1(void);
INTERRUPT_TIMCH2 void intrTimCh2(void);
INTERRUPT_TIMCH4 void intrTimCh4(void);
INTERRUPT_TIMOVF void intrTimovf(void);
// INTERRUPT_BUZ void SoundBuzzer(void);
void init(void);
void printMenu(void);
void enableBuzzer(void) {
PTT = PTT | BIT5;
}
void toggleBuzzer(void) {
PTT = PTT ^ BIT5;
}
void disableBuzzer(void) {
PTT = PTT & ~BIT5;
}
short isGarageFull() {
return gGaraceCount >= GARAGECAPACITY;
}
short isGarageEmpty() {
return gGaraceCount <= 0;
}
void main(void) {
int key = NOTAKEY;
direction d = NODIRECTION;
// Initializing RTI, LCD and Keypad
init();
for(;;) {
do {
d = getDirection();
if(d == IN) {
if(!isGarageFull()) {
gGaraceCount += 1;
gTotalGaraceInCount += 1;
}
}
else if(d == OUT) {
if(!isGarageEmpty()) {
gGaraceCount -= 1;
gTotalGaraceOutCount += 1;
}
}
if(wasHighSpeed) {
oldGMode = (gMode == MODEHIGHSPEED) ? oldGMode : gMode; // backing up the current mode
gMode = MODEHIGHSPEED;
PlaySound();
refreshLCD = TRUE;
}
if(d == IN && isGarageFull()) {
oldGMode = (gMode == MODEGARAGEFULL) ? oldGMode : gMode; // backing up the current mode
gMode = MODEGARAGEFULL;
PlaySound();
refreshLCD = TRUE;
}
if(d == OUT && isGarageEmpty()) {
oldGMode = (gMode == MODEGARAGEEMPTY) ? oldGMode : gMode; // backing up the current mode
gMode = MODEGARAGEEMPTY;
PlaySound();
refreshLCD = TRUE;
}
if(d != NODIRECTION) {
resetTimers();
refreshLCD = TRUE;
}
// if(!(rtiCount%RTIOVFPERSEC))
printMenu();
// if(!(rtiCount%5000))
// resetTimers();
//refreshLCD = TRUE;
} while((key=ReadKey()) == NOTAKEY);
switch(key) {
case KEYA: // up
gMenuSelection = (gMenuSelection-1+MAINMENUCOUNT)%MAINMENUCOUNT;
break;
case KEYB: // down
gMenuSelection = (gMenuSelection+1+MAINMENUCOUNT)%MAINMENUCOUNT;
break;
case KEYD: // return
gMode = ((gMenuSelection+MAINMENUCOUNT)%MAINMENUCOUNT);
break;
case KEYASTERISK: // escape
gMode = MODEMAINMENU;
break;
}
if(key == KEYA || key == KEYB || key == KEYD || key == KEYASTERISK)
refreshLCD = TRUE;
else
refreshLCD = (!(rtiCount % RTIOVFPERSEC));
//refresh lcd at least on each second
_FEED_COP();
} /* loop forever */
/* please make sure that you never leave main */
}
/* Initializing hw for the program */
void init() {
DisableInterrupts;
/* Enabling keypad */
DDRA = 0x0F; /* PORTA[0-3] is out, PORTA[4-7] input */
DDRT = DDRT | BIT5; /* PORTT as output for PT5 buzzer */
DDRB = 0xFF; /* Set PortB as out */
DDRP = 0x00; /* Disabling 7segment */
PTP = 0x00;
PORTB = 0x00;
/* Enabling RTI */
RTICTL = 0x64; /* Set rate to 20.48 ms */
CRGINT = BIT7; /* Enable RTI interrupts */
CRGFLG = BIT7; /* Clear RTI Flag */
/* Setup for IC1 */
TIOS = TIOS & ~BIT1; /* Configure PT1 as IC */
TCTL4 = (TCTL4 | BIT3) & ~BIT2; /* Capture Rising Edge */
TIE |= BIT1; /* Enable IC1 Interrupt */
TFLG1 = BIT1; /* Clear IC1 Flag */
/* Setup for IC2 */
TIOS = TIOS & ~BIT2; /* Configure PT2 as IC */
TCTL4 = (TCTL4 | BIT5) & ~BIT4; /* Capture Rising Edge */
TIE |= BIT2; /* Enable IC2 Interrupt */
TFLG1 = BIT2; /* Clear IC2 Flag */
/* Setup for OC5 */
TIOS |= BIT4; /* Configure PT5 as OC */
TCTL1 = (TCTL1 | BIT1) & ~BIT2; /* Capture Rising Edge */
TIE |= BIT4; /* Enable oC5 Interrupt */
TFLG1 = BIT4; /* Clear OC5 Flag */
/* Turn on timer subsystem */
TSCR1 = BIT7;
/* Set prescaler to 32 (87.38 ms), enable TOF interrupt */
TSCR2 = 0x05;
TFLG2 = BIT7; /* Clearing overflow flag */
openlcd();
EnableInterrupts;
}
// Gets pressed key number from keypad
// Waits for any key to pressed otherwise won't return.
int ReadKey() {
int row,
column;
const char row_mask[ROW_NUM] = { 0xFE,0xFD,0xFB,0xF7 };
const char col_mask[COL_NUM] = { BIT4,BIT5,BIT6,BIT7 };
const unsigned int keys[ROW_NUM][COL_NUM] =
{ 1,2,3,10,
4,5,6,11,
7,8,9,12,
14,0,15,13 };
for(row=0 ; row < ROW_NUM ; ++row) {
PORTA = 0xFF;// Reset PortA
for(column=0; column < COL_NUM ;++column) {
PORTA = PORTA & row_mask[row]; // Set specific row to 0
if( (PORTA & col_mask[column]) == 0 ) {
// Check if any key is pressed
delay_1ms(10);
// Wait 50ms and check again for make sure key is pressed.
if( (PORTA & col_mask[column]) == 0 ) {
refreshLCD = TRUE;
return keys[row][column];
}
}
}
}
return NOTAKEY;
}
INTERRUPT_RTI void intrRti(void) {
++rtiCount;
CRGFLG = BIT7;
}
// INTERRUPT_TIMOVF void intrTimovf(void) {
// ++timerCount;
// if(!(--remainingTime)) {
// disableBuzzer();
// disableTimerIntr();
// }
// TFLG2 = BIT7;
// }
INTERRUPT_TIMCH1 void intrTimCh1(void) {
PORTB ^= BIT5;
timer1Val = rtiCount;
TFLG1 |= BIT1;
refreshLCD = TRUE;
}
INTERRUPT_TIMCH2 void intrTimCh2(void) {
PORTB ^= BIT3;
timer2Val = rtiCount;
TFLG1 |= BIT2;
refreshLCD = TRUE;
}
INTERRUPT_TIMCH4 void intrTimCh4(void) {
if(remainingTime >= 0) {
--remainingTime;
toggleBuzzer();
}
// using different frequency for highspeed warning
TC4 += (gMode == MODEHIGHSPEED) ? 750 : 1250;
TFLG1 |= BIT4;
}
char direction2Char(direction d) {
if(d == NODIRECTION)
return '-';
return getDirection() ? '<' : '>';
}
char getDirectionChar() {
return direction2Char(getDirection());
}
char getLastDirectionChar() {
return direction2Char(gLastDirection);
}
void printLCD(char* txt) {
clearDisplay();
while (*txt) { /* While character to send */
if(*txt == '\n')
moveCursorToSecondLine();
else
put2lcd(*txt,DATA); /* Write data to LCD */
++txt; /* Go to next character */
}
}
/* Time functions
Returns the time since program start */
int getSec() {
return (rtiCount/RTIOVFPERSEC)%60;
}
int getMin() {
return (rtiCount/(RTIOVFPERSEC*60))%60;
}
int getHour() {
return (rtiCount/(RTIOVFPERSEC*60*60))%60;
}
int getTotalGarageInCount() {
return gTotalGaraceInCount/(getMin()+getHour()*60);
}
int getTotalGarageOutCount() {
return gTotalGaraceOutCount/(getMin()+getHour()*60);
}
void printClockMenu(char* txt) {
autoRefreshLCD = TRUE;
sprintf(txt," %02d:%02d:%02d\nAVG IN:%d OUT:%d",getHour(),getMin(),getSec(),getTotalGarageInCount(),getTotalGarageOutCount());
}
void showMainMenu(char* txt) {
autoRefreshLCD = FALSE;
sprintf(txt,"%d",ReadKey());
}
void printMainMenu(char* txt) {
/* FIXING MODULO BUG */
int a = (gMenuSelection+MAINMENUCOUNT)%MAINMENUCOUNT,
b = (gMenuSelection+1+MAINMENUCOUNT)%MAINMENUCOUNT;
autoRefreshLCD = FALSE;
sprintf(txt,">%s\n %s",menu[a],menu[b]);
}
void printGarageMenu(char* txt) {
sprintf(txt,"IN=%d DIR:%c\nSPEED = %d",gGaraceCount,gLastDirection,gLastSpeed);
}
void printHighSpeedMenu(char* txt) {
sprintf(txt,"%s\nrt=%d",MSGHIGHSPEED, remainingTime);
autoRefreshLCD = TRUE;
if(remainingTime <= 0) {
gMode = ((oldGMode == MODEHIGHSPEED) ? MODEMAINMENU : oldGMode);
refreshLCD = TRUE;
}
}
void printError(char* txt, char *msg, screenModes s) {
sprintf(txt,"%s\n",msg);
autoRefreshLCD = TRUE;
if(remainingTime <= 0) {
gMode = ((oldGMode == s) ? MODEMAINMENU : oldGMode);
refreshLCD = TRUE;
}
}
void printMenu(void) {
char txt[34]; //1 for \n
if(refreshLCD) {
switch(gMode) {
case MODECLOCK:
printClockMenu(txt);
break;
case MODEHIGHSPEED:
//printHighSpeedMenu(txt);
wasHighSpeed = wasHighSpeed ? FALSE : wasHighSpeed;
printError(txt,MSGHIGHSPEED,MODEHIGHSPEED);
break;
case MODEGARAGE:
printGarageMenu(txt);
break;
case MODEGARAGEFULL:
printError(txt,MSGGARAGEFULLERROR,MODEGARAGEFULL);
break;
case MODEGARAGEEMPTY:
printError(txt,MSGGARAGEEMPTYERROR,MODEGARAGEEMPTY);
break;
case MODEMAINMENU:
default:
printMainMenu(txt);
break;
}
printLCD(txt);
}
// refreshing LCD twice per second if autoRefreshLCD is enabled
refreshLCD = (autoRefreshLCD && !(rtiCount % (RTIOVFPERSEC/2)));
}
void PlaySound(void) {
remainingTime = BUZZERSEC * TIMOVFPERSEC * TIMERRESOLUTION;
autoRefreshLCD = TRUE;
}
#ifndef LCD_H_
#define LCD_H_
/* Dragon12 Development Board LCD */
#define LCD_DAT PORTK /* Port K drives LCD data pins, E, and RS */
#define LCD_DIR DDRK /* Direction of LCD port */
#define LCD_E 0x02 /* LCD E signal */
#define LCD_RS 0x01 /* LCD Register Select signal */
#define CMD 0 /* Command type for put2lcd */
#define DATA 1 /* Data type for put2lcd */
/* Prototypes for functions in lcd.c */
void openlcd(void); /* Initialize LCD display */
void put2lcd(char c, char type); /* Write command or data to LCD controller */
void puts2lcd (char *ptr); /* Write a string to the LCD display */
void delay_50us(int n); /* Delay n 50 microsecond intervals */
void delay_1ms(int n); /* Delay n 1 millisecond intervals */
void clearDisplay(void);
void moveCursorToSecondLine(void);
void openlcd(void) {
LCD_DIR = 0xFF; /* configure LCD_DAT port for output */
delay_1ms(50); /* Wait for LCD to be ready */
put2lcd(0x28,CMD); /* set 4-bit data, 2-line display, 5x7 font */
put2lcd(0x0F,CMD); /* turn on display, cursor, blinking */
put2lcd(0x06,CMD); /* move cursor right */
put2lcd(0x01,CMD); /* clear screen, move cursor to home */
delay_1ms(1); /* wait until "clear display" command is complete */
}
void puts2lcd (char *ptr) {
while (*ptr) { /* While character to send */
put2lcd(*ptr,DATA); /* Write data to LCD */
delay_50us(1); /* Wait for data to be written */
ptr++; /* Go to next character */
}
}
void put2lcd(char c, char type) {
char c_lo, c_hi;
c_hi = (c & 0xF0) >> 2; /* Upper 4 bits of c */
c_lo = (c & 0x0F) << 2; /* Lower 4 bits of c */
if (type == DATA) LCD_DAT |= LCD_RS; /* select LCD data register */
else LCD_DAT &= (~LCD_RS); /* select LCD command register */
if (type == DATA)
LCD_DAT = c_hi|LCD_E|LCD_RS; /* output upper 4 bits, E, RS high */
else
LCD_DAT = c_hi|LCD_E; /* output upper 4 bits, E, RS low */
LCD_DAT |= LCD_E; /* pull E signal to high */
__asm(nop); /* Lengthen E */
__asm(nop);
__asm(nop);
LCD_DAT &= (~LCD_E); /* pull E to low */
if (type == DATA)
LCD_DAT = c_lo|LCD_E|LCD_RS; /* output lower 4 bits, E, RS high */
else
LCD_DAT = c_lo|LCD_E; /* output lower 4 bits, E, RS low */
LCD_DAT |= LCD_E; /* pull E to high */
__asm(nop); /* Lengthen E */
__asm(nop);
__asm(nop);
LCD_DAT &= (~LCD_E); /* pull E to low */
delay_50us(1); /* Wait for command to execute */
}
#define D50US 133 /* Inner loop takes 9 cycles; need 50x24 = 1200 cycles */
void delay_50us(int n) {
volatile int c;
for (;n>0;n--)
for (c=D50US;c>0;c--) ;
}
#define D10US 26
void delay_10us(int n) {
volatile int c;
for (;n>0;n--)
for (c=D10US;c>0;c--) ;
}
void delay_1ms(int n) {
for (;n>0;n--) delay_50us(200);
}
void delay_halfms(int n) {
for (;n>0;n--) delay_50us(100);
}
void clearDisplay(void) {
put2lcd(0x01,CMD); /* clear screen, move cursor to home */
delay_50us(40); /* wait until "clear display" command is complete */
}
void moveCursorToSecondLine(void) {
put2lcd(0xC0,CMD);
delay_50us(40); /* wait until "clear display" command is complete */
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment