YAMBC - Yet another msp430-based clock - Часть 2. Софт

Перейдем к софту!
Программа написана под IAR Kickstart. Размер кода ограничен 4Кб, но для нашего проекта нам хватит.
Давайте рассмотрим выстраданный код работы с часами по i2c. Библиотеки и примеры от TI совершенно неработоспособны. Путем долгих экспериментов удалось подобрать работающее решение.
Пару констант для читабельности кода
unsigned char CLOCK_ADR = 0x50;
unsigned char time_adr = 0x02;
unsigned char clc_off = {0xC0};
unsigned char clc_on = {0x40};
unsigned char sec, min, hour, day, month;
Инициализиуем модуль USCI_B0. Этот модуль умеет аппаратный i2c.
void i2c_init(void)
{
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST ; // Use SMCLK, keep SW reset
UCB0BR0 = 10; // fSCL = SMCLK/10 = 100kHz
UCB0BR1 = 0;
UCB0I2CSA = CLOCK_ADR; // Slave Address is 050h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
}
Чтобы установить время, часы нужно остановить. Для этого в 7 значащий бит часов нужно записать единичку
void clock_off(void)
{
while (UCB0STAT & UCBBUSY);
UCB0CTL1 |= UCTR + UCTXSTT;
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = clc_off; // Load TX buffer
UCB0CTL1 &= (~UCTXNACK);
UCB0CTL1 |= UCTXSTP; //Send stop message
IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); //clear if any isr still pending
UCB0STAT &= ~UCNACKIFG;
}
Теперь можно установить время специальной функцией:
void mem_write(unsigned char adr, unsigned char ss, unsigned char mm,
unsigned char hh, unsigned char d, unsigned char M)
{
while (UCB0STAT & UCBBUSY);
UCB0CTL1 |= UCTR + UCTXSTT;
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = adr; // Load TX buffer
// sec, min, hour, day, month;
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = ss; // Load TX buffer
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = mm; // Load TX buffer
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = hh; // Load TX buffer
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = d; // Load TX buffer
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = M; // Load TX buffer
delay();
UCB0CTL1 |= UCTXSTP; //Send stop message
IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); //clear if any isr still pending
UCB0STAT &= ~UCNACKIFG;
}
Вызываем, например, так:
mem_write(time_adr, 0, 0x11, 0x23, 0x14, 0x15);
//0 секунд, 11 минут 23 часа...
Запускаем часы — чтобы начали считать время:
void clock_on(void)
{
while (UCB0STAT & UCBBUSY);
UCB0CTL1 |= UCTR + UCTXSTT;
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = clc_on; // Load TX buffer
UCB0CTL1 &= (~UCTXNACK);
UCB0CTL1 |= UCTXSTP; //Send stop message
IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); //clear if any isr still pending
UCB0STAT &= ~UCNACKIFG;
}
Читаем время в цикле функцией mem_read
void mem_read(unsigned char adr)
{
while (UCB0STAT & UCBBUSY);
UCB0CTL1 |= UCTR + UCTXSTT;
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = adr; // Load TX buffer
while( UCB0CTL1 & UCTXSTT); //ensure that start is sent
UCB0CTL1 &= (~UCTR); //receiver mode
UCB0CTL1 |= UCTXSTT; // I2C TX, start condition
while(UCB0CTL1 & UCTXSTT); ///ensure that start is sent
unsigned char xz;
while(! (IFG2 & UCB0RXIFG)); //wait while rx flag is set or nack is set
xz = UCB0RXBUF;
// sec, min, hour, day, month;
while(! (IFG2 & UCB0RXIFG)); //wait while rx flag is set or nack is set
sec = UCB0RXBUF;
while(! (IFG2 & UCB0RXIFG));
min = UCB0RXBUF;
while(! (IFG2 & UCB0RXIFG));
hour = UCB0RXBUF;
while(! (IFG2 & UCB0RXIFG));
day = UCB0RXBUF;
while(! (IFG2 & UCB0RXIFG));
month = UCB0RXBUF;
UCB0CTL1 |= UCTXSTP; //Send stop message
IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); //clear if any isr still pending
UCB0STAT &= ~UCNACKIFG;
}
Переменная xz не зря носит говорящее название. Дело в том, при первом вызове функции mem_read после повторного старта в первый байт считается записанное в памяти значение по адресу time_adr. При втором вызове в первый байт считывается какой-то мусор, а все остальные байты смещаются на один адрес — т.е. секунды живут в минутах, минуты в часах и т.д. Таким образом секунды надо читать с адреса 0x3 а не в 0x2. Но кроме этого глюка, часы работают хорошо и стабильно с часовым кварцем на 12.5 пикофарад.
- +1
- 01 апреля 2012, 00:03
- DeusExMachina
Комментарии (0)
RSS свернуть / развернуть