Работа с часами M41T94 в LPC2000

Часы M41T94 и микроконтроллеры серии LPC2000




Микросхема M41T94 это часы реального времени (RTC), работающие по последовательному протоколу SPI. Здесь будет рассмотрена работа этих часов совместно с микроконтроллерами серии LPC2000 (ядро ARM7TDMI-S). Используемые в коде функции spi_get_byte и spi_put_byte, служащие для обмена по протоколу SPI, описаны на странице «Протокол SPI и микроконтроллеры серии LPC2000».

Сначала описываем некоторые значения, которые используются при работе с микросхемой, а также структуру SRPD_DATE, в которой будет храниться получаемая или передаваемая в микросхему информация о дате и времени.

#define M41T94_REG_SECONDS	0x01
#define M41T94_REG_MINUTES	0x02
#define M41T94_REG_HOURS	  0x03
#define M41T94_REG_WDAY		  0x04
#define M41T94_REG_DAY		  0x05
#define M41T94_REG_MONTH	  0x06
#define M41T94_REG_YEAR		  0x07
#define M41T94_REG_HT		    0x0c

#define M41T94_BIT_HALT		  0x40
#define M41T94_BIT_STOP		  0x80
#define M41T94_BIT_CB		    0x40
#define M41T94_BIT_CEB		  0x80

#define M41T94_WRITE        0x80

typedef struct _SRPD_DATE
{
  u8 year; 
  u8 month; 
  u8 day;
  u8 wday; // день недели
  u8 hour; 
  u8 min; 
  u8 sec;
} SRPD_DATE, *PSRPD_DATE;

bool m41t94_get_time(const struct m41t94_dev * dev, PSRPD_DATE tm);
bool m41t94_set_time(const struct m41t94_dev * dev, PSRPD_DATE tm);
void m41t94_init(const struct m41t94_dev * dev);
void m41t94_print_time(PSRPD_DATE tm);

Две функции преобразования из двоичного кода (BIN) в двоично-десятичный (BCD) и обратно.

static unsigned int bcd2bin(unsigned char val)
{
  return (val & 0x0F) + (val >> 4) * 10;
}

static unsigned char bin2bcd(unsigned int val)
{
  return ((val / 10) << 4) + val % 10;
}

Дальше две функции, предназначенные для обмена по SPI с микросхемой. Первая функция m41t94_w8r8, называется так потому, что одновременно и передаёт по SPI, и получает 8 бит. DEV_OFF_PORT_1 имеет отношение к выбору микросхемы SPI, см. здесь. Суть в том, что эта функция сначала передаёт команду val, потом сразу читает ответ. Функция m41t94_write занимается только передачей.

// <0 error
static short m41t94_w8r8(const struct m41t94_dev * dev, unsigned char val)
{
  unsigned char b;
  DEV_ON_PORT_1;
  if (!spi_put_byte(SPI_DEV(dev), val)) 
  {
    DEV_OFF_PORT_1;
    return -1;
  }
  if (!spi_get_byte(SPI_DEV(dev), &b)) 
  {
    DEV_OFF_PORT_1;
    return -2;
  }
  DEV_OFF_PORT_1;
  return b;
}

// <=0 error >0 ok
static short m41t94_write(const struct m41t94_dev * dev, unsigned char *buf, size_t size)
{
  short i;

  if (NULL == buf)
    return 0;

  DEV_ON_PORT_1;
  for (i = 0; i < size; i++)
  {
    if (!spi_put_byte(SPI_DEV(dev), buf[i])) 
    {
      DEV_OFF_PORT_1;
      return (i * -1);
    }
  }
  DEV_OFF_PORT_1;

  return i;
}

Следующие функции занимаются непосредственно установкой даты и её получением с микросхемы. Тут особо комментариев не будет, и так всё понятно.

void m41t94_init(const struct m41t94_dev * dev)
{
  io_dir_out(1, dev->pin_cs);
  DEV_OFF_PORT_1;
}

bool m41t94_set_time(const struct m41t94_dev * dev, PSRPD_DATE tm)
{
  unsigned char buf[8]; /* write cmd + 7 registers */

  if (NULL == dev || NULL == tm)
    return false;

  buf[0] = M41T94_WRITE | M41T94_REG_SECONDS; /* write time + date */
  buf[M41T94_REG_SECONDS] = bin2bcd(tm->sec);
  buf[M41T94_REG_MINUTES] = bin2bcd(tm->min);
  buf[M41T94_REG_HOURS]   = bin2bcd(tm->hour);
  buf[M41T94_REG_WDAY]    = bin2bcd(tm->wday + 1);
  buf[M41T94_REG_DAY]     = bin2bcd(tm->day);
  buf[M41T94_REG_MONTH]   = bin2bcd(tm->month + 1);

  buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;
  if (tm->year >= 100)
    buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;
  buf[M41T94_REG_YEAR] = bin2bcd(tm->year % 100);

  return (m41t94_write(dev, buf, 8) > 0);
}

bool m41t94_get_time(const struct m41t94_dev * dev, PSRPD_DATE tm)
{	
	short ret, hour;
  unsigned char buf[2];  

  if (NULL == dev || NULL == tm)
    return false;

  ret = m41t94_w8r8(dev, M41T94_REG_HT);
	if (ret < 0)
  {
    xprintf("M41T94 SPI failed" CRLF);
		return false;
  }

	if (ret & M41T94_BIT_HALT) 
  {
    xprintf("Halt detected!" CRLF);
    buf[0] = M41T94_WRITE | M41T94_REG_HT;
    buf[1] = ret & ~M41T94_BIT_HALT;
    m41t94_write(dev, buf, 2);
	}

  ret = m41t94_w8r8(dev, M41T94_REG_SECONDS);
	if (ret < 0)
  {
    xprintf("M41T94 SPI failed" CRLF);
		return false;
  }

	if (ret & M41T94_BIT_STOP) 
  {
    xprintf("Stop detected!" CRLF);
    buf[0] = M41T94_WRITE | M41T94_REG_SECONDS;
    buf[1] = ret & ~M41T94_BIT_STOP;
    m41t94_write(dev, buf, 2);

    ret = m41t94_w8r8(dev, M41T94_REG_SECONDS);
  	if (ret < 0)
    {
      xprintf("M41T94 SPI failed" CRLF);
  		return false;
    }
	}

  ret = m41t94_w8r8(dev, M41T94_REG_SECONDS);
	tm->sec  = bcd2bin(ret);

  ret = m41t94_w8r8(dev, M41T94_REG_MINUTES);
	tm->min  = bcd2bin(ret);

	hour = m41t94_w8r8(dev, M41T94_REG_HOURS);
	tm->hour = bcd2bin(hour & 0x3F);

  ret = m41t94_w8r8(dev, M41T94_REG_WDAY);
	tm->wday = bcd2bin(ret) - 1;

  ret = m41t94_w8r8(dev, M41T94_REG_DAY);
	tm->day = bcd2bin(ret);

  ret = m41t94_w8r8(dev, M41T94_REG_MONTH);
	tm->month  = bcd2bin(ret) - 1;

  ret = m41t94_w8r8(dev, M41T94_REG_YEAR);
	tm->year = bcd2bin(ret);

	if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))
		tm->year += 100;     

	return true;
}

А так можно вывести дату и время для проверки:

void m41t94_print_time(PSRPD_DATE tm)
{
  if (NULL == tm)
    return;

  xprintf("%02d.%02d.%02d %02d:%02d:%02d" CRLF, 
    tm->day, tm->month, tm->year, tm->hour, tm->min, tm->sec
  );

}

Список микроконтроллеров, для которых применим данный код: LPC2101, LPC2102, LPC2103, LPC2104, LPC2106, LPC2109, LPC2114, LPC2119, LPC2124, LPC2129, LPC2131, LPC2132, LPC2134, LPC2136, LPC2138, LPC2141, LPC2142, LPC2144, LPC2146, LPC2148, LPC2194, LPC2210, LPC2212, LPC2214, LPC2220, LPC2290, LPC2292, LPC2294, LPC2361, LPC2362, LPC2364, LPC2365, LPC2366, LPC2367, LPC2368, LPC2377, LPC2378, LPC2387, LPC2420, LPC2458, LPC2460, LPC2468, LPC2470, LPC2478.



Автор: амдф
Дата: 10.03.2013


При копировании материалов хорошим тоном будет указание авторства и ссылка на сайт.