hex.pp.ua

Работа с часами 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.

система комментирования CACKLE

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


Разделы сайта
Главная
Блог
Native API
NTFS и ReFS
Микроконтроллеры
Справочник NTDLL
Коды NTSTATUS
Разное

Избранное
NTFS Stream Explorer
Native Shell
Тенгвар

Остальное
nvpnhcknn (архив)
English pages
Контакты

Ленты atom
Лента Atom сайта Лента Atom блога



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