Mini64SE R6 годинник реального часу RTC та підключення LCD Nokia 5510

Доброго дня сьогодні ми займемося підключенням LCD Nokia 5510 до плати Mini64SE R6, а також налагодимо годинник реального часу.
100_9627

 

Main.c  Принцип роботи-на екран виводиться час, напис “Mini64SER6” , круг та квадрат. При натисканні одної кнопки інкриментуються години, другої кнопки хвилини, при натисканні третьої обнуляються секунди.

#include "stm32f10x.h" 
#include "stm32f10x_rcc.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"

#include "main.h"
#include "lcd5510.h"

#define TIMER_PRESCALER		720
#define EXT_TIM_PULSE 	        150
#define TIM_PULSE		 50

GPIO_InitTypeDef GPIO_InitStructure;

extern unsigned char lcd8544_buff[84*6]; //buffer lcd

int ci,i;

int SysTickDelay; 
int IncDelay=100; 

char ch=0;

unsigned char bars[5] = {1, 2, 3, 4, 5};
/*                      Структура для збереження параметрів часу                       */
typedef struct 
{
  unsigned char  hour;     //часы	       
  unsigned char  min;	   //хвилини    
  unsigned char  sec;	   //секунди    
} RTC_Time;

RTC_Time Time;          //структура для работи з типом "час"
uint32_t tmp;           //допоміжна змінна

void SysTick_Handler(void)  
{  
   if (SysTickDelay != 0)  
   {  
      SysTickDelay--;  
   }  
}

void Delay( unsigned int Val)  
{  
   SysTickDelay = Val;  
   while (SysTickDelay != 0) {};  
}
//********************************************************************************************
//function переривання, якє генерує RTC //
//********************************************************************************************
void RTC_IRQHandler(void)
{
//причина переривання - переповнення вхідного дільника (нова секунда)
if(RTC->CRL & RTC_CRL_SECF)
{
RTC->CRL &= ~RTC_CRL_SECF; //скинути прапор (обов'язково!!!)
//виконуємо якісь дії
}

//причина переривання - збіг розрахункового та сигнального регістра
if(RTC->CRL & RTC_CRL_ALRF)
{
RTC->CRL &= ~RTC_CRL_ALRF; //скинути прапор (обов'язково!!!)
//виконуємо якісь дії
}

//причина переривання - переповнення рахункового регістра
if(RTC->CRL & RTC_CRL_OWF)
{
RTC->CRL &= ~RTC_CRL_OWF; //скинути прапор (обов'язково!!!)
//виконуємо якісь дії
}
/* if(GPIOC->IDR & GPIO_BSRR_BS8)
{ //Toggle every sec LED3
GPIOC->BRR=GPIO_BSRR_BS8;
}
else
{
GPIOC->BSRR=GPIO_BSRR_BS8;
}*/

}
//********************************************************************************************
//function init RTC                                                                //
//argument none                                                                             //
//result   1 - ініціалізація виконана; 0 - годинник вже були ініціалізовані                //
//********************************************************************************************
unsigned char  RtcInit  (void)
{
 //дозволити тактування модулів управління живленням і управлінням резервної областю
  RCC->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
  //дозволити доступ до області резервних даних
  PWR->CR |= PWR_CR_DBP;
  //якщо годинник вимкнені - ініціалізувати їх
  if ((RCC->BDCR & RCC_BDCR_RTCEN) != RCC_BDCR_RTCEN)
  {
    //виконати скидання області резервних даних
    RCC->BDCR |=  RCC_BDCR_BDRST;
    RCC->BDCR &= ~RCC_BDCR_BDRST;

    //вибрати джерелом тактових імпульсів зовнішній кварц 32768 і подати тактування
    RCC->BDCR |=  RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL_LSE;

    RTC->CRL  |=  RTC_CRL_CNF;
    RTC->PRLL  = 0x7FFF;         //регістр поділу на 32768
   	RTC->CRL  &=  ~RTC_CRL_CNF;

    //встановити біт дозволу роботи і дочекатися установки біта готовності
    RCC->BDCR |= RCC_BDCR_LSEON;
    while ((RCC->BDCR & RCC_BDCR_LSEON) != RCC_BDCR_LSEON){}

    RTC->CRL &= (uint16_t)~RTC_CRL_RSF;
    while((RTC->CRL & RTC_CRL_RSF) != RTC_CRL_RSF){}

    return 1;
  }
  return 0;
}

//********************************************************************************************
//function перетворює  "Час" в секунди (якшо 0->00:00:00)                                //
//argument покажчик на структуру, що зберігає час для перетворення                        //
//result   час у форматі "секунди"                                                       //
//********************************************************************************************
uint32_t TimeToRtc(RTC_Time *time )
{
  uint32_t result;
  result  = (uint32_t)time->hour * 3600; //врахувати години
  result += (uint32_t)time->min * 60;    //хвилини
  result +=           time->sec;         //секунди

  return result;
}

//********************************************************************************************
//function перетворює  "Час" в секунди (якшо 0->00:00:00)                          //
//argument значення лічильника, покажчик на структуру "Час"                                 //
//result   none                                                                             //
//********************************************************************************************
 void RtcToTime( uint32_t cnt, RTC_Time *time )
 {
   time->sec = cnt % 60;               //отримати секунди
   cnt /= 60;                          //кількість хвилин
   time->min = cnt % 60;               //отримати хвилини
   cnt /= 60;                          //кількість днів
   time->hour = cnt % 24;              //отримати години
 }

void PortInit(void)
{
GPIO_InitTypeDef  GPIO_InitStructure;                 //оголошуємо структуру

// Enable PORTB Periph clock
RCC_APB2PeriphClockCmd(LedBluePortRcc, ENABLE);
RCC_APB2PeriphClockCmd(LedYellowPortRcc, ENABLE);
RCC_APB2PeriphClockCmd(ButtonPortRcc, ENABLE);

	GPIO_InitStructure.GPIO_Pin = (Button1Pin|Button2Pin|Button3Pin); // кнопки
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(ButtonPort, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = LedBluePin; // Синій світлодіод
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LedBluePort, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin   = LedYellowPin; // Жовтий світлодіод
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
GPIO_Init(LedYellowPort, &GPIO_InitStructure);               
}

int main(void)
{

PortInit();

SysTick_Config(SystemCoreClock /1000);//1ms 

RtcInit  ();

//RTC->CRL |=  RTC_CRL_CNF;  //дозволити конфігурування регістрів RTC
RTC->CRH  =  RTC_CRH_SECIE;//дозволити переривання від секундних імпульсів
//RTC->CRH  =  RTC_CRH_ALRIE;//дозволити переривання при збігу рахункового і сигнального регістра
//RTC->CRH  =  RTC_CRH_OWIE; //дозволити переривання при переповненні рахункового регістра
//RTC->CRL &= ~RTC_CRL_CNF;  //вийти з режиму конфігурації

NVIC_EnableIRQ (RTC_IRQn);

//завантажити в структуру потрібний час
Time.hour= 12;
Time.min = 00;
Time.sec = 00;

tmp = TimeToRtc(&Time); //перетворити час в формат "зрозумілий" для RTC
RTC_SetCounter(tmp);    //записати час в рахунковий регістр RTC

LcdInit();

while(1) 
{
/*

		GPIO_SetBits(LedYellowPort, LedYellowPin);

    Delay(1000);

    GPIO_ResetBits(LedYellowPort, LedYellowPin);

    Delay( 1000);

*/
	tmp = RTC_GetCounter(); //прочитати час з RTC
	RtcToTime(tmp,&Time);   //перетворити в "людський" формат
		  if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0)==0)
	  {
			Time.hour++;//Години +1
			tmp = TimeToRtc(&Time); //перетворити час в формат "зрозумілий" для RTC
			RTC_SetCounter(tmp);    //записати час в рахунковий регістр RTC
	  }

			if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1)==0)
	  {
		  Time.min++;//Хвилини +1
			tmp = TimeToRtc(&Time); //перетворити час в формат "зрозумілий" для RTC
			RTC_SetCounter(tmp);    //записати час в рахунковий регістр RTC
	  }

			if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_2)==0)
	  {
		  Time.sec=0;//секунди=0
			tmp = TimeToRtc(&Time); //перетворити час в формат "зрозумілий" для RTC
			RTC_SetCounter(tmp);    //записати час в рахунковий регістр RTC
	  }

LcdDec(Time.hour, 2, 0, 0, 0);//виводимо години
LcdPutChar(14,1,':', 0);
LcdDec(Time.min, 2, 20, 0, 0);//виводимо хвилини
LcdPutChar(32,1,':', 0);
		LcdDec(Time.sec, 2, 38, 0, 0);//виводимо секунди
LcdPutStr(0,10,"MINI64SER6",0);//виводимо напис

		LcdRect(20,20,45,45,1);//виводимо квадрат
		LcdCircle(32,32,8);//виводимо круг

		LcdRefresh();//Оновити екран
Delay(1000);
LcdClearBuff();//Очистити буфер

}
}

Для роботи з виводами LCD

нам треба відредагувати файл lcd5510.h  в ньому зазначаються виводи плати Mini64SE R6 для керуванням екраном

#define LCD_PIN_ENABLE      #define LCD_PIN_ENABLE      GPIO_Pin_8
#define LCD_PIN_RESET       GPIO_Pin_9
#define LCD_PIN_COMMAND     GPIO_Pin_5
#define LCD_PIN_DATA        GPIO_Pin_6
#define LCD_PIN_CLOCK       GPIO_Pin_7

#define LCDPort GPIOB
#define LCDRcc RCC_APB2Periph_GPIOB

На цьому все чіпляю тут проект в Keil (його я вивчаю зараз для експирименту)Keil

4 коментарі Mini64SE R6 годинник реального часу RTC та підключення LCD Nokia 5510

  1. zlyt0n сказав:

    Прикольний “матрас”.
    Я тільки недавно зацінив переваги цієї “технології”.
    Ти брав його десь в нас чи замовляв з-за кордону?

  2. Андрій Гончаренко сказав:

    Дякую друже за цей допис.
    Розібрався з ALARM завдяки цій статті. Довго не виходило запустити будильник.
    Але як задаю в таймер 0 в ALARM 10 – все працює, а як щось таке в таймер 1419885900 а в будильник на 10 сек більше 1419885910, то по ALARM не спрацьовує. Не розумію чого.

Залишити відповідь