Часы 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