reklam1

reklam1

6 Ekim 2011 Perşembe

I2C ile haberleşen sensör modülü

Birden fazla Sensörle çalışırken, herbir sensör için port kullanmak çok büyük bir savurganlık.
Bunun yerine sensörler için küçük bir modül yapıp hepsini aynı porttan kullanmak mümkün. Aşağıda 16F88 ile CCS de yazdığım, kendi adresine sahip, Master ile I2C üzerinden haberleşen bir modül örneği var. CCS'de Hardware I2C bazen problem yaratabiliyor. Ancak kodda gerekli düzeltmeler yapılmış ve sorunsuz olarak çalışıyor.
Kodu, haberleşme bölümlerine dokunmadan, kendinize göre düzenleyip kullanabilirsiniz.
Sistemi bu şekilde tasarlamanın başka bir avantajı, DAQ modülünüzü değiştirmeden sensörü değiştirip kullanabiliyoruz. Çünkü sensör kodları modül tarafında bulunuyor. DAQ tarafı her sensör için aynı kalıyor.
Kodda, float değişkenin I2C ile nasıl yollandığı da bulunuyor.
Herbir sensör kendi slave adresini eepromun 1 nolu adresine daha önceden yazılmış değerden öğreniyor.
Çok hassas ölçmeler için koda CRC hata denetimi de ekledim. Her ölçme işleminin sonucunu gönderirken birlikte CRC kodu da gönderilir. Böylece Master CRC hata denetimi yapabilir.

slave.c
#include <16F88.h>
#device adc=10
#define VDD 5.00

#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOPUT //No Power Up Timer
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled

#use delay(clock=8000000)

#use standard_io(A)

#define _SCL PIN_B4
#define _SDA PIN_B1
#use i2c(SLAVE, FAST, SDA=_SDA, SCL=_SCL, FORCE_HW)

byte _SA;
byte _REV;

#byte SSPSTAT = 0x94
#byte SSPBUF = 0x13

#bit SMP = SSPSTAT.7
#bit CKE = SSPSTAT.6
#bit DA_BIT = SSPSTAT.5
#bit P_BIT = SSPSTAT.4
#bit S_BIT = SSPSTAT.3
#bit RW_BIT = SSPSTAT.2
#bit UA_BIT = SSPSTAT.1
#bit BF = SSPSTAT.0

#byte SSPCON = 0x14
#bit WCOL = SSPCON.7
#BIT SSPOV = SSPCON.6 //Indicates overflow
#bit SSPEN = SSPCON.5
#bit CKP = SSPCON.4
#bit SSPM3 = SSPCON.3
#bit SSPM2 = SSPCON.2
#bit SSPM1 = SSPCON.1
#bit SSPM0 = SSPCON.0

int8 sBUFFER[50];
int8 rBUFFER[50];
byte dREGISTER;
int8 dINDEX = 0;

BYTE _ACTIVED = FALSE;

void WRITE_FLOAT(int n, float data) {
int i;
int8 crc = (int8) 0xff;
BYTE b;
for (i = 0; i < 4; ++i) {
sBUFFER[i+5*n]= *((int8*)&data + i);
crc ^= sBUFFER[i+5*n];
for (b=0; b<8; ++b) {
if (crc & 0x80) crc = (crc << 1) ^ 0x31;
else crc = (crc << 1);
}
}
sBUFFER[5*n+4]=crc;
}

int8 crcbyte(int8 val) {
byte b;
for (b=0; b<8; ++b) {
if (val & 0x80) val = (val << 1) ^ 0x31;
else val = (val << 1);
}
return(val);
}

#define MSGACK 0xA5
#define MSGNACK 0xFF

#INT_SSP
void ssp_interupt () {
byte incoming, tmp;
if(SSPOV) // Make sure the buffer has not overflowed
{
incoming= SSPBUF;
BF=0;
SSPOV=0; // Clear the register
return;
}
if(P_BIT) {
incoming= SSPBUF;
BF=0;
SSPOV=0;
_ACTIVED=FALSE;
SSPSTAT=0;
dINDEX=0;
return;
}
tmp = (SSPSTAT & 0b00101101); // Read the status register and mask with D_A , S , R_W , BF
switch(tmp) {
CASE 0x09 /*0b00001001*/: // D_A=0, S=1, R_W=0, BF=1
incoming= SSPBUF; // Master tx, slave addr
if (incoming == _SA) _ACTIVED=TRUE; // Address bit with write operation
break;
CASE 0x29 /*0b00101001*/: // SSPSTAT bits: D_A=1, S=1, R_W=0, BF=1
if (_ACTIVED) { // Master tx, data
incoming = SSPBUF;
if (dINDEX==0) {
dREGISTER = incoming;
dINDEX++;
}
else {
rBUFFER[dREGISTER+dINDEX] = incoming;
dINDEX++;
}
}
break;
CASE 0x0C/*0b00001100*/: // SSPSTAT bits: D_A=0, S=1, R_W=1, BF=0
if (_ACTIVED) { // Master rx, slave addr+1
CKP=0;
dINDEX=0;
SSPBUF = sBUFFER[dREGISTER+dINDEX];
dINDEX++;
CKP=1;
}
break;
CASE 0x2C/*0b00101100*/: // SSPSTAT bits: D_A=1, S=1, R_W=1, BF=0:
if (_ACTIVED) { // Master rx, data with ack
CKP=0;
SSPBUF = sBUFFER[dREGISTER+dINDEX];
dINDEX++;
CKP=1;
}
break;
CASE 0x28/*0b00101000*/: // NACK --> SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 0
break; // Master rx, data with nack (high)
CASE 0x30: // SSPSTAT bits: D_A=1
break;
default:
if (BF) {
incoming= SSPBUF;
BF = 0;
break;
}
}
}

void main() {
float value;
long int ADCValue;
int i;

setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(sAN0|sAN1|VSS_VDD);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
// setup_oscillator(OSC_8MHZ|OSC_INTRC);//sets internal osc multiplier

// write_eeprom(0,100); //REVISION
// write_eeprom(1,0xA4); //SLAVE ADDRESS
_REV = read_eeprom(0);
_SA= read_eeprom(1);
i2c_slaveaddr(_SA);

bit_set(SSPCON,3); //START STOP Bit Interrupts Enabled

disable_interrupts(GLOBAL); // Turn all off
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL); // Now enable it

set_adc_channel( 0 );
delay_us( 50 );
i=0;
while(TRUE) {
ADCvalue = read_adc();
delay_us( 250 );
value= ADCvalue * 0.00488758553274682307;
WRITE_FLOAT(0,value);
sBUFFER[5]=i;
sBUFFER[6]=crcbyte(i);
i++;
if (i>127) i=0;
delay_ms(10);
}
}

Hiç yorum yok :

Yorum Gönder

reklam4

reklam4