반도체, 임베디드 Study/STM32

STM32 - 알람 시계 구현하기 (1) (시간, 알람 띄우기)

잇(IT) 2024. 7. 2. 21:41
728x90

이번 글에서는 알람 시계를 가장 기본 단계에서 구현할 것이다.

1. 지정한 날짜, 시간을 기준으로 시계가 동작하고

2. 알람으로 설정한 시간에 Alarm이 울렸다는 화면을 띄우는 작업을 할 것이다.

 

https://insoobaik.tistory.com/638 

 

STM32 - I2C를 이용한 LCD 문자 출력 (함수 분석)

https://insoobaik.tistory.com/624 STM32 - LCD 문자 출력 (I2C)https://insoobaik.tistory.com/626 STM32 - I2C 이론보호되어 있는 글입니다. 내용을 보시려면 비밀번호를 입력하세요.insoobaik.tistory.comI2C 이론에 이어 I2C

insoobaik.tistory.com

I2C에 대한 함수 분석은 위 글을 참고한다.


이전 rtc, tim 글들에 미리 작성하여 구체적으로 작성하진 않겠지만 RTC는 내부 크리스털을 사용하고, Predivider value를 통해 1초 주기를 설정한다.

 

핵심 전체 코드

static void set_time (void)
{
	RTC_TimeTypeDef sTime;
	RTC_DateTypeDef sDate;


	sTime.Hours = 18;
	sTime.Minutes = 30;
	sTime.Seconds = 00;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;

	if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
	{
	  Error_Handler();
	}

	sDate.WeekDay = RTC_WEEKDAY_MONDAY;
	sDate.Month = RTC_MONTH_JUNE;
	sDate.Date = 22;
	sDate.Year = 24;

	if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
	{
	  Error_Handler();
	}
}

static void set_alarm (void)
{
	RTC_AlarmTypeDef sAlarm = {0};

	sAlarm.AlarmTime.Hours = 18;
	sAlarm.AlarmTime.Minutes = 30;
	sAlarm.AlarmTime.Seconds = 10;
	sAlarm.AlarmTime.SubSeconds = 0;
	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
	sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;
	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
	sAlarm.AlarmDateWeekDay = 0x1;
	sAlarm.Alarm = RTC_ALARM_A;
	if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
	{
	  Error_Handler();
	}
}

static void get_time(void)
{
	RTC_DateTypeDef gDate;
	RTC_TimeTypeDef gTime;

	HAL_RTC_GetTime(&hrtc, &gTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &gDate, RTC_FORMAT_BIN);

	snprintf((char *)time, sizeof(time), "%02d:%02d:%02d", gTime.Hours, gTime.Minutes, gTime.Seconds);
	snprintf((char *)date, sizeof(date), "%02d-%02d-%02d", gDate.Date, gDate.Month, 2000+gDate.Year);
}

static void display_time(void)
{
	lcd_send_cmd(0x80);
	lcd_send_string(time);
	lcd_send_cmd(0xc0);
	lcd_send_string(date);
}

static void to_do_on_alarm (void)
{
	lcd_send_cmd (0x80);
	lcd_send_string ("Alarm ON");
	lcd_send_cmd (0xc0);
	lcd_send_string ("Wake UP!!!!!!!");
	HAL_Delay (3000);
	lcd_send_cmd (0x80);
	for (int i=0;i<60;i++)
	{
		lcd_send_data (' ');  // clear lcd
	}

}

.......


  MX_USART3_UART_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
  lcd_init();

  if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0x32F2)
  {
	  set_time();
  }

  set_alarm ();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  while (1)
  {
	  get_time();
	  display_time();
	  HAL_Delay(500);

	  if (alarm)
	  {
		  to_do_on_alarm();
		  alarm =0;
	  }

위 코드는 LCD에 시계를 띄우고 알람이 울리게 하기 위한 핵심이 되는 코드들을 작성해 놓았다. 자세한 코드 설명은 아래에서 할 것이다.


1. 시작 시간 설정하기

static void set_time (void)
{
	RTC_TimeTypeDef sTime;
	RTC_DateTypeDef sDate;


	sTime.Hours = 18;
	sTime.Minutes = 30;
	sTime.Seconds = 00;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;

	if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
	{
	  Error_Handler();
	}

	sDate.WeekDay = RTC_WEEKDAY_MONDAY;
	sDate.Month = RTC_MONTH_JUNE;
	sDate.Date = 22;
	sDate.Year = 24;

	if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
	{
	  Error_Handler();
	}
}

rtc 설정 후 code generation을 통해 생성되는 코드를 참고하게되면, 구조체를 통해 시간, 날짜 레지스터에 접근하여 시간, 날짜를 지정하게 된다.

sTime.Hours = 18;
	sTime.Minutes = 30;
	sTime.Seconds = 00;

시간과 날짜 항목을 보게되면, 위와 같이 선언할 수도 있고 0x를 통해 표현할 수 있다. (아래 설명하겠지만 위와 같이 시간 자체를 작성할 때는 GetTime, GetDate 함수 파라미터에 RTC_FORMAT_BIN 값을 넣어줘야 한다.

 

나머지 파라미터의 경우 GUI에서 설정한 값들에 관한 내용들이다.

 

2. 알람 시간 설정

static void set_alarm (void)
{
	RTC_AlarmTypeDef sAlarm = {0};

	sAlarm.AlarmTime.Hours = 18;
	sAlarm.AlarmTime.Minutes = 30;
	sAlarm.AlarmTime.Seconds = 10;
	sAlarm.AlarmTime.SubSeconds = 0;
	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
	sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES;
	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
	sAlarm.AlarmDateWeekDay = 0x1;
	sAlarm.Alarm = RTC_ALARM_A;
	if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
	{
	  Error_Handler();
	}
}

 

위 코드 역시 RTC Alarm 레지스터에 직접 접근하여 값을 변경해주는 함수에 해당한다.

시간, 분, 초, Mask가 대표적으로 사용되는 레지스터에 해당한다. Mask를 통해 비교할 범위를 지정하고 나머지 시간을 설정하게 되면 해당 시간에 도달하면 알람이 울리게 된다.

 

3. 설정한 시간 받아오기

static void get_time(void)
{
	RTC_DateTypeDef gDate;
	RTC_TimeTypeDef gTime;

	HAL_RTC_GetTime(&hrtc, &gTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &gDate, RTC_FORMAT_BIN);

	snprintf((char *)time, sizeof(time), "%02d:%02d:%02d", gTime.Hours, gTime.Minutes, gTime.Seconds);
	snprintf((char *)date, sizeof(date), "%02d-%02d-%02d", gDate.Date, gDate.Month, 2000+gDate.Year);
}

위 함수는 set_time을 통해 설정한 시간을 받아오는 함수다.

날짜와 시간 레지스터에 접근하여 GetTime, GetDate 함수를 통해 설정한 시간, 알람 값을 가져온다.

위에서 설명했지만 RTC_FORMAT_BIN(BCD도 가능)을 통해 받아오기 때문에 시간, 날짜를 10진 그대로 작성해주었다.

snprintf를 통해 time, date 문자열에 시간 값을 넣어 버퍼를 초기화 시켜준다.

 

4. LCD에 시간, 알람 문자 띄우기

static void display_time(void)
{
	lcd_send_cmd(0x80);
	lcd_send_string(time);
	lcd_send_cmd(0xc0);
	lcd_send_string(date);
}
static void to_do_on_alarm (void)
{
	lcd_send_cmd (0x80);
	lcd_send_string ("Alarm ON");
	lcd_send_cmd (0xc0);
	lcd_send_string ("Wake UP!!!!!!!");
	HAL_Delay (3000);
	lcd_send_cmd (0x80);
	for (int i=0;i<60;i++)
	{
		lcd_send_data (' ');  // clear lcd
	}
}

위 함수에 대한 설명은 위 링크를 걸어둔 글을 읽어보면 될 것이다.

위 코드는 I2C를 통한 LCD를 구동시키는 함수로 설정한 시간, 날짜를 LCD에 문자를 출력하고, 알람 시간에 도달하면 알람에 대한 문자를 LCD에 띄우게 된다.

 

 

 

 

 

* 추후에 LCD 함수를 활용 및 ADC를 이용하여 버튼을 통해 시간을 직접 설정할 수 있도록 기능을 추가할 것이다.

728x90