วันศุกร์ที่ 5 มิถุนายน พ.ศ. 2558

การใช้งาน RTC (Real Time Clock) บนบอร์ด STM32F103

MiniProject 010123120 Embedded System Design Lab นาฬิกาปลุก


RTC (Real Time Clock)


    บอร์ด STM32F103 มีวงจรRTC (Real Time Clock) พร้อมXTAL ค่า32.768KHz และBattery Backup    
   RTC คือ อุปกรณ์ที่ให้ค่าเวลาตามจริง ซึ่งทำงานโดยการจับสัญญาณนาฬิกาที่ได้มาจาก Crystal (หรือ xtal ที่ 32.768 KHz) ซึ่งการที่ต้องใช้การอ่านค่าเวลา จากRTC module เพราะว่าจะไม่มีการถูกรบกวนไปด้วยคำสั่งต่างๆซึ่งในการใช้งานฟังก์ชันของHAL_RTC นั้น โดยการ Init RTC และเซตค่าวันเริ่มต้นให้สำหรับการเริ่มทำงาน แล้วถ้าจะทำการดูเวลา ณ ขณะนั้น ก็ให้ แสดงค่าออกมาโดยฟังก์ชั่น HAL_RTC_GetTime() 


คุณสมบัติของ RTC บนบอร์ดทดลอง STM32F103

1.      32 kHz oscillator for RTC with calibration

2.    VBAT supply for RTC and backup registers

3.    VBAT = 1.8 to 3.6 V: power supply for RTC, external clock 32 kHz oscillator and backup registers (through power switch) when VDD is not present.

4.      The internal low-power RC oscillator or the high-speed external clock divided by 128.

5.      Backup registers are ten 16 bit register used to store 20 byte of user application data when VDD power is not present

Library ของ HAL_RTC ที่นำมาใช้
1.             การกำหนดค่าต่างๆให้ HAL_RTC เพื่อจะเริ่มทำงาน โดยค่าที่จะกำหนดให้สำหรับ RTC ได้แก่
1.1.  RTC_HandleTypeDef


RTC_TypeDef* RTC_HandleTypeDef::Instance เป็นการประกาศตัวแปร Register base address
RTC_InitTypeDefRTC_HandleTypeDef::Initเป็นRTC required parameters
RTC_DateTypeDefRTC_HandleTypeDef::DateToUpdateCurrent date set by userand updated automatically

1.2.  RTC_InitTypeDef : ไว้สำหรับกำหนดค่า output หรือ กำหนดว่าเป็น Asynchronous ตัวหารความถี่


uint32_t RTC_InitTypeDef::AsynchPredivSpecifies the RTC AsynchronousPredivider value.โดยที่ค่าจะเป็นตั้งแต่  0x00 ถึง 0xFFFF หรือจะเป็น RTC_AUTO_1SECOND
uint32_tRTC_InitTypeDef::OutPutSpecifies which signal will be routed to the RTCTamper pin.

1.3.  RTC_TimeTypeDef


                                เป็นตัวแปรไว้สำหรับกำหนดค่าเวลาของ RTC

1.4.  RTC_DateTypeDef


                                เป็นตัวแปรไว้สำหรับกำหนดค่าของวันที่ให้ RTC

1.5.  HAL_RTC_Init



                                เป็นฟังก์ชันไว้สำหรับตั้งค่าเริ่มต้นให้กับ HAL_RTC

1.6.  HAL_RTC_SetDate


เป็นฟังก์ชันไว้สำหรับ เซตค่าเริ่มต้นของวันที่ ที่ได้ตั้งไว้

1.7.  HAL_RTC_SetTime


เป็นฟังก์ชันไว้สำหรับ เซตค่าเริ่มต้นของเวลาที่ได้ตั้งไว้

1.8.  HAL_RTC_GetTime



เป็นฟังก์ชันไว้สำหรับ รับค่าเวลาที่อ่านได้

RTC  Code Example for STM32F103 RBT6 
main.c
#include "stm32f1xx_hal.h"
#include <stdio.h>
RTC_HandleTypeDef hrtc;
UART_HandleTypeDef huart2;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART2_UART_Init(void);

//time -- seconds, minutes, hours
int sec  = 0; // set second
int minu = 10; // set minute
int hour = 10; // set houur

int main(void)
{
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);

  MX_RTC_Init();
  MX_USART2_UART_Init();

  RTC_TimeTypeDef time_1;
  int num = 1;
  int sec1  = sec;
  int minu1 = minu;
  int hour1 = hour;
  char str[3];
  int count1=0;
  while (1)
  {
  HAL_RTC_GetTime(&hrtc,&time_1,RTC_FORMAT_BCD);

  /* USER CODE END WHILE */
  sprintf(str, "%d", hour1);
  HAL_UART_Transmit(&huart2,&str,sizeof(str),1000);
  HAL_UART_Transmit(&huart2,":",sizeof(":"),1000);
  sprintf(str, "%d", minu1);
  HAL_UART_Transmit(&huart2,&str,sizeof(str),1000);
  HAL_UART_Transmit(&huart2,":",sizeof(":"),1000);
  sprintf(str, "%d", sec1);
  HAL_UART_Transmit(&huart2,&str,sizeof(str),1000);
  HAL_UART_Transmit(&huart2,"\n",sizeof("\n"),1000);

  if(sec1 >= 60){
    sec1=0;
    minu1++;
  }
  if(minu1 >= 60){
    minu1=0;
    hour1++;
  }
  if(hour1 >=24){
    hour1=0;
  }
  if(num != time_1.Seconds ){
    num = time_1.Seconds;
    sec1 = sec1+1;
  }

  // PB8 output
  // PB9 input
  if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_9) == GPIO_PIN_SET){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
  }else{
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
  }

  HAL_Delay(900);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);

  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);

  __HAL_RCC_AFIO_CLK_ENABLE();

}

/* RTC init function */
void MX_RTC_Init(void)
{

  RTC_TimeTypeDef sTime;
  RTC_DateTypeDef DateToUpdate;

    /**Initialize RTC and set the Time and Date
    */
  hrtc.Instance = RTC;
  hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
  hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
  hrtc.DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
  hrtc.DateToUpdate.Month = RTC_MONTH_JANUARY;
  hrtc.DateToUpdate.Date = 1;
  hrtc.DateToUpdate.Year = 0;
  HAL_RTC_Init(&hrtc);

  sTime.Hours = hour;
  sTime.Minutes = minu;
  sTime.Seconds = sec ;
  HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);
  HAL_RTC_SetDate(&hrtc, &DateToUpdate, FORMAT_BCD);
}

void MX_USART2_UART_Init(void)
{
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  HAL_UART_Init(&huart2);
}

void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  /* GPIO Ports Clock Enable */
  __GPIOC_CLK_ENABLE();
  __GPIOA_CLK_ENABLE();
  __GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PB8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}

สำหรับผลการทดลอง จะได้ดังนี้




วิดีโอสาธิตการแสดงการทำงาน


**เพิ่มเติม การส่งข้อมูลโดยใช้ UART บนบอร์ด STM32F103

UART
UART (Universal Asynchronous Receiver Transmitter) คืออุปกรณ์ที่ทำหน้าที่รับและส่งข้อมูลแบบAsynchronous ซึ่งเป็นการสื่อสารอนุกรมแบบ Asynchronous

การสื่อสารอนุกรมแบบ Asynchronous
เป็นการส่งข้อมูลโดยไม่อาศัยสัญญาณ clock มาเป็นตัวกำหนดจังหวะการรับส่งข้อมูลแต่ใช้วิธีกำหนด รูปแบบ Format การรับส่งข้อมูลขึ้นมาแทน และ อาศัยการกำหนด ความเร็วของการรับและส่ง ที่เท่ากันทั้งฝั่งรับและฝั่งส่ง
ข้อดี : สามารถสื่อสารแบบ Full Duplex รับและส่งได้ในเวลาเดียวกัน
ข้อเสีย : มีโอกาสที่ข้อมูลจะสูญหายระหว่างรับส่งข้อมูลหรือมีความผิดพลาดของข้อมูลได้


รูปแบบการรับส่งข้อมูลแบบ Asynchronous มีรูปแบบดังนี้
เริ่มต้นจาก Start bit ซึ่งเป็น Logic 0 จากนั้นจะตามด้วย ข้อมูล แล้วจะถูกปิดด้วย Stop Bit เป็น Logic 1

UART บนบอร์ดทดลอง STM32F103
                พอร์ต RS232 เป็นสัญญาณ RS232 ซึ่งผ่านวงจรแปลงระดับสัญญาณ MAX3232 แล้ว โดยสามารถใช้เชื่อมต่อกับสัญญาณ RS232 เพื่อรับส่งข้อมูลได้ 
                โดยในการทำงานนี้ จะเลือกใช้ USART-2

     USART-2 ใช้ขาสัญญาณจาก PA2(TXD2) เป็นขาสำหรับส่งข้อมูล และ PA3(RXD2)เป็นขาสำหรับรับข้อมูล

สำหรับ function ในการรับส่งข้อมูลแบบ UART
1.   เป็นfunction HAL ซึ่งไว้ใช้สำหรับการกำหนดค่าของ BaudRate, WordLength, StopBits, Parity, Mode HwFlowCtl, OverSampling

           


2.   เป็น function HAL ซึ่งไว้ใช้สำหรับส่งค่าไปแสดงผลบน Serial monitor 



3.   เป็น function HAL ซึ่งไว้สำหรับกำหนดค่าต่างๆ ให้กับ UART
  •            USART_TypeDef*Instance เป็น Register base address
  •            USART_InitTypeDefInitUsart communication parameters
  •            uint8_t* USART_HandleTypeDef::pTxBuffPtrPointer to UsartTx transfer Buffer
  •            uint16_t USART_HandleTypeDef::TxXferSizeUsartTx Transfer size
  •            __IO uint16_t USART_HandleTypeDef::TxXferCountUsartTx Transfer Counter
  •            uint8_t* USART_HandleTypeDef::pRxBuffPtr Pointer to Usart Rx transfer Buffer
  •          uint16_t USART_HandleTypeDef::RxXferSizeUsart Rx Transfer size
  •         __IO uint16_t USART_HandleTypeDef::RxXferCountUsart Rx Transfer Counter
  •          DMA_HandleTypeDef* USART_HandleTypeDef::hdmatxUsartTx DMA Handleparameters
  •          DMA_HandleTypeDef* USART_HandleTypeDef::hdmarxUsart Rx DMA Handleparameters
  •          HAL_LockTypeDefUSART_HandleTypeDef::Lock Locking object
  •          __IO HAL_USART_StateTypeDefUSART_HandleTypeDef::State Usartcommunication state
  •          __IO uint32_t USART_HandleTypeDef::ErrorCode USART Error code

          อธิบายส่วนของ Code :



เป็นการประกาศตัวแปรของ RTC และ UARTซึ่งจะไว้ดำเนินการต่างๆของ RTC และ UART


เป็นฟังก์ชัน ไว้กำหนดค่าต่างๆให้กับ RTC
-      RTC_TimeTypeDefsTime              : เป็นการประกาศตัวแปรเวลาของ RTC
-      RTC_DateTypeDefDateToUpdate : เป็นการประกาศตัวแปรวันที่ของ RTC
-      กำหนดค่าต่างๆให้กับ RTC ได้แก่ Asynchronous Predivider value , Output และประกาศตัวแปรเพื่อกำหนดค่าเริ่มต้นของวันที่และเวลา
-      HAL_RTC_SetTime เป็นการกำหนดค่าเริ่มต้นให้กับเวลาของ
-      HAL_RTC_SetDate เป็นการกำหนดค่าเริ่มต้นให้กับวันที่ของ RTC

เป็นการประกาศตัวแปร RTC_TimeTypeDefไว้สำหรับเก็บค่าเวลาของ RTC

เป็นส่วนรับค่าเวลาของ RTC โดยจะใช้ในรูปแบบของ BCD(คือการเอาตัวเลขฐานสองมาเขียนแทนเลขฐานสิบ)

เป็นการเก็บค่าลงใน array ชื่อ str แล้วนำไปแสดงผลโดยส่งค่า ผ่าน UART
โดย HAL_UART_Transmit(ชื่อตัวแปรUART_HandleTypeDef, ข้อความที่จะส่ง, ขนาดข้อความ, Timeout)