Compare commits

...

5 Commits
v2.0 ... master

43 changed files with 6884 additions and 0 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ deliver/
*.ld *.ld
Debug/ Debug/
Release/ Release/
*.launch
# Keil related # Keil related
Keil/ Keil/

9
.gitmodules vendored
View File

@ -7,3 +7,12 @@
[submodule "assignment_2/Libraries/STM32CubeF4"] [submodule "assignment_2/Libraries/STM32CubeF4"]
path = assignment_2/Libraries/STM32CubeF4 path = assignment_2/Libraries/STM32CubeF4
url = https://github.com/hoo2/STM32CubeF4.git url = https://github.com/hoo2/STM32CubeF4.git
[submodule "assignment_3/thermostat_shield/AltiumLib"]
path = assignment_3/thermostat_shield/AltiumLib
url = git@gitlab.com:hoo2/altium-lib.git
[submodule "assignment_3/Libraries/STM32CubeF4"]
path = assignment_3/Libraries/STM32CubeF4
url = https://github.com/STMicroelectronics/STM32CubeF4.git
[submodule "assignment_3/report/config"]
path = assignment_3/report/config
url = https://git.hoo2.net/hoo2/LaTeX_confing.git

@ -0,0 +1 @@
Subproject commit 5d01400afd60410f6e049cbd19179a67d44d53fd

View File

@ -0,0 +1,319 @@
/*!
* \file
* NUCLEO_F401RE.h
* \brief
* Nucleo F401RE port file. This file contain the implementation of driver
* calls for F401RE board.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include "NUCLEO_F401RE.h"
/*
* =============== System ===============
*/
static clock_t volatile __ticks; //!< CPU time
static time_t volatile __now; //!< Time in UNIX seconds past 1-Jan-70
static clock_t volatile __sys_freq; //!< The CPU's time frequency (SysTick freq)
/*!
* \brief
* This is the SysTick ISR, micro-system time base service for CPU time.
* \note
* This service implements the SysTick callback function in order
* to provide micro system - os like functionalities to an application
* without RTOS
*/
void SysTick_Handler(void) {
// Time
++__ticks;
if ( !(__ticks % __sys_freq ) )
++__now; // Do not update __now when we have external time system
}
/*!
* \brief This function configures the source of the time base.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* \param sf Tick interrupt frequency.
* \retval HAL status
*/
__weak HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf) {
SystemCoreClockUpdate ();
/* Configure the SysTick to have interrupt in sf time basis */
if (SysTick_Config (SystemCoreClock/sf) != 0)
return HAL_ERROR;
__sys_freq = sf;
/*Configure the SysTick IRQ priority */
NVIC_SetPriority (SysTick_IRQn, 3U);
/* Return function status */
return HAL_OK;
}
/*!
* Select the system frequency without calling the Setting functionality
* \param sf The desired value
* \return The desired value (enable chaining)
*/
__INLINE clock_t HAL_SelectSysTickFreq (clock_t sf){
return __sys_freq =sf;
}
/*!
* \brief Get the __sys_freq.
*/
__INLINE clock_t HAL_GetSysTickFreq (void){
return __sys_freq;
}
/*!
* \brief Reconfigure the SysTick and update __sys_freq
* \param sf Tick interrupt frequency (CPU time)
* \return status of the operation
* \arg 0 Success
* \arg 1 Fail
*/
int HAL_SetSysTickFreq (clock_t sf) {
/*Configure the SysTick to have interrupt in sf time basis*/
if (__sys_freq != sf) {
// Time base configuration
SystemCoreClockUpdate ();
if (SysTick_Config ( (SystemCoreClock>>3)/sf) != 0)
return 1;
else {
__sys_freq = sf;
return 0;
}
}
return 0;
}
// Take over control of SysTick from HAL library
//! disable HAL_InitTick implementation
HAL_StatusTypeDef
HAL_InitTick(uint32_t TickPriority) { return HAL_OK; }
//! Chain GetTick to our implementation
uint32_t HAL_GetTick(void) { return clock(); }
/*!
* \brief This function provides minimum delay (in CPU time) based
* on variable incremented.
* \param Delay specifies the delay time length, in CPU time.
* \note
* uint32_t is implicitly convertible to clock_t and vice versa.
*/
void HAL_Delay(uint32_t Delay) {
uint32_t tickstart = clock();
while((clock() - tickstart) < Delay)
;
}
/*
* ================ Jiffies ======================
*/
/*!
* Provide jiffy compatible set frequency functionality
* \param jf_freq The desire frequency
* \param jiffies The number of steps (jiffies)
* \return The status of the operation
* \arg 0 Success
* \arg 1 Fail
*/
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) {
uint32_t psc=0;
JF_TIMER_CLK_ENABLE();
SystemCoreClockUpdate ();
if (jf_freq)
psc = SystemCoreClock / jf_freq - 1;
if (psc < 0xFFFF) JF_TIMER->PSC = psc;
else return 1;
if (jiffies < 0xFFFF) JF_TIMER->ARR = jiffies;
else return 1;
JF_TIMER->CR1 |= TIM_CR1_CEN;
return 0;
}
/*
* ======== OS like Functionalities ============
*/
//! SysTick frequency getter
__INLINE clock_t get_freq (void) {
return __sys_freq;
}
//! SysTick frequency setter
//! \return True on failure
int set_freq (clock_t sf) {
return HAL_SetSysTickFreq (sf);
}
/*!
* \brief
* determines the processor time.
* \return
* the implementation's best approximation to the processor time
* used by the program since program invocation. The time in
* seconds is the value returned divided by the value of the macro
* CLK_TCK or CLOCKS_PER_SEC
*/
__INLINE clock_t clock (void) {
return (clock_t) __ticks;
}
/*!
* \brief
* Set the processor time used.
* \param c The new CPU time value
* \return
* The implementation's best approximation to the processor time
* used by the program since program invocation. The time in
* seconds is the value returned divided by the value of the macro
* CLK_TCK or CLOCKS_PER_SEC
*/
clock_t setclock (clock_t c) {
return __ticks = c;
}
/*!
* \brief
* determines the current calendar time. The encoding of the value is
* unspecified.
* \return
* The implementations best approximation to the current calendar
* time. If timer is not a null pointer, the return value
* is also assigned to the object it points to.
*/
time_t time (time_t *timer) {
if (timer)
*timer = (time_t)__now;
return (time_t)__now;
}
/*!
* \brief
* Sets the system's idea of the time and date. The time,
* pointed to by t, is measured in seconds since the Epoch, 1970-01-01
* 00:00:00 +0000 (UTC).
* \param t Pointer to new system's time and date.
* \return On success, zero is returned. On error, -1 is returned
*/
int settime (const time_t *t) {
if (t) {
__now = *t;
return 0;
}
else
return -1;
}
/*
* ============== Cycle count ==============
*/
/*!
* Initialize CPU cycle measurement functionality based on DBG
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en CYCLE_Init (void) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // enable trace
//DWT->LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers
DWT->CYCCNT = 0; // clear DWT cycle counter
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable DWT cycle counter
return LLD_OK;
}
//! CPU cycle getter
__INLINE clock_t CYCLE_Get (void) {
return (clock_t)DWT->CYCCNT;
}
//! Helper digital input pin getter
__INLINE uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin) {
return ((port->IDR & pin) != 0) ? 1:0;
}
//! Helper digital output pin setter
__INLINE uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st) {
if (st) port->BSRR = (uint32_t)pin;
else port->BSRR = (uint32_t)pin << 16;
return st;
}
/*
* =============== Digital I/O ===============
* BTN -- PC13
* LED -- PA5 (SB42 is in place) [SB29: PB13]
*/
/*!
* Initialize GPIO port pins for Nucleo Board
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en NUCLEO_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;
// Enable Port clock
__HAL_RCC_GPIOA_CLK_ENABLE ();
__HAL_RCC_GPIOC_CLK_ENABLE ();
// BTN port configuration
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pin = GPIO_PIN_13;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitType);
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_5;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);
return LLD_OK;
}
//! Nucleo's user button reader
uint8_t NUCLEO_BTN (void) {
return _DINx (GPIOC, GPIO_PIN_13);
}
//! Nucleo's LD2 led setter
void NUCLEO_LED (uint8_t on) {
_DOUTx(GPIOA, GPIO_PIN_5, on);
}
/*! Low level driver init functionality
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en NUCLEO_Init (clock_t sys_freq) {
HAL_Init();
HAL_SysTick_Init (sys_freq);
CYCLE_Init ();
NUCLEO_Port_Init ();
return LLD_OK;
}

View File

@ -0,0 +1,156 @@
/*!
* \file
* NUCLEO_F401RE.h
* \brief
* Nucleo F401RE port file. This file contain the implementation of driver
* calls for F401RE board.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#ifndef NUCLEO_F401RE_H_
#define NUCLEO_F401RE_H_
#include <stm32f4xx.h>
#include <stm32f4xx_hal.h>
#include <core_cm4.h>
/*
* ========= Data types ========
*/
//! Driver status return type
typedef enum {
LLD_OK = 0, //!< Indicate successful operation
LLD_ERROR //!< Indicate Error
}LLD_Status_en;
typedef uint8_t din_t;
#define OFF (0)
#define ON (!OFF)
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
/*
* =============== System ===============
*/
#if defined ( __GNUC__ ) && !defined (__CC_ARM)
#include <sys/types.h>
#endif
#include <limits.h>
/*
* Also defined in types.h
*/
#ifndef _CLOCK_T_
#if defined (__CC_ARM)
#define _CLOCK_T_ unsigned int
#else
#define _CLOCK_T_ unsigned long
#endif
typedef _CLOCK_T_ clock_t; /*!< CPU time type */
#endif
#ifndef _TIME_T_
#if defined (__CC_ARM)
#define _TIME_T_ unsigned int
#else
#define _TIME_T_ unsigned long
#endif
typedef _TIME_T_ time_t; /*!< date/time in unix secs past 1-Jan-70 type for 68 years*/
#endif
/*
* Helper macros
*/
#define _CLOCK_T_MAX_VALUE_ (ULONG_MAX) //!< Helper macro for maximum signed CPU time calculations
/*!
* Calculate the positive time difference of _t2_ and _t1_, where
* _t1_, _t2_ are clock_t values
* \note
* _t2_ event comes is AFTER _t1_
*
* ex:
* 0 1 2 3 4 5 6 7 8 9
* ^ ^
* | |
* a b
*
* if : t1=a, t2=b then dt = b-a = t2 - t1
* if : t1=b, t2=a then dt = 9 - (b-a) + 1 = UMAX - (t1-t2) + 1
*
*/
#define _CLOCK_DIFF(_t2_, _t1_) ( ((_t2_)>(_t1_)) ? ((_t2_)-(_t1_)) : (_CLOCK_T_MAX_VALUE_ - ((_t1_) - (_t2_)) + 1) )
/*
* CPU time macros
*/
#define msec2CPUtime(_ms_) (((_ms_) * get_freq()) / 1000)
#define sec2CPUtime(_s_) ((_s_) * get_freq())
#define CPUtime2msec(_t_) (((_t_) * 1000) / get_freq())
#define CPUtime2sec(_t_) ((_t_) / get_freq())
HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf);
clock_t HAL_SelectSysTickFreq (clock_t sf);
clock_t HAL_GetSysTickFreq (void);
int HAL_SetSysTickFreq (clock_t sf);
/*
* ================ Jiffies =====================
*/
#define JF_TIMER TIM5
#define JF_TIM_CLOCK_FREQ (1000000) //1MHz it's OK
#define JF_TIM_VALUE (JF_TIMER->CNT)
#define JF_TIMER_CLK_ENABLE __HAL_RCC_TIM5_CLK_ENABLE
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies);
/*
* OS like Functionalities
*/
clock_t get_freq (void);
int set_freq (clock_t sf);
clock_t clock (void);
clock_t setclock (clock_t c);
time_t time (time_t *timer);
int settime (const time_t *t);
/*
* ============== Cycle count ==============
*/
LLD_Status_en CYCLE_Init (void);
clock_t CYCLE_Get (void);
uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin);
uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st);
/*
* =============== Digital I/O ===============
* BTN -- PC13
* LED -- PA5 (SB42 is in place) [SB29: PB13]
*/
LLD_Status_en NUCLEO_Port_Init (void);
uint8_t NUCLEO_BTN (void);
void NUCLEO_LED (uint8_t on);
/*
* ============= Board Init ==============
*/
LLD_Status_en NUCLEO_Init (clock_t sys_freq);
#endif /* NUCLEO_F401RE_H_ */

View File

@ -0,0 +1,495 @@
/*!
* \file alcd.c
* \brief
* A target independent Alpharithmetic LCD driver
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#include "alcd.h"
static int _inc_x (alcd_t *alcd);
static int _dec_x (alcd_t *alcd);
static void _inc_y (alcd_t *alcd);
static void _dec_y (alcd_t *alcd);
static void _set_bus (alcd_t *alcd, int8_t db);
static void _write_data (alcd_t *alcd, int8_t data);
static void _command (alcd_t *alcd, uint8_t c);
static void _character (alcd_t *alcd, uint8_t c);
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y);
/*!
* \brief
* increase cursor's x position. Positions start from 1.
* If the cursor loops returns 1, else returns 0.
* \param alcd pointer to active alcd.
* \return Change line status
*/
static int _inc_x (alcd_t *alcd) {
int ret=0;
if (++alcd->c.x > alcd->columns) {
alcd->c.x = 1;
ret = 1;
}
return ret;
}
/*!
* \brief
* Decrease cursor's x position. Positions start from 1.
* If the cursor loops returns 1, else returns 0.
* \param alcd pointer to active alcd.
* \return none
*/
static int _dec_x (alcd_t *alcd) {
int ret = 0;
if (--alcd->c.x < 1) {
alcd->c.x = alcd->columns;
ret = 1;
}
return ret;
}
/*!
* \brief
* increase cursor's y position. Positions start from 1.
* \param alcd pointer to active alcd.
* \return none
*/
static void _inc_y (alcd_t *alcd) {
if (++alcd->c.y > alcd->lines) {
alcd->c.y = 1;
}
}
/*!
* \brief
* Decrease cursor's y position. Positions start from 1.
* \param alcd pointer to active alcd.
* \return none
*/
static void _dec_y (alcd_t *alcd) {
if (--alcd->c.y < 1) {
alcd->c.y = alcd->lines;
}
}
/*!
* \brief
* Update the bus I/O and send it to the device.
* \param alcd pointer to active alcd.
* \param db the bus data.
* \return none
*/
static void _set_bus (alcd_t *alcd, int8_t db)
{
alcd->io.db4 (db & 0x01); //Update port
alcd->io.db5 (db & 0x02);
alcd->io.db6 (db & 0x04);
alcd->io.db7 (db & 0x08);
jf_delay_us (10); // Wait to settle
alcd->io.en (1); // Pulse out the data
jf_delay_us (10);
alcd->io.en (0);
jf_delay_us (10); // Data hold
}
/*!
* \brief
* Write the byte date to the bus using _set_bus ()
* \param alcd pointer to active alcd.
* \param data the data byte.
* \return none
*/
static void _write_data (alcd_t *alcd, int8_t data)
{
_set_bus (alcd, data >> 4);
_set_bus (alcd, data & 0x0F);
}
/*!
* \brief
* Send a command to alcd
* \param alcd pointer to active alcd.
* \param c the command byte.
* \return none
*/
static void _command (alcd_t *alcd, uint8_t c)
{
alcd->io.rs(0); // Enter command mode
jf_delay_us (100); // Wait
_write_data (alcd, c); // Send
}
/*!
* \brief
* Send a character to alcd
* \param alcd pointer to active alcd.
* \param c the character byte.
* \return none
*/
static void _character (alcd_t *alcd, uint8_t c)
{
alcd->io.rs(1); // Enter character mode
jf_delay_us (100); // Wait
_write_data (alcd, c); // Send
}
/*!
* \brief
* Set the Cursor to LCD's position line (y), column (x) starts from 1,2,...n
* \param alcd pointer to active alcd.
* \param x the x position.
* \param y the y position.
* \return none
*/
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y)
{
uint8_t cmd;
alcd->c.x = x; // Update alcd data
alcd->c.y = y;
// Calculate address
switch (y) {
default:
case 1: cmd = 0x0; break;
case 2: cmd = 0x40; break;
case 3: cmd = 0x0 + alcd->columns; break;
case 4: cmd = 0x40 + alcd->columns; break;
}
cmd |= (x - 1);
// Calculate command
cmd |= LCD_DDRAMMask;
// Command out the alcd
_command (alcd, cmd);
}
/*
* ============================ Public Functions ============================
*/
/*
* Link and Glue functions
*/
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB4 pin function
* \return none
*/
inline void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db4 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB5 pin function
* \return none
*/
inline void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db5 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB6 pin function
* \return none
*/
inline void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db6 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB7 pin function
* \return none
*/
inline void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db7 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's RS pin function
* \return none
*/
inline void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.rs = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's EN pin function
* \return none
*/
inline void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.en = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's BL pin function
* \return none
*/
inline void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.bl = pfun; }
/*!
* \brief
* Send an ascii character to alcd.
* \param alcd pointer to active alcd.
* \param ch the character to send
* \return the character send.
*
* \note
* This is the driver's "putchar()" functionality to glue.
* Tailor this function to redirect stdout to alcd.
*/
int alcd_putchar (alcd_t *alcd, int ch)
{
alcd->status = DRV_BUSY;
// LCD Character dispatcher
switch (ch) {
case 0:
// don't send null termination to device
break;
case '\n':
_inc_y (alcd);
//break; This "no break" is intentional
case '\r':
_set_cursor (alcd, 1, alcd->c.y);
break;
case '\v':
alcd->c.x = alcd->c.y = 1;
_command (alcd, LCD_RETHOME);
jf_delay_us(2000);
break;
case '\f':
//alcd->c.x = alcd->c.y = 1;
_set_cursor (alcd, 1, 1);
//_command (alcd, LCD_CLRSCR);
//jf_delay_us(5000);
//_command (alcd, LCD_RETHOME);
//_set_cursor (alcd, alcd->c.x, alcd->c.y);
jf_delay_us(2000);
break;
case '\b':
if (_dec_x (alcd)) _dec_y (alcd);
_set_cursor (alcd, alcd->c.x, alcd->c.y);
_character (alcd, ' ');
_set_cursor (alcd, alcd->c.x, alcd->c.y);
break;
default:
_character (alcd, ch);
// Increase cursor and loop inside the same line
if (_inc_x (alcd)) _set_cursor (alcd, alcd->c.x, alcd->c.y);
break;
}
// Restore status
alcd->status = DRV_READY;
//ANSI C (C99) compatible mode
return ch;
}
/*
* Set functions
*/
/*!
* \brief
* Set the number of lines for the attached lcd display
* \param alcd pointer to active alcd.
* \param lines The number of lines (usually 2 or 4)
* \return None.
*/
void alcd_set_lines (alcd_t *alcd, int lines) {
alcd->lines = lines;
}
/*!
* \brief
* Set the number of columns for the attached lcd display
* \param alcd pointer to active alcd.
* \param lines The number of columns (usually 16 or 20)
* \return None.
*/
void alcd_set_columns (alcd_t *alcd, int columns) {
alcd->columns = columns;
}
/*
* User Functions
*/
/*!
* \brief
* De-initialize the alcd.
* \param alcd pointer to active alcd.
* \return none
*/
void alcd_deinit (alcd_t *alcd)
{
memset ((void*)alcd, 0, sizeof (alcd_t));
/*!<
* This leaves the status DRV_NOINIT
*/
}
/*!
* \brief
* Initialize the alcd.
* \param alcd pointer to active alcd.
* \return Zero on success, non zero on error
*/
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs)
{
#define _lcd_assert(_x) if (!_x) return alcd->status = DRV_ERROR;
drv_status_en st = jf_probe ();
if (st == DRV_NODEV || st == DRV_BUSY)
return alcd->status = DRV_ERROR;
_lcd_assert (alcd->io.db4);
_lcd_assert (alcd->io.db5);
_lcd_assert (alcd->io.db6);
_lcd_assert (alcd->io.db7);
_lcd_assert (alcd->io.rs);
_lcd_assert (alcd->io.en);
//_lcd_assert (alcd->io.bl);
/*
* We are here, so all its OK. We can (re)initialize alcd.
*/
alcd->status = DRV_NOINIT;
alcd->c.x = alcd->c.y = 1;
alcd->io.en (0);
alcd->io.rs (0);
jf_delay_us (100000);
//Pre-Init phase 8bit at this point
_set_bus (alcd, 0x3);
jf_delay_us(50000);
_set_bus (alcd, 0x3);
jf_delay_us(5000);
_set_bus (alcd, 0x3);
jf_delay_us(5000);
_set_bus (alcd, 0x2); //4bit selection
jf_delay_us(10000);
_command (alcd, fs); //4bit selection and Function Set
jf_delay_us(5000);
_command (alcd, LCD_DISP_OFF); //Display Off Control 4bit for now on
jf_delay_us(5000);
_command (alcd, LCD_CLRSCR); //Clear Display
jf_delay_us(5000);
_command (alcd, LCD_ENTRYMODE); //Entry Mode Set
jf_delay_us(5000);
_command (alcd, LCD_RETHOME);
jf_delay_us(10000);
_command (alcd, LCD_DISP_ON);
jf_delay_us(5000);
//alcd_backlight (alcd, 1);
return alcd->status = DRV_READY;
#undef _lcd_assert
}
/*!
* \brief
* Enables and disables the lcd backlight.
* \param alcd pointer to active alcd.
* \param on
* \arg 0 disable the backlight
* \arg 1 enable the backlight
* \return none
*/
void alcd_backlight (alcd_t *alcd, uint8_t on) {
if (alcd->io.bl)
alcd->io.bl ((on)?1:0);
}
/*!
* \brief
* Enables and disables the entire lcd (+backlight).
* \param alcd pointer to active alcd.
* \param on
* \arg 0 disable the backlight
* \arg 1 enable the backlight
* \return none
*/
void alcd_enable (alcd_t *alcd, uint8_t on)
{
if (on) {
_command (alcd, LCD_DISP_ON);
alcd_backlight (alcd, 1);
} else {
_command (alcd, LCD_DISP_OFF);
alcd_backlight (alcd, 0);
}
}
/*!
* \brief
* Clears screen and returns cursor at home position (1,1).
* \param alcd pointer to active alcd.
* \return none
*/
void alcd_cls (alcd_t *alcd)
{
_command(alcd, LCD_CLRSCR);
jf_delay_us(2000);
_command (alcd, LCD_RETHOME);
jf_delay_us(2000);
}
/*!
* \brief
* Shift alcd left or right for a \a pos characters.
* \param alcd pointer to active alcd.
* \param pos The number of position to shift.
* A positive number shifts lcd data to left, so screen shows the data in the right.
* A negative number shifts lcd data to right, so screen shows the data in the left.
* \return none
*/
void alcd_shift (alcd_t *alcd, int pos)
{
uint8_t i, cmd = LCD_SHIFT_LEFT;
if (pos<0) {
pos = -pos;
cmd = LCD_SHIFT_RIGHT;
}
for (i=0 ; i<pos ; ++i) {
_command (alcd, cmd);
jf_delay_us(100);
}
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
_command (alcd, LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
_character (alcd, charmap[i]);
}
}

View File

@ -0,0 +1,177 @@
/*!
* \file alcd.c
* \brief
* A target independent Alpharithmetic LCD driver
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef __alcd_h__
#define __alcd_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "jiffies.h"
#include "driver_types.h"
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
/*
* General Defines
*/
#define ALCD_CLOCK (CLOCK)
/*!
* ----------------------------------------------------
* Hitachi HD44780 - Samsung KS0066U
* ----------------------------------------------------
*
*
* Entry Mode Set -----> 0 0 0 0 0 1 I/D S
* ----------------------------------------------------
* I/D = 1 -->Inciment Curs I/D = 0 Decriment
* S = 1 -->Display shift S = 0 Not
*
*
* DispOnOffControll --> 0 0 0 0 1 D C B
* -------------------------------------------------
* D = Display On
* C = Cursor On
* B = Blinking On
*
*
* Cursor/Display Shift --> 0 0 0 1 S/C R/L x x
* ---------------------------------------------------
* S/C = 1 -->Display Shift S/C = 0 -->Cursor Shift
* R/L = 1 -->Shift Right R/L = 0 -->Shift left
*
*
* FunctionSet ------> 0 0 1 DL N F x x
* ---------------------------------------------------
* DL = 1 -->8bit DL = 0 -->4bit
* N = 1 -->2 lines N = 0 -->1 line
* F = 1 -->5x10 dots F = 0 -->5x8 dots
*
*/
//#define LCD_LINES (4)
//#define LCD_ROWS (16)
#define LCD_CLRSCR (0x01) /*!< Clear Srean Command Number */
#define LCD_RETHOME (0x02) /*!< Cursor home Un-Shift display DDRam as is */
#define LCD_ENTRYMODE (0x06) /*!< Inc Cursor, Don't shift display */
#define LCD_DISP_ON (0x0C) /*!< No Cursos and Blink */
#define LCD_DISP_OFF (0x08)
#define LCD_CUR_DISP (0x14) /*!< Cursor shift right */
#define LCD_FUNSET_2L8 (0x28) /*!< 4bit, 2lines, 5x8 dots */
#define LCD_FUNSET_1L8 (0x20) /*!< 4bit, 1lines, 5x8 dots */
#define LCD_FUNSET_1L10 (0x24) /*!< 4bit, 1lines, 5x10 dots */
#define LCD_SETCGRAMADDR (0x40)
#define LCD_DDRAMMask (0x80) /*!< DDRAM ------------> 1 ADD[7..0] */
#define LCD_BFMask (0x80) /*!< IR ------------> BF AC[6..0] */
#define LCD_ACMask (0x7f) /*!< ____________________________| */
#define LCD_SHIFT_RIGHT (0x1C)
#define LCD_SHIFT_LEFT (0x18)
typedef enum {
ALCD_1Line_5x8 = LCD_FUNSET_1L8,
ALCD_1Line_5x10 = LCD_FUNSET_1L10,
ALCD_2Lines_5x8 = LCD_FUNSET_2L8
} alcd_funset_en;
/*!
* Alpharithmetic LCD Cursor
*/
typedef volatile struct
{
uint8_t x;
uint8_t y;
}alcd_cursor_t;
/*!
* Alpharithmetic LCD Pin assignements.
* Each one can be called xx.DB4(1); or xx.DB4(0); in order to set
* or clear the corresponding pin.
*
* \note These pointers MUST to be assigned from main application.
*/
typedef volatile struct
{
//drv_pinout_ft db0;
//drv_pinout_ft db1;
//drv_pinout_ft db2;
//drv_pinout_ft db3;
drv_pinout_ft db4; /*!< Pointer for DB4 pin */
drv_pinout_ft db5; /*!< Pointer for DB5 pin */
drv_pinout_ft db6; /*!< Pointer for DB6 pin */
drv_pinout_ft db7; /*!< Pointer for DB7 pin */
drv_pinout_ft rs; /*!< Pointer for RS pin */
drv_pinout_ft en; /*!< Pointer for EN pin */
drv_pinout_ft bl; /*!< Pointer for Back Light pin*/
}alcd_io_t;
/*!
* Alpharithmetic LCD Public Data struct
*/
typedef volatile struct
{
alcd_io_t io; //!< Link to IO struct
alcd_cursor_t c; //!< Link to Cursor struct
uint8_t lines; //!< The lines of attached lcd
uint8_t columns; //!< The columns of attached lcd
//uint8_t bus; //!< Bus length, 4 or 8 bit
drv_status_en status; //!< alcd driver status
}alcd_t;
/*
* ============= PUBLIC ALCD API =============
*/
/*
* Link and Glue functions
*/
void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun);
int alcd_putchar (alcd_t *alcd, int ch);
/*
* Set functions
*/
void alcd_set_lines (alcd_t *alcd, int lines);
void alcd_set_columns (alcd_t *alcd, int columns);
/*
* User Functions
*/
void alcd_deinit (alcd_t *alcd); /*!< For compatibility */
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs); /*!< For compatibility */
void alcd_backlight (alcd_t *alcd, uint8_t on); /*!< For compatibility */
void alcd_enable (alcd_t *alcd, uint8_t on); /*!< For compatibility */
void alcd_cls (alcd_t *alcd); /*!< For compatibility */
void alcd_shift (alcd_t *alcd, int pos); /*!< For compatibility */
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[]);
#ifdef __cplusplus
}
#endif
#endif //#ifndef __alcd_h__

View File

@ -0,0 +1,211 @@
/*!
* \file deque08.c
* \brief
* This file provides double ended queue capability based on a ring buffer
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#include "deque08.h"
/*
* ============= Private Queue API =============
*/
static iterator_t _preInc(deque08_t *q, iterator_t* it) {
return (++*it >= q->capacity) ? *it=0 : *it;
}
static iterator_t _preDec(deque08_t *q, iterator_t* it) {
return (--*it < 0) ? *it=q->capacity-1 : *it;
}
static iterator_t _postInc(deque08_t *q, iterator_t* it) {
iterator_t ret = *it;
if (++*it >= q->capacity) *it=0;
return ret;
}
static iterator_t _postDec(deque08_t *q, iterator_t* it) {
iterator_t ret = *it;
if (--*it < 0) *it=q->capacity-1;
return ret;
}
/*
* ============= Public Queue API =============
*/
/*
* Link and Glue functions
*/
void deque08_link_buffer (deque08_t *q, byte_t* buf) {
q->m = buf;
}
/*
* Set functions
*/
inline void deque08_set_capacity (deque08_t *q, size_t capacity) {
q->capacity = capacity;
}
/*
* User Functions
*/
/*!
* \brief
* Check if deque is full
* \param q Which deque to check
* \return
* \arg 0 Not full
* \arg 1 Full
*/
int deque08_is_full (deque08_t *q) {
return (q->items == q->capacity) ? 1:0;
}
/*!
* \brief
* Check if deque is empty
* \param q Which deque to check
* \return
* \arg 0 Not empty
* \arg 1 Empty
*/
int deque08_is_empty (deque08_t *q) {
return (q->items) ? 0:1;
}
/*!
* \brief
* Return the number of items on deque
* \param q Which deque to check
*/
int deque08_size (deque08_t *q) {
return q->items;
}
/*!
* \brief
* Discard all items in deque
* \param q Which deque to check
*/
void deque08_flush (deque08_t *q) {
deque08_init(q);
}
/*!
* \brief
* Initialize the queue
* \param queue Which queue to init
*/
void deque08_init (deque08_t *q) {
q->f = 0;
q->r = -1;
q->items =0;
}
/*!
* \brief
* This function push a byte in front of deque.
* \param q Pointer to deque to use
* \param b byte to push
* \return
* \arg 0 Full queue
* \arg 1 Done
*/
int deque08_push_front (deque08_t *q, byte_t b) {
if (deque08_is_full (q) == 1) //full queue
return 0;
q->m [_preDec (q, &q->f)] = b;
++q->items;
return 1;
}
/*!
* \brief
* This function pops a byte from the front of the deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_pop_front (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [_postInc (q, &q->f)];
--q->items;
return 1;
}
/*!
* \brief
* This function push a byte in the back of deque.
* \param q Pointer to deque to use
* \param b byte to push
* \return
* \arg 0 Full queue
* \arg 1 Done
*/
int deque08_push_back (deque08_t *q, byte_t b) {
if (deque08_is_full (q) == 1) //full queue
return 0;
q->m [_preInc (q, &q->r)] = b;
++q->items;
return 1;
}
/*!
* \brief
* This function pops a byte from the back of the deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_pop_back (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [_postDec (q, &q->r)];
--q->items;
return 1;
}
/*!
* \brief
* This function gives the last item in the back of deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_back (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [q->r];
return 1;
}
/*!
* \brief
* This function gives the first item in the front of deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_front (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [q->f];
return 1;
}

View File

@ -0,0 +1,65 @@
/*!
* \file deque08.h
* \brief
* This file provides double ended queue capability based on a ring buffer
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef __deque08_h__
#define __deque08_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "driver_types.h"
#include <string.h>
typedef struct {
byte_t *m; /*!< pointer to queue's buffer */
iterator_t capacity; /*!< queue's max item capacity */
iterator_t items; /*!< current item count */
iterator_t f, r; /*!< queue iterators */
}deque08_t;
/*
* ============= PUBLIC EE API =============
*/
/*
* Link and Glue functions
*/
void deque08_link_buffer (deque08_t *q, byte_t* buf);
/*
* Set functions
*/
void deque08_set_capacity (deque08_t *q, size_t capacity);
/*
* User Functions
*/
int deque08_is_full (deque08_t *q);
int deque08_is_empty (deque08_t *q);
int deque08_size (deque08_t *q);
void deque08_flush (deque08_t *q);
void deque08_init (deque08_t *q);
int deque08_push_front (deque08_t *q, byte_t b);
int deque08_pop_front (deque08_t *q, byte_t *b);
int deque08_push_back (deque08_t *q, byte_t b);
int deque08_pop_back (deque08_t *q, byte_t *b);
int deque08_back (deque08_t *q, byte_t *b);
int deque08_front (deque08_t *q, byte_t *b);
#ifdef __cplusplus
}
#endif
#endif //#ifndef __deque08_h__

View File

@ -0,0 +1,64 @@
/*!
* \file driver_types.h
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef DRIVERS_DRIVER_TYPES_H_
#define DRIVERS_DRIVER_TYPES_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef uint8_t byte_t; /*!< 8 bits wide */
typedef uint16_t word_t; /*!< 16 bits wide */
typedef uint32_t dword_t; /*!< 32 bits wide */
typedef int32_t iterator_t; /*!< general iterator type */
/*!
* This is a driver wide generic driver status type.
* \note
* DRV_NOINIT = 0, so after memset to zero called by XXXX_deinit() the
* module/device will automatically set to NOINIT state.
*/
typedef enum {
DRV_NODEV=-1, /*!< No device/module */ //!< DRV_NODEV
DRV_NOINIT=0, /*!< Module/Device exist but no initialized *///!< DRV_NOINIT
DRV_READY, /*!< Module/Device initialized succesfully */ //!< DRV_READY
DRV_BUSY, /*!< Module/Device busy */ //!< DRV_BUSY
//DRV_COMPLETE, /*!< Module/device operation complete status */
DRV_ERROR /*!< Module/Device error */ //!< DRV_ERROR
}drv_status_en;
typedef enum {
drv_pin_disable = 0,
drv_pin_input,
drv_pin_output
}drv_pin_dir_en;
/*!
* Pin function pointers
* \note
* These function pointers do not correspond to pin levels.
* They correspond to the enable/disable functionality of that pin.
*/
//! @{
typedef uint8_t (*drv_pinin_ft) (void);
typedef void (*drv_pinout_ft) (uint8_t);
typedef uint8_t (*drv_pinio_ft) (uint8_t);
typedef void (*drv_pindir_ft) (drv_pin_dir_en);
//! @}
#ifdef __cplusplus
}
#endif
#endif /* DRIVERS_DRIVER_TYPES_H_ */

View File

@ -0,0 +1,221 @@
/*!
* \file hal.c
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#include "hal.h"
/*
* Public data types / classes
*/
alcd_t alcd;
ow_uart_t ow;
proximity_t prox;
/*!
* Initialize all hardware
*/
int hal_hw_init (void) {
// Init base board
NUCLEO_Init(1000);
SHIELD_Init ();
// Start Jiffy functionality
jf_link_setfreq (JF_setfreq);
jf_link_value ((jiffy_t*)&JF_TIM_VALUE);
jf_init (JF_TIM_CLOCK_FREQ, 1000);
return 0;
}
/*
* ========== LCD ===========
*/
/*!
* \brief
* Initialize the lcd data. Not the LCD module
*/
void lcd_init (void) {
alcd_link_db4 (&alcd, SHIELD_LCD_DB4);
alcd_link_db5 (&alcd, SHIELD_LCD_DB5);
alcd_link_db6 (&alcd, SHIELD_LCD_DB6);
alcd_link_db7 (&alcd, SHIELD_LCD_DB7);
alcd_link_rs (&alcd, SHIELD_LCD_RS);
alcd_link_en (&alcd, SHIELD_LCD_EN);
alcd_link_bl (&alcd, SHIELD_LCD_BL);
alcd_set_lines (&alcd, 2);
alcd_set_columns (&alcd, 16);
alcd_init (&alcd, (alcd_funset_en)LCD_FUNSET_2L8);
}
//! lcd enable wrapper
__INLINE void lcd_enable (uint8_t en) {
alcd_enable(&alcd, en);
}
//!< lcd putchar wrapper
__INLINE int lcd_putchar (char c) {
return alcd_putchar(&alcd, c);
}
//! lcd puts wrapper
int lcd_puts (const char *s) {
int i =0;
while (alcd_putchar(&alcd, *s++))
++i;
return i;
}
/*
* ========== Led interface ==========
*/
__INLINE void led_red (uint8_t en) { LED_RED (en); }
__INLINE void led_green (uint8_t en) { LED_GREEN (en); }
/*
* ========= Relay ===========
*/
/*!
* Create pulses to re-state reay coil
*/
void relay (uint8_t on) {
switch (on) {
case 0:
SHIELD_BR1(1);
HAL_Delay(100);
SHIELD_BR1(0);
break;
default:
SHIELD_BR2(1);
HAL_Delay(100);
SHIELD_BR2(0);
break;
}
}
/*
* ========= Temperature ===========
*/
uint8_t ds18b20_rom[8];
uint8_t zero_rom[8] = {0};
/*!
* Initialize temperature measurement system
*/
int temp_init (uint8_t resolution) {
if (!IS_TEMP_RESOLUTION(resolution))
return 1;
// link with hardware
ow_uart_link_rw (&ow, (ow_uart_rw_ft)SHIELD_1W_RW);
ow_uart_link_br (&ow, (ow_uart_br_ft)SHIELD_1W_UART_BR);
ow_uart_set_timing (&ow, OW_UART_T_STANDARD);
ow_uart_init (&ow); // init
ow_uart_search(&ow, ds18b20_rom);// do a search
if (!memcmp ((const void*)ds18b20_rom, (const void*)zero_rom, 8))
return 1; // if there is no DS18b20 error
// set resolution to 9-bit
ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, WRITESCRATCH); // write scratchpad
ow_uart_tx (&ow, (byte_t)127); // Th
ow_uart_tx (&ow, (byte_t)-128); // Tl
ow_uart_tx (&ow, resolution); // Configuration 9 bit
HAL_Delay(100);
return 0;
}
/*!
* Temperature read functionality
*/
float temp_read (void) {
uint8_t t[2];
ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, STARTCONV); // convert temperature
while (ow_uart_rx(&ow) == 0) // Wait for slave to free the bus
;
//HAL_Delay (100);
ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, READSCRATCH); // read scratchpad
t[0] = ow_uart_rx(&ow); // LSB
t[1] = ow_uart_rx(&ow); // MSB
ow_uart_reset(&ow);
t[1] <<= 4;
t[1] |= (t[0] >> 4);
t[0] &= 0x0F;
return t[1] + t[0]/16.0;
}
/*
* ========= Proximity ===========
*/
/*!
* Initialize proximity system
* \param p Which proximity object to initialize
*/
void proximity_init (proximity_t* p){
for (int i =0 ; i<PROX_READINGS ; ++i)
proximity(p);
}
/*!
* Read proximity value in [cm]
* \note
* This function also implements an embedded averaging filter
* @param p Which proximity object to use
* @return The measured distance
*/
float_t proximity (proximity_t* p){
float_t ret;
clock_t t1, t2, mark;
SHIELD_TRIG(1); // send pulse and mark cycles
jf_delay_us(10);
SHIELD_TRIG(0);
// wait for response with timeout
mark = clock();
do {
t1 = CYCLE_Get();
if (clock() - mark >= PROX_TIME_MAX)
return -1;
} while (!SHIELD_ECHO());
mark = clock();
do {
t2 = CYCLE_Get();
if (clock() - mark >= PROX_TIME_MAX)
return -1;
} while (SHIELD_ECHO());
// Calculate distance
SystemCoreClockUpdate();
uint32_t c_usec = SystemCoreClock / 1000000;
// Load value
p->readings[p->iter++] = (c_usec) ? ((t2 - t1)/c_usec) / 58.2 : PROX_MAX_DISTANSE;
p->iter %= PROX_READINGS;
// Return filtered distance (moving average filter FIR)
ret =0;
for (int i=0 ; i<PROX_READINGS ; ++i)
ret += p->readings[i];
return ret/PROX_READINGS;
}

View File

@ -0,0 +1,97 @@
/*!
* \file hal.h
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef DRIVERS_HAL_H_
#define DRIVERS_HAL_H_
#include <thermostat_shield.h>
#include <alcd.h>
#include <jiffies.h>
#include <onewire_uart.h>
#include <deque08.h>
#include <thermostat.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
int hal_hw_init (void);
/*
* ========== LCD ===========
*/
void lcd_init (void);
void lcd_enable (uint8_t en) ;
int lcd_putchar (char c);
int lcd_puts (const char *s);
/*
* ========== Led interface ==========
*/
void led_red (uint8_t en);
void led_green (uint8_t en);
/*
* ========= Relay ===========
*/
void relay(uint8_t on);
/*
* ========= Temperature ===========
*/
// OneWire commands
#define SKIPROM 0xCC // Skip ROM matching transition
#define STARTCONV 0x44 // Tells device to take a temperature reading and put it on the scratchpad
#define COPYSCRATCH 0x48 // Copy EEPROM
#define READSCRATCH 0xBE // Read EEPROM
#define WRITESCRATCH 0x4E // Write to EEPROM
#define RECALLSCRATCH 0xB8 // Reload from last known
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition
// Device resolution
#define TEMP_9_BIT 0x1F // 9 bit
#define TEMP_10_BIT 0x3F // 10 bit
#define TEMP_11_BIT 0x5F // 11 bit
#define TEMP_12_BIT 0x7F // 12 bit
#define IS_TEMP_RESOLUTION(x) \
((x == TEMP_9_BIT) || (x == TEMP_10_BIT) || (x == TEMP_11_BIT) || (x == TEMP_12_BIT))
int temp_init (uint8_t resolution);
float temp_read (void);
/*
* ========= Proximity ===========
*/
#define PROX_TIME_MAX 25 // [msec]
#define PROX_READINGS 7 // How many readings for averaging
#define PROX_MAX_DISTANSE 450 // [cm]
typedef struct {
float_t readings[7];
int iter;
} proximity_t;
void proximity_init (proximity_t* p);
float_t proximity (proximity_t* p);
/*
* Public data types / classes
*/
extern alcd_t alcd;
extern ow_uart_t ow;
extern proximity_t prox;
#ifdef __cplusplus
}
#endif
#endif /* DRIVERS_HAL_H_ */

View File

@ -0,0 +1,355 @@
/*!
* \file jiffies.c
* \brief
* A target independent jiffy functionality
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#include "jiffies.h"
static jf_t _jf;
#define JF_MAX_TIM_VALUE (0xFFFF) // 16bit counters
/*
* ====================== Public functions ======================
*/
/*
* Link and Glue functions
*/
/*!
* \brief
* Connect the Driver's Set frequency function to jiffy struct
* \note
* This function get a freq value and returns the timers max jiffy value
* (usual this refers to timer'sauto reload value).
*/
void jf_link_setfreq (jf_setfreq_pt pfun) {
_jf.setfreq = (pfun != 0) ? pfun : 0;
}
/*!
* \brief
* Connect the timer's value to jiffy struct
*/
void jf_link_value (jiffy_t* v) {
_jf.value = (v != 0) ? v : 0;
}
/*
* User Functions
*/
/*!
* \brief
* Check jiffy's status
* \return status
*/
inline drv_status_en jf_probe (void) {
return _jf.status;
}
/*!
* \brief
* De-Initialize the jf data and un-connect the functions
* from the driver
*/
void jf_deinit (void)
{
if (_jf.setfreq) _jf.setfreq (0, 0);
memset ((void*)&_jf, 0, sizeof (jf_t));
_jf.status = DRV_NODEV;
}
/*!
* \brief
* Initialize the jf to a desired jiffy frequency
* \note
* This function has no effect if the inner jiffy struct
* is un-connected to driver. So you have to call
* \sa jf_connect_setfreq() and \sa jf_connect_value() first.
* \return The status of the operation
* \arg DRV_ERROR If the init process fail
* \arg DRV_NODEV If there is no linked jiffy HW, no setfreq function
* \arg DRV_READY Success
*/
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies)
{
if (_jf.setfreq) {
_jf.status = DRV_NOINIT;
if ( _jf.setfreq (jf_freq, jiffies) )
return DRV_ERROR;
_jf.jiffies = jiffies;
_jf.freq = jf_freq;
_jf.jp1ms = jf_per_msec ();
_jf.jp1us = jf_per_usec ();
_jf.jp100ns = jf_per_100nsec ();
return _jf.status = DRV_READY;
}
return _jf.status = DRV_NODEV;
}
/*!
* \brief
* Return the maximum jiffy value.
*/
jiffy_t jf_get_jiffies (void){
return _jf.jiffies;
}
/*!
* \brief
* Return the current jiffy value.
* \note
* Usual this function returns the value of a register from a timer peripheral
* in the MCU. Keep in mind that its value is a moving target!
*/
jiffy_t jf_get_jiffy (void){
return *_jf.value;
}
/*!
* \brief
* Return the systems best approximation for jiffies per msec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_msec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 1000);
/* 1
* 1000Hz = ----- , Its not a magic number
* 1msec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* Return the systems best approximation for jiffies per usec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_usec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 1000000);
/* 1
* 1000000Hz = ------ , Its not a magic number
* 1usec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* Return the systems best approximation for jiffies per usec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_100nsec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 10000000);
/* 1
* 10000000Hz = ------- , Its not a magic number
* 100nsec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 msec.
* \param msec Time in msec for delay
*/
void jf_delay_ms (jtime_t msec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
msec *= _jf.jp1ms;
// Eat the time difference from msec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
msec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (msec>0);
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param usec Time in usec for delay
*/
void jf_delay_us (jtime_t usec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
usec *= _jf.jp1us;
if ((jtime_t)(*_jf.value) - m1 > usec) // Very small delays may return here.
return;
// Eat the time difference from usec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
usec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (usec>0);
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 100 nsec.
* \param _100nsec Time in 100nsec for delay
*/
void jf_delay_100ns (jtime_t _100nsec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
_100nsec *= _jf.jp100ns;
if ((jtime_t)(*_jf.value) - m1 > _100nsec) // Very small delays may return here.
return;
// Eat the time difference from _100nsec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
_100nsec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (_100nsec>0);
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 msec.
* \param msec Time in msec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_msec (jtime_t msec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp1ms * msec;
}
// Eat the time difference from msec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param usec Time in usec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_usec (jtime_t usec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp1us * usec;
}
// Eat the time difference from usec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 100 nsec.
* \param
* _100nsec Time in 100nsec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_100nsec (jtime_t _100nsec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp100ns * _100nsec;
}
// Eat the time difference from _100nsec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}

View File

@ -0,0 +1,96 @@
/*!
* \file jiffies.h
* \brief
* A target independent jiffy functionality
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef __jiffies_h__
#define __jiffies_h__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include "driver_types.h"
typedef uint16_t jiffy_t; //!< Jiffy type 2 byte unsigned integer
typedef int32_t jtime_t; //!< Jiffy time type for delay functionalities usec/msec
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //!< Pointer to setfreq function \sa setfreq
/*!
* Jiffy inner structure,
* \info
* We use jiffies to count small time intervals and usually this is
* below SysTick Interrupt. So we use an indepentend counter for that.
* Linux names jiffies the Tick per sec. This is toooo big for us.
* We name jiffy each tick of the extra timer.
* The equalivent of linux jiffies is the return value of clock ().
*/
typedef volatile struct {
jf_setfreq_pt setfreq; /*!< Pointer to driver's timer set freq function */
/*
* \note
* This function must get an integer value for timer's desired
* frequency and returns the maximum jiffy value. This usual
* refers to timer's auto reload value.
*/
jiffy_t *value; /*!< Pointer to timers current value */
uint32_t freq; /*!< timer's frequency */
jiffy_t jiffies; /*!< jiffies max value (timer's max value) */
jiffy_t jp1ms; /*!< Jiffies per 1 msec to use in delay function */
jiffy_t jp1us; /*!< Jiffies per 1 usec to use in delay function */
jiffy_t jp100ns; /*!< Jiffies per 100 nsec to use in delay function */
drv_status_en status;
}jf_t;
/*
* ============= PUBLIC jiffy API =============
*/
/*
* Link and Glue functions
*/
void jf_link_setfreq (jf_setfreq_pt pfun);
void jf_link_value (jiffy_t* v);
/*
* Set functions
*/
/*
* User Functions
*/
drv_status_en jf_probe (void);
void jf_deinit (void);
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies);
jiffy_t jf_get_jiffies (void);
jiffy_t jf_get_jiffy (void);
jiffy_t jf_per_msec (void);
jiffy_t jf_per_usec (void);
jiffy_t jf_per_100nsec (void);
void jf_delay_ms (jtime_t msec);
void jf_delay_us (jtime_t usec);
void jf_delay_100ns (jtime_t _100nsec);
int jf_check_msec (jtime_t msec);
int jf_check_usec (jtime_t usec);
int jf_check_100nsec (jtime_t _100nsec);
/*!
* \note
* The Jiffy lib has no jiffy_t target pointer in the API. This means
* that IT CAN BE ONLY ONE jiffy timer per application.
*/
#ifdef __cplusplus
}
#endif
#endif //#ifndef __jiffies_h__

View File

@ -0,0 +1,527 @@
/*!
* \file onewire_uart.c
* \brief
* A target independent 1-wire implementation using a microprocessor's uart
* for bit timing
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#include "onewire_uart.h"
/*
* ========= Private helper macros ===========
*/
/*!
* Clear a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
*/
#define _clear_u64(_reg_) \
memset ((void*)(_reg_), 0, 8*sizeof(uint8_t))
/*!
* Read a bit value of a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
* \param _bit The bit location we want to read
*/
#define _read_bit_u64(_reg_, _bit_) \
(_reg_[(_bit_)/8] & (1<<((_bit_)%8))) ? 1:0
/*!
* Write/modify a bit value from a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
* \param _bit The bit location we want to set
* \param _v The value we want to set
* \arg 0 Set to zero
* \arg !0 Set to One
*/
#define _write_bit_u64(_reg_, _bit_, _v_) \
do { \
if (_v_) _reg_[(_bit_)/8] |= 1 << ((_bit_)%8); \
else _reg_[(_bit_)/8] &= ~(1 << ((_bit_)%8)); \
} while (0)
/*
* ============= Private functions ===========
*/
/* Data manipulation functions */
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2);
/* Set functions */
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st);
/* Bus functions */
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b);
static uint8_t _read_bit (ow_uart_t *ow);
/*!
* \brief
* Compare two 64bit virtual unsigned registers
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param reg1 Pointer to first register location. Usual the name of
* the array
* \param reg1 Pointer to 2nd register location. Usual the name of
* the array
* \return The comparison result
* \arg 0 Registers are equal
* \arg 1 Register 1 is larger than register 2
* \arg -1 Register 2 is larger than register 1
*/
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2) {
int i;
for (i=7 ; i>=0 ; --i) {
if (reg1[i] > reg2[i]) return 1; /* reg1 > reg2 */
else if (reg1[i] < reg2[i]) return -1; /* reg1 < reg2 */
}
return 0; /* reg1 equal reg2 */
}
/*!
* \brief
* Set UART Baudrate and handle all function calls and data
* manipulation
* \param ow Pointer to select 1-Wire structure for the operation.
* \param st The 1-Wire operational state \sa ow_uart_state_en
* \return The status of the operation
* \arg DRV_ERROR Could not set baudrate (callback pointer function error)
* \arg DRV_READY Success
*/
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st)
{
uint32_t st_br;
/* Get the desired baudrate */
switch (st) {
case OWS_RESET: st_br = ow->baudrate.reset; break;
default:
case OWS_OPER: st_br = ow->baudrate.oper; break;
}
if (ow->baudrate.current != st_br) {
if (ow->io.br (st_br) != DRV_READY) return DRV_ERROR;
ow->baudrate.current = st_br;
}
return DRV_READY;
}
/*!
* \brief
* Send a 1-Wire write bit
*
* --- --------------------------------------
* Write 1 \ /
* ----
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: 0xFF
*
* --- ------
* Write 0 \ /
* -------------------------------------
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0x00
* RX: 0x00
*
* \param ow Pointer to select 1-Wire structure for the operation.
* \param b The bit to send
* \return Status of the operation
* \arg 0 Success
* \arg 1 Fail
*/
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b)
{
uint8_t w;
uint16_t r;
/*
* Make sure we are at the right baudrate
*/
if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
return 1;
/* Select frame to send and check the bus by evaluating the return value */
w = (b) ? 0xFF : 0x00;
r = ow->io.rw (w);
if (r != w) return 1;
else return 0;
}
/*!
* \brief
* Read a bit from the 1-Wire bus, return it and provide
* the recovery time.
*
* --- - - - - - - - - - - - ------
* Read \ / X X X X X X X X X X X X X X X /
* ---- - - - - - - - - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* ^
* |
* Master sample
*
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
*
* \return The answer
* \arg 0 Read 0
* \arg 1 Read 1 (This is also returned on transition error).
*/
static uint8_t _read_bit (ow_uart_t *ow)
{
uint16_t r;
/*
* Make sure we are at the right baudrate
*/
if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
return 1;
/* Send frame for read */
r = ow->io.rw (0xFF);
/* Dispatch answer */
if (r < 0xFF) return 0;
else return 1;
}
/*
* ============= PUBLIC 1-Wire API =============
*/
/*
* Link and Glue functions
*/
/*!
* \brief link driver's UART read-write function
* \param ow pointer to select 1-Wire structure for the operation.
* \param tx ow_uart_rx_ft pointer to drivers UART rx function
*/
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft rw) {
ow->io.rw = (ow_uart_rw_ft)((rw != 0) ? rw : 0);
}
/*!
* \brief link driver's UART baudrate function
* \param ow pointer to select 1-Wire structure for the operation.
* \param tx ow_uart_tx_ft pointer to drivers UART baudrate function
*/
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br) {
ow->io.br = (ow_uart_br_ft)((br != 0) ? br : 0);
}
/*
* Set functions
*/
/*!
* \brief set 1-wire timing mode and update baudrate table.
* If the owt parameter is not a valid ow_uart_timing_en
* then set timings to OW_STANDTARD.
* \param ow pointer to select 1-Wire structure for the operation.
* \param owt Timing type
* \arg OWT_STANDARD Use standard timing
* \arg OWT_OVERDRIVE Use overdrive timing
*/
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt) {
ow->timing = (_ow_uart_is_timings(owt)) ? owt : OW_UART_T_STANDARD;
switch (owt) {
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
}
}
/*
* User Functions
*/
/*!
* \brief
* De-Initialize the 1-Wire interface and leave bus pin in input state
* \param ow pointer to select 1-Wire structure for the operation.
* \return none
*/
void ow_uart_deinit (ow_uart_t *ow)
{
// Clear data
memset ((void*)ow, 0, sizeof (ow_uart_t));
/*!<
* This leaves the status = DRV_NOINIT
*/
}
/*!
* \brief
* Initialize the 1-Wire interface and leave bus high
* \param ow pointer to select 1-Wire structure for the operation.
* \return The driver status after init.
* \arg DRV_READY
* \arg DRV_ERROR
*/
drv_status_en ow_uart_init (ow_uart_t *ow)
{
// Check requirements
if (!ow->io.rw) return ow->status = DRV_ERROR;
if (!ow->io.br) return ow->status = DRV_ERROR;
// Init the bus
ow->status = DRV_BUSY;
if ( _ow_uart_is_timings(ow->timing) != 1) {
ow->timing = OW_UART_T_STANDARD;
_ow_baudrate_standard (ow->baudrate);
}
switch (ow->timing) {
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
}
if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
return ow->status = DRV_ERROR;
return ow->status = DRV_READY;
}
/*!
* \brief
* Generate a 1-wire reset
*
* --- ---- - - - -------
* Reset \ / \ X X X /
* -------------------- - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ---------- 1024/174 usec ------------->
*
* 8 bits, no parity, 1 stop
* Standard: Overdrive :
* BR: 9600, BR: 57600
* TX: 0xF0, TX: 0xF8
* RX: 0xF0 not present RX: 0xF8 not present
* less if present less if present
*
* \note Does not handle alarm presence from DS2404/DS1994
* \param None
* \return The status of the operation
* \arg DRV_ERROR Error, callback baudrate error or bus error
* \arg DRV_NODEV If no presence detect was found
* \arg DRV_READY Otherwise
*/
drv_status_en ow_uart_reset (ow_uart_t *ow)
{
uint8_t w;
uint16_t r;
/*
* Make sure we are at the write baudrate
*/
if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
return DRV_ERROR;
/* Select frame to send */
w = (ow->timing == OW_UART_T_OVERDRIVE) ? 0xF8 : 0xF0;
r = ow->io.rw (w);
r = ow->io.rw (w); // Send it twice to make sure
if (w>r) return DRV_READY;
else if (w==r) return DRV_NODEV;
else return DRV_ERROR;
}
/*!
* \brief
* Read a byte from 1-Wire bus
* \param ow pointer to select 1-Wire structure for the operation.
* \return The byte received.
*/
uint8_t ow_uart_rx (ow_uart_t *ow)
{
uint8_t i;
byte_t byte;
for (i=8, byte=0 ; i>0 ; --i) {
byte >>= 1; /* shift bits to right as LSB comes first */
if (_read_bit (ow) != 0) byte |= 0x80; /* Mask bit to MSB */
}
return byte;
}
/*!
* \brief
* Write a byte to 1-Wire bus
* \param ow pointer to select 1-Wire structure for the operation.
* \param b: The byte to write
* \return none
*/
void ow_uart_tx (ow_uart_t *ow, byte_t byte)
{
uint8_t i;
for (i=8 ; i>0 ; --i) {
_write_bit (ow, byte & 0x01); /* Send LSB */
byte >>= 1; /* shift bits to right */
}
}
/*!
* \brief
* Write a byte to 1-Wire bus and read the response
* \param ow Pointer to select 1-Wire structure for the operation.
* \param byte The byte to write
* \return The byte received.
*/
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte)
{
uint8_t i;
byte_t ret;
for (i=8, ret=0 ; i>0 ; --i) {
ret >>= 1; /* shift read bits to right as LSB comes first */
if ((byte & 0x01) != 0) ret |= (_read_bit (ow) != 0) ? 0x80 : 0x0;
else _write_bit (ow, 0);
byte >>= 1; /* shift bits to right */
/*!<
* If the bit is 1 we use the read sequence, as it has the same
* waveform with write-1 and we get the slave response
* If the bit is 0, we can not read the slave response so we just write-0
*/
}
return byte;
}
/*!
* \brief
* 1-Wire search algorithm based on maxim-ic application note 187
*
* \param ow Pointer to select 1-Wire structure for the operation.
* \param romid Pointer to romid to return. If the search is success
* this points to and 64bit long array with ROM ID
* \return The status of the search
* \arg DRV_NODEV (-1) Search was failed, No device found
* \arg DRV_READY (1) Search is complete, all ROM IDs was found. This was the last
* \arg DRV_BUSY (2) Search is succeed, plus there are more ROM IDs to found
* \arg DRV_ERROR (3) Search failed, Reading error
*/
drv_status_en ow_uart_search (ow_uart_t *ow, uint8_t *romid)
{
static uint8_t dec[8]; /*!<
* Hold the algorithm's select bit when a discrepancy
* is detected. We use this variable to navigate to the
* ROM tree as we store the path we take each time (0-1).
* Each bit represent a bit position in the ROM ID.
*/
static uint8_t pos[8]; /*!<
* Hold the discrepancy position. We use this variable to
* navigate to the ROM tree as we store the crossroads(1) we encounter.
* Each bit represent a bit position in the ROM ID.
*/
uint8_t i, cur[8]; /* Current pass bit position, in a pos[8] like representation of it */
uint8_t b, b1, b2; /* bit helper vars */
if (ow_uart_reset (ow) != DRV_READY)
return DRV_NODEV;
ow_uart_tx (ow, 0xF0); /* Issue search command */
for (i=0 ; i<64 ; ++i) {
/* Get response pair bits */
b1 = _read_bit (ow);
b2 = _read_bit (ow);
switch (b1 | (b2<<1)) {
case 0x00: /* 00 - We have discrepancy */
_write_bit_u64 (cur, i, 1);
switch (_cmp_u64 (pos, cur)) {
default:
case -1: b = 0;
_write_bit_u64 (pos, i, 1); break;
case 0: b = 1;
_write_bit_u64 (dec, i, 1); break;
case 1: b = _read_bit_u64 (dec, i); break;
/*<
* -1) pos < cur: This discrepancy is the most far for now.
* Mark position and select 0.
* 0) pos == cur: This was the last discrepancy in the last pass.
* Select the other branch this time (1).
* 1) pos > cur: We had a discrepancy in a MSB than that, in a previous pass.
* Continue with the last pass decision.
*/
}
/* Send selection and update romid */
_write_bit (ow, b);
_write_bit_u64 (romid, i, b);
break;
case 0x01: /* 01 - All bits of all ROMs are 1s */
_write_bit (ow, 1);
_write_bit_u64 (romid, i, 1); break;
case 0x02: /* 10 - All bits of all ROMs are 0s */
_write_bit (ow, 0);
_write_bit_u64 (romid, i, 0); break;
default:
case 0x03: /* 11 - No device on the bus */
_clear_u64 (romid);
return DRV_NODEV;
} /* switch (b1 | (b2<<1)) */
} /* for */
switch (_cmp_u64 (dec, pos)) {
case -1: return DRV_BUSY;
case 0: _clear_u64 (dec);
_clear_u64 (pos);
return DRV_READY;
default:
case 1: _clear_u64 (dec);
_clear_u64 (pos);
return DRV_ERROR;
/*<
* -1) des < pos: We have more leafs(ROMs) to found
* 0) des == pos: We have found all the leafs(ROMs)
* 1) des > pos: We have more decision that discrepancies ?!?!?, Error.
*/
}
}
#undef _clear_u64
#undef _read_bit_u64
#undef _write_bit_u64
#undef _ow_is_timings

View File

@ -0,0 +1,194 @@
/*!
* \file onewire_uart.h
* \brief
* A target independent 1-wire implementation using a microprocessor's uart
* for bit timing
* \note
* This 1-wire implementation is based on MCU UART io functionality. In order
* to work it needs:
* 1) A Open drain tx and floating(or pull-up) rx UART pin configuration with both pins
* connected to the 1-wire bus wire
* 2) A Transmit function even in blocking/polling mode
* 3) A receive function even in blocking/polling mode
* 4) A baudrate set function
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*
*/
#ifndef __onewire_uart_h__
#define __onewire_uart_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "driver_types.h"
#include <string.h>
/* ================ General Defines ====================*/
typedef uint16_t (*ow_uart_rw_ft) (uint8_t); /*!< UART read-write function pointer */
typedef drv_status_en (*ow_uart_br_ft) (uint32_t); /*!< UART baudrate modify function pointer */
/*!
* 1-Wire operational state
*/
typedef enum {
OWS_RESET = 0, /*!< 1-Wire bus is during in Reset state */
OWS_OPER /*!< 1-Wire bus is during normal operation */
}ow_uart_state_en;
/*!
* 1-Wire UART baudrate table
*/
typedef struct {
uint32_t reset; /*!< Baudrate during reset */
uint32_t oper; /*!< Baudrate during normal operation */
uint32_t current; /*!< The current baudrate to use as flag */
}ow_uart_br_t;
/*!
* 1-Wire driver function callback pointers
* \note
* The function in this structure provided from the low level driver (usually).
*/
typedef struct {
ow_uart_rw_ft rw; /*!< Pointer UART read-write function */
ow_uart_br_ft br; /*!< Pointer to UART baudrate function */
}ow_uart_io_t;
/*!
* 1-Wire Data type
*/
typedef struct {
ow_uart_io_t io; /*!< Callback pointers and direction state */
uint32_t timing; /*!< The selected timing mode */
ow_uart_br_t baudrate; /*!< The current baudrate configuration */
drv_status_en status; /*!< Toolbox driver status */
}ow_uart_t;
/*
* ============ Helper Macros =============
*/
/*!
* 1-Wire speed
*/
#define OW_UART_T_STANDARD (0)
#define OW_UART_T_OVERDRIVE (1)
/*!
* Check if the timing is a valid \ref ow_uart_timing_en value
*/
#define _ow_uart_is_timings(_t_) ( ((_t_) == OW_UART_T_STANDARD) || ((_t_) == OW_UART_T_OVERDRIVE) )
/*
* Timing Diagram
* --------------------------------------------------
* Based on Application Note 214 (www.maxim-ic.com)
*
* --- ---- - - - -------
* Reset \ / \ X X X /
* -------------------- - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ---------- 1024/174 usec ------------->
*
* 8 bits, no parity, 1 stop
* Standard: Overdrive :
* BR: 9600, BR: 57600
* TX: 0xF0, TX: 0xF8
* RX: 0xF0 not present RX: 0xF8 not present
* less if present less if present
*
*
* --- --------------------------------------
* Write 1 \ /
* ----
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: 0xFF
*
* --- ------
* Write 0 \ /
* -------------------------------------
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0x00
* RX: 0x00
*
* --- - - - - - - - - - - - ------
* Read \ / X X X X X X X X X X X X X X X /
* ---- - - - - - - - - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* ^
* |
* Master sample
*
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
*
*/
#define _ow_baudrate_standard(_br_) \
do { \
_br_.reset = 9600; \
_br_.oper = 115200; \
_br_.current = 9600; \
} while (0)
#define _ow_baudrate_overdrive(_br_) \
do { \
_br_.reset = 115200; \
_br_.oper = 921600; \
_br_.current = 115200; \
} while (0)
/*
* ============= PUBLIC ALCD API =============
*/
/*
* Link and Glue functions
*/
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft tx); /*!< link driver's read-write function */
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br); /*!< link driver's baudrate function*/
/*
* Set functions
*/
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt); /*!< set 1-wire timing mode */
/*
* User Functions
*/
void ow_uart_deinit (ow_uart_t *ow); /*!< for compatibility */
drv_status_en ow_uart_init (ow_uart_t *ow); /*!< for compatibility */
drv_status_en
ow_uart_reset (ow_uart_t *ow);
uint8_t ow_uart_rx (ow_uart_t *ow);
void ow_uart_tx (ow_uart_t *ow, byte_t byte);
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte);
drv_status_en
ow_uart_search (ow_uart_t *ow, uint8_t *romid);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef __onewire_uart_h__ */

View File

@ -0,0 +1,495 @@
/**
******************************************************************************
* @file stm32f4xx_hal_conf_template.h
* @author MCD Application Team
* @brief HAL configuration template file.
* This file should be copied to the application folder and renamed
* to stm32f4xx_hal_conf.h.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_CONF_H
#define __STM32F4xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
#define HAL_CAN_MODULE_ENABLED
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
#define HAL_CRC_MODULE_ENABLED
#define HAL_CEC_MODULE_ENABLED
#define HAL_CRYP_MODULE_ENABLED
#define HAL_DAC_MODULE_ENABLED
#define HAL_DCMI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_DMA2D_MODULE_ENABLED
#define HAL_ETH_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_NAND_MODULE_ENABLED
#define HAL_NOR_MODULE_ENABLED
#define HAL_PCCARD_MODULE_ENABLED
#define HAL_SRAM_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
#define HAL_HASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_SMBUS_MODULE_ENABLED
#define HAL_I2S_MODULE_ENABLED
#define HAL_IWDG_MODULE_ENABLED
#define HAL_LTDC_MODULE_ENABLED
#define HAL_DSI_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_QSPI_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLED
#define HAL_SAI_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
#define HAL_IRDA_MODULE_ENABLED
#define HAL_SMARTCARD_MODULE_ENABLED
#define HAL_WWDG_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_PCD_MODULE_ENABLED
#define HAL_HCD_MODULE_ENABLED
#define HAL_FMPI2C_MODULE_ENABLED
#define HAL_SPDIFRX_MODULE_ENABLED
#define HAL_DFSDM_MODULE_ENABLED
#define HAL_LPTIM_MODULE_ENABLED
#define HAL_MMC_MODULE_ENABLED
/* ########################## HSE/HSI Values adaptation ##################### */
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */
#endif /* HSI_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSE) value.
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
/**
* @brief External clock source for I2S peripheral
* This value is used by the I2S HAL module to compute the I2S clock source
* frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined (EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY 0x0FU /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1U
#define INSTRUCTION_CACHE_ENABLE 1U
#define DATA_CACHE_ENABLE 1U
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* ################## Ethernet peripheral configuration ##################### */
/* Section 1 : Ethernet peripheral configuration */
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
#define MAC_ADDR0 2U
#define MAC_ADDR1 0U
#define MAC_ADDR2 0U
#define MAC_ADDR3 0U
#define MAC_ADDR4 0U
#define MAC_ADDR5 0U
/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
/* Section 2: PHY configuration section */
/* DP83848 PHY Address*/
#define DP83848_PHY_ADDRESS 0x01U
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY 0x000000FFU
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY 0x00000FFFU
#define PHY_READ_TO 0x0000FFFFU
#define PHY_WRITE_TO 0x0000FFFFU
/* Section 3: Common PHY Registers */
#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */
#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */
#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */
#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */
#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */
#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */
#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */
#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */
#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */
/* ################## SPI peripheral configuration ########################## */
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
* Activated: CRC code is present inside driver
* Deactivated: CRC code cleaned from driver
*/
#define USE_SPI_CRC 1U
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f4xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32f4xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32f4xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32f4xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f4xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32f4xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_CAN_MODULE_ENABLED
#include "stm32f4xx_hal_can.h"
#endif /* HAL_CAN_MODULE_ENABLED */
#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
#include "stm32f4xx_hal_can_legacy.h"
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32f4xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32f4xx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */
#ifdef HAL_DMA2D_MODULE_ENABLED
#include "stm32f4xx_hal_dma2d.h"
#endif /* HAL_DMA2D_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32f4xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_DCMI_MODULE_ENABLED
#include "stm32f4xx_hal_dcmi.h"
#endif /* HAL_DCMI_MODULE_ENABLED */
#ifdef HAL_ETH_MODULE_ENABLED
#include "stm32f4xx_hal_eth.h"
#endif /* HAL_ETH_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32f4xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_SRAM_MODULE_ENABLED
#include "stm32f4xx_hal_sram.h"
#endif /* HAL_SRAM_MODULE_ENABLED */
#ifdef HAL_NOR_MODULE_ENABLED
#include "stm32f4xx_hal_nor.h"
#endif /* HAL_NOR_MODULE_ENABLED */
#ifdef HAL_NAND_MODULE_ENABLED
#include "stm32f4xx_hal_nand.h"
#endif /* HAL_NAND_MODULE_ENABLED */
#ifdef HAL_PCCARD_MODULE_ENABLED
#include "stm32f4xx_hal_pccard.h"
#endif /* HAL_PCCARD_MODULE_ENABLED */
#ifdef HAL_SDRAM_MODULE_ENABLED
#include "stm32f4xx_hal_sdram.h"
#endif /* HAL_SDRAM_MODULE_ENABLED */
#ifdef HAL_HASH_MODULE_ENABLED
#include "stm32f4xx_hal_hash.h"
#endif /* HAL_HASH_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32f4xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32f4xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32f4xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32f4xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_LTDC_MODULE_ENABLED
#include "stm32f4xx_hal_ltdc.h"
#endif /* HAL_LTDC_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32f4xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32f4xx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32f4xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SAI_MODULE_ENABLED
#include "stm32f4xx_hal_sai.h"
#endif /* HAL_SAI_MODULE_ENABLED */
#ifdef HAL_SD_MODULE_ENABLED
#include "stm32f4xx_hal_sd.h"
#endif /* HAL_SD_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32f4xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32f4xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32f4xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32f4xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32f4xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32f4xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32f4xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32f4xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_HCD_MODULE_ENABLED
#include "stm32f4xx_hal_hcd.h"
#endif /* HAL_HCD_MODULE_ENABLED */
#ifdef HAL_DSI_MODULE_ENABLED
#include "stm32f4xx_hal_dsi.h"
#endif /* HAL_DSI_MODULE_ENABLED */
#ifdef HAL_QSPI_MODULE_ENABLED
#include "stm32f4xx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */
#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32f4xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */
#ifdef HAL_FMPI2C_MODULE_ENABLED
#include "stm32f4xx_hal_fmpi2c.h"
#endif /* HAL_FMPI2C_MODULE_ENABLED */
#ifdef HAL_SPDIFRX_MODULE_ENABLED
#include "stm32f4xx_hal_spdifrx.h"
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
#ifdef HAL_DFSDM_MODULE_ENABLED
#include "stm32f4xx_hal_dfsdm.h"
#endif /* HAL_DFSDM_MODULE_ENABLED */
#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32f4xx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */
#ifdef HAL_MMC_MODULE_ENABLED
#include "stm32f4xx_hal_mmc.h"
#endif /* HAL_MMC_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F4xx_HAL_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,651 @@
/*!
* \file
* thermostat_shield.c
* \brief
* Nucleo thermostat shield port file. This file contain the implementation of driver
* calls for the shield.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include "thermostat_shield.h"
/*
* =============== Digital I/O ===============
*/
static void SHIELD_LCD_Port_Init (void);
static void SHIELD_LED_Port_Init (void);
static void SHIELD_BRIDGE_Port_Init (void);
static void SHIELD_SR04_Port_Init (void);
/*
* =============== LCD ===============
* LCD_BD4 -- D8 -- PA9
* LCD_BD5 -- D7 -- PA8
* LCD_BD6 -- D6 -- PB10
* LCD_BD7 -- D5 -- PB4
* LCD_RS -- D15 -- PB8
* LCD_EN -- D14 -- PB9
* LCD_BL -- D2 -- PA10
*/
/*!
* LCD pin Initialize
*/
static void SHIELD_LCD_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOA_CLK_ENABLE ();
__HAL_RCC_GPIOB_CLK_ENABLE ();
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_4 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LCD_DB4 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_9, en); }
void SHIELD_LCD_DB5 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_8, en); }
void SHIELD_LCD_DB6 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_10, en); }
void SHIELD_LCD_DB7 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_4, en); }
void SHIELD_LCD_RS (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_8, en); }
void SHIELD_LCD_EN (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_9, en); }
void SHIELD_LCD_BL (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_10, en); }
/*
* =============== LED ===============
* LED0 -- D4 -- PB5
* LED1 -- D3 -- PB3
*/
/*!
* LED pin initialize
*/
static void SHIELD_LED_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOB_CLK_ENABLE ();
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_3 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LED0 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_5, on); }
void SHIELD_LED1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_3, on); }
/*
* =============== BRIDGE ===============
* BR1 -- D10 -- PB6
* BR2 -- D9 -- PC7
*/
/*!
* H-Bridge pin initialize
*/
static void SHIELD_BRIDGE_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOB_CLK_ENABLE ();
__HAL_RCC_GPIOC_CLK_ENABLE ();
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOC, &GPIO_InitType);
}
void SHIELD_BR1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_6, on); }
void SHIELD_BR2 (uint8_t on) { _DOUTx(GPIOC, GPIO_PIN_7, on); }
/*
* =============== SR04 ===============
* TRIG -- D11 -- PA7
* ECHO -- D12 -- PA6
*/
/*!
* SR04 pin initialize
*/
static void SHIELD_SR04_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOA_CLK_ENABLE ();
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
GPIO_InitType.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);
}
void SHIELD_TRIG (uint8_t on) { _DOUTx(GPIOA, GPIO_PIN_7, on); }
uint8_t SHIELD_ECHO (void) { return _DINx (GPIOA, GPIO_PIN_6); }
/*
* ============= 1 Wire UART6 (AF08)===============
* 1W_Tx -- PA11 (OD+PU)
* 1W_Rx -- PA12 (I)
*/
static UART_HandleTypeDef h1w_uart; //!< 1-wire uart handle
/*!
* \brief
* This function handles UART Communication Timeout.
* \param huart: Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* \param Flag: specifies the UART flag to check.
* \param Status: The new Flag status (SET or RESET).
* \param Timeout: Timeout duration
* \return HAL status
*/
static HAL_StatusTypeDef _WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Timeout) {
uint32_t tickstart = HAL_GetTick();
if (Status != RESET) Status = SET; /* Catch wrong Status */
/* Wait until flag is on FlagStatus Status */
while (__HAL_UART_GET_FLAG (huart, Flag) == Status) {
if ((Timeout == 0) || ((HAL_GetTick() - tickstart ) > Timeout)) {
/* Give up */
huart->gState= HAL_UART_STATE_READY; /* Mark Timeout as ready */
__HAL_UNLOCK (huart); /* Process Unlocked */
return HAL_TIMEOUT; /* Return the TIMEOUT */
}
}
return HAL_OK;
}
/*!
* \brief
* Initialize 1-Wire UART to 8bits, no parity, 1 stop, so it can
* be used for 1-Wire communication
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR The Init failed.
*/
static LLD_Status_en _1W_UART_Init (void) {
_1WIRE_UART_CLK_ENABLE (); // Enable 1-wire's USART clock
/*
* USART configured as follows:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - BaudRate = _1WIRE_UART_INIT_BR baud
* - Hardware flow control disabled (RTS and CTS signals)
*/
h1w_uart.Instance = _1WIRE_UART_INSTANCE;
h1w_uart.Init.BaudRate = _1WIRE_UART_INIT_BR;
h1w_uart.Init.WordLength = UART_WORDLENGTH_8B;
h1w_uart.Init.StopBits = UART_STOPBITS_1;
h1w_uart.Init.Parity = UART_PARITY_NONE;
h1w_uart.Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(&h1w_uart) != HAL_OK)
return LLD_ERROR;
return LLD_OK;
}
/*!
* Init the 1wire interface and allocate all resources for it
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR The Init failed.
*/
LLD_Status_en SHIELD_1W_Init (void) {
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE ();
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
HAL_GPIO_WritePin (GPIOA, GPIO_InitStruct.Pin, GPIO_PIN_SET);
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_12;
//GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
/*^
* Mark as alternate because HAL_GPIO_Init ()
* can not configure Input + alternate
*/
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);
return _1W_UART_Init ();
}
/*!
* \brief
* Set a Baudrate to the UART, to use for 1-Wire communication
* \param br The desired baudrate
* \return The status of the operation (part of toolbox)
* \arg DRV_ERROR Fail
* \arg DRV_READY Success
*/
drv_status_en SHIELD_1W_UART_BR (uint32_t br) {
/*
* Keep USART configured as already set by Init:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - Hardware flow control disabled (RTS and CTS signals)
*/
if (! IS_UART_BAUDRATE (br) )
return DRV_ERROR;
h1w_uart.Init.BaudRate = br;
/* Check the Over Sampling */
if(h1w_uart.Init.OverSampling == UART_OVERSAMPLING_8) {
/*------- UART-associated USART registers setting : BRR Configuration ------*/
if((h1w_uart.Instance == USART1)){
h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
}
else {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
}
}
else {
/*------- UART-associated USART registers setting : BRR Configuration ------*/
if((h1w_uart.Instance == USART1)) {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
}
else {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
}
}
return DRV_READY;
}
/*!
* \brief
* Read-Write functionality. We use the following USART configuration.
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* \return The byte received. On failure return 0xFFFF (bus released state)
* \note
* Due to the nature of the PCB, the received byte is the actual bus
* condition during the communication frame (time slot)
*/
uint16_t SHIELD_1W_RW (uint8_t byte)
{
if (h1w_uart.Init.WordLength != UART_WORDLENGTH_8B) return (uint8_t)0xFFFF;
if (h1w_uart.Init.Parity != UART_PARITY_NONE) return (uint8_t)0xFFFF;
if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TXE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
return 0x1FF;
WRITE_REG (h1w_uart.Instance->DR, (byte & (uint8_t)0xFF));
if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TC, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
return 0x2FF;
//if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_RXNE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
// return 0xFFFF;
return (uint8_t)(h1w_uart.Instance->DR & (uint8_t)0x00FF);
}
/*!
* \brief
* Receive functionality. We use USART blocking mode.
* \return The byte received. On failure return 0xFF (bus released state)
* \note
* Due to the nature of the PCB, the received byte is the actual bus
* condition during the communication frame (time slot)
*/
uint8_t SHIELD_1W_Rx (void) {
uint8_t rx;
if (HAL_UART_Receive (&h1w_uart, &rx, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
rx = 0xFF;
return rx;
}
/*!
* \brief
* Transmit functionality. We use USART blocking mode.
* \return The status of transition
* \arg 0 Success
* \arg 1 Fail
*/
uint8_t SHIELD_1W_Tx (uint8_t byte) {
if (HAL_UART_Transmit (&h1w_uart, &byte, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
return 1;
return 0;
}
/*!
* Shield hardware initialization
*/
LLD_Status_en SHIELD_Init (void) {
SHIELD_LCD_Port_Init ();
SHIELD_LED_Port_Init ();
SHIELD_BRIDGE_Port_Init ();
SHIELD_SR04_Port_Init ();
SHIELD_1W_Init ();
COM_Init ();
return LLD_OK;
}
/*
* ============= Serial console UART2 (AF07)===============
* COM_Tx -- PA2 (PP)
* COM_Rx -- PA3 (I)
*/
static UART_HandleTypeDef com_huart; //!< com uart handle
static deque08_t _com_rxq; //!< deque object
static byte_t _com_rxbuffer[COM_BUFFER_SIZE]; //!< buffer for deque
/*!
* \brief
* Called from USART IRQ to put the read character to queue
* \param Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
*
* \return The status of the operation
* \arg HAL_ERROR Fail
* \arg HAL_OK Success
*/
static HAL_StatusTypeDef _UART_read_data (UART_HandleTypeDef *huart, deque08_t *q) {
uint8_t r;
__HAL_LOCK(huart); /*
* We don't try to receive valid data while the USART is
* locked from transmitter. It's OK ;)
*/
/* Receive data based on Word length and parity */
switch (huart->Init.WordLength) {
default:
case UART_WORDLENGTH_8B:
if(huart->Init.Parity == UART_PARITY_NONE)
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
else
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x007F);
break;
case UART_WORDLENGTH_9B:
if(huart->Init.Parity == UART_PARITY_NONE) {
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x01FF);
__HAL_UNLOCK(huart);
return HAL_ERROR;
/* Not supported Configuration */
} else
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
break;
}
deque08_push_back (q, r);
/*!<
* \note
* We queue the received bytes. The user application MUST
* read the queue in a regular basis, or else this IRQ will
* find queue full and we will have data loss.
*/
__HAL_UNLOCK(huart);
return HAL_OK;
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_CLEAR_PEFLAG (huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
/*
* Clear all the error flag at once,
* Set USART READY for re-start,
* Error Callback
*/
}
/*!
* \brief
* USART serial handler. Pushes every received character to a queue.
*
* In the IRQ handler there is only Rx functionality provided by this driver.
* The Error handling call the HAL's callback (which are empty)
* The Tx part, is not implemented
*/
void USART2_IRQHandler (void) {
uint32_t tmp_flag = 0, tmp_it_source = 0;
// ======= Error handler =========
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_PE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_PE)) != RESET)) {
/* UART parity error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_PE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_FE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_ERR)) != RESET)) {
/* UART frame error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_FE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_NE)) != RESET) &&
(tmp_it_source != RESET)){
/* UART noise error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_NE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_ORE)) != RESET) &&
(tmp_it_source != RESET)){
/* USART Over-Run interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_ORE;
}
if(com_huart.ErrorCode != HAL_UART_ERROR_NONE) {
HAL_UART_ErrorCallback (&com_huart);
}
// ====== Get Data =========
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_RXNE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_RXNE)) != RESET)) {
// Read byte
_UART_read_data (&com_huart, &_com_rxq); // Don't check return status
}
}
/*!
* \brief
* Initialize the UART and UART IRQ handler
* \return The status of the operation
* \arg LLD_ERROR Fail
* \arg LLD_OK Success
*/
static LLD_Status_en _COM_UART_Init (void) {
/*
* Enable UART clock
*/
_COM_CLK_ENABLE();
deque08_link_buffer (&_com_rxq, _com_rxbuffer);
deque08_set_capacity (&_com_rxq, COM_BUFFER_SIZE);
deque08_init (&_com_rxq);
/*
* USART configured as follows:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - BaudRate = COM_BAUDRATE baud
* - Hardware flow control disabled (RTS and CTS signals)
*/
com_huart.Instance = COM_UART_INSTANCE;
com_huart.Init.BaudRate = COM_UART_BAUDRATE;
com_huart.Init.WordLength = UART_WORDLENGTH_8B;
com_huart.Init.StopBits = UART_STOPBITS_1;
com_huart.Init.Parity = UART_PARITY_NONE;
com_huart.Init.Mode = UART_MODE_TX_RX;
if (HAL_UART_Init(&com_huart) != HAL_OK)
return LLD_ERROR;
/*
* Enable IRQ for Rx
* Tx IRQ enabled by COM_transmit ()
*/
HAL_NVIC_SetPriority (COM_UART_IRQ, 0x0D, 0);
HAL_NVIC_EnableIRQ (COM_UART_IRQ);
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(&com_huart, UART_IT_RXNE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
//__HAL_UART_ENABLE_IT(&com_huart, UART_IT_ERR);
return LLD_OK;
}
/*!
* Initialize the COM dedicated I/O and allocate resources
* \return The status of the operation
*/
LLD_Status_en COM_Init (void) {
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE ();
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
// GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);
return _COM_UART_Init();
}
/*!
* \brief
* Set UART baudrate
* \param br The desired baudrate
* \return The status of the operation
* \arg LLD_ERROR Fail
* \arg LLD_OK Success
*/
LLD_Status_en COM_baudrate (uint32_t br) {
// Change only the Baudrate
com_huart.Init.BaudRate = br;
if (HAL_UART_Init(&com_huart) != HAL_OK)
return LLD_ERROR;
return LLD_OK;
}
/*!
* \brief
* USART's putchar functionality to link with io system
* This function is compatible with putchar() in "stdio.h"
*/
int COM_putchar (char c) {
if (_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, RESET, COM_UART_PUTCHAR_TIMEOUT) != HAL_OK)
return 0xFFFF;
WRITE_REG (COM_UART_INSTANCE->DR, (c & (uint8_t)0xFF));
/*!<
* \note
* The sequence:
* - Read operation to USART_SR register [USART_GetFlagStatus()]
* - Write operation to USART_DR register [USART_SendData()]
* clears the TC Flag
*
* The TXE Flag is cleared by the write operation to USART_DR register
* [USART_SendData()]
*/
return (int)c;
}
/*!
* \brief
* USART's getchar functionality to link with io system
* This function is compatible with getchar() in "stdio.h"
*/
int COM_getchar (void) {
clock_t mark = clock ();
clock_t to = COM_UART_GETCHAR_TIMEOUT*get_freq();
clock_t now;
byte_t r=0;
while (deque08_pop_front (&_com_rxq, &r) == 0) {
now = clock ();
if (_CLOCK_DIFF(now, mark) >= to)
return 0;
}
return r;
}
/*!
* \brief
* Transmit functionality to link with io system
* This function is compatible with htp tx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of bytes to transmit
*/
int COM_Transmit (uint8_t *data, int size) {
int r = size;
while (size--) {
//queue08_push (&_com_txq, (byte_t)*data);
COM_putchar(*data++);
}
_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, SET, COM_UART_PUTCHAR_TIMEOUT);
return r;
}
/*!
* \brief
* Check receive functionality synchronized to IRQ
* This function is compatible with htp rx functionality
*
* \return The number of bytes on queue (<package_size> indicates done)
*/
int COM_CheckReceive (void) {
return deque08_size (&_com_rxq);
}
/*!
* \brief
* Receive flush functionality to link with io system
* This function is compatible with htp rx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of received bytes
*/
void COM_ReceiveFlush (void) {
deque08_flush (&_com_rxq);
}
/*!
* \brief
* Receive functionality to link with io system
* This function is compatible with htp rx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of received bytes
*/
int COM_Receive (uint8_t *data, int size) {
int i;
uint8_t r=1, b;
for (i=0 ; r !=0 && i<size ; ++i) {
r = deque08_pop_front (&_com_rxq, &b);
data[i] = b;
}
return i;
}

View File

@ -0,0 +1,124 @@
/*!
* \file
* thermostat_shield.h
* \brief
* Nucleo thermostat shield port file. This file contain the implementation of driver
* calls for the shield.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#ifndef DRIVERS_THERMOSTAT_SHIELD_H_
#define DRIVERS_THERMOSTAT_SHIELD_H_
#include "NUCLEO_F401RE.h"
#include "driver_types.h"
#include "deque08.h"
/*
* =============== Digital I/O ===============
*/
/*
* =============== LCD ===============
* LCD_BD4 -- D8 -- PA9
* LCD_BD5 -- D7 -- PA8
* LCD_BD6 -- D6 -- PB10
* LCD_BD7 -- D5 -- PB4
* LCD_RS -- D15 -- PB8
* LCD_EN -- D14 -- PB9
* LCD_BL -- D2 -- PA10
*/
void SHIELD_LCD_DB4 (uint8_t en);
void SHIELD_LCD_DB5 (uint8_t en);
void SHIELD_LCD_DB6 (uint8_t en);
void SHIELD_LCD_DB7 (uint8_t en);
void SHIELD_LCD_RS (uint8_t en);
void SHIELD_LCD_EN (uint8_t en);
void SHIELD_LCD_BL (uint8_t en);
/*
* =============== LED ===============
* LED0 -- D4 -- PB5
* LED1 -- D3 -- PB3
*/
void SHIELD_LED0 (uint8_t on);
void SHIELD_LED1 (uint8_t on);
#define LED_RED SHIELD_LED0
#define LED_GREEN SHIELD_LED1
/*
* =============== BRIDGE ===============
* BR1 -- D10 -- PB6
* BR2 -- D9 -- PC7
*/
void SHIELD_BR1 (uint8_t on);
void SHIELD_BR2 (uint8_t on);
/*
* =============== SR04 ===============
* TRIG -- D11 -- PA7
* ECHO -- D12 -- PA6
*/
void SHIELD_TRIG (uint8_t on);
uint8_t SHIELD_ECHO (void);
/*
* ============= 1 Wire USART6 (AF08)===============
* 1W_Tx -- PA11 (OD+PU)
* 1W_Rx -- PA12 (I)
*/
// non-shared resources
#define _1WIRE_UART_INSTANCE (USART6)
#define _1WIRE_UART_INIT_BR (9600)
#define _1WIRE_UART_TIMEOUT (10) /*!< 10msec is good enough */
/*!
* Helper Macros linked to USART used
*/
#define _1WIRE_UART_CLK_ENABLE __HAL_RCC_USART6_CLK_ENABLE
#define _1WIRE_UART_CLK_DISABLE __HAL_RCC_USART6_CLK_DISABLE
LLD_Status_en SHIELD_1W_Init (void);
drv_status_en SHIELD_1W_UART_BR (uint32_t br);
uint16_t SHIELD_1W_RW (uint8_t byte);
uint8_t SHIELD_1W_Rx (void);
uint8_t SHIELD_1W_Tx (uint8_t byte);
LLD_Status_en SHIELD_Init (void);
/*
* ============= Serial console UART2 (AF07)===============
* COM_Tx -- PA2 (PP)
* COM_Rx -- PA3 (I)
*/
#define COM_UART_INSTANCE USART2
#define COM_UART_IRQ USART2_IRQn
#define COM_UART_BAUDRATE (57600)
#define COM_UART_GETCHAR_TIMEOUT (5) // 5sec
#define COM_UART_PUTCHAR_TIMEOUT (10) // 1 [CPU time]
#define COM_BUFFER_SIZE (256)
/*!
* Helper Macros linked to USART used
*/
#define _COM_CLK_ENABLE __HAL_RCC_USART2_CLK_ENABLE
#define _COM_CLK_DISNABLE __HAL_RCC_USART2_CLK_DISABLE
LLD_Status_en COM_Init (void);
LLD_Status_en COM_baudrate (uint32_t br);
int COM_putchar (char c);
int COM_getchar (void);
int COM_Transmit (uint8_t *data, int size);
int COM_CheckReceive (void);
void COM_ReceiveFlush (void);
int COM_Receive (uint8_t *data, int size);
#endif /* DRIVERS_THERMOSTAT_SHIELD_H_ */

@ -0,0 +1 @@
Subproject commit c27d16e915615bc56a7b09f56e882661ac69b860

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

View File

@ -0,0 +1,601 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="ui_states.svg">
<defs
id="defs2">
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path991"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path988"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-1"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-3"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-2-0"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-9-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-2-5"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-9-4"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-2-4"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-9-3"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-6-2-0-9"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-0-9-9-1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-6"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-2"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-6-9"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-2-1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-7"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-7"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-7-1"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-7-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-7-1-3"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-7-9-8"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend-9-6-9-4"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path991-4-2-1-9"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="305.44261"
inkscape:cy="594.04646"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
style="stroke-width:1.43562889"
id="g911"
transform="matrix(0.69672537,0,0,0.69639235,43.060245,27.179579)">
<ellipse
ry="11.496272"
rx="24.379465"
cy="97.585548"
cx="92.793152"
id="path815"
style="fill:none;stroke:#000000;stroke-width:0.71781445;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<flowRoot
transform="matrix(0.18461171,0,0,0.18461171,38.065515,17.935472)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.05752659"
id="flowRoot817"
xml:space="preserve"><flowRegion
style="stroke-width:2.05752659"
id="flowRegion819"><rect
style="stroke-width:2.05752659"
y="408.94824"
x="210.71428"
height="219.28572"
width="340.71429"
id="rect821" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';stroke-width:2.67305756"
id="flowPara823">ST_INIT</flowPara></flowRoot> </g>
<g
style="stroke-width:1.43562889"
id="g918"
transform="matrix(0.69672537,0,0,0.69639235,54.309168,82.301952)">
<ellipse
ry="11.496272"
rx="30.33259"
cy="157.90475"
cx="62.271572"
id="path815-9"
style="fill:none;stroke:#000000;stroke-width:0.71781445;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<flowRoot
transform="matrix(0.18461171,0,0,0.18461171,1.3854042,78.254686)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.05752659"
id="flowRoot817-0"
xml:space="preserve"><flowRegion
style="stroke-width:2.05752659"
id="flowRegion819-0"><rect
style="stroke-width:2.05752659"
y="408.94824"
x="210.71428"
height="219.28572"
width="340.71429"
id="rect821-2" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';stroke-width:2.67305756"
id="flowPara823-2">ST_COUNT</flowPara></flowRoot> </g>
<g
style="stroke-width:1.43562889"
id="g925"
transform="matrix(0.69672537,0,0,0.69639235,50.056064,4.1485435)">
<ellipse
ry="11.496272"
rx="24.379465"
cy="197.843"
cx="132.29842"
id="path815-6"
style="fill:none;stroke:#000000;stroke-width:0.71781445;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<flowRoot
transform="matrix(0.18461171,0,0,0.18461171,74.790787,118.19293)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.05752659"
id="flowRoot817-9"
xml:space="preserve"><flowRegion
style="stroke-width:2.05752659"
id="flowRegion819-03"><rect
style="stroke-width:2.05752659"
y="408.94824"
x="210.71428"
height="219.28572"
width="340.71429"
id="rect821-5" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';stroke-width:2.67305756"
id="flowPara823-5">ST_USER</flowPara></flowRoot> </g>
<g
style="stroke-width:1.43562889"
id="g932"
transform="matrix(0.69672537,0,0,0.69639235,-53.783037,38.526733)">
<ellipse
ry="11.496272"
rx="33.673458"
cy="147.0618"
cx="167.44435"
id="path815-9-8"
style="fill:none;stroke:#000000;stroke-width:0.71781445;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<flowRoot
transform="matrix(0.18461171,0,0,0.18461171,101.78244,67.411724)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.05752659"
id="flowRoot817-0-7"
xml:space="preserve"><flowRegion
style="stroke-width:2.05752659"
id="flowRegion819-0-1"><rect
style="stroke-width:2.05752659"
y="408.94824"
x="210.71428"
height="219.28572"
width="340.71429"
id="rect821-2-7" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Arial Black';-inkscape-font-specification:'Arial Black, ';stroke-width:2.67305756"
id="flowPara823-2-0">ST_AVERAGE</flowPara></flowRoot> </g>
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 122.93134,66.023775 c -3.65925,1.681276 -3.39681,0.755032 -7.29274,4.00432 -6.63268,5.531786 -8.54054,17.112752 -8.54054,17.112752"
id="path986"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9)"
d="m 91.594559,98.052048 c -3.65925,1.68128 -8.717171,3.761652 -16.914443,11.621502 -10.334873,9.90947 -12.282313,22.72541 -12.282313,22.72541"
id="path986-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-6)"
d="m 122.0064,99.60807 c 3.62159,1.6499 10.23233,5.15907 15.44446,11.6215 4.95933,6.14898 11.21324,22.72541 11.21324,22.72541"
id="path986-5-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-7)"
d="m 77.19729,189.78093 c -3.65925,-1.68128 -9.891429,-3.88611 -13.60715,-11.24353 -5.377559,-10.648 -4.423096,-29.22929 -4.423096,-29.22929"
id="path986-5-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-6-9)"
d="m 118.37195,189.72846 c 4.32742,-0.47857 8.96054,-1.33731 18.6517,-11.22059 9.08993,-9.27014 12.41595,-29.00625 12.41595,-29.00625"
id="path986-5-5-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-7-1)"
d="m 77.971786,147.26982 c 3.65925,1.68128 7.899204,6.35401 11.339294,12.84994 4.243174,8.01239 5.462526,24.03211 5.462526,24.03211"
id="path986-5-4-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-7-1-3)"
d="m 74.663683,133.51806 c 2.750358,-2.45653 16.924642,-8.98074 31.132187,-8.89636 11.57642,0.0688 28.4717,9.76743 28.4717,9.76743"
id="path986-5-4-1-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend-9-6-9-4)"
d="m 130.12937,147.76437 c -4.06015,2.34945 -7.62996,7.43829 -11.30178,14.02692 -4.21244,7.55875 -7.33783,23.66086 -7.33783,23.66086"
id="path986-5-5-1-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
<flowRoot
xml:space="preserve"
id="flowRoot24698"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,83.615792,43.243707)"><flowRegion
id="flowRegion24700"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702"
width="106.06602"
height="97.984795"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
id="flowPara24704"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355">start</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,108.63996,81.165381)"><flowRegion
id="flowRegion24700-3-8-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3">proximity</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,32.720964,77.378204)"><flowRegion
id="flowRegion24700-3-8-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-3"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-7">done</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,33.785864,80.708472)"><flowRegion
id="flowRegion24700-3-8-6-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-9"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-6">measuring</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,70.145367,97.280685)"><flowRegion
id="flowRegion24700-3-8-6-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-0"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-2">proximity</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,111.36366,155.62052)"><flowRegion
id="flowRegion24700-3-8-6-5"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-7"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-4">proximity</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-7-6"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,22.41547,157.56353)"><flowRegion
id="flowRegion24700-3-8-4-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-3-9"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-7-1">done</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-1-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,23.480368,160.89379)"><flowRegion
id="flowRegion24700-3-8-6-3-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-9-1"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-6-8">measuring</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-9-1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,60.534626,134.15952)"><flowRegion
id="flowRegion24700-3-8-6-5-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-7-8"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-4-9">10 sec</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-7-6-2"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,80.546592,133.6429)"><flowRegion
id="flowRegion24700-3-8-4-4-4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-3-9-5"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara25034">lost</flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot24698-5-2-8-9-3"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.6914711"
transform="matrix(0.09830435,0,0,0.09830435,79.625403,129.56174)"><flowRegion
id="flowRegion24700-3-8-6-5-0"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:3.79738355"><rect
id="rect24702-3-5-9-7-0"
width="207.95738"
height="110.4809"
x="244.45691"
y="225.50423"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Arial;-inkscape-font-specification:Arial;stroke-width:2.6914711" /></flowRegion><flowPara
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0;font-family:Arial;-inkscape-font-specification:Arial;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:3.79738355"
id="flowPara24734-0-3-4-0">proximity</flowPara></flowRoot> </g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

View File

@ -0,0 +1,208 @@
%
% Microprocessors and peripherals 3nd assignement.
%
% author:
% Χρήστος Χουτουρίδης ΑΕΜ 8997
% cchoutou@ece.auth.gr
% Document configuration
\newcommand{\ClassName}{Μικροεπεξεργαστές και Περιφερειακά}
\newcommand{\DocTitle}{3η Εργασία}
\newcommand{\InstructorName}{Παπαευσταθίου Ιωάννης}
\newcommand{\InstructorMail}{ygp@ece.auth.gr}
\newcommand{\CurrentDate}{\today}
\input{config/AuthReportConfig.tex}
%\renewcommand{\AuthorName}{Χρήστος Χουτουρίδης}
%\renewcommand{\AuthorMail}{cchoutou@ece.auth.gr}
%\renewcommand{\AuthorAEM}{8997}
\setFancyHeadLR{\ClassName}{\DocTitle}
%\setFancyHeadLERO{\ClassName}{\DocTitle}
% Document
% =================
\begin{document}
\FirstPage
%\TitleHeader
%\tableofcontents
%\listoffigures
%\listoftables
\section{Εισαγωγή}
Στην παρούσα εργασία το ζητούμενο ήταν η υλοποίηση ενός “έξυπνου θερμοστάτη” χρησιμοποιώντας αναπτυξιακό \eng{Nucleo-F401RE} της εταιρίας \eng{ST Microelectronics.}
Η τελική εφαρμογή θα πρέπει να έχει οθόνη, \eng{leds} αισθητήρα θερμοκρασίας και αισθητήρα εγγύτητας, υλικά που δεν είναι διαθέσιμα από το αναπτυξιακό.
Για το σκοπό αυτό αποφασίσαμε να προχωρήσουμε την εργασία λιγάκι παραπάνω και να κατασκευάσουμε ένα \eng{shield} για το \eng{Nucleo,} το οποίο ενσωματώνει σε ένα τυπωμένο κύκλωμα όλα τα απαραίτητα στοιχεία.
Τέλος, λόγο του ότι η διεπαφή χρήστη της εκφώνησης ήταν λιγάκι “φτωχή”, πήραμε την πρωτοβουλία και υλοποιήσαμε ένα μικρό \eng{serial interface} το οποίο μπορεί να χρησιμοποιηθεί και για να ρυθμίσει τον θερμοστάτη.
Η ανάπτυξη έγινε σε γλώσσα \eng{C} και χρησιμοποιήθηκε το εργαλείο \eng{Keil uVision.}
Ο κώδικας της εργασίας, της παρούσας αναφοράς, αλλά και τα σχέδια της κατασκευής υπάρχουν και στον προσωπικό \eng{server}του συντάκτη, στο \href{https://git.hoo2.net/hoo2/Micro2020/src/branch/master/assignment_3}{αποθετήριο} για την εργασία.
\section{Παραδοτέα}
Στο παραδοτέο \eng{.zip} αρχείο μπορείτε να βρείτε:
\begin{itemize}
\item Τον κατάλογο \textbf{\eng{/src}} που περιέχει τον κώδικα της εφαρμογής.
\item Τον κατάλογο \textbf{\eng{/Libraries}} που περιέχει τον κώδικα των βιβλιοθηκών που χρησιμοποιήσαμε, όπως το \eng{CMSIS} και το \eng{ST HAL,} αλλά και τους \eng{drivers} για τα περιφερειακά.
\item Το αρχείο \textbf{\eng{report.pdf}} που είναι η παρούσα αναφορά.
\item Τον κατάλογο \textbf{\eng{/Keil}} που περιέχει το \eng{project} που χρησιμοποιήθηκε στο \eng{Keil.}\\
Στο \eng{project} αυτό περιέχονται επιπλέων οι ρυθμίσεις καθώς και τα αρχεία από τις βιβλιοθήκες που χρησιμοποιήθηκαν.
\end{itemize}
\par
Για την παρούσα εργασία χρησιμοποιήσαμε το \eng{CMSIS} και το \eng{STM32F4xx\_HAL} που παρέχει η εταιρία \eng{ST} στο επίσημο αποθετήριό της.
Η επιλογή αυτού έναντι των αρχείων από το \eng{STM32F4xx Std\_Peripheral} που περιεχόταν στο \eng{e-learning} του μαθήματος έγινε για να συμβαδίσουμε με τις βιβλιοθήκες που προτείνει η κατασκευάστρια εταιρία.
Επίσης η χρήση τους έγινε στο ίδιο χαμηλό επίπεδο της \eng{STM32F4xx\_Std\_Peripheral} κάτι το οποίο προτείνεται και από τον διδάσκοντα.
\emph{\textbf{Εξάλλου μια υψηλότερου επιπέδου χρήση δεν θα είχε νόημα καθώς θα ξέφευγε από τον μαθησιακό χαρακτήρα της εργασίας}}.
\section{Υλοποίηση}
\subsection{Κατασκευή του\eng{shiled}}
\InsertFigure{0.8}{fig:shield_pcb}{shield_pcb.png}{
\eng{3D} απεικόνιση του \eng{PCB.}
}
Η υλοποίηση της εφαρμογής έγινε σε δύο φάσεις.
Η πρώτη ήταν η ανάπτυξη και κατασκευή του \eng{shiled.}
Αυτό το κομμάτι δεν ήταν στα απαιτούμενα και γιαυτό δεν θα ασχοληθούμε πολύ παρουσιάζοντάς το.
Θα πρέπει όμως να αναφέρουμε κάποια βασικά στοιχεία.
Έτσι εν συντομία η κατασκευή απαρτίζεται από:
\begin{itemize}
\item Μια \textbf{οθόνη} υγρών κρυστάλλων \eng{2 x 16,} σε \eng{4bit} παράλληλη επικοινωνία με τον επεξεργαστή.\\
Εκτός από την επικοινωνία ο επεξεργαστής ελέγχει και το \eng{back light} μέσω ενός μικρού \eng{MOSFET,} του \eng{MMBF170.}
Η οθόνη είναι σε μόνιμο \eng{write mode,} μιας και ο ακροδέκτης \eng{RW} είναι συνδεδεμένος μόνιμα στην γείωση.
\item Ένα \eng{\textbf{relay}} τύπου \eng{latching,} το\eng{\textbf{G2SU-2}} συνδεδεμένο μέσω Η-γέφυρας.\\
Η επιλογή \eng{latching relay} έγινε με γνώμονα την πιθανή κατανάλωση της κατασκευής σε περίπτωση μελλοντικής χρήσης της.
Σε μια τέτοια περίπτωση ενώ τα υπόλοιπα υλικά της κατασκευής λίγο πολύ θα μπορούσαν να περιορίσουν την κατανάλωση τους, το \eng{relay} θα έπρεπε να καταναλώνει συνέχεια ρεύμα για να παραμένει οπλισμένο.
\item Ένα αισθητήριο θερμοκρασίας τύπου\eng{\textbf{DS18B20}.}\\
Το αισθητήριο αυτό κάνει χρήση του πρωτοκόλλου επικοινωνίας \eng{1-wire} της \eng{Dallas semiconductors.}
Παρόλα αυτά στην κατασκευή είναι συνδεδεμένο στη σειριακή επικοινωνία του \eng{shield,} επιτρέποντας έτσι τη χρήση του \eng{\href{https://www.maximintegrated.com/en/design/technical-documents/tutorials/2/214.html}{application note 214}} της \eng{maxim,} όπου περιγράφεται ένας τρόπος δημιουργίας του χρονισμού του \eng{1-wire bus} χρησιμοποιώντας τη σειριακή θύρα.
Με τον τρόπο αυτό ο επεξεργαστής αποδεσμεύεται από τον φόρτο να δημιουργεί ακριβείς χρονοκαθυστερήσεις, πιθανότατα απενεργοποιώντας τα \eng{interrupts} και αφήνει ένα περιφερειακό του να εκτελέσει αυτή τη δουλειά.
\item Ένα αισθητήριο εγγύτητας \eng{\textbf{HC-SR04}} που λειτουργεί με υπερήχους.
\item Διάφορα “\textbf{μικρούτσικα}” υλικά, όπως τρανζιστορ-άκια, αντιστάσεις, πυκνωτές, \eng{leds} κ.α.
\end{itemize}
\subsection{Οδηγός του \eng{Nucleo} και του \eng{shiled}}
Η δεύτερη φάση της ανάπτυξης ήταν ο προγραμματισμός.
Ο επεξεργαστής που φέρει το εν λόγο αναπτυξιακό είναι πολύ μεγαλύτερος από τις ανάγκες της παρούσας εργασίας.
Έτσι τα υποσυστήματα που χρησιμοποιήσαμε ήταν ελάχιστα.
Για την ακρίβεια έγινε χρήση:
\begin{itemize}
\item Του \eng{\textbf{SysTick timer}} ώς βάση μέτρησης χρόνου.\\
Η συχνότητα που επιλέξαμε είναι το \eng{1Khz,} το οποίο μας οδηγεί σε επαρκές βήμα \eng{1msec}.
\item Του \eng{\textbf{GPIO}} για την ανάγνωση του κουμπιού και την οδήγηση του \eng{LED} της πλακέτας, αλλά και την οδήγηση όλων των ψηφιακών σημάτων του \eng{shield.}
\item Του \eng{\textbf{RCC}} για τον έλεγχο και των σημάτων ρολογιού εσωτερικά του επεξεργαστή στα διάφορα υποσυστήματα.
\item Του \eng{\textbf{Cycle count}} μηχανισμού στον \eng{debugger.}\\
Ο εν λόγο μηχανισμός χρησιμοποιήθηκε για την μέτρηση του χρόνου απόκρισης του αισθητηρίου εγγύτητας.
\end{itemize}
\par
Αξίζει ίσως σε αυτό το σημείο να αναφέρουμε πως για την μέτρηση χρόνου χρησιμοποιήσαμε μεταβλητές για απαρίθμηση των διακοπών του \eng{SysTick.}
Η εφαρμογή έτσι μπορούσε βλέποντας την τιμή τους να έχει εικόνα του χρόνου που έχει περάσει από το \eng{power up.}
\par
Για την οδήγηση των περιφερειακών του \eng{shield} χρησιμοποιήσαμε επιπλέον:
\begin{itemize}
\item Τη σειριακή \eng{\textbf{USART2}} για την επικοινωνία με το υπολογιστή.\\
Τη θύρα αυτή τη χρησιμοποιήσαμε για την δημιουργία ενός \eng{command interface,} μέσω του οποίου μπορούμε να δούμε την κατάσταση του θερμοστάτη, αλλά και να του αλλάξουμε τις ρυθμίσεις.
\item Τη σειριακή \eng{\textbf{USART6}} για το \eng{1-wire.}\\
Η χρήση αυτής της θύρας έγινε όπως αναφέρθηκε και παραπάνω σύμφωνα με τις οδηγίες της \eng{maxim-ic (Dallas semiconductors).}
\end{itemize}
\par
Εδώ θα πρέπει να αναφέρουμε πως στο \eng{nucleo} οι ακροδέκτες της σειριακής επικοινωνίας\eng{(D0-D1)} είναι συνδεμένοι στην σειριακή του \eng{”USB to serial”} του \eng{ST-LINK2.}
Για να συνδέαμε μέσω αυτών των ακροδεκτών τη σειριακή για το \eng{1-wire} του \eng{shield} στον επεξεργαστή, θα έπρεπε να τοποθετούσαμε τα \eng{jumpers SB62, SB63.}
Έτσι η κατασκευή μας θα πληρούσε τις προδιαγραφές της εκφώνησης, αλλά δεν θα είχε την έξτρα δυνατότητα του \eng{serial console.}
Ανταυτού λοιπόν “αφήσαμε” το \eng{nucleo} απείραχτο και συνδέσαμε τη σειριακή του \eng{shield} στη θύρα \eng{USART6,} μέσω των \eng{morpho headers.}
Αυτό μας αφήνει με το \eng{configuration} που περιγράψαμε παραπάνω, ενώ η κατασκευή μας είναι η ίδια είτε υλοποιήσουμε μόνο τις προδιαγραφές της εκφώνησης είτε υλοποιήσουμε και το έξτρα \eng{command interface.}
\subsection{Οδηγός περιφερειακών}
Στον κατάλογο \eng{Libraries/drivers/} εκτός από τους οδηγούς του \eng{nucleo} και του \eng{shield,} υπάρχουν οι οδηγοί των περιφερειακών πάνω στο \eng{shield,} αλλά και οι επιπλέων λειτουργίες που χρειαστήκαμε για την ορθή λειτουργία τους.
Οι οδηγοί είναι σε ζεύγη αρχείων κώδικα-κεφαλίδας(\eng{.c/.h}) και ο καθένας αποτελεί ένα \eng{module.}
Η αναλυτική παρουσίαση του κώδικα εδώ θα πλάτιαζε χωρίς να προσφέρει τίποτε χρήσιμο.
Θα αναφέρουμε όμως συνοπτικά το κάθε \eng{modul-}άκι και τον τρόπο λειτουργίας του γενικά.
\begin{itemize}
\item \textbf{\eng{jiffies:}}\\
Στο \eng{module} αυτό ρυθμίζουμε ένα \eng{timer} του επεξεργαστή ώστε να μετράει αδιάκοπα μέχρι μία τιμή με \eng{auto-reload.}
Κάνοντας χρήση αυτού του \eng{timer} μπορούμε στη συνέχεια να δημιουργήσουμε χρονοκαθυστερήσεις μικρότερες από το \eng{time base} της εφαρμογής.
\item \textbf{\eng{deque08:}}\\
Το \eng{module} αυτό υλοποιεί μια \eng{double-ended queue.}
Την ουρά αυτή τη χρησιμοποιούμε στη σειριακή επικοινωνία με τον υπολογιστή για το \eng{serial console.}
Η υλοποίηση είναι “όσο \eng{object oriented} γίνεται”.
Οι συναρτήσεις δηλαδή του \eng{module} έχουν όλες ένα δείκτη σ' ένα “αντικείμενο” τύπου ουράς που παίζει το ρόλο του \eng{this pointer} άλλων γλωσσών.
Έτσι μπορούμε να χρησιμοποιήσουμε περισσότερες από μία ουρές στο ίδιο \eng{project} με τον ίδιο κώδικα.
\item \textbf{\eng{onewire\_uart:}}\\
Το \eng{module} αυτό υλοποιεί το πρωτόκολλο επικοινωνίας \eng{1-wire} κάνοντας χρήση της σειριακής.
Ομοίως και εδώ η υλοποίηση είναι \eng{object oriented like.}
Εδώ όμως \textbf{κάνουμε ένα ακόμη κόλπο}.
Αρχικά το \eng{module} προϋποθέτει πως οι ακροδέκτες \eng{Tx-Rx} της θύρας είναι βραχυκυκλωμένοι.
Το βασικό “αντικείμενο” του \eng{module} εσωτερικά έχει δύο δείκτες σε συναρτήσεις.
Τη μία την καλεί για να γράψει στη σειριακή και ταυτόχρονα να διαβάσει τo αποτέλεσμα της πραγματικής κατάστασης του \eng{bus} κατά την προσπάθεια.
Την άλλη τη χρησιμοποιεί για να αλλάξει το \eng{baudrate} της θύρας.
Σε όλο το σώμα του κώδικα του \eng{module} γίνεται χρήση μόνο αυτών των δύο δεικτών και έτσι \textbf{\textit{δεν υπάρχει καμία εξάρτηση από το \eng{hardware.}}}
Ο χρήστης του \eng{module} μπορεί να το χρησιμοποιήσει σε οποιαδήποτε κατασκευή που πληροί τις προϋποθέσεις, να υλοποιήσει για το δικό του \eng{hardware} τις δύο παραπάνω συναρτήσεις και να τις συνδέσει με το \eng{module.}
Κάτι τέτοιο κάναμε και εμείς εδώ, όπου υλοποιήσαμε τις συναρτήσεις \eng{\textit{SHIELD\_1W\_RW()}} και \eng{\textit{SHIELD\_1W\_UART\_BR()}} και τις συνδέσαμε με το \eng{module.}
\item \textbf{\eng{alcd:}}\\
Το \eng{module} αυτό υλοποιεί ένα οδηγό για την οθόνη.
Ομοίως και εδώ η υλοποίηση είναι \eng{object oriented like,} αλλά και απεξαρτημένη από το \eng{hardware} μέσω δεικτών σε συναρτήσεις για τα \eng{pins DB[4..7], RS, EN, Back-light.}
Για τον χρονισμό των σημάτων εδώ κάνουμε χρήση των \eng{jiffies,} καθώς οι χρόνοι που χρειαζόμαστε είναι πολύ μικρότεροι από το \eng{time base.}
\item Τέλος το \eng{\textbf{hal:}}\\
Το \eng{module} αυτό είναι ο συνδετικός κρίκος της εφαρμογής με τους οδηγούς.
Σε αυτό το αρχείο επίσης είναι υλοποιημένες και οι λειτουργίες για την αναγνώριση της εγγύτητας και η ανάγνωση της θερμοκρασίας.
\textit{Αυτές \textbf{οι τελευταίες λειτουργίες είναι οι πιο “ριγμένες”} της εργασίας, καθώς ο συντάκτης από καθαρή τεμπελιά δεν αξιώθηκε να τις κάνει ξεχωριστά \eng{modules.}}
Εξάλλου φαίνεται και με μια ματιά πως οι λειτουργίες που είναι υλοποιημένες είναι οι άκρως απαραίτητες για την εφαρμογή μας.
\end{itemize}
\subsection{Εφαρμογή}
\WrapFigure{0.45}{r}{fig:uistates}{ui_states.png}{
Μηχανή καταστάσεων της διεπαφής χρήστη.
}
Έχοντας υλοποιήσει όλα τα παραπάνω η δουλειά μας για την εφαρμογή ήταν πολύ εύκολη.
Έτσι στην βασική λειτουργία της εκφώνησης προσθέσαμε ορισμένα πράγματα.
Για παράδειγμα η εφαρμογή έχει μια δομή \eng{\textbf{settings}} στην οποία υπάρχουν οι ρυθμίσεις του θερμοστάτη.
Πιο συγκεκριμένα αποθηκεύουμε τον τρόπο λειτουργίας, αν δηλαδή ο θερμοστάτης δουλεύει για \textbf{ψύξη ή θέρμανση}.
Την θερμοκρασία λειτουργίας και μια υστέρηση για αυτήν.
Την απόσταση κάτω από την οποία θεωρεί ο θερμοστάτης ότι έχει εγγύτητα και ομοίως μια απόσταση υστέρησης.
\par
Ο κώδικας της εφαρμογής μας χωρίζεται σε τέσσερεις \eng{non-blocking} συναρτήσεις που καλούνται σε βρόχο επανάληψης από την \eng{main.}
\\
1. \textbf{\eng{control():}}\\
Η συνάρτηση αυτή αναλαμβάνει να διαβάσει τα αισθητήρια εγγύτητας και θερμοκρασίας και να υπολογίσει τη μέση τιμή τις θερμοκρασίας στο τέλος του κάθε παράθυρου.
Η επικοινωνία με τις άλλες συναρτήσεις για την εγγύτητα και την ολοκλήρωση του κύκλου μετρήσεων γίνεται μέσω των σημαιών \eng{flag\_proximity}και\eng{signal\_cycle}αντίστοιχα.
Ακόμα με βάση τις ρυθμίσεις και την τρέχουσα μέση θερμοκρασία, ορίζει τη σημαία της κατάστασης εξόδου \eng{flag\_output.}
\\
2. \textbf{\eng{display():}}\\
Η συνάρτηση αυτή υλοποιεί μια μηχανή καταστάσεων και αναλαμβάνει να εμφανίζει τα μηνύματα της οθόνης.
Στο διάγραμμα \ref{fig:uistates} φαίνονται οι καταστάσεις και ο τρόπος με τον οποίο γίνεται η εναλλαγή.
Σε κάθε κατάσταση η συνάρτηση διαμορφώνει ανάλογα το κείμενο στην οθόνη ώστε να πληρούνται οι προδιαγραφές της εργασίας.
\\
3. \textbf{\eng{outputs():}}\\
Η συνάρτηση αυτή ενεργοποιεί ή απενεργοποιεί τις εξόδους της κατασκευής μας, δηλαδή τα δύο \eng{led} και το \eng{relay.}
Το πράσινο \eng{led} ενεργοποιείται όταν ο θερμοστάτης είναι ρυθμισμένος για ψύξη και η μέση θερμοκρασία είναι πάνω από τη ρύθμιση.
Το κόκκινο αντίστοιχα όταν ο θερμοστάτης είναι ρυθμισμένος για θέρμανση και η μέση θερμοκρασία είναι κάτω από τη ρύθμιση.
Το \eng{relay} ενεργοποιείται όταν θέλουμε ψύξη ή θέρμανση.
\\
4. \textbf{\eng{console():}}\\
Η συνάρτηση αυτή υλοποιεί ένα πολύ απλό \eng{command interface} μέσω του οποίου μπορούμε από την σειριακή του υπολογιστή να δούμε όλες τις θερμοκρασίες και ρυθμίσεις της συσκευής.
Ακόμα μπορούμε να αλλάξουμε όλες τις ρυθμίσεις.
\InsertFigure{0.8}{fig:console}{console.png}{
Στιγμιότυπο από την σειριακή επικοινωνία με τον θερμοστάτη.
}
\par
Στο σημείο αυτό θα πρέπει να αναφέρουμε πως η λειτουργία των \eng{led} είναι λιγάκι αλλαγμένη από την εκφώνηση.
Ο λόγος είναι ότι ο εν λόγο θερμοστάτης πλέον έχει λειτουργία και ψύξης και θέρμανσης και θέλαμε να δώσουμε στο \eng{user interface} ένα πιο “δεμένο” ύφος.
\section{Συμπεράσματα - Παρατηρήσεις}
Συνοψίζοντας την εμπειρία μας με την παρούσα εργασία δεν έχουμε να αναφέρουμε κάποιο ιδιαίτερο πρόβλημα ή δυσκολία.
Η κατασκευή του τυπωμένου ευτυχώς δεν δημιούργησε εκπλήξεις με αποτέλεσμα η συγγραφή του κώδικα να γίνει απρόσκοπτα, αν και ομολογούμε ότι την κάναμε τελευταία στιγμή.
Παρατηρώντας την υλοποίηση βέβαια δεν μπορούμε παρά να τονίσουμε και μια παράβλεψη.
Ο θερμοστάτης δεν έχει κάποιο τρόπο να αποθηκεύει τις ρυθμίσεις στη \eng{flash.}
Αυτή η λειτουργία θα μπορούσε να είναι αιτία για να ξανασχοληθούμε στο μέλλον με την εργασία και ελπίζουμε αυτή μας η παράβλεψη να πέσει στην κατηγορία \textit{“για το μάτι”}.
% References
% ============================
%\begin{thebibliography}{100}
%\bibitem{item}item...
%\end{thebibliography}
\end{document}

138
assignment_3/src/console.c Normal file
View File

@ -0,0 +1,138 @@
/*!
* \file console.c
* \brief
* A simple serial console implementation for out thermostat
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include "console.h"
static char _buffer[COM_BUFFER_SIZE];
static int _cursor;
static char _ans[512];
/*!
* Parse and respond funcionality for serial console
* \param buffer Pointer to buffer
*/
void parse (char* buffer) {
int i;
float_t s;
if ((strncmp((const void*)buffer, "help", 4) == 0) ||
(strncmp((const void*)buffer, "?", 1) == 0) ) {
i = sprintf (_ans, "\r\nThermostat commands:\r\n");
i += sprintf (&_ans[i], "info : Get information\r\n");
i += sprintf (&_ans[i], "set Tset <val> : Set Thermostat\'s temperature\r\n");
i += sprintf (&_ans[i], "set Thyst <val> : Set Thermostat\'s hysteresis\r\n");
i += sprintf (&_ans[i], "set Pset <val> : Set Proximity\r\n");
i += sprintf (&_ans[i], "set Physt <val> : Set Proximity\'s hysteresis\r\n");
i += sprintf (&_ans[i], "set mode heating : Set Thermostat to heating mode\r\n");
i += sprintf (&_ans[i], "set mode cooling : Set Thermostat to cooling mode\r\n");
i += sprintf (&_ans[i], "\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)buffer, "info", 4) == 0) {
i = sprintf (_ans, "\r\nThermostat data:\r\n");
i += sprintf (&_ans[i], "Tcur = %4.1f\r\n", temp_get_current ());
i += sprintf (&_ans[i], "Tav = %4.1f\r\n", app_data.Tav);
i += sprintf (&_ans[i], "Mode = %s\r\n", (settings.mode == HEATING) ? "Heating" : "Cooling");
i += sprintf (&_ans[i], "Output = %s\r\n", (app_data.flag_output) ? "On" : "Off");
i += sprintf (&_ans[i], "Tset = %4.1f, Hyst = %4.1f\r\n", settings.Tset, settings.Thyst);
i += sprintf (&_ans[i], "Pset = %4.1f, Hyst = %4.1f\r\n", settings.Pset, settings.Physt);
i += sprintf (&_ans[i], "\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)buffer, "set ", 4) == 0) {
if (strncmp((const void*)&buffer[4], "Tset ", 5) == 0) {
sscanf((const void*)&buffer[9], "%f", &s);
if (s > -20 && s < 80) {
settings.Tset = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Thyst ", 6) == 0) {
sscanf((const void*)&buffer[10], "%f", &s);
if (s > 0 && s < 20) {
settings.Thyst = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Pset ", 5) == 0) {
sscanf((const void*)&buffer[9], "%f", &s);
if (s > 0 && s < 100)
settings.Pset = s;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Physt ", 6) == 0) {
sscanf((const void*)&buffer[10], "%f", &s);
if (s > 0 && s < 50) {
settings.Physt = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "mode ", 5) == 0) {
if (strncmp((const void*)&buffer[9], "heating", 7) == 0) {
settings.mode = HEATING;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[9], "cooling", 7) == 0) {
settings.mode = COOLING;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
}
else {
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
}
else {
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
COM_Transmit((uint8_t*)_ans, i);
}
/*!
* A simple terminal with echo
*/
void console (void) {
int ch;
if (COM_CheckReceive()) {
ch = COM_getchar(); // get character
COM_putchar((char)ch); // Echo back
_buffer[_cursor++] = ch; // store
// Backspace, delete
if (ch == 0x08 || ch == 0x7F)
--_cursor;
if (ch == 0 || ch == '\n' || ch == '\r') {
COM_putchar('\n'); // Echo an extra '\n'
_buffer[_cursor -1] = 0;
_cursor =0;
parse(_buffer);
}
if (_cursor >= COM_BUFFER_SIZE) {
_buffer[_cursor -1] = 0;
_cursor =0;
parse(_buffer);
}
}
}

View File

@ -0,0 +1,20 @@
/*!
* \file console.h
* \brief
* A simple serial console implementation for out thermostat
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#ifndef CONSOLE_H_
#define CONSOLE_H_
#include <hal.h>
#include "thermostat.h"
#include <string.h>
extern float_t temp_get_current (void);
void console (void);
#endif /* CONSOLE_H_ */

206
assignment_3/src/main.c Normal file
View File

@ -0,0 +1,206 @@
/*!
* \file
* main.c
* \brief
* Main application file
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include <hal.h>
#include "thermostat.h"
#include "console.h"
/*
* Zero initialized globals
*/
app_data_t app_data;
state_en state;
// Value initialized globals
settings_t _Init_settings(settings);
/*
* helper api
*/
float_t temp_get_current (void) {
return (app_data.cur) ? app_data.T[app_data.cur-1] : app_data.T[MEASUREMENTS-1];
}
/*!
* Control functionality
* Handles:
* * Sensor reading
* * Temp averaging
* * Output calculation
* \note Non-blocking
*/
void control (void) {
static time_t sample =0;
time_t now = time(0); // get time
// Proximity
if (proximity(&prox) < settings.Pset)
app_data.flag_proximity = 1;
else if (proximity(&prox) < settings.Pset + settings.Physt)
;
else
app_data.flag_proximity = 0;
// Temperature calculation
if (now - sample >= MEAS_INTERVAL) {
sample = now;
app_data.T[app_data.cur] = temp_read();
if (++app_data.cur >= MEASUREMENTS) {
app_data.cur =0;
float_t f =0;
for (int i=0 ; i<MEASUREMENTS ; ++i) {
f += app_data.T[i];
}
app_data.Tav = f / MEASUREMENTS;
app_data.signal_cycle = 1;
app_data.flag_init = 0;
}
}
// Output handling
if (!app_data.flag_init) {
switch (settings.mode) {
case HEATING: {
if (app_data.Tav <= settings.Tset)
app_data.flag_output = 1;
else if (app_data.Tav < settings.Tset + settings.Thyst)
;
else
app_data.flag_output = 0;
}
break;
case COOLING: {
if (app_data.Tav <= settings.Tset - settings.Thyst)
app_data.flag_output = 0;
else if (app_data.Tav < settings.Tset)
;
else
app_data.flag_output = 1;
}
break;
}
}
}
/*!
* Display functionality
* Implement a state machine for lcd display
* \note Non-blocking
*/
void display (void) {
static time_t mark =0;
char line1[18];
char line2[18];
time_t now = time(0);
switch (state) {
case ST_INIT:
sprintf(line1, "\fInitializing %c ", (time(0)%2) ? '*' : ' ');
sprintf(line2, "\n ");
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (app_data.signal_cycle) {
app_data.signal_cycle =0;
mark = now;
state = ST_AVERAGE;
}
break;
case ST_COUNT:
sprintf(line1, "\fMeasuring %c ", (time(0)%2) ? '*' : ' ');
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (app_data.signal_cycle) {
app_data.signal_cycle =0;
mark = now;
state = ST_AVERAGE;
}
break;
case ST_AVERAGE:
sprintf(line1, "\fTav=%4.1f ", app_data.Tav);
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (now - mark >= UI_AVERAGE_TIME)
state = ST_COUNT;
break;
case ST_USER:
sprintf(line1, "\fTav=%4.1f T=%4.1f", app_data.Tav, temp_get_current());
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (!app_data.flag_proximity)
state = ST_COUNT;
break;
}
lcd_puts(line1);
lcd_puts(line2);
}
/*!
* Set outputs
* \note Non-blocking
*/
void outputs (void) {
static uint8_t pr_output =0;
if (app_data.flag_init)
return;
led_green(app_data.flag_output && settings.mode == COOLING);
led_red (app_data.flag_output && settings.mode == HEATING);
if (app_data.flag_output != pr_output) {
relay(app_data.flag_output);
pr_output = app_data.flag_output;
}
}
/*
* Main loop
*/
int main(void) {
hal_hw_init ();
lcd_init ();
proximity_init(&prox);
temp_init (TEMP_11_BIT);
lcd_enable(1);
app_data.flag_init = 1;
while (1) {
control ();
display ();
outputs();
console ();
HAL_Delay(10);
}
}

View File

@ -0,0 +1,84 @@
/*!
* \file thermostat.h
* \brief
* Application wide data type declarations
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#ifndef THERMOSTAT_H_
#define THERMOSTAT_H_
/*
* Hard coded user settings
*/
#define MEAS_WINDOW (120) // [sec]
#define MEAS_INTERVAL (5) // [sec]
#define MEASUREMENTS (MEAS_WINDOW / MEAS_INTERVAL) // keep this integer
#define UI_AVERAGE_TIME (10) // [sec]
//#define UI_USER_TIME (10)
typedef float float_t; //!< Select the floating point type for application
typedef int int_t; //!< Select the integer type for application
/*!
* Thermostat mode enumerator
*/
typedef enum {
HEATING =0, //!< HEATING
COOLING //!< COOLING
} mode_en;
/*!
* Application common data type
*/
typedef struct {
float_t T[MEASUREMENTS]; //!< Temperature samples
float_t Tav; //!< Average temperature
uint32_t cur; //!< Cursor on sample array
uint8_t flag_output; //!< Momentary flag to indicate the relay state
uint8_t flag_init; //!< Momentary flag to indicate the end of initialization state
uint8_t flag_proximity; //!< Momentary flag to indicate that the user is near
uint8_t signal_cycle; //!< Acknolegable flag to indicate the end of measurement cycle
} app_data_t;
/*!
* Settings struct
*/
typedef struct {
mode_en mode; //!< Operational mode
float_t Tset; //!< Target temperature
float_t Thyst; //!< Target temperature hysteresis
float_t Pset; //!< Proximity distance
float_t Physt; //!< Proximity distance hysteresis
} settings_t;
/*!
* User interface states
*/
typedef enum {
ST_INIT =0, //!< ST_INIT: Still initializing
ST_COUNT, //!< ST_COUNT: Measurement cycle
ST_AVERAGE, //!< ST_AVERAGE: Display average
ST_USER //!< ST_USER: Display when a user is near
} state_en;
/*
* globals
*/
extern app_data_t app_data;
extern state_en state;
extern settings_t settings;
/*!
* Factory defaults
*/
#define _Init_settings(s) s = { \
.mode = HEATING, \
.Tset = 21.0, \
.Thyst = 2.0, \
.Pset = 75.0, \
.Physt = 10.0 \
}
#endif /* THERMOSTAT_H_ */

View File

@ -0,0 +1,3 @@
History/
__Previews/
Project\ Logs\ for\ Thermostat/

@ -0,0 +1 @@
Subproject commit 430c900e41cda0cc88fd8b8b59c48bee025d8b41

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,143 @@
[OutputJobFile]
Version=1.0
Caption=
Description=
VaultGUID=
ItemGUID=
ItemHRID=
RevisionGUID=
RevisionId=
VaultHRID=
AutoItemHRID=
NextRevId=
FolderGUID=
LifeCycleDefinitionGUID=
RevisionNamingSchemeGUID=
[PublishSettings]
OutputFilePath2=\\vmware-host\Shared Folders\Shares\Micro\assignment_3\thermostat_shield\.PDF
ReleaseManaged2=0
OutputBasePath2=\\vmware-host\Shared Folders\Shares\Micro\assignment_3\thermostat_shield\
OutputPathMedia2=
OutputPathMediaValue2=
OutputPathOutputer2=[Output Type]
OutputPathOutputerPrefix2=
OutputPathOutputerValue2=
OutputFileName2=Thermostat.pdf
OutputFileNameMulti2=
UseOutputNameForMulti2=1
OutputFileNameSpecial2=
OpenOutput2=1
PromptOverwrite2=1
PublishMethod2=0
ZoomLevel2=50
FitSCHPrintSizeToDoc2=0
FitPCBPrintSizeToDoc2=0
GenerateNetsInfo2=1
MarkPins2=1
MarkNetLabels2=1
MarkPortsId2=1
GenerateTOC=1
ShowComponentParameters2=1
GlobalBookmarks2=0
OutputFilePath3=
ReleaseManaged3=1
OutputBasePath3=
OutputPathMedia3=
OutputPathMediaValue3=
OutputPathOutputer3=[Output Type]
OutputPathOutputerPrefix3=
OutputPathOutputerValue3=
OutputFileName3=
OutputFileNameMulti3=
UseOutputNameForMulti3=1
OutputFileNameSpecial3=
OpenOutput3=1
OutputFilePath4=
ReleaseManaged4=1
OutputBasePath4=
OutputPathMedia4=
OutputPathMediaValue4=
OutputPathOutputer4=[Output Type]
OutputPathOutputerPrefix4=
OutputPathOutputerValue4=
OutputFileName4=
OutputFileNameMulti4=
UseOutputNameForMulti4=1
OutputFileNameSpecial4=
OpenOutput4=1
PromptOverwrite4=1
PublishMethod4=5
ZoomLevel4=50
FitSCHPrintSizeToDoc4=1
FitPCBPrintSizeToDoc4=1
GenerateNetsInfo4=1
MarkPins4=1
MarkNetLabels4=1
MarkPortsId4=1
MediaFormat4=Windows Media file (*.wmv,*.wma,*.asf)
FixedDimensions4=1
Width4=352
Height4=288
MultiFile4=0
FramesPerSecond4=25
FramesPerSecondDenom4=1
AviPixelFormat4=7
AviCompression4=MP42 MS-MPEG4 V2
AviQuality4=100
FFmpegVideoCodecId4=13
FFmpegPixelFormat4=0
FFmpegQuality4=80
WmvVideoCodecName4=Windows Media Video V7
WmvQuality4=80
[GeneratedFilesSettings]
RelativeOutputPath2=\\vmware-host\Shared Folders\Shares\Micro\assignment_3\thermostat_shield\.PDF
OpenOutputs2=1
RelativeOutputPath3=
OpenOutputs3=1
AddToProject3=1
TimestampFolder3=0
UseOutputName3=0
OpenODBOutput3=0
OpenGerberOutput3=0
OpenNCDrillOutput3=0
OpenIPCOutput3=0
EnableReload3=0
RelativeOutputPath4=
OpenOutputs4=1
[OutputGroup1]
Name=
Description=
TargetOutputMedium=PDF
VariantName=[No Variations]
VariantScope=0
CurrentConfigurationName=
TargetPrinter=Virtual Printer
PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintJobKind=1|PrintWhat=1
OutputMedium1=Print Job
OutputMedium1_Type=Printer
OutputMedium1_Printer=
OutputMedium1_PrinterOptions=Record=PrinterOptions|Copies=1|Duplex=1|TrueTypeOptions=3|Collate=1|PrintJobKind=1|PrintWhat=1
OutputMedium2=PDF
OutputMedium2_Type=Publish
OutputMedium3=Folder Structure
OutputMedium3_Type=GeneratedFiles
OutputMedium4=Video
OutputMedium4_Type=Multimedia
OutputType1=Schematic Print
OutputName1=Schematic Prints
OutputCategory1=Documentation
OutputDocumentPath1=
OutputVariantName1=
OutputEnabled1=1
OutputEnabled1_OutputMedium1=0
OutputEnabled1_OutputMedium2=1
OutputEnabled1_OutputMedium3=0
OutputEnabled1_OutputMedium4=0
OutputDefault1=0
PageOptions1=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.09|XCorrection=1.00|YCorrection=1.00|PrintKind=0|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-3|MediaType=1|DitherType=10|PrintScaleMode=1|PaperKind=A4|PaperIndex=9
Configuration1_Name1=OutputConfigurationParameter1
Configuration1_Item1=Record=SchPrintView|ShowNoERC=True|ShowParamSet=True|ShowProbe=True|ShowBlanket=True|NoERCSymbolsToShow="Thin Cross","Thick Cross","Small Cross",Checkbox,Triangle|ShowNote=True|ShowNoteCollapsed=True|ExpandDesignator=True|ExpandNetLabel=False|ExpandPort=False|ExpandSheetNum=False|ExpandDocNum=False|PrintArea=0|PrintAreaRect.X1=0|PrintAreaRect.Y1=0|PrintAreaRect.X2=0|PrintAreaRect.Y2=0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
Record=TopLevelDocument|FileName=Main.SchDoc
Record=SheetSymbol|Record=SheetSymbol|SourceDocument=Main.SchDoc|Designator=R|SchDesignator=R|FileName=Relay.SchDoc|SymbolType=Normal|RawFileName=Relay.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=

Binary file not shown.

Binary file not shown.

Binary file not shown.