Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Revise the code in “main.c” such that the program shows a running clock on the d

ID: 3888560 • Letter: R

Question

Revise the code in “main.c” such that the program shows a running clock on the display, with the following requirements:

1. The clock shows two digits of minutes to the left of the colon, and two digits of seconds to the right of the colon. The clock advances every second.

2. The colon (‘:’) flashes on and off every half second.

3. The user may push pushbutton SW1 to fast forward the minutes of the clock with wrap-around. Hint: You may use the pushbutton function in lab 1 as template.

4. The user may push pushbutton SW2 to fast forward the seconds of the block with wrap-around.

/*

* main.c

*

* Created on:

* Author:

*/

#include <stdint.h>

#include <stdbool.h>

#include <stdio.h>

#include <driverlib/sysctl.h>

#include <inc/hw_ints.h>

#include <inc/hw_memmap.h>

#include <inc/hw_i2c.h>

#include <driverlib/gpio.h>

#include <driverlib/pin_map.h>

#include <driverlib/i2c.h>

#include "launchpad.h"

#include "seg7.h"

// 7-segment coding table. See https://en.wikipedia.org/wiki/Seven-segment_display. The segments

// are named as A, B, C, D, E, F, G. In this coding table, segments A-G are mapped to bits 0-7.

// Bit 7 is not used in the coding. This display uses active high signal, in which '1' turns ON a

// segment, and '0' turns OFF a segment.

static uint8_t seg7Coding[10] = {

       0b00111111,        // digit 0

       0b00000110,        // digit 1

       0b01011011,           // digit 2

       0b01001111,           // digit 3

       0b01100110, // digit 4

       0b01101101, // digit 5

       0b01111101, // digit 6

       0b00000111, // digit 7

       0b01111111, // digit 8

       0b01101111, // digit 9

};

// The colon status: if colon == 0b10000000, then the colon is on,

// otherwise it is off.

static uint8_t colon = 0;

// Update the clock display

void

clockUpdate(uint32_t time)                               // pointer to a 4-byte array

{

   uint8_t code[4];                                   // The 7-segment code for the four clock digits

   // Display 01:23 on the 7-segment displays

   // The colon ':' will flash on and off every 0.5 seconds

   code[0] = seg7Coding[3] + colon;

   code[1] = seg7Coding[2] + colon;

   code[2] = seg7Coding[1] + colon;

   code[3] = seg7Coding[0] + colon;

   seg7Update(code);

   // Calculate the display digits and colon setting for the next update

   if (colon == 0b00000000) {

       colon = 0b10000000;

   }

   else {

       colon = 0b00000000;

   }

   // Call back after 1 second

   schdCallback(clockUpdate, time + 500);

}

int main(void)

{

   lpInit();

   seg7Init();

   uprintf("%s ", "Lab 2: Wall clock");

   // Schedule the first callback events for LED flashing and push button checking.

   // Those trigger callback chains. The time unit is millisecond.

   schdCallback(clockUpdate, 1000);

   // Loop forever

   while (true) {

       schdExecute();

   }

}

Explanation / Answer

main.c
--------------------------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <driverlib/sysctl.h>
#include <inc/hw_ints.h>
#include <inc/hw_memmap.h>
#include <inc/hw_i2c.h>
#include <driverlib/gpio.h>
#include <driverlib/pin_map.h>
#include <driverlib/i2c.h>
#include "launchpad.h"
#include "seg7.h"

// 7-segment coding table. The segments
// are named as A, B, C, D, E, F, G. In this coding table, segments A-G are mapped to bits 0-7.
// Bit 7 is not used in the coding. This display uses active high signal, in which '1' turns ON a
// segment, and '0' turns OFF a segment.
static uint8_t seg7Coding[10] = {
        0b00111111,        // digit 0
        0b00000110,        // digit 1
        0b01011011,           // digit 2
        0b01001111,           // digit 3
        0b01100110,         // digit 4
        0b01101101,         // digit 5
        0b01111101,         // digit 6
        0b00000111,         // digit 7
        0b01111111,         // digit 8
        0b01100111          // digit 9
        // MORE CODINGS
};

// The colon status: if colon == 0b10000000, then the colon is on,
// otherwise it is off.
static uint8_t colon = 0;

//these variables will hold the state for each digit of the display
static unsigned short seconds = 0;
static unsigned short tensOfSeconds = 0;
static unsigned short minutes = 0;
static unsigned short tensOfMinutes = 0;
//if updateSeconds == 1, we will increment the seconds digit.
static unsigned short updateSeconds = 0;


void handleDigitUpdate() {

    if(seconds >= 10) {
        seconds = 0;
        ++tensOfSeconds;
    }

    if(tensOfSeconds >= 6) {
        tensOfSeconds = 0;
        ++minutes;
    }

    if(minutes >= 10) {
        minutes = 0;
        ++tensOfMinutes;
    }

    if(tensOfMinutes >= 6) {
        tensOfMinutes = 0;
    }
}

// Update the clock display
void
clockUpdate(uint32_t time)                               // pointer to a 4-byte array
{
    uint8_t code[4];                                   // The 7-segment code for the four clock digits

    if(updateSeconds == 1) {
        ++seconds;
    }
    handleDigitUpdate();
    // Display a clock on the 7 digit display.
    // The colon ':' will flash on and off every 0.5 seconds
    code[0] = seg7Coding[seconds] + colon;
    code[1] = seg7Coding[tensOfSeconds] + colon;
    code[2] = seg7Coding[minutes] + colon;
    code[3] = seg7Coding[tensOfMinutes] + colon;
    seg7Update(code);

    // Calculate the display digits and colon setting for the next update
    if (colon == 0b00000000) {
        colon = 0b10000000;
    }
    else {
        colon = 0b00000000;
    }

    if (updateSeconds == 1) {
        updateSeconds = 0;
    }
    else {
        ++updateSeconds;
    }

    // Call back after 1/2 second
    schdCallback(clockUpdate, time + 500);
}

// Event driven code for checking push button
void
checkPushButton(uint32_t time)
{
    int code = pbRead();
    uint32_t delay;

    switch (code) {
        case 1:
            ++minutes;
            handleDigitUpdate();
            delay = 250;                           // Use an inertia for soft debouncing
            break;

        case 2:
            ++seconds;
            handleDigitUpdate();
            delay = 250;                           // Use an inertia for soft debouncing
            break;

        default:
            delay = 10;
    }

    schdCallback(checkPushButton, time + delay);
}

int main(void)
{
    lpInit();
    seg7Init();

    uprintf("%s ", "Lab 2: Wall clock");

    // Schedule the first callback events for LED flashing and push button checking.
    // Those trigger callback chains. The time unit is millisecond.
    schdCallback(clockUpdate, 1000);
    schdCallback(checkPushButton, 1005);

    // Loop forever
    while (true) {
        schdExecute();
    }
}
----------------------------------------------------------------------------------------------------
seg7.c
-------------------------------------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include <driverlib/sysctl.h>
#include <inc/hw_memmap.h>
#include <driverlib/gpio.h>
#include <driverlib/pin_map.h>
#include "launchpad.h"
#include "seg7.h"

// MCU connections to TiM1637's CLK and DIO pins. The default pin connections are as follows:
// MCU Pin     Grove Pin       TiM1637 Pin
//    PA6         J10 SCL         CLK
//    PA7         J10 SDA         DIO
// CHANGE THE MACROS if you use a different jumper of the Grove boosterpack.
#define PORT_PERIPH     SYSCTL_PERIPH_GPIOA // The peripheral def of Port A
#define PORT            GPIO_PORTF_BASE     // The base address of the I2C port
#define CLK             GPIO_PIN_2          // The 8-bit pin value (mask format) for clock
#define DIO             GPIO_PIN_3          // The 8-bit pin value (mask format) for data IO

// Signal timing of CLK and DIO
#define HALF_CCT        5                   // Half clock cycle is 5 milliseconds
#define DELTA           1                   // Time difference between CLK and DIO change, for tolerance

// Initialize the port connection to TiM1637 and the 7-segment display. TiM1637 is connected to
// the SCL and SDA pins of I2C #1, which are PA6 and PA7, respectively. However, TiM1637 is NOT I2C
// comptatible and thus we have to use PA6 and PA7 as GPIO pins (and use bit banging to emulate
// the START, STOP, and data bits of I2C).
void
seg7Init()
{
    // Enable GPIO Port B as peripheral.
    SysCtlPeripheralEnable(PORT_PERIPH);

    // Set the pads for standard push-pull operation, with 8ma strength
    GPIOPadConfigSet(PORT, CLK | DIO, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);

    // Make the pin be outputs
    GPIODirModeSet(PORT, CLK | DIO, GPIO_DIR_MODE_OUT);

    // Initial states are high
    GPIOPinWrite(PORT, CLK | DIO, CLK | DIO);
}

// Send START bit of I2C: Keep CLK high (inactive), pull DIO from high to low.
static void
tmSendStart()
{
    // Pull the CLK high for high CCT, and pull DIO high shortly after pulling CLK high
    GPIOPinWrite(PORT, CLK, CLK);
    waitUs(DELTA);
    GPIOPinWrite(PORT, DIO, DIO);
    waitUs(HALF_CCT - DELTA);

    // Pull the DIO low for half CCT
    GPIOPinWrite(PORT, DIO, 0);
    waitUs(HALF_CCT);
}

static void
tmSendDataBit(bool bit)
{
    // The DIO pin value to write
    uint8_t pinValue = bit ? DIO : 0;

    // Pull CLK low, wait for DELTA time, write data bit value, then wait for a time of
    // half CCT minus DELTA
    GPIOPinWrite(PORT, CLK, 0);
    waitUs(DELTA);
    GPIOPinWrite(PORT, DIO, pinValue);
    waitUs(HALF_CCT - DELTA);

    // Pull CLK high, wait for half CCT
    GPIOPinWrite(PORT, CLK, CLK);
    waitUs(HALF_CCT);
}

// Wait for ACK. The function does not really check for ACK, just wait for 1 CCT.
static void
tmWaitAck()
{
    // Pull CLK low
    GPIOPinWrite(PORT, CLK, 0);
    GPIODirModeSet(PORT, DIO, GPIO_DIR_MODE_IN);

    // Pull CLK high after half CCT
    waitUs(HALF_CCT);
    GPIOPinWrite(PORT, CLK, CLK);

    // Change DIO to input after another half CCT
    waitUs(HALF_CCT);
    GPIOPinWrite(PORT, CLK, 0);
    GPIODirModeSet(PORT, DIO, GPIO_DIR_MODE_OUT);
}

// Send STOP bit of I2C: Pull both low, pull DIO high in the middle of CCT
static void
tmSendStop()
{
    // Pull CLK and DIO low
    GPIOPinWrite(PORT, CLK, 0);
    waitUs(DELTA);
    GPIOPinWrite(PORT, DIO, 0);

    // Pull CLK high after half CCT
    waitUs(HALF_CCT - DELTA);
    GPIOPinWrite(PORT, CLK, CLK);

    // Pull DIO high after another half CCT
    waitUs(HALF_CCT);
    GPIOPinWrite(PORT, DIO, DIO);
}

// Send a single byte (eight bits)
static void
tmSendByte(uint8_t byte)
{
    int i;
    bool bit;

    // Send the eight data bits of byte, from LSB to MSB
    for (i = 0; i < 8; i++, byte >>= 1) {
        bit = (byte & 0b00000001);
        tmSendDataBit(bit);
    }
}

// Update all 4 digits of the 7-segment displays
void
seg7Update(uint8_t code[])
{
    tmSendStart();
    tmSendByte(0x40);
    tmWaitAck();
    tmSendStop();

    tmSendStart();
    tmSendByte(0xc0);
    tmWaitAck();
    tmSendByte(code[3]);
    tmWaitAck();
    tmSendByte(code[2]);
    tmWaitAck();
    tmSendByte(code[1]);
    tmWaitAck();
    tmSendByte(code[0]);
    tmWaitAck();
    tmSendStop();

    tmSendStart();
    tmSendByte(0x8A);
    tmWaitAck();
    tmSendStop();
}
-----------------------------------------------------------------------------
seg7.h
-----------------------------------------------
#ifndef SEG7_H_
#define SEG7_H_

// Initialize the port connection to TiM1637 and the 7-segment display
void seg7Init();

// Update all 4 digits of the 7-segment displays
void seg7Update(uint8_t code[]);

#endif /* SEG7_H_ */
------------------------------------------------------------------------------
launchpad.c
---------------------------------------
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <inc/hw_ints.h>
#include <inc/hw_types.h>
#include <driverlib/interrupt.h>
#include <driverlib/sysctl.h>
#include <driverlib/systick.h>

#include "launchpad.h"

// System tick clock frequency, which is the PIOSC in this library
#define SYSTICK_CLOCK_RATE        16000000L

// maximum size for callback queue, see below
#define MAX_CALLBACK       16

// The system clock rate in Hz. It will be configured to 50MHz
static uint32_t clockRate;

/***************************************************************************************
* System time wait functions
**************************************************************************************/

// System time in milliseconds
static volatile uint32_t sysTime = 0;

// System tick interrupt handler, for maintaining system time in microseconds
static void
sysTickIntHandler()
{
    sysTime++;
}

// Get sysTime
uint32_t                                           // return the current value of sysTime
sysTimeGet()
{
    return sysTime;
}

// Compare a given time with a system time, return 1 if the given time is reached, and 0 otherwise.
// It's assumed a program compares a desired time with sysTime frequently enough such that
// a signed 32-bit overflow won't happen.
bool                                               // return whether the given time is reached
sysTimeReached(uint32_t time)                       // the time to be compared with sysTime
{
    int32_t diff = (int32_t) (sysTime - time);

    return (diff >= 0) ? true : false;
}

// Compare two times using sysTime as the reference point. This function handles
// 32-bit wrap-around. Return true if time1 <= time2
static inline bool
sysTimeLE(uint32_t time1, uint32_t time2)
{
    uint32_t t = sysTime;                           // Get a local copy of sysTime

    int32_t t1 = (int32_t) (time1 - t);
    int32_t t2 = (int32_t) (time2 - t);

    return (t1 <= t2);
}

// Wait for sysTime for a delay.
// FIXME This function uses busy waiting which is not energy-efficient. It can utilize a CPU sleep
// mode to save energy.
void
sysTimeWait(uint32_t delay)                           // delay in milliseconds
{
    uint32_t time = sysTime + delay;
    int32_t diff;

    do {
        diff = (int32_t) (sysTime - time);
    } while (diff < 0);
}

// Wait for system time to reach a time point
void
sysTimeWaitAbsolute(uint32_t time)                   // time point in milliseconds
{
    int32_t diff;

    do {
        diff = (int32_t) (sysTime - time);
    } while (diff < 0);
}

/*************************************************************************************
* An event-driven scheduling system using sysTime
************************************************************************************/

// Heap for an event-driven lightweight scheduling system
static unsigned callbackHeapSize = 0;
static struct {
    void (*callback)(uint32_t time);
    uint32_t time;
} callbackHeap[MAX_CALLBACK];

// Initize the callback heap
static void
schdInit()
{
    int i;

    for (i = 0; i < MAX_CALLBACK; i++) {
        callbackHeap[i].callback = NULL;
        callbackHeap[i].time = 0;
    }
}

// Swap two items in the callback heap
static inline
heapSwap(m, n)
{
uint32_t time;
void (*callback)(uint32_t time);

time = callbackHeap[m].time;
callbackHeap[m].time = callbackHeap[n].time;
callbackHeap[n].time = time;
callback = callbackHeap[m].callback;
callbackHeap[m].callback = callbackHeap[n].callback;
callbackHeap[n].callback = callback;
}

// Schedule a callback event
void
schdCallback(void (*callback)(uint32_t time),    // the callback function
             uint32_t time)                       // when to call back
{
    int parent, child;

    // Check for callback queue overflow
    if (callbackHeapSize >= MAX_CALLBACK-1) {
        uprintf("%s ", "Error: callback queue overflows; some event is lost.");
        return;
    }

    // Add the callback event to the end of the heap
    child = callbackHeapSize++;
    callbackHeap[child].callback = callback;
    callbackHeap[child].time = time;

    // Re-build the heap
    while (child > 0) {
        parent = (child - 1) >> 1;

        // Stop if the parent is at least as old as the child
        if (sysTimeLE(callbackHeap[parent].time, callbackHeap[child].time))
            break;

        // Otherwise, swap parent and child, and continue
        heapSwap(parent, child);
        child = parent;
    }
}


// Execute all callbacks whose time is the same as or prior to sysTime. This function is non-blocking.
// FIXME: We can add a blocking version that utilizes CPU power saving features.
bool                                                           // return true if any callback is executed
schdExecute()
{
    int parent, leftChild, rightChild, elder;
    uint32_t time;
    void (*callback)(uint32_t time);
    bool executed = false;

    // Return immediately if the callback heap is empty
    if (callbackHeapSize == 0)
        return executed;

    // Execute all callbacks prior to sysTime. If there is none, no callback will be executed
    while (sysTimeLE(callbackHeap[0].time, sysTime)) {
        // Get the time and callback of the root and reduce the heap size
        time = callbackHeap[0].time;
        callback = callbackHeap[0].callback;
        callbackHeapSize--;

        // If there is no other callback, clear the root
        if (callbackHeapSize == 0) {
            callbackHeap[0].time = 0;
            callbackHeap[0].callback = NULL;
        }
            // Otherwise, rebuild the heap: Move the last node to the root, travel down
            // the heap until the parent at least as old as the child
        else {
            callbackHeap[0].time = callbackHeap[callbackHeapSize].time;
            callbackHeap[0].callback = callbackHeap[callbackHeapSize].callback;
            parent = 0;

            while (true) {
                // Check if left child is valid. If not, stop
                leftChild = (parent << 1) + 1;
                if (leftChild >= callbackHeapSize)
                    break;

                // Check the right child, if valid then decide the elder of
                // the left child and the right child
                rightChild = leftChild + 1;
                if (rightChild < callbackHeapSize
                    && sysTimeLE(callbackHeap[leftChild].time, callbackHeap[rightChild].time))
                    elder = leftChild;
                else
                    elder = rightChild;

                // If the parent is as old as the elder, stop and return;
                // otherwise, make the elder as the new parent, and travel down
                // the heap
                if (sysTimeLE(callbackHeap[parent].time, callbackHeap[elder].time))
                    return true;
                else {
                    heapSwap(parent, elder);
                    parent = elder;
                }
            }
        }

        // Execute its callback, check first if it is NULL or not.
        // IMPORTANT: This should be done after heap-rebuilding, because the
        // callback to be executed may insert one or more callbacks to the heap.
        // Double check the root of the heap is valid
        if (callback == NULL) {
            uprintf("%s ", "Error: NULL callback at the heap's root.");
            continue;
        }
        else {
            callback(time);
            executed = true;
        }
    }

    return executed;
}

/*
* Wait for a given number of milliseconds, using the SysCtlDelay() function.
* Note: sysTimeWait() is more accurate because it uses the system tick counter,
* which is not affect by CPU execution delay.
*/
void
waitMs(uint32_t timeMs)
{
    // Return immediately if timeMs is zero; otherwise, SysCtlDelay() would wait for a long time
    if (timeMs == 0)
        return;

    // Note: delayCount for SysCtlDelay() is three clock cycles
    uint32_t delayCount = (uint64_t) timeMs * clockRate / 1000;
    delayCount /= 3;
    SysCtlDelay(delayCount);
}

/*
* Wait for a given number of microseconds
*/
void
waitUs(uint32_t timeUs)
{
    // Return immediately if timeMs is zero; otherwise, SysCtlDelay() would wait for a long time
    if (timeUs == 0)
        return;

    // Note: delayCount for SysCtlDelay() is three clock cycles
    uint32_t delayCount = (uint64_t) timeUs * clockRate / 1000000;
    delayCount /= 3;
    SysCtlDelay(delayCount);
}

/*
* Initialize the clock of the LaunchPad
*/
void
lpInit()
{
    /// Specifies a 50-MHz CPU clock with a PLL divider of 4, using the
    /// main OSC.
    // Note: The code is from the workshop workbook.
    // Guess: The base clock is 25MHz (default value), boosted by PLL to
    // 200MHz, and then divided by 4 to 50MHz (I checked the datasheet).
    // I am not sure about the last flag.
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN
                   | SYSCTL_XTAL_16MHZ);

    /// Get the system running clock
    clockRate = SysCtlClockGet();

    // Configure and enable System Tick for 1 millisecond period,
    // and register an interrupt handler to maintain system time.
    // FIXME The overhead of 1ms interrupt can be high for some application.
    // It is desirable to make the period configurable.
    SysTickPeriodSet(clockRate/1000-1);
    SysTickIntRegister(sysTickIntHandler);
    SysTickIntEnable();
    SysTickEnable();

    // Initialize the event-based scheduler
    schdInit();

    // Initialize push button
    pbInit();

    // Initialize LEDs
    ledInit();

    // Initialize UART0
    uartInit();
}
-----------------------------------------------------------------------
launchpad.h
-----------------------------------
#ifndef LAUNCHPAD_H_
#define LAUNCHPAD_H_

#include <stdint.h>
#include <stdbool.h>
#include <driverlib/gpio.h>


// Initialize the most fundamental part of the LaunchPad
void lpInit();

/*****************************************************************************
* Time functions
****************************************************************************/

// Get sysTime, which is the system time in microseconds
uint32_t sysTimeGet();

// Check if sysTime has reached a give time
bool sysTimeReached(uint32_t time);

// Wait for sysTime to advance for a given number of microseconds
void sysTimeWait(uint32_t delay);

// Wait for a given number of milliseconds, using loop waiting
void waitMs(uint32_t timeMs);

// Wait for a given number of microseconds, using loop waiting
void waitUs(uint32_t timeUs);

/*****************************************************************************
* Schedule functions
****************************************************************************/

// Schedule a callback event at a given time
void schdCallback(void (*callback)(uint32_t time), uint32_t time);

// Execute all callback events; return true if at least one event is ececuted.
// Note: The function may not return if callback event chain never ends.
bool schdExecute();

// Execute callback events for a certain duration in milliseconds
void schdExecuteAndWait(uint32_t delay);

/*****************************************************************************
* LEDs functions
*
* There are three LEDs: red, green, and blue.
****************************************************************************/

// Initialize the LEDs
void ledInit();

// Turn on/off the LEDs individually. There are three LEDs of color red, blue, or green.
void ledTurnOnOff(bool red, bool blue, bool green);

/****************************************************************************
* Push button functions
****************************************************************************/

// Initialize the push button
void pbInit();

// Read either push button SW1 or SW2, return 1 if SW1 is pushed, 2 if SW2 is pushed,
// and 0 otherwise. This function is non-blocking, and there is no software debouncing.
int pbRead();

/****************************************************************************
* UART functions
****************************************************************************/

// Enable UART0 with baud rate of 115,200 bps, and 8-N-1 frame
void uartInit();

// Send a character
void uartPutChar(char ch);

// Receive a character
char uartGetChar();

// Send a string
int uartPutString(char *buffer);

// Print a string through UART0 using an internal buffer of 80 characters.
// Return the number of characters printed.
int uprintf(char* fmt, ...);

#endif // LAUNCHPAD_H_

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote