Venus AlemanjiSurina LivingstonJoseph GioiaPeter RieraDaniel JoshuaAlexis Nicolas
Published

Impress the Button

A game that teaches children how to count

Beginner1 hour446
Impress the Button

Things used in this project

Hardware components

EK-TM4C123GXL TM4C Tiva LaunchPad
Texas Instruments EK-TM4C123GXL TM4C Tiva LaunchPad
×1
Seeed Studio Sidekick Basic Kit for TI Launchpad
×1
Tilt Switch, SPST
Tilt Switch, SPST
×1
LED (generic)
LED (generic)
×2
7 Segment LED Display, Mechanically Rugged
7 Segment LED Display, Mechanically Rugged
×1
Resistor 100 ohm
Resistor 100 ohm
×1
Jumper wires (generic)
Jumper wires (generic)
×10

Software apps and online services

Windows 10
Microsoft Windows 10
Code Composer Studio
Texas Instruments Code Composer Studio

Story

Read more

Schematics

ImPress the Button TI Launchpad Schematics

Code

main.c

C Header File
Contains most of the code, including the main function that runs on startup.
#include "helpers.h"
#include <time.h>
#include <stdlib.h>

// current_number is the number of times the player should hit the button
int current_number = 0;

void change_segment_display(int number){

    //Defines pins and ports the segments of the 7-segment display are connected to
    unsigned int volatile *pGPIODATAPortA = (unsigned int *) (PortA + GPIODATA);
    unsigned int volatile *pGPIODATAPortC = (unsigned int *) (PortC + GPIODATA);
    unsigned int volatile *pGPIODATAPortE = (unsigned int *) (PortE + GPIODATA);
    unsigned int volatile a = pin1;
    unsigned int volatile b = pin2;
    unsigned int volatile c = pin3;
    unsigned int volatile d = pin2;
    unsigned int volatile e = pin4;
    unsigned int volatile f = pin5;
    unsigned int volatile g = pin6;

    //clear display
    *pGPIODATAPortE |= a;
    *pGPIODATAPortE |= b;
    *pGPIODATAPortE |= c;
    *pGPIODATAPortA |= d;
    *pGPIODATAPortC |= e;
    *pGPIODATAPortC |= f;
    *pGPIODATAPortC |= g;

    //display number
    if(number == 1){
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
    }else if(number == 2){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~e;
        *pGPIODATAPortC &= ~g;
    }else if(number == 3){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~g;
    }else if(number == 4){
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortC &= ~f;
        *pGPIODATAPortC &= ~g;
    }else if(number == 5){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~f;
        *pGPIODATAPortC &= ~g;
    }else if(number == 6){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~e;
        *pGPIODATAPortC &= ~f;
        *pGPIODATAPortC &= ~g;
    }else if(number == 7){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
    }else if(number == 8){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~e;
        *pGPIODATAPortC &= ~f;
        *pGPIODATAPortC &= ~g;
    }else if(number == 9){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortC &= ~f;
        *pGPIODATAPortC &= ~g;
    }else if(number == 0){
        *pGPIODATAPortE &= ~a;
        *pGPIODATAPortE &= ~b;
        *pGPIODATAPortE &= ~c;
        *pGPIODATAPortA &= ~d;
        *pGPIODATAPortC &= ~e;
        *pGPIODATAPortC &= ~f;
    }

}

void button_press(){
    // Register to turn on and off the LEDs
    unsigned int volatile *pGPIODATA = (unsigned int *) (PortA + GPIODATA);

    // Turn off the leds
    *pGPIODATA &= ~pin3;
    *pGPIODATA &= ~pin4;

    // Based on what the current number is, change the number and turn on the correct LED
    if(current_number > 1){
        // Turn on red LED and decrement current_number by 1
        *pGPIODATA |= pin4;
        current_number--;
    }else if(current_number == 1){
        // Turn on green LED and decrement current_number by 1
        *pGPIODATA |= pin3;
        current_number--;
    }else{
        // Turn on red LED, set current_number to a new random number from 1-10 and display current_number
        *pGPIODATA |= pin4;
        current_number = rand() % 9 + 1;
        change_segment_display(current_number);
    }

    // Wait to prevent debounce
    int i=0;
    while(i<300000){
        i++;
    }

}

int main(void)
{
    // Set up ports that we need to use
    SetupDigitalGPIO(PortF, pin0, INPUT, NoINTERRUPT); // Button
    SetupDigitalGPIO(PortE, pin1, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment A
    SetupDigitalGPIO(PortE, pin2, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment B
    SetupDigitalGPIO(PortE, pin3, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment C
    SetupDigitalGPIO(PortA, pin2, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment D
    SetupDigitalGPIO(PortC, pin4, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment A
    SetupDigitalGPIO(PortC, pin5, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment A
    SetupDigitalGPIO(PortC, pin6, OUTPUT, NoINTERRUPT); // 7-Segment Display, segment A
    SetupDigitalGPIO(PortA, pin4, OUTPUT, NoINTERRUPT); // Red LED
    SetupDigitalGPIO(PortA, pin3, OUTPUT, NoINTERRUPT); // Green LED

    // Set priority
    NVIC_PRI7_R = (NVIC_PRI7_R&0xFF00FFFF)|0x00A00000; // priority 5

    //Enable
    //   For this register, each bit corresponds to a different interrupt
    //   that can be enabled.
    //   For interrupt 1, you'd need a 1 in bit position 1.
    NVIC_EN0_R |= 0x40000000;

    // Registers to turn on and off the LEDs and detect a button press
    unsigned int volatile *pGPIODATAPortF = (unsigned int *) (PortF + GPIODATA);
    unsigned int volatile *pGPIODATAPortA = (unsigned int *) (PortA + GPIODATA);

    // Start with red LED on because player hasn't won yet
    *pGPIODATAPortA |= pin4;

    // Set current_number to a new random number from 1-10 and display current_number
    current_number = rand() % 9 + 1;
    change_segment_display(current_number);

    // Define the current position of the button as off
    int switch_position = *pGPIODATAPortF & pin0;
    int prev_position = switch_position;
    int on = 0;
    while (1)
    {
        // Find the current position of the button
        switch_position = *pGPIODATAPortF & pin0;

        // If the position of the button has changed to be on, run the button_press function
        if(switch_position!=prev_position){
            if(on == 0){
                on = 1;
                button_press();
            }else{
                on = 0;
            }
        }

        // Define the previous position of the button to be what the current position is now
        prev_position = switch_position;
    }
}

helpers.h

C Header File
File that implements standard functions and definitions for using GPIO ports.
/*
 * helpers.h
 *
 *  Created on: Mar 15, 2018
 *      Author: Chance Tarver
 */

#ifndef HELPERS_H_
#define HELPERS_H_


// Base addresses of each port
#define PortA       0x40004000
#define PortB       0x40058000
#define PortC       0x40006000
#define PortD       0x40007000
#define PortE       0x40024000
#define PortF       0x40025000

//  General-Purpose Input/Output Run Mode Clock Gating Control. Each bit corresponds to a Port.
#define RCGCGPIO    0x400FE608
#define ClocksA     0x01
#define ClocksB     0x02
#define ClocksC     0x04
#define ClocksD     0x08
#define ClocksE     0x10
#define ClocksF     0x20

// Define the bitmask for each pin
#define pin0     0x01
#define pin1     0x02
#define pin2     0x04
#define pin3     0x08
#define pin4     0x10
#define pin5     0x20
#define pin6     0x40

//Other defines for code readability
#define OUTPUT  1
#define INPUT   0
#define INTERRUPT    1
#define NoINTERRUPT  0

// Offsets corresponding to registers we may need to configure
#define GPIODATA    0x3FC   // pg662 : GPIO Data // Why isn't this 0x000
#define GPIODIR     0x400   // pg663 : GPIO Direction
#define GPIOIS      0x404   // pg664 : GPIO Interrupt Sense
#define GPIOIBE     0x408   // pg665 : GPIO Interrupt Both Edges
#define GPIOIEV     0x40C   // pg666 : GPIO Interrupt Event     -   0: falling edge or Low level is trigger.    1: rising edge or High level is trigger
#define GPIOIM      0x410   // pg667 : GPIO Interrupt Mask      -   0: the pin is masked.                       1: the interrupt is sent to the controller
#define GPIOICR     0x41C   // pg670 : GPIO Interrupt Clear     -   0: no affect                                1: the corresponding interrupt is cleared
#define GPIOAFSEL   0x420   // pg671 : GPIO Alternative Function Select - 0: pin functions as GPIO              1: Function as something else depending on port
#define GPIOPUR     0x510   // pg677 : GPIO Pull-Up Select      -   0: turn off pull up resistor                1: turn on pull up for corresponding pin
#define GPIOPDR     0x514   // pg679 : GPIO Pull-Down Select    -   0: turn off pull down resistor              1: turn on pull down for corresponding pin
#define GPIODEN     0x51C   // pg682 : GPIO Digital Enable      -   0: disable digital functions                1: enable pin's digital functions
#define GPIOLOCK    0x520   // pg684 : GPIO Lock. A write of the value 0x4C4F.434B unlocks the GPIO Commit (GPIOCR) register for write access.
#define GPIOKEY     0x4C4F434B // pg684. Special key for the GPIOLOCK register
#define GPIOCR      0x524   // pg685 : GPIO Commit              -   0: Corresponding GPIOAFSEL, GPIOPUR, GPIOPDR, or GPIODEN bits cannot be written. 1: They can

#define NVIC_EN0_R              (*((volatile unsigned long *)0xE000E100))  // pg142 IRQ 0 to 31 Set Enable Register

#define NVIC_PRI0_R             (*((volatile unsigned long *)0xE000E41C))  // pg152 IRQ 0 to 3 Priority Register
#define NVIC_PRI7_R             (*((volatile unsigned long *)0xE000E41C))  // pg152 IRQ 28 to 31 Priority Register  pg 104 has interrupt assignments. GPIO Port F is Interrupt #30. Bits 23:21

void WaitForInterrupt(void);  // low power mode

void SetupDigitalGPIO(unsigned int port, unsigned int pinMask, int direction,
                        int useInterrupts)
{
    /*Function for setting up a digital GPIO Pin

     This function will do all the register configs for a give port and pin.

     Examples
     -------
     SetupOnDigitalGPIO(PortF, pin3, INPUT, INTERRUPT) // Set up an input with interrupts on PF3.
     SetupOnDigitalGPIO(PortE, pin4, OUTPUT, NoINTERRUPT) // Set up an output with no interrupts on PE4.
     Notes
     -----
     We assume a pullup resistor.
     We also assume an edge based trigger.
     It is best the header with the #defines for each port and pin are included.

     Inputs
     ------
     (*((volatile unsigned long *) port  - Base address of the port being used.
     (*((volatile unsigned long *) pin   - Bit mask of the pin being used
     int direction - Boolean flag for direction of the pin. 1 = Output. 0 = input
     int UseInterrupts - Boolean flag to use interrupts. 1 = use them. 0 = don't
     */

    //Define the generic pointers
    unsigned int volatile *pRCGCGPIO = (unsigned int *) RCGCGPIO;
    unsigned int volatile *pGPIOLOCK = (unsigned int *) (port + GPIOLOCK);
    unsigned int volatile *pGPIOCR = (unsigned int *) (port + GPIOCR);
    unsigned int volatile *pGPIODIR = (unsigned int *) (port + GPIODIR);
    unsigned int volatile *pGPIOAFSEL = (unsigned int *) (port + GPIOAFSEL);
    unsigned int volatile *pGPIOPUR = (unsigned int *) (port + GPIOPUR);
    unsigned int volatile *pGPIODEN = (unsigned int *) (port + GPIODEN);
    unsigned int volatile *pGPIODATA = (unsigned int *) (port + GPIODATA);

    // Define the pointers for interrupt configuration
    unsigned int volatile *pGPIOIS = (unsigned int *) (port + GPIOIS);
    unsigned int volatile *pGPIOIBE = (unsigned int *) (port + GPIOIBE);
    unsigned int volatile *pGPIOIEV = (unsigned int *) (port + GPIOIEV);
    unsigned int volatile *pGPIOIM = (unsigned int *) (port + GPIOIM);
    unsigned int volatile *pGPIOICR = (unsigned int *) (port + GPIOICR);

    // activate the clocks for the port
    int clocks;
    switch ((int) port)
    {
    case PortA:
        clocks = ClocksA;
        break;
    case PortB:
        clocks = ClocksB;
        break;
    case PortC:
        clocks = ClocksC;
        break;
    case PortD:
        clocks = ClocksD;
        break;
    case PortE:
        clocks = ClocksE;
        break;
    case PortF:
        clocks = ClocksF;
        break;
    default:
        clocks = ClocksF; //ERROR. TODO: Add an exception to handle this. Send to Error ISR or something
    }

    *pRCGCGPIO |= clocks;
    while ((*pRCGCGPIO & clocks) == 0)
        ;

    *pGPIOLOCK = GPIOKEY;
    *pGPIOCR |= pinMask;
    if (direction == 0)
    {
        *pGPIODIR &= ~pinMask;
        *pGPIOPUR |= pinMask;
    }
    else if (direction == 1)
    {
        *pGPIODIR |= pinMask;
    }
    else
    {
        *pGPIODIR |= pinMask; // TODO. Addd an exception to handle this.
    }

    *pGPIOAFSEL &= ~pinMask;
    *pGPIODEN |= pinMask;

    if (useInterrupts)
    {
        *pGPIOIS &= ~pinMask;  // Edge-sensitive (default setting)
        *pGPIOIBE &= ~pinMask;  // Not both edges (default setting)
        *pGPIOIEV &= ~pinMask;  // Falling edge event (default setting)
        *pGPIOICR |= pinMask;   // clear flag
        *pGPIOIM |= pinMask;   // enable interrupt. Unmask it
    }
}


void WaitForInterrupt(void)
{
    __asm ("    WFI\n"
            "    BX     LR\n");
}


#endif /* HELPERS_H_ */

Credits

Venus Alemanji
1 project • 0 followers
Contact
Surina Livingston
1 project • 0 followers
Contact
Joseph Gioia
1 project • 0 followers
Contact
Peter Riera
1 project • 0 followers
Contact
Daniel Joshua
1 project • 0 followers
Contact
Alexis Nicolas
1 project • 0 followers
Contact

Comments

Please log in or sign up to comment.