TWI (I2C) помогите разобраться с проблемой
- Войдите на сайт для отправки комментариев
Всем привет.
Я осваиваю TWI. В Proteus у меня получилось связать Atmega328p и Atmega48.
Теперь я кодом мастера прошиваю Arduino UNO с Atmega328p, который соединен с мультисервошилдом v1 (общение у них происходит по TWI, и на мультисервошилде стоит atmega48 ), и код не работает (((
Я наставил дебагов через usart, и судя по всему код даже в прерывание по TWI_vect не заходит.
Код для прошивки ардуино компилирую через avrdude который идет в комплекте к Arduino IDE.
Подскажите, куда копать? в чем может быть проблема?
Вот мой код:
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usart.h"
#define TW_START 0x08
#define TW_MT_SLA_ACK 0x18
#define TW_MT_DATA_ACK 0x28
#define TW_MR_SLA_ACK 0x40
#define TW_MR_DATA_ACK 0x50
//#define MULTISERVO_ADDR (0x40)
#define SLAVE_ADDRESS (0x47)
uint8_t value;
uint8_t ongoing_transmission = 0;
uint8_t status;
uint8_t angle = 50, pin = 2;
uint8_t flag;
//interrupt routine for the TWI interrupt
ISR(TWI_vect)
{
status = TWSR & 0xFC; //mask-out theprescaller bits
switch(status)
{
case TW_START: //start transmitted
usart_set_message("start transmitted U1");
usart_print();
ongoing_transmission = 1;
flag = 0;
// write SLA+R, SLA=0x01
//TWDR = (SLAVE_ADDRESS << 1) | 0x01;
// write SLA+W, SLA=0x00
TWDR = (SLAVE_ADDRESS << 1) | 0x00;
TWCR &= ~((1<<TWSTA)); // clear TWSTA
break;
case TW_MT_SLA_ACK: // own SLA+W received, acknoledge sent
usart_set_message("own SLA+R received, acknoledge sent");
usart_print();
switch(flag)
{
case 0:
usart_set_message("send pin");
usart_print();
TWDR = (pin & 0xFF);
flag = 1;
break;
default:
usart_set_message("ALARM! emergency stop");
usart_print();
TWCR |= (1<<TWSTO); // write stop bit
TWCR &= ~(1<<TWSTA); // clear start bit
ongoing_transmission = !ongoing_transmission;
break;
}
usart_print_number(TWDR);
break;
case TW_MT_DATA_ACK: // last byte transmitted ACK received
//TWCR |= (1<<TWEA); // set TWEA to enter slave mode
usart_set_message("last byte transmitted ACK received");
usart_print();
switch(flag)
{
case 1:
usart_set_message("send angle");
usart_print();
TWDR = (angle & 0xFF);
flag = 2;
break;
case 2:
TWCR |= (1<<TWSTO); // write stop bit
TWCR &= ~(1<<TWSTA); // clear start bit
ongoing_transmission = !ongoing_transmission;
flag = 0;
break;
}
usart_print_number(TWDR);
TWCR &= ~((1<<TWSTO) | (1<<TWEA));
break;
case TW_MR_SLA_ACK: // SLA+R transmitted, ACK received
usart_set_message("SLA+R transmitted, ACK received");
usart_print();
TWCR &= ~((1<<TWSTA) | (1<<TWSTO));
break;
}
TWCR |= (1<<TWINT); // hand over to TWI hardware
}
int main()
{
usart_init();
usart_set_message("init usart U1");
usart_print();
value = 12;
sei();
TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
// Write your code here
while (1)
{
if (!ongoing_transmission)
{
usart_set_message("!ongoing_transmission");
usart_print();
TWCR |= (1<<TWSTA);
}
_delay_ms(3000);
}
return 0;
}
Исследуя проблему, я дебажу значение в регистре TWCR. Как ни странно, после строки TWCR |= (1<<TWSTA); в регистре TWCR получаю 01100101. Если я правильно интерпретирую значение - в регистре TWCR установлен флаг TWSTA, судя из описания из книги Евстифеева "Микроконтроллеры AVR семейств Tiny и Mega фирмы ATMEL"(стр 366) "Флаг состояния СТАРТ. При записи в разряд TWSTA лог. 1 модуль проверяет со стояние шины TWI и, если шина свободна, формирует состояние СТАРТ. Если шина занята, модуль TWI ожидает появления состояния СТОП, и только после этого формирует состояние СТАРТ. Флаг сбрасывается аппаратно по окончании формирования состояния СТАРТ", и дальше на протяжении работы программы значение в этом регистре не меняется. Значит что TWI занят? а чем? чет я не пойму.
Еще я в настройке фьюзов не уверен. в Proteus я устанавливаю фьюзы CKSEL3:0 в 0000, а с МК от ардуинки прочитав фьюзы CKSEL3:0 увидел 1111
В Proteus по умолчанию включен фьюз CLDIV8 - и частота в 8 раз ниже источника тактирования !!!
Также если используется кварц, то CKSEL0:3, SUT0:1 должны быть все 1 или вернее они должны быть противоположны SPIEN
Фьюзы МК ардуинки я не трогал, на сколько мне известно в контексте Ардуино фьюзы "доступны чисто теоретически и достаточно сложным путем (через команды загрузчика avrdude)".
Я наставил дебагов через usart,
В обработчике ,перед использованием usart попробуйте установить флаг разр. прерывания sei(), а затем , по завершении работы с usart, сбросить cli();