Mam problem z połączeniem dwóch ATmeg8 za pomocą sprzętowego TWI.
Otóż chciałbym połączyć dwie ATmegi, z których pierwsza - SLAVE TRANSMITTER - obsługuje akcelerometr poprzez ADC i przekazuje dane drugiej - MASTER RECEIVER - która to z kolei wyświetla dane na wyświetlaczu LCD.
Przewertowałem elektrodę, google, datasheeta ATmegi i znalazłem wydawałoby się wszystko co potrzebne do napisania obsługi TWI a nawet więcej. Jednak już nie wiem, gdzie szukać problemu. Sprawdzałem program wiele razy i nie mogę dopatrzeć się gdzie leży błąd(y).
Jeżeli jest ktoś, kto jest na bieżąco z TWI to bardzo proszę o pomoc.
Być może problemem jest typ zmiennej, która jest przesyłana ze slave'a do mastera - zmienna typu int. Wiem, że w paczkach danych jest przesyłana zmienna 8bitowa, a więc typu char, ale nie mogłem znaleźć algorytmu/ funkcji konwertującej zmienną typu char na typ string, który jest wyświetlany na LCD, dlatego próbowałem z typem int - możliwe, że właśnie tu leży błąd - w złym typie przesyłanej zmiennej.
Obsługa TWI w slave'ie działa na przerwaniu.
Linie TWI są podciągnięte poprzez rezystory 4,7k.
W kodzie slave'a pomijam obsługę ADC.
Kod mastera:
Kod slave'a:
Jednym z błędów, których nie zauważyłem było brak ustawionego bitu TWIE w rejestrze TWCR w kodzie slave'a, który odblokowuje przerwania. Jednak TWI nadal nie chce działać.
Sprawdzając w którym miejscu kod działa błędnie, dodałem na końcu kodu mastera wyświetlanie napisu - "koniec programu". Jednak napis nie jest wyświetlany. Po odłączeniu magistrali TWI program w masterze biegnie do końca - napis jest wyświetlany. Jednak po drodze nie są wyświetlane żadne komunikaty o błędnej procedurze startu czy błędzie adresu slve'a. Czy ktoś może przypuszcza dlaczego tak jest ?
Otóż chciałbym połączyć dwie ATmegi, z których pierwsza - SLAVE TRANSMITTER - obsługuje akcelerometr poprzez ADC i przekazuje dane drugiej - MASTER RECEIVER - która to z kolei wyświetla dane na wyświetlaczu LCD.
Przewertowałem elektrodę, google, datasheeta ATmegi i znalazłem wydawałoby się wszystko co potrzebne do napisania obsługi TWI a nawet więcej. Jednak już nie wiem, gdzie szukać problemu. Sprawdzałem program wiele razy i nie mogę dopatrzeć się gdzie leży błąd(y).
Jeżeli jest ktoś, kto jest na bieżąco z TWI to bardzo proszę o pomoc.
Być może problemem jest typ zmiennej, która jest przesyłana ze slave'a do mastera - zmienna typu int. Wiem, że w paczkach danych jest przesyłana zmienna 8bitowa, a więc typu char, ale nie mogłem znaleźć algorytmu/ funkcji konwertującej zmienną typu char na typ string, który jest wyświetlany na LCD, dlatego próbowałem z typem int - możliwe, że właśnie tu leży błąd - w złym typie przesyłanej zmiennej.
Obsługa TWI w slave'ie działa na przerwaniu.
Linie TWI są podciągnięte poprzez rezystory 4,7k.
W kodzie slave'a pomijam obsługę ADC.
Kod mastera:
#include <avr/io.h>
#include "LCD.h"
#include <stdlib.h>
#include <util/delay.h>
int pomiar;
char pomiar_bufor [1];
char adres = (0x02<<1);
unsigned char ACK = 1; //gotowosc odbioru
unsigned char NACK = 0; //brak gotowosci
unsigned char READ = 1; //odczyt ze slave'a
unsigned char WRITE = 0; //zapis do slave'a
void inicjalizacja (void)
{
DDRC |= _BV(PC4) | _BV(PC5); //wyprowadzenia TWI jako wyjscia
TWSR = (0<<TWPS1) | (1<<TWPS0); //prskaler = 4
TWBR = 0x64; //wartosc TWBR = 100
LCD_Init(); //inicjalizacja LCD
}
//=============================================
//(transmisja w trybie Master Receiver) - sekwencja START
void TWI_start(void)
{
TWCR |= _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
while (!(TWCR & (1<<TWINT)));{} //oczekiwanie na ustawienie flagi
if ((TWSR&0xF8) != 0x08) //sprawdzenie poprawnosci startu
{
LCD_Go_To(0,1);
LCD_Write_String("blad startu");
}
}
//=============================================
//sekwencja STOP
void TWI_stop(void)
{
TWCR |= _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
while (!(TWCR & (1<<TWINT)));{}
}
//=============================================
//wyslanie adresu slave'a z bitem R/W (Read/Write)
void TWI_sla_rw (unsigned char adres, unsigned char rw)
{
TWDR = ((adres<<1) | rw);
TWCR |= _BV(TWINT) | _BV(TWEN);
while (!(TWCR & (1<<TWINT)));{}
if ((TWSR&0xF8)!=0x40) //sprawdzenie odebrania ACK
{
LCD_Go_To(0,2);
LCD_Write_String("blad adresu");
}
}
//=============================================
//zapis danych
void TWI_write (float dane)
{
TWDR = dane;
TWCR |= _BV(TWINT) | _BV(TWEN);
while (!(TWCR & (1<<TWINT)));{}
}
//=============================================
//odczyt danych
int TWI_read (unsigned char ack)
{
if(ack)
{
TWCR |= _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
}
else
{
TWCR |= _BV(TWINT) | _BV(1TWEN);
}
while (!(TWCR & (1<<TWINT)));{}
if ((TWSR&0xF8)!=0x58) //sprawdzenie wyslania ACK
{
LCD_Go_To(0,3);
LCD_Write_String("blad odczytu");
}
return TWDR;
}
int main(void)
{
inicjalizacja();
TWI_start();
TWI_sla_rw(adres,READ);
pomiar = TWI_read(NACK);
TWI_stop();
//=============================================
itoa(pomiar,pomiar_bufor,10); //zamiana int na string
LCD_Go_To(0,0);
LCD_Write_String(pomiar_bufor);
while(1){}
return 0;
}Kod slave'a:
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <util/twi.h>
volatile int dane = (4<<8); //przesunięcie na pozycję osmiu starszych botow
void inicjalizacja (void)
{
DDRC |= _BV(PC4) | _BV(PC5); //wyprowadzenia TWI jako wyjscia
TWAR = (0x02<<1); //adres slave'a
}
SIGNAL (SIG_2WIRE_SERIAL)
{
switch (TW_STATUS)
{
case TW_ST_SLA_ACK: // odpowidz ACK na wywolanie
TWCR |= _BV(TWEA); // wyslanie ACK
break;
case TW_ST_DATA_ACK: //wyslanie danych, odbior ACK
case TW_ST_DATA_NACK: //wyslanie danych, odbior NACK
TWDR = dane;
break;
}
TWCR |= _BV(TWINT);
}
int main(void)
{
inicjalizacja();
sei();
while(1){}
return 0;
}Jednym z błędów, których nie zauważyłem było brak ustawionego bitu TWIE w rejestrze TWCR w kodzie slave'a, który odblokowuje przerwania. Jednak TWI nadal nie chce działać.
Sprawdzając w którym miejscu kod działa błędnie, dodałem na końcu kodu mastera wyświetlanie napisu - "koniec programu". Jednak napis nie jest wyświetlany. Po odłączeniu magistrali TWI program w masterze biegnie do końca - napis jest wyświetlany. Jednak po drodze nie są wyświetlane żadne komunikaty o błędnej procedurze startu czy błędzie adresu slve'a. Czy ktoś może przypuszcza dlaczego tak jest ?