Witam. Mam następujący problem z niedziałającym TWI. Mam kod na atmegę w C.
Problem polega na tym, że jak wysyłam do czujnika na adres 0x10 wartość 0x01 to nie zapala mi się dioda, tak samo z odczytem. Testuje za pomocą arduino. Nie mam pojęcia co robię źle, to pierwsze moje spotkanie z TWI i nie wiem, może popełniłem jakiś prosty błąd.
Wrzuciłem program zmodyfikowany do tego, żeby testować sam interfejs.
Kod arduino za pomocą którego testuję magistralę:
Serial pokazuje, że magistrala nie jest gotowa, czyli wywala liczbe 15... zamiast odczytu z czujnika.
Przewaliłem tony dokumentacji i nadal nie wiem co jest...
/*
Czujnik ultradzwiekowy sterowany z magistrali i2c
C= 2010 Grzegorz Eliszewski
grzegorz@eliszewski.pl
esio.eu
*/
#define F_CPU 12000000UL // czestotliwosc kwarcu 12MHz
#include <avr/io.h>
#include <util/delay.h> // obsluga opoznien
#include <compat/twi.h> // obsluga magistrali i2c
#include <avr/wdt.h> // obsluga watchdoga
#include <avr/interrupt.h> // przerwania
volatile uint8_t time=124; // czas potrzebny na powrot odbitych ultradzwiekow
volatile uint8_t value; // dane odebrane na magistrali TWI
// deklaracje wystąpienia funcji
void pomiar(void);
void signal(unsigned int o);
unsigned int distance(unsigned int time);
void twi_init(char adres);
// obsluga magistrali i2c
// przerwanie od TWI
SIGNAL (SIG_2WIRE_SERIAL)
{
switch(TWSR) //odczytanie bitu sterujacego
{
case 0x00: // nieoczekiwany start lub stop
TWCR = (1<<TWSTO); // ustawienie 1 na bicie TWSTO = STOP!
TWCR = (1<<TWINT); // ustawienie 1 na bicie TWINT = START!
// w wypadku, gdy pojawi sie nieoczekiwany start lub stop na TWI to:
// 1. transmisja jest zatrzymywana
// 2. transmisja startuje ponownie
break;
// TWI w trybie MASTER - RECIVER
case 0x60:
// TWSR = 0b11000000
// wlasny SLA+W odebrany ACK nadane
break;
case 0x68:
// utrata kontroli nad magistrala, master odlaczony
// wlasny SLA+W odebrany ACK nadane
break;
case 0x80:
// transmisja - odbior!
// 1. odebrano SLA+W (adres + W jak write, czyli zapis do slave :))
// 2. odebrano dane
// 3. nadano ACK = bit potwierdzenia, oczekuje dalszej transmisji
// value = TWDR; // TWDR = rejestr z danymi TWI
if (TWDR == 0x01) // jezeli TWDR = 0b00000001
{
//pomiar(); // wykonanie pomiaru
PORTD = 0xFF;
}
break;
case 0x88:
// transmisja - odbior!
// 1. odebrano SLA+W
// 2. odebrano dane
// 3. nie nadano ACK (nadano NACK), potwierdzenie i koniec transmisji
value = TWDR; // TWDR = rejestr z danymi TWI
if (value == 0x01) // jezeli TWDR = 0b00000001
{
PORTD = 0xFF;
// pomiar(); // wykonanie pomiaru
}
break;
// TWI w trybie MASTER - TRANSMITER
case 0xA8:
// transmisja - nadawanie!
// 1. odebrano SLA+R (adres + odczyt ze slave)
// 2. nadano ACK
TWDR = time; // zapisanie zmiennej czasu do TWDR
TWCR = (1<<TWINT) | (1<<TWEN); // wyczyszczenie TWINT
// wlaczenie TWI poprzez 1 na TWEN
// przygotowanie do wyslania danych
while(!(TWCR & (1<<TWINT))); // transmisja danych <- patrz dataszit
// sprawdzanie statusu TWI
if ((TW_STATUS) & (0xF8 != TW_MT_DATA_ACK))
{
// blad nadawania
}
break;
}
}
// funkcja generujaca sygnal, o = ilosc okresow
// generowanie sygnalu zblizonego do 40kHz, zmiana stanu co 12us zamiast co 12.5us
void signal(unsigned int o)
{
int i;
DDRB = 0xFF; // ustawienie portu B jako wyjscie
// sbi(DDRB,6);
// sbi(DDRB,2);
for(i=0;i<o;i++)
{
// ustaw 1 na PB2 i 0 na PB1
PORTB = 0x04;
_delay_us(12); // czekaj 12us
PORTB = 0x02;
_delay_us(12);
}
// ustawienie stanu niskiego na porcie nadajnika
// tlumienie nadajnika
PORTB = 0x00;
_delay_ms(1); // odczekanie 1ms = tlumienie nadajnika
}
// pomiar odleglosci, o = ilosc okresow
// wyslanie sygnalu i odbior odbitego od przeszkody
void pomiar(void)
{
TCNT1 = 0x0000; // zerowanie licznika T1
signal(5); // emitowanie 5 okresow sygnalu sterujacego
// _delay_ms(10); // odczekanie 10ms przed pomiarem
TCCR1B = 0x05; // start T1 jako licznik z prescalerem /1024 0b00000010
// zliczanie co 12Mhz/1024
// czestotliwosc 11.71875kHz
// czas jednego impulsu to okolo 85us
while(TCNT1 < 0x0FA0) // dopoki licznik nie doliczy do 0x0FA
{
while(bit_is_clear(ADCSRA,ADIF)); // koniec pomiaru na ADC
{
// jezeli wartosc na ADC jest mniejsze niz !czulosc! to przerwij odliczanie czasu
if(ADCH > 100)
{
time = TCNT1; // przepisanie wartosci licznika do zmiennej
TCNT1 = 0xFFFF; // przepelnienie licznika == wyjscie z petli
}
}
}
TCCR1B = 0x00; // wylaczenie licznika
// wdt_reset(); // resetowanie watchdoga
/*
for(echo=0;echo<666;echo++) // petla obliczajaca odleglosc
{
if(bit_is_set(ACSR,ACO)) // jezeli odebrano sygnal powracajacy
{
break; // wyjscie z petli
}
}*/
// return time;
}
// obliczanie rzeczywistej odleglosci w zaleznosci od czasu
// sprawdzic jak to ma sie do siebie :P
unsigned int distance(unsigned int time)
{
unsigned int czas_s;
if (time < 60 )
// 60 przebiegow zegara czyli okolo 5ms
// mierzymy tylko w jedna strone
// wynika z opoznienia na zwarcie czujnikow
{
return 0;
}
else
{
return 50 + time*1.5;
}
// V_dzwieku w powietrzu +/- 343 m/s
// S = (V*t)/2 || droga [m] = predkosc [m/s] * czas [s]
// czas [s] = time * 0.000085 | jeden cykl zegara to 85us
// jeden cykl zegara to okolo 1.5cm
}
// inicjacja i konfiguracja magistrali TWI
void twi_init(char adres)
{
DDRC = 0b00000000; // konfiguracja portu C jako wyjscie
PORTC = 0b00110011; // PC5 PC4 jako wyjscie
TWAR = adres; // przypisanie adresu
TWSR = 0; // zerowanie statusu TWI
TWCR = 0xC5; // ustawienie TWCR 0b11000101
// TWINT - oczekiwanie na odpowiedzi, uaktywnienie przerwania
// TWEA - wlaczenie generowania ACK
// TWEN - aktywacja obslugi TWI, aktywacja interface TWI
// TWIE - uaktywnienie obslugi przerwan TWI
}
// funkcja glowna
int main(void)
{
twi_init(0x02); // inicjacja TWI z adresem 0x02
// konfiguracja ADC
ADMUX = 0x61; // konfiguracja działania ADC 0b01100001
ADCSRA = 0xC6; // start ADC prescaler /64, f = 187.5kHz
// wdt_enable(WDTO_250MS); // watchdog na 250ms
sei(); // wlaczenie obslugi przerwan
DDRD = 0xFF; // port D jako wyjscie
}
Problem polega na tym, że jak wysyłam do czujnika na adres 0x10 wartość 0x01 to nie zapala mi się dioda, tak samo z odczytem. Testuje za pomocą arduino. Nie mam pojęcia co robię źle, to pierwsze moje spotkanie z TWI i nie wiem, może popełniłem jakiś prosty błąd.
Wrzuciłem program zmodyfikowany do tego, żeby testować sam interfejs.
Kod arduino za pomocą którego testuję magistralę:
#include <Wire.h>
int ledPin = 13;
void setup()
{
Serial.begin(9600);
Wire.begin(); // join i2c bus (address optional for master)
pinMode(ledPin, OUTPUT);
}
int zz = 0;
byte x = 0x01;
void loop()
{
Wire.beginTransmission(0x10); // transmit to device #4
//Wire.send("x is "); // sends five bytes
Wire.send(0x01); // sends one byte
Wire.endTransmission(); // stop transmitting
digitalWrite(ledPin, HIGH); // set the LED on
// wait for a second
Wire.requestFrom(0x10, 8);
if (Wire.available()) {
zz = Wire.receive();
}
else zz = 15;
//x++;
Serial.print(zz);
digitalWrite(ledPin, LOW);
delay(500);
}
Serial pokazuje, że magistrala nie jest gotowa, czyli wywala liczbe 15... zamiast odczytu z czujnika.
Przewaliłem tony dokumentacji i nadal nie wiem co jest...