Делаю большие наружные часы с термометром. Железо сделал, софт часовой сделал (учитывает високосные года, автоматически время переводит на зимнее/летнее). Часы с термометром DS1621. Вот тут и начались проблемы. В CVAVR подключил встроенные программный i2c, библиотеку работы с термомером. красота, почти ничего писать не пришлось. Но часы почему то перезагружались в случайный момент времени. Чаще всего в районе 3:10 - 3:11, но иногда в 3:00, а если проскакивал этот момент, то уже спустя пару часов. Ломал голову в чем дело, и код перетряхнул, и железо. Оказалось - не поверете, в подключенном #include <i2c.h> из комплекта CVAVR. Причем достаточно было просто подключить и не использовать что бы так глючило.
Ну да ладно. Термометр к своей меге 16 я подключал на аппаратный TWI порт, поэтому решил воспользоваться этим. причем мне прерывания не нужны, чисто раз в минуту байтиками перекинуться. А вот с этим проблемы.
начнем с того, что как сказано в даташите флаг TWINT регистра TWCR сбрасывается записью единицы. Когда флаг установлен железом - начинка ждет указаний от программы. Программой записываем единичку - и у нас начинка делает определенную операцию, по завершении которой снова ставит флаг (ноль). тогда непонятно, почему в том же даташите такой кусок:
- Код: Выделить всё
while (!(TWCR & (1<<TWINT)));
//Wait for TWINT Flag set. This indicates that the START condition has been transmitted
Или я чего то не понимаю, или цикл будет выполняться когда TWINT равен 0.
и это никак не вяжется с примером из апноута AVR315
- Код: Выделить всё
unsigned char TWI_Transceiver_Busy( void )
{
return ( TWCR & (1<<TWIE) ); // IF TWI Interrupt is enabled then the Transceiver is busy
}
затем я решил написать свою библиотеку i2c и подменить. не тут то было, оказалось что i2c библиотека зашита в компилятор, поэтому функции везде называются fi2c, т.к. на i2c ругается.
вот они, коменты надерганы из апноута и с доков CVAVR:
- Код: Выделить всё
#define TWINT 7
#define TWEA 6
#define TWSTA 5
#define TWSTO 4
#define TWWC 3
#define TWEN 2
#define TWIE 0
void fi2c_init(void)
TWBR = 20;
TWSR &= 0x03;
TWCR = (1<<TWEN)| // Enable TWI-interface and release TWI pins.
(0<<TWIE)|(0<<TWINT)| // Disable Interupt.
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // No Signal requests.
(0<<TWWC);
};
unsigned char fi2c_start(void)/*issues a START condition.
Returns 1 if bus is free or 0 if the I2C bus is busy or error.*/
{
TWCR = (1<<TWEN)| // TWI Interface enabled.
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag.
(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)| // Initiate a START condition.
(0<<TWWC); //
while (!(TWCR & (1<<TWINT)));
if (((TWSR & 0xF8) == 0x08) || ((TWSR & 0xF8) == 0x10)) //$ 08 - start condition has been transmitted, $ 10 repeated start condition has been transmitted
{
return 1;
}
else
{
return 0;
};
};
void fi2c_stop(void)//issues a STOP condition.
{
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC);
};
unsigned char fi2c_read(unsigned char ack)
/*reads a byte from the bus.
The ack parameter specifies if an acknowledgement is to be issued after the byte was read.
Set ack to 0 for no acknowledgement or 1 for acknowledgement.*/
{
unsigned char data;
if (ack == 0)
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send NACK after reception
(0<<TWWC); //TWCR &= 0x40; //TWEA = 0
else
TWCR = (1<<TWEN)| // TWI Interface enabled
(1<<TWIE)|(1<<TWINT)| // Enable TWI Interupt and clear the flag to read next byte
(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)| // Send ACK after reception
(0<<TWWC); // //TWCR |= 0x40; //TWEA =1
//while (TWI_Transceiver_Busy()); //waits until TWINT set (=0)
while (!(TWCR & (1<<TWINT)));
data = TWDR;
return data;
};
unsigned char fi2c_write(unsigned char data)
/*writes the byte data to the bus.
Returns 1 if the slave acknowledges or 0 if not.
*/
{
TWDR = data;
TWCR &= 0xcf; //TWSTA, TWSTO =0
TWCR |= 0x84; //TWNT TWEN =1
while (!(TWCR & (1<<TWINT)));
if (((TWSR & 0xF8) == 0x18) || ((TWSR & 0xF8) == 0x28) || ((TWSR & 0xF8) == 0x40)) //$ 40 SLA+R transmiteed, $18 SLA+W transmitted, $ 28 DATA transmitted ACK received
{
return 1;
};
if (((TWSR & 0xF8) == 0x20) || ((TWSR & 0xF8) == 0x30) || ((TWSR & 0xF8) == 0x48)) //$20 SLA+W transmited, $ 30 - DATA transmited NOT ACK received $ 48 SLA+R transmitted
{
return 0;
};
};
не работает. причем AVR Studio вообще паршиво себя ведет - TWI не эмулирует. В конструкции
- Код: Выделить всё
TWCR = (1<<TWEN)| // TWI Interface enabled
(0<<TWIE)|(1<<TWINT)| // Disable TWI Interrupt and clear the flag
(0<<TWEA)|(0<<TWSTA)|(1<<TWSTO)| // Initiate a STOP condition.
(0<<TWWC);
указанные биты устанавливает, кроме TWINT, который просто игнорирует. В протеусе еще интереснее. если у меня идет
- Код: Выделить всё
fi2c_start();
fi2c_stop();
у меня i2c debagger пишет S P. но еслия повторю иснтрукции 2 раза, т.е.
- Код: Выделить всё
fi2c_start();
fi2c_stop();fi2c_start();
fi2c_stop();
while(1);
у меня идет бесконечный Sr Sr Sr.. Непонятно почему, ведь иснтрукции всего 4 а после этого должен уходить в бесконечный цикл. Прерывания TWI не задействованы.
при подмене CVAVR i2c на мою fi2c интересное происходит. Байт в термометр отправляет, ACK от него получает, но дальше дело не двигается, причем часы почему то перезагружаются в момент переключения с режима индикации температуры на режим индикации часов. В чём дело - непонятно, тот же код отлично работал. В меню часов выключаю опрос термометра - всё отлично работает.
кто натыкался на такое? буду признателен, если кто -нибудь опубликует свою реализацию i2c через аппаратный TWI для CVAVR, что б всего 4 функции как выше, иначе много переписывать придется((