Отговори на тема  [ 281 мнения ]  Отиди на страница Предишна  1 ... 3, 4, 5, 6, 7, 8, 9 ... 19  Следваща
I2C малко помощ 
Автор Съобщение
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
stefan63 написа:
Там- дето ще те наплюе компилатора - е лесно.


Това вече го разбрах по трудния начин. Днес такова "дебъгвъне" му хвърлих, докато разбера, че вместо "u=(u-i)*2;" съм написал "u=(u-1)*2;"
Явно трябва да сменям очилата :)


Вто Авг 01, 2017 9:57 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение Re: I2C малко помощ
Дилей минута ,изпълнен с по тоя начин е нонсенс.
Тая функция дилей трябва да я изключат от Ц-то.
Ама засега е легална де, споко :P .


Вто Авг 01, 2017 10:08 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
С по-стара версия на XC8 я нямаше и много ми липсваше. Ползвах void pause или там където искам пауза за нещо от периферията, ползвам брояч, който си увеличава състоянието на всеки цикъл и "if.....".


Вто Авг 01, 2017 10:17 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
Нещо не се получава.

Постановката е следната:

На Slave устройството в main.c съм написал:

Код:
#include "mcc_generated_files/mcc.h"


/*
                         Main application
*/
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts
    //INTERRUPT_GlobalInterruptEnable();

    // Enable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();

    while (1)
        // Add your application code
    {
        if(RA5==0)
        {
            LATA4=1;
            EEPROM_Buffer[0] =1;
        }
        else
        {
            LATA4=0;
            EEPROM_Buffer[0] =0;
        }
    }
}



но "EEPROM_Buffer[0] =1;" не ми го приема.


Това, което искам е, като направя входа RA5 в 0, да се запише някаква стойност, примерно 1 в клетка от буфера. После от Master да се изчете съдържанието на въпросната клетка и ако то е 1, респективно той да си вдигне LATA4. Така, ако всичко е ОК с I2C, като натисна бутон на Slave, трябва да светне светодиод на Master.


Пон Авг 07, 2017 1:17 pm
Профил
Ранг: Професионалист
Ранг: Професионалист
Аватар

Регистриран на: Съб Май 21, 2016 9:47 pm
Мнения: 577
Местоположение: Бургас
Мнение Re: I2C малко помощ
Ето това е кода на slave контролера, който ползвам и работи. Контролера е 16F886, ползвам го за управление на три стъпкови двигателя- подавам данни за движението им и чета докъде е стигнал. С малки промени работи и на 16F1938. Втория има три таймера, които позволяват да се регулира времето за една стъпка на всеки двигател поотделно.
Не съм програмист, може да ми се смеете ;).

Код:
unsigned char addr=0;
char dataPIC[11];
unsigned char indexPICin;
unsigned char datawork[11];
char dataPICout[24]; // out buffer;
unsigned char dataindex;
unsigned char datareceived;
char readreg;  // content count of bytes;
char newdata; // 1 if new data received else- 0;

void i2c_slave_init(void)
{
   ....
    SSPADD = Slave_addr; //device address
    SSPCON = 0X36; //SSPEN =1 and set i2c to slave mode with 7 bit address
    SSPSTAT =0;
   ....
}

void interrupt I2C_slave()
{
    if(PIR1bits.SSPIF == 1)
    {
       if ((SSPCONbits.SSPOV) || (SSPCONbits.WCOL))  // reset bus, if error
       {
             count1 = SSPBUF;           // Read the previous value to clear the buffer
             SSPCONbits.SSPOV = 0;      // Clear the overflow flag
             SSPCONbits.WCOL = 0;       // Clear the collision bit
             PIR1bits.SSPIF = 0;           // Clear interrupt flag
             SSPCONbits.CKP = 1;
       };
       if (SSPSTATbits.S==1 && SSPSTATbits.R_nW==0 && SSPSTATbits.D_nA==0 && SSPSTATbits.BF==1)
              //start bit, buffer full, address
             // get ready slave to receive data
       {
           addr = SSPBUF;
           if (addr==Slave_addr) {datareceived=0;indexPICin=0;};   //reset counters
       }
       else
       if (SSPSTATbits.R_nW==0 && SSPSTATbits.D_nA==1 && SSPSTATbits.BF==1) // receive data
       {
           dataPIC[datareceived]=SSPBUF;
           if (datareceived==0) {readreg=dataPIC[0];}
            datareceived++;
           if (SSPSTATbits.P==1) // if detect end of data -> move receive buffer to work buffer;
            {
               for (i=0;i<datareceived;i++) {datawork[i]=dataPIC[i];}
               datawork[10]=datareceived;newdata=1;
            }
       }
       else
       if (SSPSTATbits.S==1 && SSPSTATbits.R_nW==1 && SSPSTATbits.D_nA==0)
             //start bit, buffer full, address
             // get ready slave to SEND data
       {
         SSPCONbits.CKP = 0;
         indexPICin=0; addr= SSPBUF;  dataindex=24;
         switch (readreg)  // get a point of outbuffer;
          {
           case 0:{count1=0;break;}
           case 1:{count1=4;break;}
           case 2:{count1=8;break;}
          }
         for (i=0;i<dataindex;i++) {dataPICout[i]=usedPICdata[count1];count1++;}  // move work data buffer in out data buffer
         SSPBUF = dataindex;
         SSPCONbits.CKP = 1;
         while (SSPSTATbits.BF);// {}
       };
       if (SSPSTATbits.R_nW==1 && addr == Slave_addr+1)     
           // Master is expecting data from this device
          // slave send data;
       {
        SSPCONbits.CKP = 0;
        SSPBUF = dataPICout[indexPICin];
        SSPCONbits.CKP = 1;
        while (SSPSTATbits.BF);// {}
         indexPICin++;
       }
     SSPCONbits.CKP = 1;
     PIR1bits.SSPIF = 0;
    }
}


Пон Авг 07, 2017 2:51 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
Благодаря ти за примера!

Този MCC нещо ми бърка в здравето :) , та ще взема да ги накълва ръчно нещата.


Пон Авг 07, 2017 4:05 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
lcr написа:
.........
но "EEPROM_Buffer[0] =1;" не ми го приема.


Това, което искам е, като направя входа RA5 в 0, да се запише някаква стойност, примерно 1 в клетка от буфера. После от Master да се изчете съдържанието на въпросната клетка и ако то е 1, респективно той да си вдигне LATA4. Така, ако всичко е ОК с I2C, като натисна бутон на Slave, трябва да светне светодиод на Master.


Това го оправих. Грешката ми беше в това, че все забравям да правя декларациите в main, като си мисля, че това става автоматично, след като са направени за другите функции.

Остава да пусна и master - а.


Пон Авг 07, 2017 8:52 pm
Профил
Ранг: Професионалист
Ранг: Професионалист
Аватар

Регистриран на: Съб Май 21, 2016 9:47 pm
Мнения: 577
Местоположение: Бургас
Мнение Re: I2C малко помощ
Ето какво имам в мастер:

Код:
void i2c_waitForIdle()
{
while (( SSPCON2 & 0x1F ) | SSPSTATbits.R_NOT_W ) {}; // wait for idle and not writing
}

void i2c_start()
{
i2c_waitForIdle();
SSPCON2bits.SEN=1;
}

void i2c_repStart()
{
i2c_waitForIdle();
SSPCON2bits.RSEN=1;
}

void i2c_stop()
{
i2c_waitForIdle();
SSPCON2bits.PEN=1;
}

int i2c_read( unsigned char ack )
{
unsigned char i2cReadData;

i2c_waitForIdle();
SSPCON2bits.RCEN=1;
i2c_waitForIdle();
i2cReadData = SSPBUF;
i2c_waitForIdle();
if ( ack )
  {SSPCON2bits.ACKDT=0;}
else
  {SSPCON2bits.ACKDT=1;}
  SSPCON2bits.ACKEN=1;               // send acknowledge sequence
return( i2cReadData );
}

unsigned char i2c_write( unsigned char i2cWriteData )
{
i2c_waitForIdle();
SSPBUF = i2cWriteData;
return ( !SSPCON2bits.ACKSTAT  ); // function returns '1' if transmission is acknowledged
}

Четене в буфер Temp_data:
Код:
void read_extPIC(unsigned char PIC_address,unsigned char reg_addr, unsigned char index)
{
// reg_addr съдържа информация какво да прави slave- примерно брой байтове или команда,
// а прочетените байтове да са резултата.
   Temp_data[index]=PIC_address;
   i2c_start();
    i2c_write(PIC_address);
    i2c_write(reg_addr);
   i2c_repStart();
    i2c_write(PIC_address+1);
     Temp_data[index+1]=i2c_read(1);

// Ако байтовете за четене са повече се добавят съответните редове:
//    Temp_data[index+1]=i2c_read(1);
// и последния байт завършва с
     Temp_data[index+2]=i2c_read(0);

//  i2c_read(0) - казва на slave PICa, че няма да се чете повече от него и освобождава линията.
//  Следващите прочетени байтове с таз команда ще са 0xFF;
//  i2c_read(1) - казва на slave PICa, че ще има следващо четене на байт.

   i2c_stop();
}


ПП: Според мен това MCC.h не ти трябва за комуникацията ако вкараш тия процедурки.


Вто Авг 08, 2017 10:12 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
Колега @ig_ivanov, благодаря ти за помощта, но към настоящия момент удрям греда :)


примерно тук:

while (( SSPCON2 & 0x1F ) | SSPSTATbits.R_NOT_W ) {}; // wait for idle and not writing

впредвид описанието на 12f1840:

SSPSTAT:

bit 7 SMP: SPI Data Input Sample bit
SPI Master mode:
1 = Input data sampled at end of data output time
0 = Input data sampled at middle of data output time
SPI Slave mode:
SMP must be cleared when SPI is used in Slave mode
In I2 C Master or Slave mode:
1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz)
0 = Slew rate control enabled for high speed mode (400 kHz)
bit 6 CKE: SPI Clock Edge Select bit (SPI mode only)
In SPI Master or Slave mode:
1 = Transmit occurs on transition from active to Idle clock state
0 = Transmit occurs on transition from Idle to active clock state
In I2 C™ mode only:
1 = Enable input logic so that thresholds are compliant with SMBus specification
0 = Disable SMBus specific inputs
bit 5 D/A: Data/Address bit (I2C mode only)
1 = Indicates that the last byte received or transmitted was data
0 = Indicates that the last byte received or transmitted was address
bit 4 P: Stop bit
(I2C mode only. This bit is cleared when the MSSP module is disabled, SSPEN is cleared.)
1 = Indicates that a Stop bit has been detected last (this bit is ‘0’ on Reset)
0 = Stop bit was not detected last
bit 3 S: Start bit
(I2C mode only. This bit is cleared when the MSSP module is disabled, SSPEN is cleared.)
1 = Indicates that a Start bit has been detected last (this bit is ‘0’ on Reset)
0 = Start bit was not detected last
bit 2 R/W: Read/Write bit information (I2C mode only)
This bit holds the R/W bit information following the last address match. This bit is only valid from the address match
to the next Start bit, Stop bit, or not ACK bit.
In I2 C Slave mode:
1 = Read
0 = Write
In I2 C Master mode:
1 = Transmit is in progress
0 = Transmit is not in progress
OR-ing this bit with SEN, RSEN, PEN, RCEN or ACKEN will indicate if the MSSP is in Idle mode.
bit 1 UA: Update Address bit (10-bit I2C mode only)
1 = Indicates that the user needs to update the address in the SSPADD register
0 = Address does not need to be updated
bit 0 BF: Buffer Full Status bit
Receive (SPI and I2 C modes):
1 = Receive complete, SSPBUF is full
0 = Receive not complete, SSPBUF is empty
Transmit (I2 C mode only):
1 = Data transmit in progress (does not include the ACK and Stop bits), SSPBUF is full
0 = Data transmit complete (does not include the ACK and Stop bits), SSPBUF is empty

предполагам, че трябва да запиша:

SSPSTAT<2>=0

но не съм сигурен.

за останалото уж не ме плюе, но при изпълнението на кода за четене на буфера, нищо не се случва. Не наблюдавам (с осцилоскоп) и никаква комуникация между двата контролера. Нито данни, нито клок.


Вто Авг 08, 2017 3:50 pm
Профил
Ранг: Професионалист
Ранг: Професионалист
Аватар

Регистриран на: Съб Май 21, 2016 9:47 pm
Мнения: 577
Местоположение: Бургас
Мнение Re: I2C малко помощ
Като гледам документацията на контролера и колко неща са нацвъкали на всеки извод- може да e нещо с инициализацията, още повече, че и клок няма.
Трябва всичко да е забранено- ADC, Реф. модула (за опорно напрежение), тъч модула, компараторите, CCP, PWM, EUSART, модулатора, входа на TIMER0 и най вече изводите (RA1 и RA2) да са инициализирани като цифрови входове.


Вто Авг 08, 2017 5:23 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
RA1 и RA2 при конфигурацията на MSSP модула, MCC ги прави автоматично на цифрови входове с WPU.

Нещо бъркам с аргументите на функцията I2CMasterRead за които говори Стефан:

stefan63 написа:
void I2C1_Initialize(void) е в самото начало;


Викаш
void I2C1_MasterRead(
uint8_t *pdata, //тук даващ адрес от РАМ , където да дойдат данните
uint8_t length, // брой байтове
uint16_t address, //адрес на малкия пик
I2C1_MESSAGE_STATUS *pflag) //тук даваш адрес на флаг, който ще следиш.

Системата се движи от
void I2C1_ISR ( void ) .
Значи - когато опашката е празна тази функция не би трябвало да се активира,
и като издадеш заявка - би трябвало някак да я извикаш - може би със сетване на
PIR1bits.SSP1IF = 1;
и оттам нататък - следиш флага на заявката pflag ;


Не ми е ясно, какъв адрес да дам за *pdata и после, как да приравня съдържанието му на някаква променлива D.
За length давам 1
За address задавам това, което съм конфигурирал на slave, а именно 0x08 (маската, която ми генерира MCC заедно с адреса, също не знам за какво служи).
С флага също не знам, какво да правя.

Изобщо - тръгнал съм на сватба без ... :)


Вто Авг 08, 2017 5:33 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение Re: I2C малко помощ
покажи цялата програма - някой може да му е скучно и да ти я прегледа.
Много е трудно да пишеш нов код за 2 у-ва.
Бих ти препоръчл да направиш първо Мастера - за слейв ползвай някаква И2Ц памет - първо я запиши някак си де ,например на адрес 0='h', 1='e',2='l',3='l'- нататък - както ти харесва...
Тоя подход пък е гаден, щото паметите са с повече адресно инфо в пакета, отколкото ти май планираш.
Но поне ще си сигурен - че слейвът е адекватен.


Вто Авг 08, 2017 10:29 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Вто Фев 07, 2012 11:22 pm
Мнения: 3084
Мнение Re: I2C малко помощ
#include <stdio.h>
typedef unsigned short I2C1_MESSAGE_STATUS ;
typedef unsigned short uint8_t ;
void I2C1_MasterRead(
unsigned short *pdata, //тук даващ адрес от РАМ , където да дойдат данните
unsigned short length, // брой байтове
unsigned short address, //адрес на малкия пик
I2C1_MESSAGE_STATUS * pflag) ;


//globally accessible RAM
uint8_t RXbuffer_forslave_1[10];
uint8_t RXbuffer_forslave_2[10];
uint8_t RXbuffer_forslave_3[10];
I2C1_MESSAGE_STATUS statusReadSlave1;
I2C1_MESSAGE_STATUS statusReadSlave2;
I2C1_MESSAGE_STATUS statusReadSlave3;

void main(void)
{
I2C1_MasterRead(RXbuffer_forslave_1,10,1,&statusReadSlave1);
I2C1_MasterRead(RXbuffer_forslave_2,10,2,&statusReadSlave2);
I2C1_MasterRead(RXbuffer_forslave_3,10,2,&statusReadSlave3);
}



Ей това се компилира без синтактична грешка, исках да ти покажа,как аз го разбирам.
Типовете съм ги дефинирал някак си, за да не избива в грешка "непознат тип"


Вто Авг 08, 2017 11:10 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Пон Май 12, 2014 11:49 pm
Мнения: 4394
Местоположение: София
Мнение Re: I2C малко помощ
i2c конфигурацията на slave e:


Код:
#include "i2c.h"

#define I2C_SLAVE_ADDRESS 0x01
#define I2C_SLAVE_MASK    0x7F

typedef enum
{
    SLAVE_NORMAL_DATA,
    SLAVE_DATA_ADDRESS,
    SLAVE_GENERAL_CALL,
} SLAVE_WRITE_DATA_TYPE;

/**
Section: Global Variables
*/

volatile uint8_t    I2C_slaveWriteData      = 0x55;

/**
Section: Local Functions
*/
void I2C_StatusCallback(I2C_SLAVE_DRIVER_STATUS i2c_bus_state);



/**
  Prototype:        void I2C_Initialize(void)
  Input:            none
  Output:           none
  Description:      I2C_Initialize is an
                    initialization routine that takes inputs from the GUI.
  Comment:         
  Usage:            I2C_Initialize();

*/
void I2C_Initialize(void)
{
    // initialize the hardware
    // R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP High Speed; UA dontupdate; CKE enabled; D_nA lastbyte_address;
    SSP1STAT = 0x40;
    // SSPEN enabled; WCOL no_collision; CKP disabled; SSPM 7 Bit Polling; SSPOV no_overflow;
    SSP1CON1 = 0x26;
    // ACKEN disabled; GCEN enabled; PEN disabled; ACKDT acknowledge; RSEN disabled; RCEN disabled; ACKSTAT received; SEN enabled;
    SSP1CON2 = 0x81;
    // ACKTIM ackseq; SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
    SSP1CON3 = 0x00;
    // SSPMSK 127;
    SSP1MSK = (I2C_SLAVE_MASK << 1);  // adjust UI mask for R/nW bit           
    // SSPADD 1;
    SSP1ADD = (I2C_SLAVE_ADDRESS << 1);  // adjust UI address for R/nW bit

    // clear the slave interrupt flag
    PIR1bits.SSP1IF = 0;
    // enable the master interrupt
    PIE1bits.SSP1IE = 1;

}

void I2C_ISR ( void )
{
    uint8_t     i2c_data                = 0x55;


    // NOTE: The slave driver will always acknowledge
    //       any address match.

    PIR1bits.SSP1IF = 0;        // clear the slave interrupt flag
    i2c_data        = SSP1BUF;  // read SSPBUF to clear BF
    if(1 == SSP1STATbits.R_nW)
    {
        if((1 == SSP1STATbits.D_nA) && (1 == SSP1CON2bits.ACKSTAT))
        {
            // callback routine can perform any post-read processing
            I2C_StatusCallback(I2C_SLAVE_READ_COMPLETED);
        }
        else
        {
            // callback routine should write data into SSPBUF
            I2C_StatusCallback(I2C_SLAVE_READ_REQUEST);
        }
    }
    else if(0 == SSP1STATbits.D_nA)
    {
        // this is an I2C address

        if(0x00 == i2c_data)
        {
            // this is the General Call address
            I2C_StatusCallback(I2C_SLAVE_GENERAL_CALL_REQUEST);
        }
        else
        {
            // callback routine should prepare to receive data from the master
            I2C_StatusCallback(I2C_SLAVE_WRITE_REQUEST);
        }
    }
    else
    {
        I2C_slaveWriteData   = i2c_data;

        // callback routine should process I2C_slaveWriteData from the master
        I2C_StatusCallback(I2C_SLAVE_WRITE_COMPLETED);
    }

    SSP1CON1bits.CKP    = 1;    // release SCL

} // end I2C_ISR()



/**

    Example implementation of the callback

    This slave driver emulates an EEPROM Device.
    Sequential reads from the EEPROM will return data at the next
    EEPROM address.

    Random access reads can be performed by writing a single byte
    EEPROM address, followed by 1 or more reads.

    Random access writes can be performed by writing a single byte
    EEPROM address, followed by 1 or more writes.

    Every read or write will increment the internal EEPROM address.

    When the end of the EEPROM is reached, the EEPROM address will
    continue from the start of the EEPROM.
*/

void I2C_StatusCallback(I2C_SLAVE_DRIVER_STATUS i2c_bus_state)
{

    static uint8_t EEPROM_Buffer[] =
    {
        0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
        0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
        0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
        0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
        0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
        0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
    };

    static uint8_t eepromAddress    = 0;
    static uint8_t slaveWriteType   = SLAVE_NORMAL_DATA;


    switch (i2c_bus_state)
    {
        case I2C_SLAVE_WRITE_REQUEST:
            // the master will be sending the eeprom address next
            slaveWriteType  = SLAVE_DATA_ADDRESS;
            break;

        case I2C_SLAVE_GENERAL_CALL_REQUEST:
            // the master will be sending general call data next
            slaveWriteType  = SLAVE_GENERAL_CALL;
            break;

        case I2C_SLAVE_WRITE_COMPLETED:

            switch(slaveWriteType)
            {
                case SLAVE_DATA_ADDRESS:
                    eepromAddress   = I2C_slaveWriteData;
                    break;

                case SLAVE_GENERAL_CALL:
                    // process general call data here
                    break;

                case SLAVE_NORMAL_DATA:
                default:
                    // the master has written data to store in the eeprom
                    EEPROM_Buffer[eepromAddress++]    = I2C_slaveWriteData;
                    if(sizeof(EEPROM_Buffer) <= eepromAddress)
                    {
                        eepromAddress = 0;    // wrap to start of eeprom page
                    }
                    break;

            } // end switch(slaveWriteType)

            slaveWriteType  = SLAVE_NORMAL_DATA;
            break;

        case I2C_SLAVE_READ_REQUEST:
            SSP1BUF = EEPROM_Buffer[eepromAddress++];
            if(sizeof(EEPROM_Buffer) <= eepromAddress)
            {
                eepromAddress = 0;    // wrap to start of eeprom page
            }
            break;

        case I2C_SLAVE_READ_COMPLETED:
        default:;

    } // end switch(i2c_bus_state)

}



Моят код на Slave e:

Код:
#include "mcc_generated_files/mcc.h"

/*
                         Main application
*/
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

   
   
    unsigned int D;

    while (1)
    {
         // Add your application code
       
       if(RA4)
           D=11;
       else
           D=22;
           
     
    }
}




Въпросът ми е, какъв код трябва да добавя в while(1) за да може променливата D да бъде прочетена от master - a?


i2c конфигурацията на master-а e:

Код:
#include "i2c.h"

/**
  I2C Driver Queue Status Type

  @Summary
    Defines the type used for the transaction queue status.

  @Description
    This defines type used to keep track of the queue status.
*/

typedef union
{
    struct
    {
            uint8_t full:1;
            uint8_t empty:1;
            uint8_t reserved:6;
    }s;
    uint8_t status;
}I2C_TR_QUEUE_STATUS;

/**
  I2C Driver Queue Entry Type

  @Summary
    Defines the object used for an entry in the i2c queue items.

  @Description
    This defines the object in the i2c queue. Each entry is a composed
    of a list of TRBs, the number of the TRBs and the status of the
    currently processed TRB.
*/
typedef struct
{
    uint8_t                             count;          // a count of trb's in the trb list
    I2C_TRANSACTION_REQUEST_BLOCK *ptrb_list;     // pointer to the trb list
    I2C_MESSAGE_STATUS            *pTrFlag;       // set with the error of the last trb sent.
                                                        // if all trb's are sent successfully,
                                                        // then this is I2C_MESSAGE_COMPLETE
} I2C_TR_QUEUE_ENTRY;

/**
  I2C Master Driver Object Type

  @Summary
    Defines the object that manages the i2c master.

  @Description
    This defines the object that manages the sending and receiving of
    i2c master transactions.
  */

typedef struct
{
    /* Read/Write Queue */
    I2C_TR_QUEUE_ENTRY          *pTrTail;       // tail of the queue
    I2C_TR_QUEUE_ENTRY          *pTrHead;       // head of the queue
    I2C_TR_QUEUE_STATUS         trStatus;       // status of the last transaction
    uint8_t                         i2cDoneFlag;    // flag to indicate the current
                                                    // transaction is done
    uint8_t                         i2cErrors;      // keeps track of errors


} I2C_OBJECT ;

/**
  I2C Master Driver State Enumeration

  @Summary
    Defines the different states of the i2c master.

  @Description
    This defines the different states that the i2c master
    used to process transactions on the i2c bus.
*/

typedef enum
{
    S_MASTER_IDLE,
    S_MASTER_RESTART,
    S_MASTER_SEND_ADDR,
    S_MASTER_SEND_DATA,
    S_MASTER_SEND_STOP,
    S_MASTER_ACK_ADDR,
    S_MASTER_RCV_DATA,
    S_MASTER_RCV_STOP,
    S_MASTER_ACK_RCV_DATA,
    S_MASTER_NOACK_STOP,
    S_MASTER_SEND_ADDR_10BIT_LSB,
    S_MASTER_10BIT_RESTART,
   
} I2C_MASTER_STATES;

/**
Section: Macro Definitions
*/

/* defined for I2C */

#ifndef I2C_CONFIG_TR_QUEUE_LENGTH
        #define I2C_CONFIG_TR_QUEUE_LENGTH 1
#endif

#define I2C_TRANSMIT_REG                       SSP1BUF                 // Defines the transmit register used to send data.
#define I2C_RECEIVE_REG                        SSP1BUF                 // Defines the receive register used to receive data.

// The following control bits are used in the I2C state machine to manage
// the I2C module and determine next states.
#define I2C_WRITE_COLLISION_STATUS_BIT         SSP1CON1bits.WCOL     // Defines the write collision status bit.
#define I2C_MODE_SELECT_BITS                   SSP1CON1bits.SSPM     // I2C Master Mode control bit.
#define I2C_MASTER_ENABLE_CONTROL_BITS         SSP1CON1bits.SSPEN    // I2C port enable control bit.

#define I2C_START_CONDITION_ENABLE_BIT         SSP1CON2bits.SEN      // I2C START control bit.
#define I2C_REPEAT_START_CONDITION_ENABLE_BIT  SSP1CON2bits.RSEN     // I2C Repeated START control bit.
#define I2C_RECEIVE_ENABLE_BIT                 SSP1CON2bits.RCEN     // I2C Receive enable control bit.
#define I2C_STOP_CONDITION_ENABLE_BIT          SSP1CON2bits.PEN      // I2C STOP control bit.
#define I2C_ACKNOWLEDGE_ENABLE_BIT             SSP1CON2bits.ACKEN    // I2C ACK start control bit.
#define I2C_ACKNOWLEDGE_DATA_BIT               SSP1CON2bits.ACKDT    // I2C ACK data control bit.
#define I2C_ACKNOWLEDGE_STATUS_BIT             SSP1CON2bits.ACKSTAT  // I2C ACK status bit.

#define I2C_7bit    true
/**
Section: Local Functions
*/

void I2C_FunctionComplete(void);
void I2C_Stop(I2C_MESSAGE_STATUS completion_code);

/**
Section: Local Variables
*/

static I2C_TR_QUEUE_ENTRY                  i2c_tr_queue[I2C_CONFIG_TR_QUEUE_LENGTH];
static I2C_OBJECT                          i2c_object;
static I2C_MASTER_STATES                   i2c_state = S_MASTER_IDLE;
static uint8_t                                 i2c_trb_count = 0;

static I2C_TRANSACTION_REQUEST_BLOCK       *p_i2c_trb_current = NULL;
static I2C_TR_QUEUE_ENTRY                  *p_i2c_current = NULL;


/**
  Section: Driver Interface
*/


void I2C_Initialize(void)
{
    i2c_object.pTrHead = i2c_tr_queue;
    i2c_object.pTrTail = i2c_tr_queue;
    i2c_object.trStatus.s.empty = true;
    i2c_object.trStatus.s.full = false;

    i2c_object.i2cErrors = 0;

    // R_nW write_noTX; P stopbit_notdetected; S startbit_notdetected; BF RCinprocess_TXcomplete; SMP High Speed; UA dontupdate; CKE enabled; D_nA lastbyte_address;
    SSP1STAT = 0x40;
    // SSPEN enabled; WCOL no_collision; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD_I2C; SSPOV no_overflow;
    SSP1CON1 = 0x28;
    // ACKTIM ackseq; SBCDE disabled; BOEN disabled; SCIE disabled; PCIE disabled; DHEN disabled; SDAHT 100ns; AHEN disabled;
    SSP1CON3 = 0x00;
    // Baud Rate Generator Value: SSPADD 3;   
    SSP1ADD = 0x03;

   
    // clear the master interrupt flag
    PIR1bits.SSP1IF = 0;
    // enable the master interrupt
    PIE1bits.SSP1IE = 1;
   
}

       
uint8_t I2C_ErrorCountGet(void)
{
    uint8_t ret;

    ret = i2c_object.i2cErrors;
    return ret;
}

void I2C_ISR ( void )
{
 
    static uint8_t  *pi2c_buf_ptr;
    static uint16_t i2c_address         = 0;
    static uint8_t  i2c_bytes_left      = 0;
    static uint8_t  i2c_10bit_address_restart = 0;

    PIR1bits.SSP1IF = 0;

    // Check first if there was a collision.
    // If we have a Write Collision, reset and go to idle state */
    if(I2C_WRITE_COLLISION_STATUS_BIT)
    {
        // clear the Write colision
        I2C_WRITE_COLLISION_STATUS_BIT = 0;
        i2c_state = S_MASTER_IDLE;
        *(p_i2c_current->pTrFlag) = I2C_MESSAGE_FAIL;

        // reset the buffer pointer
        p_i2c_current = NULL;

        return;
    }

    /* Handle the correct i2c state */
    switch(i2c_state)
    {
        case S_MASTER_IDLE:    /* In reset state, waiting for data to send */

            if(i2c_object.trStatus.s.empty != true)
            {
                // grab the item pointed by the head
                p_i2c_current     = i2c_object.pTrHead;
                i2c_trb_count     = i2c_object.pTrHead->count;
                p_i2c_trb_current = i2c_object.pTrHead->ptrb_list;

                i2c_object.pTrHead++;

                // check if the end of the array is reached
                if(i2c_object.pTrHead == (i2c_tr_queue + I2C_CONFIG_TR_QUEUE_LENGTH))
                {
                    // adjust to restart at the beginning of the array
                    i2c_object.pTrHead = i2c_tr_queue;
                }

                // since we moved one item to be processed, we know
                // it is not full, so set the full status to false
                i2c_object.trStatus.s.full = false;

                // check if the queue is empty
                if(i2c_object.pTrHead == i2c_object.pTrTail)
                {
                    // it is empty so set the empty status to true
                    i2c_object.trStatus.s.empty = true;
                }

                // send the start condition
                I2C_START_CONDITION_ENABLE_BIT = 1;
               
                // start the i2c request
                i2c_state = S_MASTER_SEND_ADDR;
            }

            break;

        case S_MASTER_RESTART:

            /* check for pending i2c Request */

            // ... trigger a REPEATED START
            I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

            // start the i2c request
            i2c_state = S_MASTER_SEND_ADDR;

            break;

        case S_MASTER_SEND_ADDR_10BIT_LSB:

            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                i2c_object.i2cErrors++;
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);
            }
            else
            {
                // Remove bit 0 as R/W is never sent here
                I2C_TRANSMIT_REG = (i2c_address >> 1) & 0x00FF;

                // determine the next state, check R/W
                if(i2c_address & 0x01)
                {
                    // if this is a read we must repeat start
                    // the bus to perform a read
                    i2c_state = S_MASTER_10BIT_RESTART;
                }
                else
                {
                    // this is a write continue writing data
                    i2c_state = S_MASTER_SEND_DATA;
                }
            }

            break;

        case S_MASTER_10BIT_RESTART:

            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                i2c_object.i2cErrors++;
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);
            }
            else
            {
                // ACK Status is good
                // restart the bus
                I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                // fudge the address so S_MASTER_SEND_ADDR works correctly
                // we only do this on a 10-bit address resend
                i2c_address = 0x00F0 | ((i2c_address >> 8) & 0x0006);

                // set the R/W flag
                i2c_address |= 0x0001;

                // set the address restart flag so we do not change the address
                i2c_10bit_address_restart = 1;

                // Resend the address as a read
                i2c_state = S_MASTER_SEND_ADDR;
            }

            break;

        case S_MASTER_SEND_ADDR:

            /* Start has been sent, send the address byte */

            /* Note:
                On a 10-bit address resend (done only during a 10-bit
                device read), the original i2c_address was modified in
                S_MASTER_10BIT_RESTART state. So the check if this is
                a 10-bit address will fail and a normal 7-bit address
                is sent with the R/W bit set to read. The flag
                i2c_10bit_address_restart prevents the  address to
                be re-written.
             */
            if(i2c_10bit_address_restart != 1)
            {
                // extract the information for this message
                i2c_address    = p_i2c_trb_current->address;
                pi2c_buf_ptr   = p_i2c_trb_current->pbuffer;
                i2c_bytes_left = p_i2c_trb_current->length;
            }

            // check for 10-bit address
            if(!I2C_7bit && (0x0 != i2c_address))
            { 
                if (0 == i2c_10bit_address_restart)
                {
                    // we have a 10 bit address
                    // send bits<9:8>
                    // mask bit 0 as this is always a write                   
                    I2C_TRANSMIT_REG = 0xF0 | ((i2c_address >> 8) & 0x0006);
                    i2c_state = S_MASTER_SEND_ADDR_10BIT_LSB;
                }
                else
                {
                    // resending address bits<9:8> to trigger read
                    I2C_TRANSMIT_REG = i2c_address;
                    i2c_state = S_MASTER_ACK_ADDR;
                    // reset the flag so the next access is ok
                    i2c_10bit_address_restart = 0;
                }
            }
            else
            {
                // Transmit the address
                I2C_TRANSMIT_REG = i2c_address;
                if(i2c_address & 0x01)
                {
                    // Next state is to wait for address to be acked
                    i2c_state = S_MASTER_ACK_ADDR;
                }
                else
                {
                    // Next state is transmit
                    i2c_state = S_MASTER_SEND_DATA;
                }
            }
            break;

        case S_MASTER_SEND_DATA:

            // Make sure the previous byte was acknowledged
            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {
                // Transmission was not acknowledged
                i2c_object.i2cErrors++;

                // Reset the Ack flag
                I2C_ACKNOWLEDGE_STATUS_BIT = 0;

                // Send a stop flag and go back to idle
                I2C_Stop(I2C_DATA_NO_ACK);

            }
            else
            {
                // Did we send them all ?
                if(i2c_bytes_left-- == 0U)
                {
                    // yup sent them all!

                    // update the trb pointer
                    p_i2c_trb_current++;

                    // are we done with this string of requests?
                    if(--i2c_trb_count == 0)
                    {
                        I2C_Stop(I2C_MESSAGE_COMPLETE);
                    }
                    else
                    {
                        // no!, there are more TRB to be sent.
                        //I2C_START_CONDITION_ENABLE_BIT = 1;

                        // In some cases, the slave may require
                        // a restart instead of a start. So use this one
                        // instead.
                        I2C_REPEAT_START_CONDITION_ENABLE_BIT = 1;

                        // start the i2c request
                        i2c_state = S_MASTER_SEND_ADDR;

                    }
                }
                else
                {
                    // Grab the next data to transmit
                    I2C_TRANSMIT_REG = *pi2c_buf_ptr++;
                }
            }
            break;

        case S_MASTER_ACK_ADDR:

            /* Make sure the previous byte was acknowledged */
            if(I2C_ACKNOWLEDGE_STATUS_BIT)
            {

                // Transmission was not acknowledged
                i2c_object.i2cErrors++;

                // Send a stop flag and go back to idle
                I2C_Stop(I2C_MESSAGE_ADDRESS_NO_ACK);

                // Reset the Ack flag
                I2C_ACKNOWLEDGE_STATUS_BIT = 0;
            }
            else
            {
                I2C_RECEIVE_ENABLE_BIT = 1;
                i2c_state = S_MASTER_ACK_RCV_DATA;
            }
            break;

        case S_MASTER_RCV_DATA:

            /* Acknowledge is completed.  Time for more data */

            // Next thing is to ack the data
            i2c_state = S_MASTER_ACK_RCV_DATA;

            // Set up to receive a byte of data
            I2C_RECEIVE_ENABLE_BIT = 1;

            break;

        case S_MASTER_ACK_RCV_DATA:

            // Grab the byte of data received and acknowledge it
            *pi2c_buf_ptr++ = I2C_RECEIVE_REG;

            // Check if we received them all?
            if(--i2c_bytes_left)
            {

                /* No, there's more to receive */

                // No, bit 7 is clear.  Data is ok
                // Set the flag to acknowledge the data
                I2C_ACKNOWLEDGE_DATA_BIT = 0;

                // Wait for the acknowledge to complete, then get more
                i2c_state = S_MASTER_RCV_DATA;
            }
            else
            {

                // Yes, it's the last byte.  Don't ack it
                // Flag that we will nak the data
                I2C_ACKNOWLEDGE_DATA_BIT = 1;

                I2C_FunctionComplete();
            }

            // Initiate the acknowledge
            I2C_ACKNOWLEDGE_ENABLE_BIT = 1;
            break;

        case S_MASTER_RCV_STOP:               
        case S_MASTER_SEND_STOP:

            // Send the stop flag
            I2C_Stop(I2C_MESSAGE_COMPLETE);
            break;

        default:

            // This case should not happen, if it does then
            // terminate the transfer
            i2c_object.i2cErrors++;
            I2C_Stop(I2C_LOST_STATE);
            break;

    }
}

void I2C_FunctionComplete(void)
{

    // update the trb pointer
    p_i2c_trb_current++;

    // are we done with this string of requests?
    if(--i2c_trb_count == 0)
    {
        i2c_state = S_MASTER_SEND_STOP;
    }
    else
    {
        i2c_state = S_MASTER_RESTART;
    }

}

void I2C_Stop(I2C_MESSAGE_STATUS completion_code)
{
    // then send a stop
    I2C_STOP_CONDITION_ENABLE_BIT = 1;

    // make sure the flag pointer is not NULL
    if (p_i2c_current->pTrFlag != NULL)
    {
        // update the flag with the completion code
        *(p_i2c_current->pTrFlag) = completion_code;
    }

    // Done, back to idle
    i2c_state = S_MASTER_IDLE;
   
}

void I2C_MasterWrite(
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address,
                                I2C_MESSAGE_STATUS *pflag)
{
    static I2C_TRANSACTION_REQUEST_BLOCK   trBlock;

    // check if there is space in the queue
    if (i2c_object.trStatus.s.full != true)
    {
        I2C_MasterWriteTRBBuild(&trBlock, pdata, length, address);
        I2C_MasterTRBInsert(1, &trBlock, pflag);
    }
    else
    {
        *pflag = I2C_MESSAGE_FAIL;
    }

}

void I2C_MasterRead(
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address,
                                I2C_MESSAGE_STATUS *pflag)
{
    static I2C_TRANSACTION_REQUEST_BLOCK   trBlock;


    // check if there is space in the queue
    if (i2c_object.trStatus.s.full != true)
    {
        I2C_MasterReadTRBBuild(&trBlock, pdata, length, address);
        I2C_MasterTRBInsert(1, &trBlock, pflag);
    }
    else
    {
        *pflag = I2C_MESSAGE_FAIL;
    }

}

void I2C_MasterTRBInsert(
                                uint8_t count,
                                I2C_TRANSACTION_REQUEST_BLOCK *ptrb_list,
                                I2C_MESSAGE_STATUS *pflag)
{

    // check if there is space in the queue
    if (i2c_object.trStatus.s.full != true)
    {
        *pflag = I2C_MESSAGE_PENDING;

        i2c_object.pTrTail->ptrb_list = ptrb_list;
        i2c_object.pTrTail->count     = count;
        i2c_object.pTrTail->pTrFlag   = pflag;
        i2c_object.pTrTail++;

        // check if the end of the array is reached
        if (i2c_object.pTrTail == (i2c_tr_queue + I2C_CONFIG_TR_QUEUE_LENGTH))
        {
            // adjust to restart at the beginning of the array
            i2c_object.pTrTail = i2c_tr_queue;
        }

        // since we added one item to be processed, we know
        // it is not empty, so set the empty status to false
        i2c_object.trStatus.s.empty = false;

        // check if full
        if (i2c_object.pTrHead == i2c_object.pTrTail)
        {
            // it is full, set the full status to true
            i2c_object.trStatus.s.full = true;
        }

    }
    else
    {
        *pflag = I2C_MESSAGE_FAIL;
    }

    // for interrupt based
    if (*pflag == I2C_MESSAGE_PENDING)
    {
        while(i2c_state != S_MASTER_IDLE);
        {
            // force the task to run since we know that the queue has
            // something that needs to be sent
            PIR1bits.SSP1IF = true;
        }
    }   // block until request is complete

}

void I2C_MasterReadTRBBuild(
                                I2C_TRANSACTION_REQUEST_BLOCK *ptrb,
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address)
{
    ptrb->address  = address << 1;
    // make this a read
    ptrb->address |= 0x01;
    ptrb->length   = length;
    ptrb->pbuffer  = pdata;
}

void I2C_MasterWriteTRBBuild(
                                I2C_TRANSACTION_REQUEST_BLOCK *ptrb,
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address)
{
    ptrb->address = address << 1;
    ptrb->length  = length;
    ptrb->pbuffer = pdata;
}

bool I2C_MasterQueueIsEmpty(void)
{
    return(i2c_object.trStatus.s.empty);
}

bool I2C_MasterQueueIsFull(void)
{
    return(i2c_object.trStatus.s.full);
}       
       
void I2C_BusCollisionISR( void )
{
    // enter bus collision handling code here
}       



моят код в master е:

Код:
#include "mcc_generated_files/mcc.h"

/*
                         Main application
*/
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();

   
    unsigned int D;

    while (1)
    {
        if(D=11)
            LATA4=1;
        else
            LATA4=0;
       
       
        // Add your application code
    }
}



Въпросът ми е, какъв код трябва да добавя в while(1) за да мога да прочета стойността на D от slave устройството?


Сря Авг 09, 2017 2:40 pm
Профил
Ранг: Професионалист
Ранг: Професионалист
Аватар

Регистриран на: Съб Май 21, 2016 9:47 pm
Мнения: 577
Местоположение: Бургас
Мнение Re: I2C малко помощ
На пръв прочит- D ти е дефинирана локално и по никакъв начин не е свързана с буфера или данните, които се обменят.
Трябва да имаш нещо от рода:
D = EEPROM_buffer[index] или EEPROM_buffer[index] = D;

ПП: Последния if (D=11) логически е вярно, практически- не. Трябва да е if (D==11).


Сря Авг 09, 2017 3:35 pm
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 281 мнения ]  Отиди на страница Предишна  1 ... 3, 4, 5, 6, 7, 8, 9 ... 19  Следваща

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 10 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни