docs: docs/
This commit is contained in:
parent
276ac618b3
commit
878077ffc3
2699
docs/diagrams/state_diagram.gaphor
Normal file
2699
docs/diagrams/state_diagram.gaphor
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/images/abstract.png
Normal file
BIN
docs/images/abstract.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
docs/images/state_diagram.png
Normal file
BIN
docs/images/state_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@ -1096,7 +1096,7 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which Doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE = driverlib/
|
||||
EXCLUDE = driverlib/ jsmn/ src/Board.h
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
/**
|
||||
* \file door_sensor.c
|
||||
* \brief Implementation of the door sensor driver using MSP430 GPIO interrupts.
|
||||
*
|
||||
* This module configures a GPIO pin to detect door open/close events and invokes
|
||||
* user-provided callbacks on confirmed state changes.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <msp430.h>
|
||||
#include <driverlib.h>
|
||||
@ -5,32 +13,60 @@
|
||||
#include "door_sensor.h"
|
||||
#include "constants.h"
|
||||
|
||||
/**\brief GPIO port used for the door sensor. */
|
||||
#define SENSOR_PORT GPIO_PORT_P2
|
||||
/**\brief GPIO pin used for the door sensor. */
|
||||
#define SENSOR_PIN GPIO_PIN0
|
||||
/**\brief Interrupt vector associated with the sensor port. */
|
||||
#define SENSOR_VECTOR PORT2_VECTOR
|
||||
|
||||
/** User callback invoked on confirmed key press */
|
||||
/**
|
||||
* \brief Callback invoked when the door is detected as opened.
|
||||
*
|
||||
* User must supply a function matching this type to be notified of an open event.
|
||||
*/
|
||||
static DoorOpenedCallback_t doorOpenedCallback = NULL;
|
||||
/**
|
||||
* \brief Callback invoked when the door is detected as closed.
|
||||
*
|
||||
* User must supply a function matching this type to be notified of a close event.
|
||||
*/
|
||||
static DoorClosedCallback_t doorClosedCallback = NULL;
|
||||
|
||||
/**
|
||||
* \brief Initialize the door sensor driver.
|
||||
*
|
||||
* Configures the GPIO pin for input with pull-up resistor and enables
|
||||
* interrupts on the specified edge. Also stores the user-provided callbacks.
|
||||
*
|
||||
* \param ocb Function to call when the door opens (rising edge).
|
||||
* \param ccb Function to call when the door closes (falling edge).
|
||||
*/
|
||||
void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb) {
|
||||
doorOpenedCallback = ocb;
|
||||
doorClosedCallback = ccb;
|
||||
|
||||
/* Configure port as pull up with interrupt */
|
||||
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN0);
|
||||
GPIO_clearInterrupt(GPIO_PORT_P2, GPIO_PIN0);
|
||||
GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION);
|
||||
GPIO_enableInterrupt(GPIO_PORT_P2, GPIO_PIN0);
|
||||
GPIO_setAsInputPinWithPullUpResistor(SENSOR_PORT, SENSOR_PIN);
|
||||
GPIO_clearInterrupt(SENSOR_PORT, SENSOR_PIN);
|
||||
GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
|
||||
GPIO_enableInterrupt(SENSOR_PORT, SENSOR_PIN);
|
||||
|
||||
/* Enable global interrupts */
|
||||
__enable_interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Tracks the last known door state (open = true, closed = false).
|
||||
*/
|
||||
volatile bool door_last_open = false;
|
||||
|
||||
/**
|
||||
* @brief Interrupt Service Routine for PORT2
|
||||
* \brief ISR for PORT2 interrupt handling door sensor events.
|
||||
*
|
||||
* Detects whether the door is opening or closing based on interrupt edge,
|
||||
* invokes the corresponding callback, and reconfigures the interrupt edge
|
||||
* for the next transition.
|
||||
*/
|
||||
#pragma vector=SENSOR_VECTOR
|
||||
__interrupt void SENSOR_ISR(void)
|
||||
@ -39,17 +75,19 @@ __interrupt void SENSOR_ISR(void)
|
||||
|
||||
if (status) {
|
||||
if (door_last_open) {
|
||||
/* Door was open, now closed */
|
||||
if (doorClosedCallback)
|
||||
doorClosedCallback();
|
||||
GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_LOW_TO_HIGH_TRANSITION);
|
||||
GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_LOW_TO_HIGH_TRANSITION);
|
||||
} else {
|
||||
/* Door was closed, now opened */
|
||||
if (doorOpenedCallback)
|
||||
doorOpenedCallback();
|
||||
GPIO_selectInterruptEdge(GPIO_PORT_P2, GPIO_PIN0, GPIO_HIGH_TO_LOW_TRANSITION);
|
||||
GPIO_selectInterruptEdge(SENSOR_PORT, SENSOR_PIN, GPIO_HIGH_TO_LOW_TRANSITION);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the interrupt flag and toggle stored state */
|
||||
GPIO_clearInterrupt(SENSOR_PORT, SENSOR_PIN);
|
||||
|
||||
door_last_open = !door_last_open;
|
||||
}
|
||||
|
||||
@ -1,13 +1,38 @@
|
||||
/**
|
||||
* \file door_sensor.h
|
||||
* \brief Public interface for the door sensor driver.
|
||||
*
|
||||
* This header declares the callback types and initialization function
|
||||
* for detecting door open and close events using GPIO interrupts.
|
||||
*/
|
||||
|
||||
#ifndef DOOR_H
|
||||
#define DOOR_H
|
||||
|
||||
/**
|
||||
* @brief Callback invoked on a confirmed key press.
|
||||
* @param key ASCII character of the pressed key.
|
||||
* \brief Callback type invoked when the door is detected as opened.
|
||||
*
|
||||
* This function is called by the driver on a confirmed open event.
|
||||
*/
|
||||
typedef void (*DoorOpenedCallback_t)(void);
|
||||
|
||||
/**
|
||||
* \brief Callback type invoked when the door is detected as closed.
|
||||
*
|
||||
* This function is called by the driver on a confirmed close event.
|
||||
*/
|
||||
typedef void (*DoorClosedCallback_t)(void);
|
||||
|
||||
/**
|
||||
* \brief Initialize the door sensor driver.
|
||||
*
|
||||
* Configures the GPIO pin for input with pull-up resistor and enables
|
||||
* interrupts on the door sensor line. The provided callbacks are invoked
|
||||
* on door open and close events respectively.
|
||||
*
|
||||
* \param ocb User-provided callback to invoke on door open.
|
||||
* \param ccb User-provided callback to invoke on door close.
|
||||
*/
|
||||
void door_init(DoorOpenedCallback_t ocb, DoorClosedCallback_t ccb);
|
||||
|
||||
#endif // DOOR_H
|
||||
155
src/i2c.c
155
src/i2c.c
@ -1,12 +1,13 @@
|
||||
/* ========================================================================== */
|
||||
/* I2C.c */
|
||||
/* ========================================================================== */
|
||||
/* File: i2c.c */
|
||||
/**
|
||||
* @file I2C.c
|
||||
* @author wehrberger
|
||||
* @date 31.05.2025
|
||||
* @file i2c.c
|
||||
* @brief I²C master routines and missing standard C90 constants for MSP430FR2355.
|
||||
*
|
||||
* @brief Implementierung eines minimalen blockierenden I²C-Master-Treibers.
|
||||
* Implements byte-wise I²C transmit and single-register read with automatic
|
||||
* STOP handling and interrupt-driven operation.
|
||||
*
|
||||
* @author (based on work by) Luis Wehrberger
|
||||
* @date 2025-07-02
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
@ -14,104 +15,127 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** Pointer auf das aktuell zu übertragende Byte. */
|
||||
static char *packet;
|
||||
/** Pointer to the current transmit buffer. */
|
||||
static char *i2c_tx_buffer;
|
||||
|
||||
/** Index des nächsten zu übertragenden Bytes. */
|
||||
static unsigned int dataCount;
|
||||
/** Number of bytes left to send (buffer length). */
|
||||
static unsigned int i2c_tx_length;
|
||||
|
||||
/** Anzahl der Bytes in @ref packet. */
|
||||
static unsigned int packetLength;
|
||||
/** Index of the next byte to transmit. */
|
||||
static unsigned int i2c_tx_index;
|
||||
|
||||
/** Speicher für das zuletzt vom ISR empfangene Byte. */
|
||||
static char dataIn;
|
||||
/** Last byte received by the ISR. */
|
||||
static char i2c_rx_byte;
|
||||
|
||||
static volatile bool i2cDone = false;
|
||||
/** Flag set when I²C transfer completes (STOP or NACK). */
|
||||
static volatile bool i2c_transfer_complete = false;
|
||||
|
||||
/**
|
||||
* @brief Initialize USCI_B0 module for I²C master mode at 50 kHz.
|
||||
*
|
||||
* Configures SMCLK source, sets clock divider, 7-bit addressing,
|
||||
* automatic STOP generation, port mapping for SDA/SCL, and enables
|
||||
* relevant interrupts.
|
||||
*/
|
||||
void i2c_init(void)
|
||||
{
|
||||
// USCI in Reset setzen um Konfiguration zu ermöglichen
|
||||
// Put eUSCI_B0 into reset state for configuration
|
||||
UCB0CTLW0 |= UCSWRST;
|
||||
|
||||
// SMCLK wählen und durch 20 teilen → 50 kHz SCL
|
||||
// Select SMCLK and divide by 20 → 50 kHz SCL
|
||||
UCB0CTLW0 |= UCSSEL_3;
|
||||
UCB0BRW = 50;
|
||||
|
||||
// I²C Master, 7-Bit Adressierung
|
||||
// Configure as I²C master with 7-bit addressing
|
||||
UCB0CTLW0 |= UCMODE_3 | UCMST;
|
||||
|
||||
// Automatischer STOP nach Byte-Zähler (UCB0TBCNT) erreicht Null
|
||||
// Enable automatic STOP when byte counter (UCB0TBCNT) reaches zero
|
||||
UCB0CTLW1 |= UCASTP_2;
|
||||
|
||||
// Port-Mapping: P1.2 = SDA, P1.3 = SCL
|
||||
// Assign P1.2 = SDA, P1.3 = SCL via port mapping
|
||||
P1SEL1 &= ~(BIT2 | BIT3);
|
||||
P1SEL0 |= BIT2 | BIT3;
|
||||
P1SEL0 |= (BIT2 | BIT3);
|
||||
|
||||
// Modul aktivieren
|
||||
// Release eUSCI_B0 for operation
|
||||
UCB0CTLW0 &= ~UCSWRST;
|
||||
|
||||
// Interrupts: RX, TX, STOP, NACK
|
||||
// Enable RX, TX, STOP, and NACK interrupts
|
||||
UCB0IE |= UCRXIE0 | UCTXIE0 | UCSTPIE | UCNACKIE;
|
||||
|
||||
__enable_interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmit a sequence of bytes to a given I²C slave.
|
||||
*
|
||||
* @param slaveAddress 7-bit I²C address of the slave device.
|
||||
* @param data Pointer to data buffer to send.
|
||||
* @param length Number of bytes to transmit.
|
||||
*/
|
||||
void i2c_write(uint8_t slaveAddress, char data[], uint8_t length)
|
||||
{
|
||||
// Set target slave address
|
||||
UCB0I2CSA = slaveAddress;
|
||||
packet = data;
|
||||
packetLength = length;
|
||||
dataCount = 0;
|
||||
|
||||
// Master-Transmit-Modus
|
||||
// Initialize transmit buffer and counters
|
||||
i2c_tx_buffer = data;
|
||||
i2c_tx_length = length;
|
||||
i2c_tx_index = 0;
|
||||
|
||||
// Configure for master-transmit mode and set byte counter
|
||||
UCB0CTLW0 |= UCTR;
|
||||
UCB0TBCNT = length;
|
||||
|
||||
// START generieren, dann schlafen bis STOP
|
||||
// Generate START and wait for STOP flag in ISR
|
||||
UCB0CTLW0 |= UCTXSTT;
|
||||
|
||||
i2cDone = false;
|
||||
while (!i2cDone)
|
||||
i2c_transfer_complete = false;
|
||||
while (!i2c_transfer_complete)
|
||||
{
|
||||
LPM3; // Warten auf STOP → ISR weckt uns auf
|
||||
LPM3; // Enter low-power mode, will wake on STOP or NACK
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a single register byte from an I²C slave.
|
||||
*
|
||||
* Performs a write of the register address, followed by a repeated START
|
||||
* to read one byte, with automatic STOP and interrupt-based wake-up.
|
||||
*
|
||||
* @param slaveAddress 7-bit I²C address of the slave device.
|
||||
* @param registerAddress Register address to read.
|
||||
* @return Byte read from the register.
|
||||
*/
|
||||
char i2c_read_reg(uint8_t slaveAddress, uint8_t registerAddress)
|
||||
{
|
||||
// Registeradresse zuerst senden
|
||||
char addressBuffer[1] = {registerAddress};
|
||||
i2c_write(slaveAddress, addressBuffer, 1);
|
||||
// Send register address first
|
||||
char addr_buf[1] = { (char)registerAddress };
|
||||
i2c_write(slaveAddress, addr_buf, 1);
|
||||
|
||||
// In Empfangsmodus wechseln und 1 Byte anfordern
|
||||
// Switch to master-receive mode and request one byte
|
||||
UCB0CTLW0 &= ~UCTR;
|
||||
UCB0TBCNT = 1;
|
||||
|
||||
UCB0CTLW0 |= UCTXSTT; // Repeated START
|
||||
// Generate repeated START condition
|
||||
UCB0CTLW0 |= UCTXSTT;
|
||||
|
||||
i2cDone = false;
|
||||
while (!i2cDone)
|
||||
i2c_transfer_complete = false;
|
||||
while (!i2c_transfer_complete)
|
||||
{
|
||||
LPM3; // Warten auf STOP → ISR weckt uns auf
|
||||
LPM3; // Wait for ISR to clear STOP flag
|
||||
}
|
||||
|
||||
return dataIn;
|
||||
return i2c_rx_byte;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* Interrupt Service Routine */
|
||||
/* ========================================================================== */
|
||||
|
||||
/**
|
||||
* @brief Vereinheitlichte ISR für alle USCI_B0 I²C-Ereignisse.
|
||||
* @brief USCI_B0 I²C interrupt handler.
|
||||
*
|
||||
* Nur vier Interrupt-Ursachen werden derzeit behandelt:
|
||||
* - UCNACKIFG : Kennzeichnet fehlendes ACK (nur Debug-Hook)
|
||||
* - UCSTPIFG : STOP erkannt → LPM3 verlassen
|
||||
* - UCRXIFG0 : Ein Byte empfangen
|
||||
* - UCTXIFG0 : Sendepuffer bereit für nächstes Byte
|
||||
*
|
||||
* Alle anderen Ursachen fallen durch zum default.
|
||||
* Handles NACK, STOP, RX, and TX events:
|
||||
* - NACK: terminate transfer and wake CPU
|
||||
* - STOP: terminate transfer and wake CPU
|
||||
* - RXBUF: store received byte
|
||||
* - TXBUF: send next byte or reset index
|
||||
*/
|
||||
#pragma vector = EUSCI_B0_VECTOR
|
||||
__interrupt void EUSCI_B0_I2C_ISR(void)
|
||||
@ -119,31 +143,34 @@ __interrupt void EUSCI_B0_I2C_ISR(void)
|
||||
switch (__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
|
||||
{
|
||||
case USCI_I2C_UCNACKIFG:
|
||||
// NACK → CPU aufwecken (LPM3 verlassen)
|
||||
i2cDone = true;
|
||||
// NACK received: signal completion and wake CPU
|
||||
i2c_transfer_complete = true;
|
||||
__bic_SR_register_on_exit(LPM3_bits);
|
||||
break;
|
||||
|
||||
case USCI_I2C_UCSTPIFG:
|
||||
// STOP → CPU aufwecken (LPM3 verlassen)
|
||||
i2cDone = true;
|
||||
// STOP condition detected: signal completion and wake CPU
|
||||
i2c_transfer_complete = true;
|
||||
__bic_SR_register_on_exit(LPM3_bits);
|
||||
break;
|
||||
|
||||
case USCI_I2C_UCRXIFG0:
|
||||
// Empfangenes Byte speichern
|
||||
dataIn = UCB0RXBUF;
|
||||
// Read received byte into buffer
|
||||
i2c_rx_byte = UCB0RXBUF;
|
||||
break;
|
||||
|
||||
case USCI_I2C_UCTXIFG0:
|
||||
// Nächstes Datenbyte senden oder Übertragung beenden
|
||||
UCB0TXBUF = packet[dataCount++];
|
||||
if (dataCount >= packetLength)
|
||||
dataCount = 0; // Für nächste Transaktion zurücksetzen
|
||||
// Transmit next byte or reset index if done
|
||||
UCB0TXBUF = i2c_tx_buffer[i2c_tx_index++];
|
||||
if (i2c_tx_index >= i2c_tx_length)
|
||||
{
|
||||
// Reset index for subsequent transactions
|
||||
i2c_tx_index = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unbehandelter Vektor – nichts zu tun
|
||||
// Unhandled interrupts: no action
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize the I2C module as master (SMCLK/20 → 50 kHz SCL).
|
||||
* @brief Initialize the I2C module as master.
|
||||
*/
|
||||
void i2c_init(void);
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
* - Wait for key release and debounce
|
||||
* - Clear flags and re-enable column interrupts
|
||||
*
|
||||
* @author
|
||||
* @author Frederik Beimgraben
|
||||
* @date 2025-07-02
|
||||
*/
|
||||
|
||||
|
||||
@ -5,10 +5,7 @@
|
||||
*
|
||||
* Interrupt-driven scanning with callback on key press.
|
||||
*
|
||||
* @authors
|
||||
* Frederik Beimgraben
|
||||
* Minh Dan Cam
|
||||
* Luis Meyer
|
||||
* @author Frederik Beimgraben
|
||||
* @date 2025-07-02
|
||||
*/
|
||||
|
||||
|
||||
89
src/lcd.c
89
src/lcd.c
@ -1,34 +1,65 @@
|
||||
/**
|
||||
* \file lcd.c
|
||||
* \brief I2C-based LCD driver for MSP430FR2355.
|
||||
*
|
||||
* This module provides initialization and basic control functions
|
||||
* for a character LCD connected via an I2C expander. It supports
|
||||
* 4-bit communication mode and includes routines for sending commands
|
||||
* and data to the display.
|
||||
*/
|
||||
|
||||
#include "lcd.h"
|
||||
#include "i2c.h" /* Ihr I²C-Master-Treiber */
|
||||
#include <msp430fr2355.h> /* für __delay_cycles() */
|
||||
#include "i2c.h" /**< I²C master driver */
|
||||
#include <msp430fr2355.h> /**< MSP430 definitions for __delay_cycles() */
|
||||
#include <stdint.h>
|
||||
|
||||
/* --- Interne Helfer: sendet eine 4-Bit-Halbnibble plus Control-Bits --- */
|
||||
/**
|
||||
* \brief Send a 4-bit nibble with control flags over I2C to the LCD.
|
||||
*
|
||||
* This helper composes a byte containing the nibble (in the high 4 bits),
|
||||
* the control signals (RS, RW, EN), and the backlight bit, then toggles
|
||||
* the enable line to latch the data.
|
||||
*
|
||||
* \param nibble 4-bit data to send (lower nibble used).
|
||||
* \param control Control flags (e.g., RS, R/W).
|
||||
*/
|
||||
static void lcd_write_nibble(uint8_t nibble, uint8_t control)
|
||||
{
|
||||
char buf[1];
|
||||
|
||||
/* High-Nibble in die oberen 4 Bits */
|
||||
buf[0] = (nibble << 4) | control | LCD_BACKLIGHT;
|
||||
/* EN=1 */
|
||||
/* High nibble placed in upper data bits, include control and backlight */
|
||||
buf[0] = (uint8_t)((nibble << 4) | control | LCD_BACKLIGHT);
|
||||
/* Pulse EN high */
|
||||
i2c_write(LCD_I2C_ADDR, buf, 1);
|
||||
buf[0] |= LCD_ENABLE;
|
||||
i2c_write(LCD_I2C_ADDR, buf, 1);
|
||||
__delay_cycles(500); /* ca. 50 µs @ 1 MHz */
|
||||
/* EN=0 */
|
||||
buf[0] &= ~LCD_ENABLE;
|
||||
__delay_cycles(500); /**< ~50µs at 1MHz */
|
||||
/* EN low */
|
||||
buf[0] &= (char)~LCD_ENABLE;
|
||||
i2c_write(LCD_I2C_ADDR, buf, 1);
|
||||
__delay_cycles(500);
|
||||
}
|
||||
|
||||
/* Sendet ein volles Byte (2×4-Bit) als Befehl (RS=0) */
|
||||
/**
|
||||
* \brief Send an 8-bit command to the LCD.
|
||||
*
|
||||
* Splits the command into two 4-bit nibbles and sends each with RS=0.
|
||||
*
|
||||
* \param cmd Command byte to send.
|
||||
*/
|
||||
static void lcd_send_cmd(uint8_t cmd)
|
||||
{
|
||||
lcd_write_nibble(cmd >> 4, 0x00);
|
||||
lcd_write_nibble(cmd & 0x0F, 0x00);
|
||||
}
|
||||
|
||||
/* Sendet ein volles Byte als Daten (RS=1) */
|
||||
/**
|
||||
* \brief Send an 8-bit data value (character) to the LCD.
|
||||
*
|
||||
* Splits the data into two 4-bit nibbles and sends each with RS=1.
|
||||
*
|
||||
* \param data Data byte (character) to display.
|
||||
*/
|
||||
static void lcd_send_data(uint8_t data)
|
||||
{
|
||||
lcd_write_nibble(data >> 4, LCD_RS);
|
||||
@ -37,10 +68,10 @@ static void lcd_send_data(uint8_t data)
|
||||
|
||||
void lcd_init(void)
|
||||
{
|
||||
/* Wartezeit nach Power-Up */
|
||||
__delay_cycles(50000); /* ca. 50 ms */
|
||||
/* Delay for LCD power-up (approx. 50 ms) */
|
||||
__delay_cycles(50000);
|
||||
|
||||
/* Initialsequenz 8-Bit-Befehle (3×) */
|
||||
/* Initialization sequence in 8-bit mode: 3 pulses */
|
||||
lcd_write_nibble(0x03, 0x00);
|
||||
__delay_cycles(20000);
|
||||
lcd_write_nibble(0x03, 0x00);
|
||||
@ -48,37 +79,57 @@ void lcd_init(void)
|
||||
lcd_write_nibble(0x03, 0x00);
|
||||
__delay_cycles(2000);
|
||||
|
||||
/* In 4-Bit-Modus schalten */
|
||||
/* Switch to 4-bit mode */
|
||||
lcd_write_nibble(0x02, 0x00);
|
||||
__delay_cycles(2000);
|
||||
|
||||
/* Funktion: 4-Bit, 2 Zeilen, 5×8 Punkte */
|
||||
/* Function set: 4-bit, 2 lines, 5x8 dots */
|
||||
lcd_send_cmd(0x28);
|
||||
/* Display off */
|
||||
lcd_send_cmd(0x08);
|
||||
/* Clear */
|
||||
/* Clear display */
|
||||
lcd_send_cmd(0x01);
|
||||
__delay_cycles(2000);
|
||||
/* Entry mode: Cursor++ */
|
||||
/* Entry mode set: increment cursor */
|
||||
lcd_send_cmd(0x06);
|
||||
/* Display on, Cursor off, Blink off */
|
||||
/* Display on, cursor off, blink off */
|
||||
lcd_send_cmd(0x0C);
|
||||
}
|
||||
|
||||
void lcd_clear(void)
|
||||
{
|
||||
/**
|
||||
* \brief Clear display and reset cursor.
|
||||
*
|
||||
* Sends the clear command and waits for the LCD to process it.
|
||||
*/
|
||||
lcd_send_cmd(0x01);
|
||||
__delay_cycles(2000);
|
||||
}
|
||||
|
||||
void lcd_set_cursor(uint8_t row, uint8_t col)
|
||||
{
|
||||
/**
|
||||
* \brief Set cursor to specified position.
|
||||
*
|
||||
* Calculates the DDRAM address based on row and column.
|
||||
*
|
||||
* \param row Row index (0 or 1).
|
||||
* \param col Column index (0-15).
|
||||
*/
|
||||
uint8_t addr = (row == 0 ? 0x00 : 0x40) + (col & 0x0F);
|
||||
lcd_send_cmd(0x80 | addr);
|
||||
}
|
||||
|
||||
void lcd_print(const char *str)
|
||||
{
|
||||
/**
|
||||
* \brief Print a null-terminated string to the LCD.
|
||||
*
|
||||
* Iterates through the string and sends each character as data.
|
||||
*
|
||||
* \param str Pointer to a null-terminated C string.
|
||||
*/
|
||||
while (*str)
|
||||
{
|
||||
lcd_send_data((uint8_t)*str++);
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
* This module drives a keypad‐and‐LCD UI to select beverage types (A–D),
|
||||
* choose quantities, confirm orders, detect door events, and edit stock levels.
|
||||
*
|
||||
* @author Frederik Beimgraben
|
||||
* @author Minh Dan Cam
|
||||
* @author Luis Meyer
|
||||
* @authors
|
||||
* Frederik Beimgraben
|
||||
* Minh Dan Cam
|
||||
* Luis Meyer
|
||||
* @date 2025-07-03
|
||||
*/
|
||||
|
||||
|
||||
53
src/timer.c
53
src/timer.c
@ -1,41 +1,70 @@
|
||||
/**
|
||||
* \file timer.c
|
||||
* \brief MSP430 Timer B driver and blocking delay implementation.
|
||||
*
|
||||
* This module provides a millisecond-level blocking delay function using
|
||||
* low-power mode and global interrupts, as well as initialization for Timer B
|
||||
* in up mode to generate periodic 1ms interrupts.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <msp430.h>
|
||||
#include <driverlib.h>
|
||||
#include "timer.h"
|
||||
|
||||
/**
|
||||
* @brief Führt eine blockierende Wartezeit aus.
|
||||
* @param ms Zeit in Millisekunden
|
||||
* \brief Block execution for a given number of milliseconds.
|
||||
*
|
||||
* Implements a blocking delay by entering LPM0 and waking up via the
|
||||
* Timer interrupt on each millisecond tick.
|
||||
*
|
||||
* \param ms Number of milliseconds to delay.
|
||||
*/
|
||||
void sleep(uint16_t ms) {
|
||||
while (ms--) {
|
||||
/* Enter low-power mode 0 with interrupts enabled */
|
||||
__bis_SR_register(LPM0_bits + GIE);
|
||||
/* No operation, wait for interrupt */
|
||||
__no_operation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize Timer B0 in up mode to generate 1ms period interrupts.
|
||||
*
|
||||
* Configures Timer B0 to use SMCLK, no divider, and a period of 999 ticks
|
||||
* to achieve a 1ms overflow (assuming 1MHz SMCLK). Enables CCR0 interrupt
|
||||
* to exit low-power mode on each tick.
|
||||
*/
|
||||
void init_timer(void) {
|
||||
static Timer_B_initUpModeParam param = {0};
|
||||
|
||||
/* Select SMCLK as clock source */
|
||||
param.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
|
||||
/* No division: tick = 1MHz / 1 = 1MHz */
|
||||
param.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_1;
|
||||
param.timerPeriod = 999; // wenn 1000 Taktimpulse gezählt
|
||||
// wurden, erfolgt ein Interrupt
|
||||
// Periodendauer somit 1ms
|
||||
param.timerInterruptEnable_TBIE =
|
||||
TIMER_B_TBIE_INTERRUPT_DISABLE; // no interrupt on 0x0000
|
||||
/* Period = 999 -> interrupt every 1000 ticks => 1ms */
|
||||
param.timerPeriod = 999;
|
||||
/* Disable interrupt on timer rollover (TBIE) */
|
||||
param.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE;
|
||||
/* Enable CCR0 interrupt on timer compare match */
|
||||
param.captureCompareInterruptEnable_CCR0_CCIE =
|
||||
TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE; // interrupt on TRmax
|
||||
TIMER_B_CAPTURECOMPARE_INTERRUPT_ENABLE;
|
||||
/* Clear timer and start immediately */
|
||||
param.timerClear = TIMER_B_DO_CLEAR;
|
||||
param.startTimer = true;
|
||||
|
||||
// start Timer:
|
||||
/* Initialize and start Timer B0 in up mode */
|
||||
Timer_B_initUpMode(TB0_BASE, ¶m);
|
||||
}
|
||||
|
||||
// TimerB0 Interrupt Vector (TBxIV) handler
|
||||
/**
|
||||
* \brief ISR for Timer0_B0 (CCR0) comparison event.
|
||||
*
|
||||
* Exits low-power mode 0 to resume the sleeping function.
|
||||
*/
|
||||
#pragma vector=TIMER0_B0_VECTOR
|
||||
__interrupt void TIMER0_B0_ISR(void)
|
||||
{
|
||||
__interrupt void TIMER0_B0_ISR(void) {
|
||||
/* Clear LPM0 bits on exit to wake up CPU */
|
||||
__bic_SR_register_on_exit(LPM0_bits);
|
||||
}
|
||||
|
||||
24
src/timer.h
24
src/timer.h
@ -1,7 +1,31 @@
|
||||
/**
|
||||
* \file timer.h
|
||||
* \brief Interface for millisecond delay and Timer B initialization on MSP430.
|
||||
*
|
||||
* This header declares functions for creating a blocking delay using low-power
|
||||
* mode and for initializing Timer B0 in up mode to generate periodic 1ms interrupts.
|
||||
*/
|
||||
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
/**
|
||||
* \brief Block execution for a specified number of milliseconds.
|
||||
*
|
||||
* This function enters low-power mode 0 (LPM0) and wakes on each
|
||||
* Timer B CCR0 interrupt to achieve an approximate millisecond delay.
|
||||
*
|
||||
* \param ms Number of milliseconds to sleep.
|
||||
*/
|
||||
void sleep(uint16_t ms);
|
||||
|
||||
/**
|
||||
* \brief Initialize Timer B0 to generate 1ms interrupts.
|
||||
*
|
||||
* Configures Timer B0 with SMCLK as the clock source, no divider,
|
||||
* and a period of 999 ticks (for a 1MHz clock) to create a 1ms interval.
|
||||
* Enables CCR0 compare interrupt to wake from low-power mode on each tick.
|
||||
*/
|
||||
void init_timer(void);
|
||||
|
||||
#endif // TIMER_H
|
||||
Loading…
Reference in New Issue
Block a user