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();