200117StepMotorControl

Dependencies:   X_NUCLEO_IHM02A1 TextLCD

Files at this revision

API Documentation at this revision

Comitter:
danjecsr
Date:
Thu Jan 16 06:27:47 2020 +0000
Parent:
27:b25816ce6043
Child:
29:d5c13978c8e9
Commit message:
1st(2020.01.16)

Changed in this revision

TextLCD2.lib Show annotated file Show diff for this revision Revisions of this file
eeprom/eeprom.cpp Show annotated file Show diff for this revision Revisions of this file
eeprom/eeprom.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD2.lib	Thu Jan 16 06:27:47 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/wim/code/TextLCD/#111ca62e8a59
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eeprom/eeprom.cpp	Thu Jan 16 06:27:47 2020 +0000
@@ -0,0 +1,747 @@
+/**
+  ******************************************************************************
+  * @file    EEPROM/EEPROM_Emulation/src/eeprom.c 
+  * @author  MCD Application Team
+  * @version V1.0.1
+  * @date    29-January-2016
+  * @brief   This file provides all the EEPROM emulation firmware functions.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+
+/** @addtogroup EEPROM_Emulation
+  * @{
+  */ 
+
+/* Includes ------------------------------------------------------------------*/
+#include "eeprom.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+
+/* Dummy variables to protect eeprom pages if code size is bigger than 32kb (F401) 
+needed in Mbed online compiler to avoid conflict with linker (N.S.) */
+const uint8_t Eeprom_area0[PAGE_SIZE] __attribute__((at(PAGE0_BASE_ADDRESS),used))={ [0 ... (PAGE_SIZE-1)] = 0xFF };
+const uint8_t Eeprom_area1[PAGE_SIZE] __attribute__((at(PAGE1_BASE_ADDRESS),used))={ [0 ... (PAGE_SIZE-1)] = 0xFF };
+
+
+/* Global variable used to store variable value in read sequence */
+uint16_t DataVar = 0;
+
+/* Virtual address defined by the user: 0xFFFF value is prohibited */
+extern uint16_t VirtAddVarTab[NB_OF_VAR];
+
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+static HAL_StatusTypeDef EE_Format(void);
+static uint16_t EE_FindValidPage(uint8_t Operation);
+static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data);
+static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data);
+static uint16_t EE_VerifyPageFullyErased(uint32_t Address);
+
+/**
+  * @brief  Restore the pages to a known good state in case of page's status
+  *   corruption after a power loss.
+  * @param  None.
+  * @retval - Flash error code: on write Flash error
+  *         - FLASH_COMPLETE: on success
+  */
+uint16_t EE_Init(void)
+{
+  uint16_t PageStatus0 = 6, PageStatus1 = 6;
+  uint16_t VarIdx = 0;
+  uint16_t EepromStatus = 0, ReadStatus = 0;
+  int16_t x = -1;
+  HAL_StatusTypeDef  FlashStatus;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+
+  /* Get Page0 status */
+  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
+  /* Get Page1 status */
+  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
+
+  pEraseInit.TypeErase = TYPEERASE_SECTORS;
+  pEraseInit.Sector = PAGE0_ID;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  
+  /* Check for invalid header states and repair if necessary */
+  switch (PageStatus0)
+  {
+    case ERASED:
+      if (PageStatus1 == VALID_PAGE) /* Page0 erased, Page1 valid */
+      {
+          /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        {
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else if (PageStatus1 == RECEIVE_DATA) /* Page0 erased, Page1 receive */
+      {
+        /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+        /* Mark Page1 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else /* First EEPROM access (Page0&1 are erased) or invalid state -> format EEPROM */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      break;
+
+    case RECEIVE_DATA:
+      if (PageStatus1 == VALID_PAGE) /* Page0 receive, Page1 valid */
+      {
+        /* Transfer data from Page1 to Page0 */
+        for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+        {
+          if (( *(__IO uint16_t*)(PAGE0_BASE_ADDRESS + 6)) == VirtAddVarTab[VarIdx])
+          {
+            x = VarIdx;
+          }
+          if (VarIdx != x)
+          {
+            /* Read the last variables' updates */
+            ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+            /* In case variable corresponding to the virtual address was found */
+            if (ReadStatus != 0x1)
+            {
+              /* Transfer the variable to the Page0 */
+              EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+              /* If program operation was failed, a Flash error code is returned */
+              if (EepromStatus != HAL_OK)
+              {
+                return EepromStatus;
+              }
+            }
+          }
+        }
+        /* Mark Page0 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else if (PageStatus1 == ERASED) /* Page0 receive, Page1 erased */
+      {
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+        /* Mark Page0 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else /* Invalid state -> format eeprom */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      break;
+
+    case VALID_PAGE:
+      if (PageStatus1 == VALID_PAGE) /* Invalid state -> format eeprom */
+      {
+        /* Erase both Page0 and Page1 and set Page0 as valid page */
+        FlashStatus = EE_Format();
+        /* If erase/program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+      }
+      else if (PageStatus1 == ERASED) /* Page0 valid, Page1 erased */
+      {
+        pEraseInit.Sector = PAGE1_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page1 */
+        if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      else /* Page0 valid, Page1 receive */
+      {
+        /* Transfer data from Page0 to Page1 */
+        for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+        {
+          if ((*(__IO uint16_t*)(PAGE1_BASE_ADDRESS + 6)) == VirtAddVarTab[VarIdx])
+          {
+            x = VarIdx;
+          }
+          if (VarIdx != x)
+          {
+            /* Read the last variables' updates */
+            ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+            /* In case variable corresponding to the virtual address was found */
+            if (ReadStatus != 0x1)
+            {
+              /* Transfer the variable to the Page1 */
+              EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+              /* If program operation was failed, a Flash error code is returned */
+              if (EepromStatus != HAL_OK)
+              {
+                return EepromStatus;
+              }
+            }
+          }
+        }
+        /* Mark Page1 as valid */
+        FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE1_BASE_ADDRESS, VALID_PAGE);        
+        /* If program operation was failed, a Flash error code is returned */
+        if (FlashStatus != HAL_OK)
+        {
+          return FlashStatus;
+        }
+        pEraseInit.Sector = PAGE0_ID;
+        pEraseInit.NbSectors = 1;
+        pEraseInit.VoltageRange = VOLTAGE_RANGE;
+        /* Erase Page0 */
+        if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+        { 
+          FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);
+          /* If erase operation was failed, a Flash error code is returned */
+          if (FlashStatus != HAL_OK)
+          {
+            return FlashStatus;
+          }
+        }
+      }
+      break;
+
+    default:  /* Any other state -> format eeprom */
+      /* Erase both Page0 and Page1 and set Page0 as valid page */
+      FlashStatus = EE_Format();
+      /* If erase/program operation was failed, a Flash error code is returned */
+      if (FlashStatus != HAL_OK)
+      {
+        return FlashStatus;
+      }
+      break;
+  }
+
+  return HAL_OK;
+}
+
+/**
+  * @brief  Verify if specified page is fully erased.
+  * @param  Address: page address
+  *   This parameter can be one of the following values:
+  *     @arg PAGE0_BASE_ADDRESS: Page0 base address
+  *     @arg PAGE1_BASE_ADDRESS: Page1 base address
+  * @retval page fully erased status:
+  *           - 0: if Page not erased
+  *           - 1: if Page erased
+  */
+uint16_t EE_VerifyPageFullyErased(uint32_t Address)
+{
+  uint32_t readstatus = 1;
+  uint16_t addressvalue = 0x5555;
+  uint32_t end_address;
+  
+  if (PAGE0_BASE_ADDRESS==Address)
+  {
+    end_address = PAGE0_END_ADDRESS;
+  }
+  else
+  {
+    end_address = PAGE1_END_ADDRESS;
+  };
+  
+    
+  /* Check each active page address starting from end */
+  while (Address <= end_address)
+  {
+    /* Get the current location content to be compared with virtual address */
+    addressvalue = (*(__IO uint16_t*)Address);
+
+    /* Compare the read address with the virtual address */
+    if (addressvalue != ERASED)
+    {
+      
+      /* In case variable value is read, reset readstatus flag */
+      readstatus = 0;
+
+      break;
+    }
+    /* Next address location */
+    Address = Address + 4;
+  }
+  
+  /* Return readstatus value: (0: Page not erased, 1: Page erased) */
+  return readstatus;
+}
+
+/**
+  * @brief  Returns the last stored variable data, if found, which correspond to
+  *   the passed virtual address
+  * @param  VirtAddress: Variable virtual address
+  * @param  Data: Global variable contains the read variable value
+  * @retval Success or error status:
+  *           - 0: if variable was found
+  *           - 1: if the variable was not found
+  *           - NO_VALID_PAGE: if no valid page was found.
+  */
+uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data)
+{
+  uint16_t ValidPage = PAGE0;
+  uint16_t AddressValue = 0x5555, ReadStatus = 1;
+  uint32_t Address = EEPROM_START_ADDRESS, PageStartAddress = EEPROM_START_ADDRESS;
+
+  /* Get active Page for read operation */
+  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);
+
+  /* Check if there is no valid page */
+  if (ValidPage == NO_VALID_PAGE)
+  {
+    return  NO_VALID_PAGE;
+  }
+
+  /* Get the valid Page start Address */
+  PageStartAddress = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
+
+  /* Get the valid Page end Address */
+  Address = (uint32_t)((EEPROM_START_ADDRESS - 2) + (uint32_t)((1 + ValidPage) * PAGE_SIZE));
+
+  /* Check each active page address starting from end */
+  while (Address > (PageStartAddress + 2))
+  {
+    /* Get the current location content to be compared with virtual address */
+    AddressValue = (*(__IO uint16_t*)Address);
+
+    /* Compare the read address with the virtual address */
+    if (AddressValue == VirtAddress)
+    {
+      /* Get content of Address-2 which is variable value */
+      *Data = (*(__IO uint16_t*)(Address - 2));
+
+      /* In case variable value is read, reset ReadStatus flag */
+      ReadStatus = 0;
+
+      break;
+    }
+    else
+    {
+      /* Next address location */
+      Address = Address - 4;
+    }
+  }
+
+  /* Return ReadStatus value: (0: variable exist, 1: variable doesn't exist) */
+  return ReadStatus;
+}
+
+/**
+  * @brief  Writes/upadtes variable data in EEPROM.
+  * @param  VirtAddress: Variable virtual address
+  * @param  Data: 16 bit data to be written
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data)
+{
+  uint16_t Status = 0;
+
+  /* Write the variable virtual address and value in the EEPROM */
+  Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
+
+  /* In case the EEPROM active page is full */
+  if (Status == PAGE_FULL)
+  {
+    /* Perform Page transfer */
+    Status = EE_PageTransfer(VirtAddress, Data);
+  }
+
+  /* Return last operation status */
+  return Status;
+}
+
+/**
+  * @brief  Erases PAGE and PAGE1 and writes VALID_PAGE header to PAGE
+  * @param  None
+  * @retval Status of the last operation (Flash write or erase) done during
+  *         EEPROM formating
+  */
+static HAL_StatusTypeDef EE_Format(void)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+  pEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;  
+  pEraseInit.Sector = PAGE0_ID;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  /* Erase Page0 */
+  if(!EE_VerifyPageFullyErased(PAGE0_BASE_ADDRESS))
+  {
+    FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError); 
+    /* If erase operation was failed, a Flash error code is returned */
+    if (FlashStatus != HAL_OK)
+    {
+      return FlashStatus;
+    }
+  }
+  /* Set Page0 as valid page: Write VALID_PAGE at Page0 base address */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE); 
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  pEraseInit.Sector = PAGE1_ID;
+  /* Erase Page1 */
+  if(!EE_VerifyPageFullyErased(PAGE1_BASE_ADDRESS))
+  {  
+    FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError); 
+    /* If erase operation was failed, a Flash error code is returned */
+    if (FlashStatus != HAL_OK)
+    {
+      return FlashStatus;
+    }
+  }
+  
+  return HAL_OK;
+}
+
+/**
+  * @brief  Find valid Page for write or read operation
+  * @param  Operation: operation to achieve on the valid page.
+  *   This parameter can be one of the following values:
+  *     @arg READ_FROM_VALID_PAGE: read operation from valid page
+  *     @arg WRITE_IN_VALID_PAGE: write operation from valid page
+  * @retval Valid page number (PAGE or PAGE1) or NO_VALID_PAGE in case
+  *   of no valid page was found
+  */
+static uint16_t EE_FindValidPage(uint8_t Operation)
+{
+  uint16_t PageStatus0 = 6, PageStatus1 = 6;
+
+  /* Get Page0 actual status */
+  PageStatus0 = (*(__IO uint16_t*)PAGE0_BASE_ADDRESS);
+
+  /* Get Page1 actual status */
+  PageStatus1 = (*(__IO uint16_t*)PAGE1_BASE_ADDRESS);
+
+  /* Write or read operation */
+  switch (Operation)
+  {
+    case WRITE_IN_VALID_PAGE:   /* ---- Write operation ---- */
+      if (PageStatus1 == VALID_PAGE)
+      {
+        /* Page0 receiving data */
+        if (PageStatus0 == RECEIVE_DATA)
+        {
+          return PAGE0;         /* Page0 valid */
+        }
+        else
+        {
+          return PAGE1;         /* Page1 valid */
+        }
+      }
+      else if (PageStatus0 == VALID_PAGE)
+      {
+        /* Page1 receiving data */
+        if (PageStatus1 == RECEIVE_DATA)
+        {
+          return PAGE1;         /* Page1 valid */
+        }
+        else
+        {
+          return PAGE0;         /* Page0 valid */
+        }
+      }
+      else
+      {
+        return NO_VALID_PAGE;   /* No valid Page */
+      }
+
+    case READ_FROM_VALID_PAGE:  /* ---- Read operation ---- */
+      if (PageStatus0 == VALID_PAGE)
+      {
+        return PAGE0;           /* Page0 valid */
+      }
+      else if (PageStatus1 == VALID_PAGE)
+      {
+        return PAGE1;           /* Page1 valid */
+      }
+      else
+      {
+        return NO_VALID_PAGE ;  /* No valid Page */
+      }
+
+    default:
+      return PAGE0;             /* Page0 valid */
+  }
+}
+
+/**
+  * @brief  Verify if active page is full and Writes variable in EEPROM.
+  * @param  VirtAddress: 16 bit virtual address of the variable
+  * @param  Data: 16 bit data to be written as variable value
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint16_t ValidPage = PAGE0;
+  uint32_t Address = EEPROM_START_ADDRESS, PageEndAddress = EEPROM_START_ADDRESS+PAGE_SIZE;
+
+  /* Get valid Page for write operation */
+  ValidPage = EE_FindValidPage(WRITE_IN_VALID_PAGE);
+  
+  /* Check if there is no valid page */
+  if (ValidPage == NO_VALID_PAGE)
+  {
+    return  NO_VALID_PAGE;
+  }
+
+  /* Get the valid Page start Address */
+  Address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(ValidPage * PAGE_SIZE));
+
+  /* Get the valid Page end Address */
+  PageEndAddress = (uint32_t)((EEPROM_START_ADDRESS - 1) + (uint32_t)((ValidPage + 1) * PAGE_SIZE));
+
+  /* Check each active page address starting from begining */
+  while (Address < PageEndAddress)
+  {
+    /* Verify if Address and Address+2 contents are 0xFFFFFFFF */
+    if ((*(__IO uint32_t*)Address) == 0xFFFFFFFF)
+    {
+      /* Set variable data */
+      FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, Address, Data);       
+      /* If program operation was failed, a Flash error code is returned */
+      if (FlashStatus != HAL_OK)
+      {
+        return FlashStatus;
+      }
+      /* Set variable virtual address */
+      FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, Address + 2, VirtAddress);       
+      /* Return program operation status */
+      return FlashStatus;
+    }
+    else
+    {
+      /* Next address location */
+      Address = Address + 4;
+    }
+  }
+
+  /* Return PAGE_FULL in case the valid page is full */
+  return PAGE_FULL;
+}
+
+/**
+  * @brief  Transfers last updated variables data from the full Page to
+  *   an empty one.
+  * @param  VirtAddress: 16 bit virtual address of the variable
+  * @param  Data: 16 bit data to be written as variable value
+  * @retval Success or error status:
+  *           - FLASH_COMPLETE: on success
+  *           - PAGE_FULL: if valid page is full
+  *           - NO_VALID_PAGE: if no valid page was found
+  *           - Flash error code: on write Flash error
+  */
+static uint16_t EE_PageTransfer(uint16_t VirtAddress, uint16_t Data)
+{
+  HAL_StatusTypeDef FlashStatus = HAL_OK;
+  uint32_t NewPageAddress = EEPROM_START_ADDRESS;
+  uint16_t OldPageId=0;
+  uint16_t ValidPage = PAGE0, VarIdx = 0;
+  uint16_t EepromStatus = 0, ReadStatus = 0;
+  uint32_t SectorError = 0;
+  FLASH_EraseInitTypeDef pEraseInit;
+
+  /* Get active Page for read operation */
+  ValidPage = EE_FindValidPage(READ_FROM_VALID_PAGE);
+
+  if (ValidPage == PAGE1)       /* Page1 valid */
+  {
+    /* New page address where variable will be moved to */
+    NewPageAddress = PAGE0_BASE_ADDRESS;
+
+    /* Old page ID where variable will be taken from */
+    OldPageId = PAGE1_ID;
+  }
+  else if (ValidPage == PAGE0)  /* Page0 valid */
+  {
+    /* New page address  where variable will be moved to */
+    NewPageAddress = PAGE1_BASE_ADDRESS;
+
+    /* Old page ID where variable will be taken from */
+    OldPageId = PAGE0_ID;
+  }
+  else
+  {
+    return NO_VALID_PAGE;       /* No valid Page */
+  }
+
+  /* Set the new Page status to RECEIVE_DATA status */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, NewPageAddress, RECEIVE_DATA);  
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+  
+  /* Write the variable passed as parameter in the new active page */
+  EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddress, Data);
+  /* If program operation was failed, a Flash error code is returned */
+  if (EepromStatus != HAL_OK)
+  {
+    return EepromStatus;
+  }
+
+  /* Transfer process: transfer variables from old to the new active page */
+  for (VarIdx = 0; VarIdx < NB_OF_VAR; VarIdx++)
+  {
+    if (VirtAddVarTab[VarIdx] != VirtAddress)  /* Check each variable except the one passed as parameter */
+    {
+      /* Read the other last variable updates */
+      ReadStatus = EE_ReadVariable(VirtAddVarTab[VarIdx], &DataVar);
+      /* In case variable corresponding to the virtual address was found */
+      if (ReadStatus != 0x1)
+      {
+        /* Transfer the variable to the new active page */
+        EepromStatus = EE_VerifyPageFullWriteVariable(VirtAddVarTab[VarIdx], DataVar);
+        /* If program operation was failed, a Flash error code is returned */
+        if (EepromStatus != HAL_OK)
+        {
+          return EepromStatus;
+        }
+      }
+    }
+  }
+
+  pEraseInit.TypeErase = TYPEERASE_SECTORS;
+  pEraseInit.Sector = OldPageId;
+  pEraseInit.NbSectors = 1;
+  pEraseInit.VoltageRange = VOLTAGE_RANGE;
+  
+  /* Erase the old Page: Set old Page status to ERASED status */
+  FlashStatus = HAL_FLASHEx_Erase(&pEraseInit, &SectorError);  
+  /* If erase operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  /* Set new Page status to VALID_PAGE status */
+  FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, NewPageAddress, VALID_PAGE);   
+  /* If program operation was failed, a Flash error code is returned */
+  if (FlashStatus != HAL_OK)
+  {
+    return FlashStatus;
+  }
+
+  /* Return last operation flash status */
+  return FlashStatus;
+}
+
+/**
+  * @}
+  */ 
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eeprom/eeprom.h	Thu Jan 16 06:27:47 2020 +0000
@@ -0,0 +1,105 @@
+/**
+  ******************************************************************************
+  * @file    EEPROM/EEPROM_Emulation/inc/eeprom.h 
+  * @author  MCD Application Team
+  * @version V1.0.1
+  * @date    29-January-2016
+  * @brief   This file contains all the functions prototypes for the EEPROM 
+  *          emulation firmware library.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */ 
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __EEPROM_H
+#define __EEPROM_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f4xx_hal.h"
+
+/* Exported constants --------------------------------------------------------*/
+/* EEPROM emulation firmware error codes */
+#define EE_OK      (uint32_t)HAL_OK
+#define EE_ERROR   (uint32_t)HAL_ERROR
+#define EE_BUSY    (uint32_t)HAL_BUSY
+#define EE_TIMEOUT (uint32_t)HAL_TIMEOUT
+
+/* Define the size of the sectors to be used */
+#define PAGE_SIZE               (uint32_t)0x4000  /* Page size = 16KByte */
+
+/* Device voltage range supposed to be [2.7V to 3.6V], the operation will 
+   be done by word  */
+#define VOLTAGE_RANGE           (uint8_t)VOLTAGE_RANGE_3
+
+/* EEPROM start address in Flash */
+#define EEPROM_START_ADDRESS  ((uint32_t)0x08008000) /* EEPROM emulation start address:
+                                                  from sector2 : after 16KByte of used 
+                                                  Flash memory */
+
+/* Pages 0 and 1 base and end addresses */
+#define PAGE0_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
+#define PAGE0_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
+#define PAGE0_ID               FLASH_SECTOR_2
+
+#define PAGE1_BASE_ADDRESS    ((uint32_t)(EEPROM_START_ADDRESS + 0x4000))
+#define PAGE1_END_ADDRESS     ((uint32_t)(EEPROM_START_ADDRESS + (2 * PAGE_SIZE - 1)))
+#define PAGE1_ID               FLASH_SECTOR_3
+
+/* Used Flash pages for EEPROM emulation */
+#define PAGE0                 ((uint16_t)0x0000)
+#define PAGE1                 ((uint16_t)0x0001) /* Page nb between PAGE0_BASE_ADDRESS & PAGE1_BASE_ADDRESS*/
+
+/* No valid page define */
+#define NO_VALID_PAGE         ((uint16_t)0x00AB)
+
+/* Page status definitions */
+#define ERASED                ((uint16_t)0xFFFF)     /* Page is empty */
+#define RECEIVE_DATA          ((uint16_t)0xEEEE)     /* Page is marked to receive data */
+#define VALID_PAGE            ((uint16_t)0x0000)     /* Page containing valid data */
+
+/* Valid pages in read and write defines */
+#define READ_FROM_VALID_PAGE  ((uint8_t)0x00)
+#define WRITE_IN_VALID_PAGE   ((uint8_t)0x01)
+
+/* Page full define */
+#define PAGE_FULL             ((uint8_t)0x80)
+
+/* Variables' number */
+#define NB_OF_VAR             ((uint8_t)0x03)
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported macro ------------------------------------------------------------*/
+/* Exported functions ------------------------------------------------------- */
+uint16_t EE_Init(void);
+uint16_t EE_ReadVariable(uint16_t VirtAddress, uint16_t* Data);
+uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data);
+
+#endif /* __EEPROM_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
--- a/main.cpp	Mon Jul 03 11:53:02 2017 +0000
+++ b/main.cpp	Thu Jan 16 06:27:47 2020 +0000
@@ -1,81 +1,107 @@
 /**
  ******************************************************************************
- * @file    main.cpp
- * @author  Davide Aliprandi, STMicroelectronics
- * @version V1.0.0
- * @date    November 4th, 2015
- * @brief   mbed test application for the STMicroelectronics X-NUCLEO-IHM02A1
- *          Motor Control Expansion Board: control of 2 motors.
- ******************************************************************************
- * @attention
- *
- * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *   1. Redistributions of source code must retain the above copyright notice,
- *      this list of conditions and the following disclaimer.
- *   2. Redistributions in binary form must reproduce the above copyright notice,
- *      this list of conditions and the following disclaimer in the documentation
- *      and/or other materials provided with the distribution.
- *   3. Neither the name of STMicroelectronics nor the names of its contributors
- *      may be used to endorse or promote products derived from this software
- *      without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ 이프로그램은 16x2크기의 LCD표시 및 제어, 스텝모터 제어 2가지 기능을 한다.
+ 사용자에서 실시간으로 LCD와 스텝모터의 동시제어를 위하여 2개의 쓰레드로 분리시켰다.
+ 모터가 회전할때는 적어도 1~2초의 시간이 소모되는데, 싱글 쓰레드로 한다면 모터가 작동할때
+ LCD제어는 멈추게 된다. 따라서 작은시간을 서로 쪼개어 사용하여 서로간의 제어에
+ 영향을 받지 않도록 하기 위하여 2개의 쓰레드로 분리 시켰음.
  ******************************************************************************
  */
 
 
 /* Includes ------------------------------------------------------------------*/
 
-/* mbed specific header files. */
+// mbed의 기능을 사용하기 위한 헤더파일
 #include "mbed.h"
 #include "rtos.h"
 
-/* Helper header files. */
+
+//텍스트LCD를 사용하기 위한 라이브러리의 헤더파일
+#include "TextLCD.h"
+
+//내부 FLASH ROM을 사용하기 위한 라이브러리 헤더파일
+#include "eeprom.h"
+#include <ctype.h>
+
+//스텝모터 드라이버와 SPI통신을 위한 헤더파일
 #include "DevSPI.h"
 
-/* Expansion Board specific header files. */
+//스텝모터 확장보드 사용을 위한 라이브러리 헤더파일
 #include "XNucleoIHM02A1.h"
 
 
-/* Definitions ---------------------------------------------------------------*/
+
 
-/* Number of movements per revolution. */
-#define MPR_1 4
+/*----------------------------------------------LCD제어관련 변수정의 -------------------------------------------------------*/
+//16x2 크기의 LCD를 제어하기 위한 객체생성
+TextLCD lcd(D10, D9, D8, D7, D6, D5,TextLCD::LCD16x2); // H/L Register(RS) 선택핀, Enable(E) 선택핀, D4,D5,D6,D7(LCD출력핀)
+//DigitalOut rw(D7);                                    // H/L Read,Write신호핀
+
+//Digital 입력핀 설정(기본으로 신호가 없을시 풀다운신호(0V)를 출력하도록 설정한다.)
+DigitalIn setin(A3,PullDown);   //설정버튼
+DigitalIn movin(D15,PullDown);   //자릿수선택 버튼
+DigitalIn upin(D14,PullDown);    //값올림 버튼
+DigitalIn downin(D2,PullDown);  //값내림 버튼
 
-/* Number of steps. */
-#define STEPS_1 (400 * 128)   /* 1 revolution given a 400 steps motor configured at 1/128 microstep mode. */
-#define STEPS_2 (STEPS_1 * 2)
+//DigitalIn set(D9);   //설정버튼
+//DigitalIn mov(D8);   //자릿수선택 버튼
+//DigitalIn up(D1);    //값올림 버튼
+//DigitalIn down(D0);  //값내림 버튼
+//LCD 출력의 현재시각 측정(단위:초)
+time_t NOWLCD;
+//LCD 출력을 조절하기 위한 이전시각(NOWLCD)저장
+time_t DISPLAY_TIME;
 
-/* Delay in milliseconds. */
-#define DELAY_1 1000
-#define DELAY_2 2000
-#define DELAY_3 5000
+float SV  = 10.5;             //절삭유 농도 지시값(기준값)
+int   SV1 = 1;                //화면에 표시될 절삭유 농도 지시값(10의 자릿수값 정수값1문자)
+int   SV2 = 0;                //화면에 표시될 절삭유 농도 지시값(1의 자릿수값 정수값1문자)
+int   SV3 = 5;                //화면에 표시될 절삭유 농도 지시값(소수점1의 자릿수값 정수값1문자)
+
+int   SET_SV1 = 0;            //설정모드에서 표시될 농도 지시값(10의 자릿수값)
+int   SET_SV2 = 0;            //설정모드에서 표시될 농도 지시값(1의 자릿수값)
+int   SET_SV3 = 0;            //설정모드에서 표시될 농도 지시값(소수점1의 자릿수값)
 
 
-/* Variables -----------------------------------------------------------------*/
+uint16_t VirtAddVarTab[2] = {0x0000, 0x0001};
+uint16_t VarDataTab[] = {0, 0};
+
+float PV  = 0;                //현재측정 절삭유 농도값
+float PPV = 0;                //이전측정 절각유 농도값
+
+int OIL_VALVE_OPEN_P = 0;     //오일밸브 열림%
+int WATER_VALVE_OPEN_P = 0;   //희석수밸브 열림%
+int OIL_VALVE_OPEN_PP = 0;    //오일밸브 열림%(이전값)
+int WATER_VALVE_OPEN_PP = 0;  //희석수밸브 열림%(이전값)
+
+bool set_button  = false;     //설정버튼 눌림 플래그
+bool mov_button  = false;     //자릿수선택 버튼 눌림 플래그
+bool up_button   = false;     //값올림버튼 눌림 플래그
+bool down_button = false;     //값내림버튼 눌림 플래그
 
-/* Motor Control Expansion Board. */
+bool set_mode = false;        //설정버튼 ON/OFF모드  
+int cursor_loc = 0;           //SV값을 설정하기 위하여 현재cursor의 위치를 저장(2번째행 11번열, 12번열 두개값중에 하나를 저장하고 있음)
+
+
+
+
+/*----------------------------------------------STEP모터 제어관련 변수정의 -------------------------------------------------------*/
+
+
+//스텝수 정의
+#define STEPS_1 (200 * 128)   //1바퀴에 200스텝(1스텝당 1.8도)을 가지고 있는 스텝모터를 1/128정밀도의 마이크로 스텝을 제어.(1바퀴 회전정의)
+#define STEPS_2 (STEPS_1 * 2) //2바퀴 회전정의
+
+
+
+//스텝모터 확장모듈 드라이버 객체생성
 XNucleoIHM02A1 *x_nucleo_ihm02a1;
 
-/* Initialization parameters of the motors connected to the expansion board. */
+//스텝모터 파라미터값 정의
 L6470_init_t init[L6470DAISYCHAINSIZE] = {
-    /* First Motor. */
+    // 첫번째 Motor.(절삭유밸브 모터)
     {
-        9.0,                           /* Motor supply voltage in V. */
-        400,                           /* Min number of steps per revolution for the motor. */
+        12.0,                          /* Motor supply voltage in V. */
+        200,                           /* Min number of steps per revolution for the motor. */
         1.7,                           /* Max motor phase voltage in A. */
         3.06,                          /* Max motor phase voltage in V. */
         300.0,                         /* Motor initial speed [step/s]. */
@@ -100,10 +126,10 @@
         0x2E88                         /* Ic configuration. */
     },
 
-    /* Second Motor. */
+    //두번째 Motor(희석수밸브 모터)
     {
-        9.0,                           /* Motor supply voltage in V. */
-        400,                           /* Min number of steps per revolution for the motor. */
+        12.0,                          /* Motor supply voltage in V. */
+        200,                           /* Min number of steps per revolution for the motor. */
         1.7,                           /* Max motor phase voltage in A. */
         3.06,                          /* Max motor phase voltage in V. */
         300.0,                         /* Motor initial speed [step/s]. */
@@ -130,306 +156,615 @@
 };
 
 
+
+//현재 농도를 받아오는 Analog input 핀번호를 선택한다.(PA_0)즉 핀번호 Analog 0번핀을 선택한다.
+AnalogIn  CurCon(A0);
+
+
+//절삭유밸브와 희석수밸브의 초기위치
+int oilhomeposition = 0;
+int waterhomeposition = 0;
+
+//오일탱크밸브와 수탱크밸브가 오픈된 시간을 저장
+Timer OIL_VALVE_TIMER;
+Timer WATER_VALVE_TIMER;
+
+
+//밸브가 열린후 카운트 시간
+time_t OIL_VALVE_OPEN_TIME;
+time_t WATER_VALVE_OPEN_TIME;
+
+//현재시각
+time_t NOW;
+
+//오일탱크밸브와 수탱크밸브가 열려있는지 저장
+bool OIL_VALVE_ON = false;
+bool WATER_VALVE_ON = false;
+
+
+//딜레이시간 정의 (milli seconds)
+#define DELAY_1 1000
+#define DELAY_2 2000
+#define DELAY_3 5000
+
+
+
+//LCD제어를 위한 쓰레드 생성
+void LCD_CTRL_THREAD(void const *args)
+{
+    
+    //설정값을 FLASH메모리에서 읽고쓰기하기 위하여 락을 해제한다.
+    HAL_FLASH_Unlock();
+    EE_Init();
+    
+    
+    //SV값은 총4byte float값인데 EEPROM Library는 기본적으로 2byte씩메모리를 엑세스하게 되어있음
+    //따라서 2byte메모리를 읽어서 4byte값으로 만들것임.
+    for (int i=0; i<2; i++)
+    {
+        EE_ReadVariable(VirtAddVarTab[i], &VarDataTab[i]);
+    }
+    
+    //읽은값을 정수자릿수 2byte + 소숫점1자릿수 2byte값을 합쳐서 4byte float값으로 변경(설정값 저장)
+    SV = VarDataTab[0] + VarDataTab[1]*0.1;
+    
+    
+    //SV값을 LCD에 출력하기위하여 SV1,SV2,SV3로 분리한다.
+    SV1 = (int)(SV/10);
+    SV2 = (int)(SV-(SV1*10));
+    SV3 = (int)(((SV-((SV1*10)+SV2))*10)+0.5);
+    
+
+    
+    
+    //rw =0;
+    lcd.cls(); //화면을 초기화 한다.
+    
+    
+
+    //절삭유 공급밸브 열림% LCD출력
+    lcd.locate(0,0);
+    lcd.printf("P1:");
+    lcd.printf("%03d%%",OIL_VALVE_OPEN_P);
+    
+    //절삭유 현재 농도값 LCD출력
+    lcd.locate(8,0);
+    lcd.printf("PV:");
+    lcd.printf("%02.1f%%",PV);
+    
+    //희석수 공급밸브 열림% LCD출력
+    lcd.locate(0,1);
+    lcd.printf("P2:");
+    lcd.printf("%03d%%",WATER_VALVE_OPEN_P);
+    
+    //절삭유 지시(목표) 농도값 LCD출력
+    lcd.locate(8,1);
+    lcd.printf("SV:");
+    lcd.printf("%d%d.%d%%",SV1,SV2,SV3);
+    
+    
+    //커서표시와 깜밖임을 없앤다.
+    lcd.setCursor(lcd.CurOff_BlkOff);
+    
+    
+    
+    while (1)
+    {
+        NOWLCD = time(NULL);
+        /*------------------------------- LCD표시 ---------------------------------------------------*/
+        //1.5초마다 화면을 갱신한다.
+        if(NOWLCD - DISPLAY_TIME >= 1.5 and !set_mode)
+        {
+        
+            //현재 측정한 절삭유 농도값이 이전측정값과 다르다면 LCD화면을 갱신한다.
+            if(PV != PPV)
+            {
+                lcd.locate(11,0);
+                lcd.printf("%02.1f%%",PV);
+                
+                //현재값을 이전값변수에 입력한다.(다음타이밍에 비교하기 위하여)
+                PPV = PV;
+            }
+            
+            //현재 오일밸브의 오픈%가 이전값과 달다면 LCD화면을 갱신한다.
+            if(OIL_VALVE_OPEN_P != OIL_VALVE_OPEN_PP)
+            {
+                lcd.locate(3,0);
+                lcd.printf("%03d%%",OIL_VALVE_OPEN_P);
+                
+                //현재값을 이전 측정값을 저장하는 변수에 복사
+                OIL_VALVE_OPEN_PP = OIL_VALVE_OPEN_P;
+            }
+            
+            
+            //현재 희석수밸브의 오픈%가 이전값과 달다면 LCD화면을 갱신한다.
+            if(WATER_VALVE_OPEN_P != WATER_VALVE_OPEN_PP)
+            {
+                lcd.locate(3,1);
+                lcd.printf("%03d%%",WATER_VALVE_OPEN_P);
+                
+                //현재값을 이전 측정값을 저장하는 변수에 복사
+                WATER_VALVE_OPEN_PP = WATER_VALVE_OPEN_P;
+            }
+            
+            //다음 시간비교를 위해서 현재시각을 저장한다.
+            DISPLAY_TIME = NOWLCD;
+        }
+        
+        
+        
+        
+        /*------------------------------- LCD설정 ---------------------------------------------------*/
+        
+        //----------농도 설정
+        //SV(농도지시값)값 설정버튼(SET)을 눌렀을경우 플래그를 세팅한다.(정확한 세팅상태를 지정하기 위함) 
+        if(setin and set_button == false)
+        {         
+            set_button = true;                    //설정버튼 플래그 활성화
+        }
+        
+        //SET버튼이 눌려지다가 떨어지면 세팅모드로 들어간다.
+        if(!setin and set_button == true and set_mode == false)
+        {
+            printf("LCD SETTING MODE IN\r\n");         
+            lcd.locate(14,1);                     //설정값 첫번째 위치로 이동
+            cursor_loc = 14;                      //현재 커서위치 저장          
+            lcd.setCursor(lcd.CurOff_BlkOn);      //설정위치에서 커서 깜박임
+                      
+            set_mode = true;                      //설정모드 활성화
+            set_button = false;                   //설정버튼 플래그 초기화
+        }
+               
+        //만약 SV설정 버튼이 true인 상태에서 한번더 누르면 현재값을 저장하고 모드를 빠져나온다(커서의 깜박임을 멈춘다.)
+        if(!setin and set_button == true and set_mode == true )
+        {  
+            printf("LCD SETTING MODE OUT\r\n");
+            SV = (SV1*10) + (SV2*1) + (SV3*0.1);  //설정값을 float형(4byte 부동소수점형)으로 저장한다.
+            
+            //플래쉬메모리에 설정값을 저장한다.
+            
+            //정수자릿수와 소수점 자릿수로 나눈다.
+            VarDataTab[0] = (uint16_t)SV;                            //정수자릿수
+            VarDataTab[1] = (uint16_t)(((SV-VarDataTab[0])*10)+0.5); //소수점1자릿수(45.5라는 숫자가 45.4999999같은 값이 될수 있으므로 소수점 첫번째에서 반올림한다.)
+    
+            //내부 플래쉬 메모리에 값을 저장한다.
+            EE_WriteVariable(VirtAddVarTab[0],VarDataTab[0] );
+            EE_WriteVariable(VirtAddVarTab[1],VarDataTab[1] );
+                
+            lcd.setCursor(lcd.CurOff_BlkOff);     //설정위치의 커버 깜박임 꺼짐
+                      
+            set_mode = false;                     //설정모드 종료        
+            set_button = false;                   //설정버튼 플래그 초기화
+        }
+        
+        
+        
+        
+        
+        
+        
+        
+        //-------------자릿수 설정
+        //자릿수 지정버튼(◁)을 눌렀을경우 플래그를 세팅한다.(정확한 세팅상태를 지정하기 위함)
+        if(movin and mov_button == false and set_mode == true)
+        {
+            mov_button = true;                    //자릿수 이동버튼 플래그 활성화
+        }
+        
+        //만약 현재 설정모드이고 자릿수 버튼이 눌려졌다면 커서를 앞뒤로 이동한다.
+        if(!movin and mov_button == true and set_mode == true)
+        {
+            printf("LCD MOVE\r\n");
+            //만약 현재 cursor의 위치가 11이라면 14로 옮기고, 12라면 11로, 14라면 12로 옮긴다.
+            if(cursor_loc == 11)
+            { 
+                //커서의 위치를 옮긴후 현재의 위치를 저장한다.
+                lcd.locate(14,1); 
+                cursor_loc = 14;
+            }
+            //만약 현재 cursor의 위치가 12라면 11로 옮긴다.
+            else if(cursor_loc == 12)
+            {
+                //커서의 위치를 옮긴후 현재의 위치를 저장한다.
+                lcd.locate(11,1); 
+                cursor_loc = 11; 
+            }
+            //만약 현재 cursor의 위치가 14라면 12로 옮긴다.
+            else if(cursor_loc == 14)
+            {
+                //커서의 위치를 옮긴후 현재의 위치를 저장한다.
+                lcd.locate(12,1);               
+                cursor_loc = 12;
+            }
+            
+            
+            mov_button = false;                   //자릿수 이동버튼 플래그 초기화  
+        }
+        
+        
+        
+        
+        
+        //------------지시값 설정
+        //설정모드에서 값올림(△)버튼을 눌렀을 경우 올림버튼 플래그를 활성화 한다.
+        if(upin and up_button == false and set_mode == true)
+        {
+            up_button = true;                     //값올림 버튼 플래그 활성화
+        }    
+        
+        //설정모드에서 값올림 버튼을 눌렀다면 현재 커서가 깜박이는 위치의 자릿수 값을 1씩 올린다.
+        if(!upin and up_button == true and set_mode == true)
+        {
+            printf("LCD UP\r\n");
+            //10의 자릿수에 커서가 위치해 있다면 10의자릿수 값에 1을 더한다.
+            if(cursor_loc == 11)
+            {
+                SV1++;
+                //만약 더한값이 10이상이라면 다시 0으로 바꾼다.
+                if(SV1 >= 10) SV1 = 0;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV1);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(11,1);
+                cursor_loc == 11;
+                    
+            }
+            //1의 자릿수에 커서가 위치해 있다면 1의자릿수 값에 1을 더한다.
+            else if(cursor_loc == 12)
+            {
+                SV2++;
+                //만약 더한값이 10이상이라면 다시 0으로 바꾼다.
+                if(SV2 >= 10) SV2 = 0;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV2);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(12,1);
+                cursor_loc == 12;
+            }
+            //소수점1의 자릿수에 커서가 위치해 있다면 소수점1의자릿수 값에 1을 더한다.
+            else if(cursor_loc == 14)
+            {
+                SV3++;
+                //만약 더한값이 10이상이라면 다시 0으로 바꾼다.
+                if(SV3 >= 10) SV3 = 0;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV3);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(14,1);
+                cursor_loc == 14;
+            }
+            
+            up_button = false;                    //값올림 버튼 플래그 초기화       
+        }
+        
+        
+        
+        
+        //설정모드에서 값내림(▽)버튼을 눌렀을 경우 내림버튼 플래그를 활성화 한다.
+        if(downin and down_button == false and set_mode == true)
+        {
+            down_button = true;                   //값내림 버튼 플래그 활성화
+        }    
+        
+        //설정모드에서 값내림 버튼을 눌렀다면 현재 커서가 깜박이는 위치의 자릿수 값을 1씩 내린다.
+        if(!downin and down_button == true and set_mode == true)
+        {
+            printf("LCD DOWN\r\n");
+            //10의 자릿수에 커서가 위치해 있다면 10의자릿수 값에 1을 뺀다.
+            if(cursor_loc == 11)
+            {
+                SV1--;
+                //만약 뺀값이 -1이하라면 값을 9로 바꾼다.
+                if(SV1 <= -1) SV1 = 9;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV1);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(11,1);
+                cursor_loc == 11;
+                    
+            }
+            //1의 자릿수에 커서가 위치해 있다면 1의자릿수 값에 1을 뺀다
+            else if(cursor_loc == 12)
+            {
+                SV2--;
+                //만약 뺀값이 -1이하라면 값을 9로 바꾼다.
+                if(SV2 <= -1) SV2 = 9;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV2);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(12,1);
+                cursor_loc == 12;
+            }
+            //소수점1의 자릿수에 커서가 위치해 있다면 소수점1의자릿수 값에 1을 뺀다
+            else if(cursor_loc == 14)
+            {
+                SV3--;
+                //만약 뺀값이 10이하라면 값을 9로 바꾼다.
+                if(SV3 <= -1) SV3 = 9;
+                //LCD화면의 값을 바꾼다.
+                lcd.printf("%d",SV3);
+                //화면에 프린트하면 location이 자동으로 증가하므로 다시 원래위치로 돌린다.
+                lcd.locate(14,1);
+                cursor_loc == 14;
+            }
+            
+            down_button = false;                    //값내림 버튼 플래그 초기화       
+        }
+        
+        
+        
+        
+        //쓰레드 대기
+        Thread::wait(10);
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
 /* Main ----------------------------------------------------------------------*/
 
 int main()
 {
-    /*----- Initialization. -----*/
+    
+    
+    //LCD제어를 위한 쓰레드를 호출
+    Thread thread(LCD_CTRL_THREAD);
 
-    /* Initializing SPI bus. */
+    
+    
+    //while(1);
+    
+    
+    //스텝모터 드라이브와 F401RE보드와 통신하기 위하여 SPI통신핀을 초기화 해준다.
 #ifdef TARGET_STM32F429
     DevSPI dev_spi(D11, D12, D13);
 #else
     DevSPI dev_spi(D11, D12, D3);
 #endif
 
-    /* Initializing Motor Control Expansion Board. */
+    //확장보드 초기화
     x_nucleo_ihm02a1 = new XNucleoIHM02A1(&init[0], &init[1], A4, A5, D4, A2, &dev_spi);
 
-    /* Building a list of motor control components. */
+    //모터 컨트롤 모터리스트 객체
     L6470 **motors = x_nucleo_ihm02a1->get_components();
 
-    /* Printing to the console. */
+    //콘솔화면 프린트
     printf("Motor Control Application Example for 2 Motors\r\n\n");
 
 
-    /*----- Setting home and marke positions, getting positions, and going to positions. -----*/
-
-    /* Printing to the console. */
-    printf("--> Setting home position.\r\n");
-
-    /* Setting the home position. */
+    //제일처음 전원이 들어왔을경우 현재값을 초기값으로 지정한다.
+    printf("--> Set Home position.\r\n");
     motors[0]->set_home();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Getting the current position. */
-    int position = motors[0]->get_position();
-
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Moving forward %d steps.\r\n", STEPS_1);
-
-    /* Moving. */
-    motors[0]->move(StepperMotor::FWD, STEPS_1);
-
-    /* Waiting while active. */
-    motors[0]->wait_while_active();
-
-    /* Getting the current position. */
-    position = motors[0]->get_position();
+    oilhomeposition = motors[0]->get_position();
+    
     
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Printing to the console. */
-    printf("--> Marking the current position.\r\n");
-
-    /* Marking the current position. */
-    motors[0]->set_mark();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Moving backward %d steps.\r\n", STEPS_2);
-
-    /* Moving. */
-    motors[0]->move(StepperMotor::BWD, STEPS_2);
-
-    /* Waiting while active. */
-    motors[0]->wait_while_active();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
+    motors[1]->set_home();
+    waterhomeposition = motors[0]->get_position();
+    //wait_ms(DELAY_1);
+    
+    
+    
 
-    /* Getting the current position. */
-    position = motors[0]->get_position();
-    
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Going to marked position.\r\n");
-
-    /* Going to marked position. */
-    motors[0]->go_mark();
-    
-    /* Waiting while active. */
-    motors[0]->wait_while_active();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Getting the current position. */
-    position = motors[0]->get_position();
-    
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Going to home position.\r\n");
-
-    /* Going to home position. */
-    motors[0]->go_home();
-    
-    /* Waiting while active. */
-    motors[0]->wait_while_active();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Getting the current position. */
-    position = motors[0]->get_position();
-    
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Halving the microsteps.\r\n");
-
-    /* Halving the microsteps. */
-    init[0].step_sel = (init[0].step_sel > 0 ? init[0].step_sel -  1 : init[0].step_sel);
-    if (!motors[0]->set_step_mode((StepperMotor::step_mode_t) init[0].step_sel)) {
-        printf("    Step Mode not allowed.\r\n");
+    //루프를 돌면서 농도값,밸브열림%,설정,모터제어 관련 작업을 진행한다.
+    while(1)
+    {
+        
+        
+        //현재 농도값을 읽는다.
+        //아날로그 값은 0~1값으로 들어온다. (참고로 STM32F401보드는 ADC의 분해능이 12bit이다.)
+        //250옴 저항을 사용했을경우 아래와 같은 범위에서 값이 들어온다. 
+        //4ma = 1V, 20ma = 5v이다. 
+        
+        
+        //Nucleo-64보드의 아날로그read()함수는 값을 아두이노처럼 0~5v사이의 값을 분해능값으로 (즉 0~4095)로 
+        //리턴하는것이 아니라 Voltage값으로 리턴한다.(내부적으로 아날로그값을 Voltage로 바꾸어준다.)
+        //0~1 사이의 값을 리턴하는데 그값을 보드의 기준전압인 5.0을 곱해주면 현재 아날로그 입력으로 들어오는 전압값을 알수 있다.
+        //따라서 4ma의 전압값은 1.0v이고 20ma의 값은 5.0v이므로 (입력값-최저값)*100/(최대값-최저값) 계산으로 농도가 몇%인지 계산이 가능하다. 
+        
+        float cc = CurCon.read()* 3.3;
+        printf("CC = %f \r\n",cc);
+        
+        
+        //5V시그널을 사용할것이므로 250옴의 저항을 연결하면 4ma = 1.0V, 20ma = 5.0v가된다.
+        //따라서 현재들어오는 전압값을 100분율로 계산하면 몇%의 절삭유농도인지 알수가 있다.
+        //PV = ((cc - 1)*100.0)/(5.0 - 1);
+        //3.3V로 계산
+        PV = ((cc - 0.66)*100.0)/(3.3 - 0.66);
+        printf("PV = %f \r\n",PV);
+        
+        
+        
+        
+             
+        
+        //현재시간을 체크한다.
+        NOW = time(NULL);
+        
+        
+        //만약 절삭유 농도가  10%(기준농도) 미만이라면 절삭유탱크 밸브를 연다.
+        if(PV < SV - 0.5)
+        {
+            //수탱크 밸브가 열려있다면
+            if(waterhomeposition != motors[1]->get_position())
+            {
+                //수탱크 밸브를 원상복귀 시킨다.
+                printf("--> Going Home Position Water Tank Value.\r\n");
+                motors[1]->go_home();  
+                //수탱크 밸브가 HOME 위치로 갈때까지 대기
+                motors[1]->wait_while_active();
+                
+                WATER_VALVE_ON = false;
+                
+                //현재밸브가 열린%를 계산한다.
+                WATER_VALVE_OPEN_P = 0.0;
+            }
+            
+            
+            //만약 절삭유밸브가 열려있지 않다면 밸브를 연다.
+            if(oilhomeposition == motors[0]->get_position())
+            {
+                //밸브를 앞방향으로 90도(모터2바퀴) 돌린다.
+                printf("--> Moving forward Oil Tank Valve %d steps.\r\n", STEPS_2);
+                //모터회전 명령을 내린다.
+                motors[0]->move(StepperMotor::FWD, STEPS_2);
+                //모터의 회전이 완료될때까지 기다린다.
+                motors[0]->wait_while_active();
+                
+                OIL_VALVE_ON = true;
+                
+                //오일밸브 타이머 시작
+                //OIL_VALVE_TIMER.start();
+                OIL_VALVE_OPEN_TIME = time(NULL);
+                
+                //현재밸브가 열린%를 계산한다.
+                OIL_VALVE_OPEN_P = (STEPS_2*100)/STEPS_2;         
+                
+            }
+        
+            //만약 오일밸브 타이머가 시작되어 있다면 시간을 체크한다.
+            if(OIL_VALVE_ON == true)
+            {
+                
+                //만약 절삭유의 현재값이 목표값(설정값) - 0.5 이상이고 절삭유밸브가 OPEN되고 2초이상 지났다면 절삭유가 파이프를 통해서 흘러가는 잔류량을 고려하여 밸브를 닫는다.
+                if(PV >= SV - 0.5)
+                {
+                    if((NOW - OIL_VALVE_OPEN_TIME) > 2)
+                    {
+                        printf("--> Going Home Position Oil Tank Value.\r\n");
+                        motors[0]->go_home();  
+                        //절삭유탱크 밸브가 HOME 위치로 갈때까지 대기
+                        motors[0]->wait_while_active();
+                        
+                        OIL_VALVE_ON = false;    
+                    }    
+                }
+                //printf("--> Aready Oil Tank Valve Opened\r\n");
+            }
+            
+            
+            
+            
+        }
+        //만약 절삭유 농도가 10%(기준농도) < 현재농도 < 12% 라면 수탱크 밸브를 연다.
+        else if(SV + 0.5 <= PV )
+        {
+            //절삭유 탱크 밸브가 열려있다면
+            if(waterhomeposition != motors[0]->get_position())
+            {
+                //절삭유 탱크 밸브를 원상복귀 시킨다.
+                printf("--> Going Home Position Oil Tank Valve\r\n");
+                motors[0]->go_home();  
+                //절삭유탱크 밸브가 HOME 위치로 갈때까지 대기
+                motors[0]->wait_while_active();
+                
+                OIL_VALVE_ON = false;
+                
+                //현재밸브가 열린%를 계산한다.
+                OIL_VALVE_OPEN_P = 0.0;
+            }
+            
+            
+            //만약 절삭유밸브가 열려있지 않다면 밸브를 연다.
+            if(waterhomeposition == motors[1]->get_position())
+            {
+                //밸브를 앞방향으로 45도(1바퀴) 돌린다.
+                printf("--> Moving forward Water Tank Valve %d steps.\r\n", STEPS_2);
+                //모터회전 명령을 내린다.
+                motors[1]->move(StepperMotor::FWD, STEPS_2);
+                //모터의 회전이 완료될때까지 기다린다.
+                motors[1]->wait_while_active();
+                
+                WATER_VALVE_ON = true;
+                
+                //희석수탱크밸브 타이머 시작
+                //WATER_VALVE_TIMER.start()
+                WATER_VALVE_OPEN_TIME = time(NULL);
+                
+                //현재밸브가 열린%를 계산한다.
+                WATER_VALVE_OPEN_P = (STEPS_2*100)/STEPS_2;
+                
+            }
+            
+            //만약 수탱크 타이머가 시작되어 있다면 시간을 체크한다.
+            if(WATER_VALVE_ON == true)
+            {
+                //만약 절삭유의 현재값이 기준값(목표값)+ 0.5 이하이고 절삭유밸브가 OPEN되고 2초이상 지났다면 절삭유가 파이프를 통해서 흘러가는 잔류량을 고려하여 밸브를 닫는다.
+                if(PV <= SV + 0.5)
+                {
+                    if((NOW - WATER_VALVE_OPEN_TIME) > 2)
+                    {
+                        printf("--> Going Home Position Oil Tank Value.\r\n");
+                        motors[1]->go_home();  
+                        //희석수탱크 밸브가 HOME 위치로 갈때까지 대기
+                        motors[1]->wait_while_active();
+                        
+                        OIL_VALVE_ON = false;    
+                    }    
+                }
+            }
+            
+        }
+        //정상이라면 절삭유탱크밸브 및 수탱크밸브를 HOME위치로 이동시킨다.
+        else
+        {
+            //절삭유 탱크 밸브를 원상복귀 시킨다.
+            //절삭유 탱크 밸브가 열려있다면
+            if(waterhomeposition != motors[0]->get_position())
+            {
+                printf("--> Going Home Position Oil Tank Value.\r\n");
+                motors[0]->go_home();  
+                //절삭유탱크 밸브가 HOME 위치로 갈때까지 대기
+                motors[0]->wait_while_active();
+                
+                OIL_VALVE_ON = false;
+                
+                //현재밸브가 열린%를 계산한다.
+                OIL_VALVE_OPEN_P = 0.0;
+            }
+            
+            
+            //희석수탱크 밸브가 열려있다면
+            if(waterhomeposition != motors[1]->get_position())
+            {
+                //수탱크 밸브를 원상복귀 시킨다.
+                printf("--> Going Home Position Water Tank Value.\r\n");
+                motors[1]->go_home();  
+                //희석수탱크 밸브가 HOME 위치로 갈때까지 대기
+                motors[1]->wait_while_active();
+                
+                WATER_VALVE_ON = false;
+                
+                //현재밸브가 열린%를 계산한다.
+                WATER_VALVE_OPEN_P = 0.0;
+            }   
+        }
+        
+        
+        
+        
+        
+        
+        
+             
+        
+        //내부적인 프로세스 처리를 우해서 반드시 일정시간 멈추어야한다.
+        Thread::wait(10);
+                          
+        //wait_ms(100);
+        
+        
+         
     }
 
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Setting home position.\r\n");
-
-    /* Setting the home position. */
-    motors[0]->set_home();
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Getting the current position. */
-    position = motors[0]->get_position();
-    
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-    /* Printing to the console. */
-    printf("--> Moving forward %d steps.\r\n", STEPS_1);
-
-    /* Moving. */
-    motors[0]->move(StepperMotor::FWD, STEPS_1);
-
-    /* Waiting while active. */
-    motors[0]->wait_while_active();
-
-    /* Getting the current position. */
-    position = motors[0]->get_position();
-    
-    /* Printing to the console. */
-    printf("--> Getting the current position: %d\r\n", position);
-
-    /* Printing to the console. */
-    printf("--> Marking the current position.\r\n");
-
-    /* Marking the current position. */
-    motors[0]->set_mark();
-
-    /* Waiting. */
-    wait_ms(DELAY_2);
-
-
-    /*----- Running together for a certain amount of time. -----*/
-
-    /* Printing to the console. */
-    printf("--> Running together for %d seconds.\r\n", DELAY_3 / 1000);
-
-    /* Preparing each motor to perform a run at a specified speed. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_run(StepperMotor::BWD, 400);
-    }
-
-    /* Performing the action on each motor at the same time. */
-    x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Waiting. */
-    wait_ms(DELAY_3);
 
 
-    /*----- Increasing the speed while running. -----*/
-
-    /* Preparing each motor to perform a run at a specified speed. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_get_speed();
-    }
-
-    /* Performing the action on each motor at the same time. */
-    uint32_t* results = x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Printing to the console. */
-    printf("    Speed: M1 %d, M2 %d.\r\n", results[0], results[1]);
-
-    /* Printing to the console. */
-    printf("--> Doublig the speed while running again for %d seconds.\r\n", DELAY_3 / 1000);
-
-    /* Preparing each motor to perform a run at a specified speed. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_run(StepperMotor::BWD, results[m] << 1);
-    }
-
-    /* Performing the action on each motor at the same time. */
-    results = x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Waiting. */
-    wait_ms(DELAY_3);
-
-    /* Preparing each motor to perform a run at a specified speed. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_get_speed();
-    }
-
-    /* Performing the action on each motor at the same time. */
-    results = x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Printing to the console. */
-    printf("    Speed: M1 %d, M2 %d.\r\n", results[0], results[1]);
-
-    /* Waiting. */
-    wait_ms(DELAY_1);
-
-
-    /*----- Hard Stop. -----*/
-
-    /* Printing to the console. */
-    printf("--> Hard Stop.\r\n");
-
-    /* Preparing each motor to perform a hard stop. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_hard_stop();
-    }
-
-    /* Performing the action on each motor at the same time. */
-    x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Waiting. */
-    wait_ms(DELAY_2);
-
-
-    /*----- Doing a full revolution on each motor, one after the other. -----*/
-
-    /* Printing to the console. */
-    printf("--> Doing a full revolution on each motor, one after the other.\r\n");
-
-    /* Doing a full revolution on each motor, one after the other. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        for (int i = 0; i < MPR_1; i++) {
-            /* Computing the number of steps. */
-            int steps = (int) (((int) init[m].fullstepsperrevolution * pow(2.0f, init[m].step_sel)) / MPR_1);
-
-            /* Moving. */
-            motors[m]->move(StepperMotor::FWD, steps);
-            
-            /* Waiting while active. */
-            motors[m]->wait_while_active();
-
-            /* Waiting. */
-            wait_ms(DELAY_1);
-        }
-    }
-
-    /* Waiting. */
-    wait_ms(DELAY_2);
-
-
-    /*----- High Impedance State. -----*/
-
-    /* Printing to the console. */
-    printf("--> High Impedance State.\r\n");
-
-    /* Preparing each motor to set High Impedance State. */
-    for (int m = 0; m < L6470DAISYCHAINSIZE; m++) {
-        motors[m]->prepare_hard_hiz();
-    }
-
-    /* Performing the action on each motor at the same time. */
-    x_nucleo_ihm02a1->perform_prepared_actions();
-
-    /* Waiting. */
-    wait_ms(DELAY_2);
 }