Часы 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
Избранное
Остальное
Лента atom