logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

TWI błędny pierwszy odczyt. Czy brakuje jakiegoś stopu?

Goompas 03 Sie 2006 16:20 1302 1
  • #1 2876837
    Goompas
    Poziom 13  
    Posty: 123
    Pomógł: 3
    Ocena: 2
    Witam.
    Mam problem z odczytem przez TWI, tzn w programie zamieszczonym ponizej najpierw zapisuje do pamieci podlaczonej przez TWI 2 wartosci, a pozniej gdy chce je odczytac, pierwsza odczytana wartosc jest bledna, natomiast druga dobra. Mysle, ze moze to byc blad w funkcji i2c_readAck, gdyz i2c_readNak jak powiedzialem odczytuje poprawna wartosc. A moze brakuje jakiegos stopu? Zamieszczam listingi. Dodam, ze bledny odczyt wystepuje w przypadku wiekszych liczb, tzn liczb dwucyfrowych, jezeli odczytywana wartosc jest jednocyfrowa, dziala dobrze.
    Cytat:

    #include <avr/io.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <avr\eeprom.h>
    #include "globalne.h"
    #include "lcd.h"
    #include "klawiatura.h"
    #include "uart.h"
    #include "mojtwi.h"

    #define Dev24C02 0xA0

    int adres1i, wartoscadres1i, adresodczyti, wartosc2i;
    char adres1u[]="";
    char wartoscadres1[]="";
    char adresodczyt[]="";
    char wartosc2[]="";
    u08 ret, ret1;

    int main (void){
    USART_Init(UART_CONST); // inicjalizacja portu szeregowego
    LCD_init();
    i2c_init();
    LCD_PL_chars_init();
    KBD_init();
    LCD_clear();
    LCD_putstr_P(PSTR("Witaj. Uruchomiono program"));
    delayms1000();
    USART_putstr("Witaj w programie komunikacyjnym\n\r");
    USART_putstr("Podaj adres pod ktory chcesz zapisac: ");
    USART_getstr(adres1u);
    adres1i=atoi(adres1u);
    USART_putstr("\n\rPodaj wartosc jaka zapisac: ");
    USART_getstr(wartoscadres1);
    USART_putstr_P(PSTR("\n\rPodaj 2 wartosc"));
    USART_getstr(wartosc2);
    wartosc2i=atoi(wartosc2);
    wartoscadres1i=atoi(wartoscadres1);
    i2c_start(Dev24C02+I2C_WRITE);
    i2c_write(adres1i);
    i2c_write(wartoscadres1i);
    i2c_write(wartosc2i);
    i2c_stop();
    delayms1000();
    USART_putstr("\n\rA teraz odczyt z i2c\n\r");
    USART_putstr("Podaj skad odczytac ");
    USART_getstr(adresodczyt);
    adresodczyti=atoi(adresodczyt);
    i2c_start_wait(Dev24C02+I2C_WRITE);
    i2c_write(adresodczyti);
    i2c_rep_start(Dev24C02+I2C_READ);
    ret = i2c_readAck();
    ret1=i2c_readNak();
    i2c_stop();
    delayms1000();
    LCD_clear();
    LCD_putstr_P(PSTR("odczytano z i2c "));
    LCD_putU08(ret);
    delayms1000();
    USART_putstr("\n\rOdczytano: ");
    USART_putint(ret, 10);
    USART_putstr("\n\rOdczytano: ");
    USART_putint(ret1, 10);
    delayms1000();
    return 0;
    }


    plik mojtwi.h z funkcjami
    Cytat:

    #ifndef _I2CMASTER_H
    #define _I2CMASTER_H 1

    #ifdef DOXYGEN

    #endif

    /**@{*/

    #if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
    #error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
    #endif

    //definicja kierunku transmisji danych(odczyt)
    #define I2C_READ 1

    //definicja kierunku transmisji danych(zapis)
    #define I2C_WRITE 0

    /**@}*/
    #endif

    #include <inttypes.h>
    #include <C:\WinAVR\avr\include\compat\twi.h>

    //Definicja czestotliwosci taktowania zegara
    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif

    //Czestotliwosc magistrali I2C
    #define SCL_CLOCK 100000L


    //Inicjalizacja magistrali I2C
    void i2c_init(void)
    {
    //Czestotliwosc TWI 100 KHz TWPS = 0 => preskaler = 1

    TWSR = 0; //brak preskalera
    TWBR = ((F_CPU/SCL_CLOCK)-16)/2;

    }

    /*Wysyla sygnal start na magistrale,
    adresuje urzadzenie oraz okresla kierunek transmisji
    zwraca 0 jezeli urzadzenie jest dostepne, 1 gdy wystapil blad*/
    unsigned char i2c_start(unsigned char address)
    {
    uint8_t twst;
    //START
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    // czekaj na zakonczenie transmisji
    while(!(TWCR & (1<<TWINT)));
    // Sprawdz rejestr statusu
    twst = TW_STATUS & 0xF8;
    //wystapil blad, zwroc 1
    if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
    // wyslij adres urzadzenia
    TWDR = address;
    TWCR = (1<<TWINT) | (1<<TWEN);
    //czekaj na zakonczenie transmisji i odbierz ACK/NAK
    while(!(TWCR & (1<<TWINT)));
    //sprawdz rejestr statusu
    twst = TW_STATUS & 0xF8;
    //wystapil blad, zwroc 1
    if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
    //w przeciwnym wypadku operacja powiodla sie zwroc 0
    return 0;
    }

    /*Wysyla sygnal start na magistrale
    adres urzadzenia oraz okresla kierunek transmisji
    jezeli urzadzenie jest zajete, oczekuje na nie*/
    void i2c_start_wait(unsigned char address)
    {
    uint8_t twst;
    while ( 1 )
    {
    //START
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    // czekaj na zakonczenie transmisji
    while(!(TWCR & (1<<TWINT)));
    //sprawdz rejestr statusu
    twst = TW_STATUS & 0xF8;
    if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
    //wyslij adres urzadzenia
    TWDR = address;
    TWCR = (1<<TWINT) | (1<<TWEN);
    //czekaj na zakonczenie transmisji
    while(!(TWCR & (1<<TWINT)));
    //sprawdz rejestr statusu
    twst = TW_STATUS & 0xF8;
    if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
    {
    //urzadzenie zajete, wyslij stop i przerwij zapis
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    //czekaj na stop i zwolnij szyne
    while(TWCR & (1<<TWSTO));
    continue;
    }
    break;
    }
    }

    /*Wysyla powtorzony sygnal start na magistrale
    adres urzadzenia i kierunek transmisji
    zwraca 0 gdy urzadzenie dostepne, w przeciwnym wypadku 1*/
    unsigned char i2c_rep_start(unsigned char address)
    {
    return i2c_start( address );

    }


    //Wysyla sygnal stop i zwalnia magistrale
    void i2c_stop(void)
    {
    //STOP
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
    //czekaj na wykonanie sygnalu stop i zwolnienie magistrali
    while(TWCR & (1<<TWSTO));
    }


    /*Wysyla 1 bajt do urzadzenia
    zwraca 1 gdy blad, w przeciwnym wypadku 0*/
    unsigned char i2c_write( unsigned char data )
    {
    uint8_t twst;
    //wyslij dane do uprzednio zaadresowanego urzadzenia
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    //czekaj na zakonczenie transmisji
    while(!(TWCR & (1<<TWINT)));
    //sprawdz rejestr statusu
    twst = TW_STATUS & 0xF8;
    //jezeli blad zwroc 1
    if( twst != TW_MT_DATA_ACK) return 1;
    //gdy operacja zakonczona sukcesem zwroc 0
    return 0;

    }

    /*Czyta 1 bajt z magistrali i oczekuje na nastepne dane
    zwraca odczytany bajt*/
    unsigned char i2c_readAck(void)
    {
    TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
    while(!(TWCR & (1<<TWINT)));
    return TWDR;
    }

    /*Czyta 1 bajt z magistrali i konczy transmisje
    zwraca odczytany bajt*/
    unsigned char i2c_readNak(void)
    {
    TWCR = (1<<TWINT) | (1<<TWEN);
    while(!(TWCR & (1<<TWINT)));
    return TWDR;

    }
REKLAMA