Software I2c - Pic x Pic.
 Mosaico
 Mosaico
 PIC
 Software I2c - Pic x Pic.
  Registrar   Ajuda   Login

Tópico AnteriorTópico Anterior - Próximo TópicoPróximo Tópico
Tópico com 5137 visitas e 8 mensagens
Autor
Tópico: Software I2c - Pic x Pic.
carlos
Usuário Nivel 4

Postagens: 28
Registro: 06/05/2005
Local: curitiba - PR - Brasil
Idade: 46 anosSexo Masculino
 Postado em 05/08/2006 6:56:00 PM

Bem pessoal, estou postando um software para comunicacao I2c com pic.
Mestre e escravo.

Rotina do Pic 16F877. - Mestre.

#include <16f877.h>
#device adc=10 // CONFIG. ADC.
#use delay(clock=4000000)
#fuses HS,WDT,PUT,NOBROWNOUT,NOLVP
#use rs232(baud=1200, xmit=PIN_C6,rcv=PIN_C7) // configuracao rs232
#use i2c(master,sda = pin_c4,scl = pin_c3,SLOW,restart_wdt)

#define scl pin_c3 // pino de clock
#define sda pin_c4 // pino de dados
#define seta_scl output_float(scl) // seta o pino scl
#define apaga_scl output_low(scl) // apaga o pino scl
#define seta_sda output_float(sda) // seta o pino sda
#define apaga_sda output_low(sda) // apaga o pino sda

// algumas declaracoes fazer parte do software que fiz, he so retirar o que nao e necessario.

unsigned char dispositivo;
unsigned char endereco;
unsigned char dado;
int8 dado1;
int8 dado2;
int16 entrada;
int16 entrada1;
int conta;
boolean flag_erro_remota;

//Inicio das rotinas de comunicacao de leitura e escrita no servo.

void i2c_nack()
// coloca sinal de não reconhecimento (nack) no barramento
{
seta_sda; // coloca a linha de dados em alta impedância (1)
seta_scl; // coloca a linha de clock em alta impedância (1)
apaga_scl; // coloca a linha de clock em nível 0
}

void i2c_ack()
// coloca sinal de reconhecimento (ack) no barramento
{
apaga_sda; // coloca a linha de dados em nível 0
seta_scl; // coloca a linha de clock em alta impedância (1)
apaga_scl; // coloca a linha de clock em nível 0
seta_sda; // coloca a linha de dados em alta impedância (1)
}

boolean i2c_le_ack()
// efetua a leitura do sinal de ack/nack
{
boolean estado;
seta_sda; // coloca a linha de dados em alta impedância (1)
seta_scl; // coloca a linha de clock em alta impedância (1)
estado = input(sda); // lê o bit (ack/nack)
apaga_scl; // coloca a linha de clock em nível 0
return estado;
}

void I2C_escreve_byte(unsigned char dado)
// ESCREVE UM BYTE NA SAIDA I2C.
{
int conta = 8;
// envia um byte pelo barramento I2C
apaga_scl; // coloca SCL em 0
while (conta)
{
// envia primeiro o MSB
if (shift_left(&dado,1,0)) seta_sda; else apaga_sda;
// dá um pulso em scl
seta_scl;
conta--;
apaga_scl;
}
// ativa sda
seta_sda;
}
unsigned char I2C_le_byte(int conta)
// recebe um byte pelo barramento I2C
{
long int bytelido;
bytelido = 0;
apaga_scl;
seta_sda;
while (conta)
{
// ativa scl
seta_scl;
// lê o bit em sda, deslocando em bytelido
shift_left(&bytelido,1,input(sda));
conta--;
// desativa scl
apaga_scl;
}
return bytelido;
}
int le_remoto()
// FAZ A LEITURA DA ESTACAO REMOTA
{
byte dado;
if (dispositivo>7) dispositivo = 7;
i2c_start();
i2c_escreve_byte(0xa0 | (dispositivo << 1)); // endereça o dispositivo
i2c_le_ack();
i2c_escreve_byte((endereco >> 8)); // envia a parte alta do endereço
i2c_le_ack();
i2c_escreve_byte(endereco); // envia a parte baixa do endereço
i2c_le_ack();
i2c_start(); // envia comando de leitura
i2c_escreve_byte(0x0A);
i2c_le_ack();
dado1 = i2c_le_byte(8); // LE DADO DO REMOTO
i2c_nack();
dado2 = i2c_le_byte(8); // LE DADO DO REMOTO
i2c_nack();
flag_erro_remota = i2c_le_byte(8); // LE DADO DO REMOTO
i2c_nack();

i2c_stop();

return (dado1,dado2); // RETORNA OS DADOS PARA SER UTILIZADO NO SOFTWARE.
}

void envia_remoto()
// ENVIA DADOS PARA O REMOTO.
{

if (dispositivo>7) dispositivo = 7;
i2c_start();
i2c_escreve_byte(0xa0 | (dispositivo << 1)); // endereça o dispositivo
i2c_le_ack();
i2c_escreve_byte(endereco >> 8); // parte alta do endereço
i2c_le_ack();
i2c_escreve_byte(endereco); // parte baixa do endereço
// NESTE PONTO PODE COLOCAR + INFORMACOES OU RETIRAR.
// TEM QUE ALTERAR NO ESCRAVO PARA RECEBER + OU - VARIAVEIS.
i2c_le_ack();
i2c_escreve_byte(dado);// ENVIA DADO OU COMANDO PARA ESCRAVO
i2c_le_ack();
i2c_stop();
delay_ms(10); // aguarda a programação da memória

}
// esta declaracao vai na funcao main(), aonde pode-se aumentar o //valor do wdt, se for muitas palavras a enviar.
// eu utilizei um valor de 2304 ms inicial no mestre, aos poucos
// fui melhorando as logicas e cheguei em 72 ms.
***************************************************
//################################################################
//##### nao esquecer dos resistores de pull-up nas linhas ########
//##### quanto menor seu valor + rapido a transmissao ########
//################################################################

setup_counters(RTCC_INTERNAL,WDT_72MS); // INICIALIZA WTD


As rotinas abaixo vao fazer parte do seftware que voces vao desenvolver.

// eu coloquei um botao, ao pressionar escreve no escravo.
// o dispositivo soma-se ao 0xA (que endereca o escravo).
// Voces tem que colocar primeiramente o endereco, funcao e depois os
// dados, pode transmitir quantos bytes houver necessidade.
// basta implementar, o software original envia 8 palavras de 8 bytes
// ao escravo.

if (!input(pin_a1)) // escrita nos escravos
{
while (!input(pin_a1));
dispositivo = 0x01;
endereco = 0x00;
DADO = 0;
DADO = 0x01;
envia_remoto();
}

// leitura do pic escravo.
// ao pressionar um botao no mestre, o mesmo vai ler no escravo.

if (!input(pin_a2)) // leitura nos escravos
{
while (!input(pin_a2));

dispositivo = 0x01;
endereco = 0x0A;
le_remoto();
entrada = make16( dado1, dado2);
}

// O dispositivo e o endereco do escravo.
// Endereco foi uma funcao, se mando 0x0A ao escravo endente como
// comando de leitura, pode-se criar varios codigos de leitura.

###################################################################### SOFTWARE DO ESCRAVO - PIC 16F876.
#####################################################################

// SOFTWARE UNIDADE ESCRAVA I2C.
#include <16F876.h>// PROCESSADOR UTILIZADO
#device adc=10 // CONFIG. ADC.
#use delay(clock=4000000) // CONFIGURACAO DO CLOCK INTERNO.
#fuses WDT,XT, NOPUT, NOPROTECT, BROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG // FUSIVEIS
// A DECLARACAO ABAIXO - ENDERECO REMOTO SEMPRE COMECAR COM 0XAX.
#use i2c(slave,sda = pin_c4,scl = pin_c3,address = 0xA2,SLOW,restart_wdt,force_hw)

// NOTEM QUE O ENDERECO DE ESCRAVOS SEMPRE INICIA COM 0XA!.
// A ! HE O NUMERO DA ESTACAO.

// CONFIGURACOES DA I2C - PINAGENS.

#define scl pin_c3 // pino de clock
#define sda pin_c4 // pino de dados
#define seta_scl output_float(scl) // seta o pino scl
#define apaga_scl output_low(scl) // apaga o pino scl
#define seta_sda output_float(sda) // seta o pino sda
#define apaga_sda output_low(sda) // apaga o pino sda

// DECLARACAO DAS VARIAVEIS UTILIZACAS NO SOFTWARE.
// ESTAS VARIAVEIS DEVEM SER AUMENTADAS DE ACORDO COM AS VARIAVEIS
// QUE O MESTRE TRANSMITE.
// ESTAS VARIAVEIS PODEM SER FEITAS DE OUTRAS MANEIRAS, MAS ERA A
// MINHA NECESSIDADE, E AGORA FICA FACIL PARA VOCES ALTERAREM.

unsigned char bytelido;
unsigned char string_A;
unsigned char string_B;
unsigned char string_C;
unsigned char string_D;

// ROTINAS I2C DE LEITURA DOS COMANDOS E ENVIO DE VARIAVEIS PARA O
// MESTRE.
// ESTE SOFTWARE ESTA UTILIZANDO INTERRUPCAO PARA DETECTAR O RECEBI-
// MENTO DE INFORMACOES DO MESTRE.


void i2c_nack()
// coloca sinal de não reconhecimento (nack) no barramento
{
seta_sda; // coloca a linha de dados em alta impedância (1)
seta_scl; // coloca a linha de clock em alta impedância (1)
apaga_scl; // coloca a linha de clock em nível 0
}

void i2c_ack()
// coloca sinal de reconhecimento (ack) no barramento
{
apaga_sda; // coloca a linha de dados em nível 0
seta_scl; // coloca a linha de clock em alta impedância (1)
apaga_scl; // coloca a linha de clock em nível 0
seta_sda; // coloca a linha de dados em alta impedância (1)
}

void I2C_escreve_byte(int16 dado)
{
// envia um byte pelo barramento I2C
int conta=8;
apaga_scl; // coloca SCL em 0
while (conta)
{
// envia primeiro o MSB
if (shift_left(&dado,1,0)) seta_sda; else apaga_sda;
// dá um pulso em scl
seta_scl;
conta--;
apaga_scl;
}
// ativa sda
seta_sda;
}

unsigned char I2C_le_byte()
// recebe um byte pelo barramento I2C
{
bytelido = 0;
apaga_scl;
seta_sda;
while (conta)
{
// ativa scl
seta_scl;
// lê o bit em sda, deslocando em bytelido
shift_left(&bytelido,1,input(sda));
// desativa scl
conta--;
apaga_scl;
}

return bytelido;
}

#int_SSP // Interrupcao de entrada de dados I2C.

SSP_isr()
{

disable_interrupts(INT_SSP); // Desabilita a interrupcao I2C
disable_interrupts(GLOBAL); // Desabilita a interrupcao Global.

apaga_scl;
seta_sda;

string_A=0;
string_B=0;
string_C=0;

conta = 8; // RECEBE A STRING DO ENDERECO.
string_A = I2C_le_byte();
i2c_ack();

conta = 7; // RECEBE A STRING COMANDO BITS + SIGNIFICATIVOS
string_B = I2C_le_byte();
i2c_ack();

conta = 8; // RECEBE A STRING COMANDO BITS - SIGNIFICATIVOS
string_C = I2C_le_byte();
i2c_ack();

// SE COMANDO == 5 - ENVIA DADOS SOLICITADOS.

if (string_c == 0x05) // Se for comando leitura envia os dados.
{

i2c_escreve_byte((dado >> 8)); // envia a parte alta do endereço
i2c_ack();
i2c_escreve_byte(dado); // envia a parte baixa do endereço
i2c_ack();
i2c_escreve_byte(FLAG_ERRO); // envia a parte baixa do endereço
i2c_ack();

string_c=0x00;
}

// ESTAS STRINGS RECEBIDAS SAO PARA UTILIZACAO GERAL NO SOFTWARE.

conta = 8; // RECEBE A STRING ENVIADA PELO MESTRE.
string_D = I2C_le_byte();
i2c_ack();

// RETORNA AS STRINGS RECEBIDAS NA I2C PARA UTILIZACAO NO SOFTWARE.

return (string_A,string_B,string_C);
}

// INICIO DAS CONFIGURACOES GERAIS DO PROCESSADOR E SEU //FUNCIONAMENTO.

// ESTA DECLARACAO VAI NA FUNCAO MAIN().
// CONFIGURACAO DO WDT.

setup_counters(RTCC_INTERNAL,WDT_72MS);// CONFIGURA WDT.

// ESTAS FUNCOES VAO NO LOOP WHILE(TRUE).
// SEMPRE AO INICIAR UMA LEITURA NA INTERRUPCAO O PIC DESABILITA
// AS MESMAS.

enable_interrupts(INT_SSP); // Habilita a interrupcao I2C.
enable_interrupts(GLOBAL); // Habilita a interrupcao Global

// RESULTADOS.
// OS DADOS QUE O PIC MESTRE ENVIAR PARA O ESCRAVO ESTAO DISPONIVEIS
// NESTAS MEMORIAS ABAIXO, QUE ESTA NO FIM DA INTERRUPCAO.

return (string_A,string_B,string_C);

// PARA ENVIAR UMA VARIAVEL AO MESTRE, SEMPRE QUE FOR COMANDO ATUALIZE A VARIAVEL DADO DENTRO DO SOFTWARE, POIS O MESTRE VAI LER ESTA VARIAVEL.

BEM PESSOAL, ESPERO TER AUXILIADO A TODOS, E DUVIDAS, FAVOR ENVIAR UM EMAIL.....OU POSTAREM AQUI.

BOA SORTE A TODOS.
ABRACOS
CARLOS


IP LogadoPróxima Mensagem
vmax
Usuário Nivel 5

Postagens: 461
Registro: 20/08/2003
Local: São Paulo - SP - Brasil
Idade: 47 anosSexo Masculino
 Postado em 07/08/2006 9:25:00 AM

Carlos,

Muito obrigado pelo código. Apesar de ainda não o ter testado, com certeza vai ajudar muitos colegas do fórum.

Parabéns!

[ ]s

VMAX

IP LogadoMensagem AnteriorPróxima Mensagem
Vitor
Usuário Nivel 1

Postagens: 3
Registro: 08/03/2007
Local: São Paulo - SP - Brasil
Idade: 30 anosSexo Masculino
 Postado em 08/03/2007 11:01:00 AM

Carlos,

Muito obrigado, o seu código será de extrema serventia no projeto que estou desenvolvendo.

Se houver algum problema (ou melhoria) postarei novamente no forum para o pessoal aproveitar.

Abraços.

IP LogadoMensagem AnteriorPróxima Mensagem
LUMENS-TEL
Usuário Nivel 5

Postagens: 293
Registro: 07/04/2003
Local: Charqueada - SP - Brasil
Idade: 49 anosSexo Masculino
 Postado em 23/03/2007 8:28:00 AM

Olá Carlos, estou tentando implementar, seu exemplo, porem estou com dificuldades,em exibir os valores das strings no display.
vc poderia enviar um exemplo, com saida p/ o display?

IP LogadoMensagem AnteriorPróxima Mensagem
LUMENS-TEL
Usuário Nivel 5

Postagens: 293
Registro: 07/04/2003
Local: Charqueada - SP - Brasil
Idade: 49 anosSexo Masculino
 Postado em 23/03/2007 1:14:00 PM

Olá Carlos.
Tenho mais algumans duvidas..

#fuses WDT,XT, NOPUT, NOPROTECT, BROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG

quando mando gravar aparece um erro de conflito entre o BODEN e o WRT

como faço p/ determiran o endereço do escravo??, pela dica sua entendi que pode ter até 7 escravos?? ai no caso do exemplo vc determinou address = 0xA2 , quer dizer escravo 2 ??

quanto aos resistores pull-up estou usando 4K7, acredito não ser um valor muito elevado ou é??
grato!!!!

IP LogadoMensagem AnteriorPróxima Mensagem
kaedros
Usuário Nivel 1

Postagens: 1
Registro: 13/08/2008
Local: Porto Alegre - RS - Brasil
Idade: 34 anosSexo Masculino
 Postado em 13/08/2008 9:56:00 AM

Como eu faço para ligar fisicamente eles... pois liguei os I2C, SCK e SDI mas acho q esta colocando em curto pois esta aquecendo d+ um dos PICs.
Eles nascem tudo em tristate?

IP LogadoMensagem AnteriorPróxima Mensagem
ALDO BERNARDO
Usuário Nivel 4

Postagens: 29
Registro: 07/08/2008
Local: SÃO BERNARDO - SP - Brasil
Idade: 31 anosSexo Masculino
 Postado em 13/08/2008 1:33:00 PM

bom dia carlos, parabens pela atitude!!!!!!!

vc poderia postar algum esquema de ligação entre os 2 pic, ou ate no proteus ?

IP LogadoMensagem AnteriorPróxima Mensagem
Eliezer
Usuário Nivel 1

Postagens: 1
Registro: 19/08/2011
Local: - PR - Brasil
Idade: 30 anosSexo Masculino
 Postado em 19/08/2011 5:54:00 PM

Ola Carlos, estou tentando usar esta rotina para o freecale e esta rotina abaixo esta dando erro, voce pode me ajudar a entender como funciona?
Grato

boolean i2c_le_ack()
// efetua a leitura do sinal de ack/nack
{
boolean estado;
seta_sda; // coloca a linha de dados em alta impedância (1)
seta_scl; // coloca a linha de clock em alta impedância (1)
estado = input(sda); // lê o bit (ack/nack)
apaga_scl; // coloca a linha de clock em nível 0
return estado;
}

IP LogadoMensagem Anterior
 Todos os horários são de Brasília (GMT -03:00)
 Nova Mensagem desde a sua Última Visita.
[***] Palavra proibida pelo moderador do Grupo de Discussão

Tópico AnteriorTópico Anterior - Próximo TópicoPróximo Tópico

Volta para o Topo da Página



Forum Now! - Criar seu forum grátis