Archive

Archive for the ‘Data Acquisition System’ Category

(13) Interfacing ENC28J60 Ethernet controller to PIC16F877A and developing UDP/IP services through program & GUI that communicate with hardware through UDP/IP/Ethernet.

Now we are in last phase of our Project Data Acquisition system.

We are going to use ENC28J60 ethernet controller from microchip which has SPI interface to the host controller(here PIC16F877A). It is 28 PIN and its a smallest ethernet controller. Once you go through the datasheet of ENC28J60

I used PICtail Ethernet Board which is a board having all necessary connections required for ENC28J60. We just need to provide SPI and Interrupt connection to our PIC.

I will post entire code for PIC16F877A communicating through UDP/IP/Ethernet with VB application. But if you are new to this stuff then i am providing a way i approached.

First of all you must have basic idea about UDP (User Datagram Protocol), IP (Internet Protocol), Ethernet Protocol. ENC28J60 does not provide UDP/IP services so we need to create those facilities via programming PIC16F877A.

Once you had idea about the UDP/IP/Ethernet frame structure. You should try making Peer to Peer communication using UDP socket programming in VB (see at bottom of this page – UDP Basics).

Now you are ready with the applications Peer A and Peer B. Now you should use wireshark to analyze the frame structure. You will now get idea how data to be transmitted is sent. At the time of first data transfer you will find a ARP request(like who is at 10.156.1.100? tell ….) and ARP reply(like 10.56.1.100 is at ….) frame. This protocol is also needed to be understood.

Protocol understanding was somewhat time taking work to me because its not been my field till now. But its interesting.

Once you get an idea byte by byte format of UDP/IP/Ethernet and ARP, how all messages are transferred from peer A to peer B. Try to figure out those bytes whose values are remaining constant. Those bytes will be taken as constants in our program only the varying bytes are needed to be taken care.

In program you will find array of ARP request, ARP reply, UDP packet. These array contains the fixed bytes and that will help us creating udp/ip/ethernet packet and arp/ethernet packet.

Settings on PC side : IP address : 10.156.1.100. thats it you dont need to do any more settings.

For your information I am using 10.156.1.200 IP address for PIC16F877A.

UDP ports : 1100 at PIC16F877A side, and 1200 at computer side.

******************************************************************************************

Program

******************************************************************************************

#include<htc.h>
#define _XTAL_FREQ 11059200
__CONFIG(0X3F3A);

#define reset_enc                RC1
#define cs_spi                    RC2
#define bit_field_clear         0xA0
#define bit_field_set             0x80
#define write_control_register    0x40
#define write_buffer_memory        0x7A
#define read_buffer_memory        0x3A

// common
#define EIE            0x1B
#define EIR            0x1C
#define ESTAT         0x1D
#define ECON2         0x1E
#define ECON1         0x1F

// bank 0
#define ERDPTL        0x00
#define ERDPTH        0x01
#define EWRPTL        0x02
#define EWRPTH        0x03
#define ETXSTL        0x04
#define ETXSTH        0x05
#define ETXNDL        0x06
#define ETXNDH        0x07
#define ERXSTL         0x08
#define ERXSTH         0x09
#define ERXNDL         0x0A
#define ERXNDH         0x0B
#define ERXRDPTL     0x0C
#define ERXRDPTH     0x0D
#define ERXWRPTL     0x0E    //read only
#define ERXWRPTH     0x0F    //read only

// bank 1
#define ERXFCON        0x18
#define EPKTCNT        0x19

// bank 2
#define MACON1        0x00
#define MACON2        0x01
#define MACON3        0x02
#define MACON4        0x03
#define MABBIPG        0x04
#define MAIPGL        0x06
#define MAIPGH        0x07
#define MACLCON1    0x08
#define MACLCON2    0x09
#define MAMXFLL        0x0A
#define MAMXFLH        0x0B
#define MAPHSUP        0x0D
#define MICMD        0x12
#define MIREGADR    0x14
#define MIWRL        0x16
#define MIWRH        0x17
#define MIRDL        0x18
#define MIRDH        0x19

// bank 3
#define MAADR1        0x00
#define MAADR0        0x01
#define MAADR3        0x02
#define MAADR2        0x03
#define MAADR5        0x04
#define MAADR4        0x05
#define MISTAT        0x0A
#define ECOCON        0x15
#define EFLOCON        0x17

// PHY registers
#define PHCON1        0x00
#define PHSTAT1        0x01
#define PHCON2        0x10
#define PHSTAT2        0x11
#define PHLCON        0x14

void uart_init(void);
void TX(unsigned char TX_BYTE);
void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

void enc_bank_sel(unsigned char BANK_SEL);
unsigned char read_enc(unsigned char REG_ADR);
void write_enc(unsigned char REG_ADR, unsigned char REG_DATA);
void read_phy(unsigned char PHY_ADR);
void write_phy(unsigned char PHY_ADR);
void read_packet(void);
void write_packet(void);

#define read_packet_len 70
unsigned char spi_data;
unsigned char phy_byte_high,phy_byte_low;
unsigned char transmit_packet[45] = {0};
unsigned char received_packet[read_packet_len] = {0};

unsigned const char arp_reply[43] = {    0x0E,
0xE0,0xCB,0x4E,0x35,0xCB,0x6F,    // dmac
0x00,0x04,0xA3,0x00,0x26,0xBC,    // smac
0x08,0x06,
0x00,0x01,                        // hardware type ethernet
0x08,0x00,                        // protocol type IP
0x06,0x04,                        // hardware size and protocol size
0x00,0x02,                        // opcode for reply
0x00,0x04,0xA3,0x00,0x26,0xBC,    // sender mac address
0x0A,0x9C,0x01,0xC8,            // sender ip
0xE0,0xCB,0x4E,0x35,0xCB,0x6F,    // target mac address
0x0A,0x9C,0x01,0x64    };            // target ip address

unsigned const char arp_request[43] = {    0x0E,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x00,0x04,0xA3,0x00,0x26,0xBC,
0x08,0x06,
0x00,0x01,                        // hardware type ethernet
0x08,0x00,                        // protocol type IP
0x06,0x04,                        // hardware size and protocol size
0x00,0x01,                        // opcode for request
0x00,0x04,0xA3,0x00,0x26,0xBC,    // sender mac address
0x0A,0x9C,0x01,0xC8,            // sender ip
0x00,0x00,0x00,0x00,0x00,0x00,    // target mac address
0x0A,0x9C,0x01,0x64    };            // target ip  address

unsigned const char udp_packet[43] = {    0x0E,        // per packet control byte
0xE0,0xCB,0x4E,0x35,0xCB,0x6F,    // dmac
0x00,0x04,0xA3,0x00,0x26,0xBC,    // smac
0x08,0x00,                        // type field =  ip protocol

0x45,0x00,                        // version =4 , header len=20, service field
0x00,0x1E,                        // total length = 30 excluding smac, dmac, type
0x10,0xDA,                        // identification number
0x00,0x00,                        // flags and fragmentation offset
0x80,                            // ttl = 128
0x11,                            // udp protocol
0x00,0x00,                        // header checksum
0x0A,0x9C,0x01,0xC8,            // sip
0x0A,0x9C,0x01,0x64,            // dip

0x04,0xB0,                        // sport
0x04,0x4C,                        // dport
0X00,0X0A,                        // length
0x00,0x1B    };                    // udp checksum

unsigned char i,packeti=0;
unsigned int received_packet_adr=0;

void SPI_init(void);
unsigned char TXSPI(unsigned char TX_BYTE);

#define arp_request_start        0x1060
#define arp_request_end            0x108A

#define send_packet_start        0x1010
#define send_packet_end            0x103C

#define arp_reply_start            0x1090
#define arp_reply_end            0x10BA

const char ADCON0_value[8] = {0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39};
unsigned char adc_last_channel=0,adc_complete=0;

__EEPROM_DATA(0x30,0xFF,0xFF,0x00,0x01,0xFF,0xFF,0xFF); // 0x00 0x01 0x30 // max rate 375 for ethernet
void main()
{

EEPGD = 0;    // 0 means EEPROM read write .. 1 means Program data

T1CON = 0x30;

EEADR = 1;
RD = 1;
CCPR1H=EEDATA;

EEADR = 2;
RD = 1;
CCPR1L=EEDATA;

EEADR = 3;
RD = 1;
TRISA = 0xff;
TRISE = TRISE | 0X07;
ADCON1=0x80; // data right justified. 8 adc channels
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
ADIE =1;

PEIE =1;

CCP1IE =0; // AVOID FALSE INTERRUPT WHILE CHANGING CAPTURE MODE
CCP1CON = 0X0B; // CCPxIF sets, ADC conversion starts,TMR1 resets.
CCP1IE =1;

// ENC28J60 Initialisation
reset_enc = 1;        //    reset
cs_spi = 1;
TRISC2 = 0;      //cs spi tris
TRISC1 = 0;        // reset tris

uart_init();
SPI_init();
__delay_us(700);

while(( read_enc(ESTAT) & 0x01) == 0);

cs_spi = 0;
TXSPI(bit_field_clear | ESTAT);
TXSPI(0x68);
cs_spi = 1;

// clock out disabled
enc_bank_sel(3);
cs_spi = 0;
TXSPI(bit_field_clear | ECOCON);
TXSPI(0x07);
cs_spi = 1;

phy_byte_high = 0x01;        // TRANSMIT ACTIVITY
phy_byte_low = 0x22;        // RECEIVE ACTIVITY
write_phy(PHLCON);

//Recieve buffer initialization
enc_bank_sel(0);
received_packet_adr = 0x0000;
write_enc(ERXSTL,(received_packet_adr & 0x00FF));    write_enc(ERXSTH,(received_packet_adr >> 8));        // 0x0000    even address    because ERXWRPT = 0x0000 at start up
write_enc(ERXRDPTL,0xFF);    write_enc(ERXRDPTH,0x0F);    // at last.. hardware writes upto ERXRDPT – 1
write_enc(ERXNDL,0xFF);        write_enc(ERXNDH,0x0F);        // 0x0FFF end of receive buffer

// receive filter initialization
enc_bank_sel(1);
write_enc(ERXFCON,0x81);    // UCEN=1, ANDOR=0, CRCEN PMEN MPEN HTEN MCEN BCEN=1

enc_bank_sel(2);
write_enc(MACON2,0x00);        // normal operation  reset bits.

write_enc(MACON1, 0x01);    // 000 LOOPBK, TXPAUS,RXPAUS,PASSALL, MARXEN    // actual transmit
//    write_enc(MACON1, 0x11);    // 000 LOOPBK, TXPAUS,RXPAUS,PASSALL, MARXEN    // loop back

//    write_enc(MACON3, 0x05);    // PADCFG2:0,TXCRCEN,PHDRLEN,HFRMEN=1,FRMLNEN,FULDPX=1  // no padding and no crc
write_enc(MACON3, 0x35);    // PADCFG2:0,TXCRCEN,PHDRLEN,HFRMEN=1,FRMLNEN,FULDPX=1  // padding up to 60 and crc
// no need to modify MACON4 = 0x00 on reset
// no need to change MAMXFLH = 0x06, MAMXFLL = 0x00 on reset

write_enc(MABBIPG, 0x15);    // 0x15 for full duplex , 0x12 for half duplex
write_enc(MAIPGL, 0x12);    // 0x12 for most application
// MAIPGH = 0x0C for half duplex
// no need to modify MACLCON1 , MACLCON2,  if you want you can increase it
// MAPHSUP = RSTINTFC =0, 0, 0, 1, RSTMII = 0, 0,0,0

enc_bank_sel(3);
write_enc(MAADR5,udp_packet[7]);
write_enc(MAADR4,udp_packet[8]);
write_enc(MAADR3,udp_packet[9]);
write_enc(MAADR2,udp_packet[10]);
write_enc(MAADR1,udp_packet[11]);
write_enc(MAADR0,udp_packet[12]);

//    EFLOCON = 0000    0,FULL PULEX SHADOW BIT = 1,  FCEN1:FCEN0 = 00

// PHY initialization
phy_byte_high = 0x01;    //PRST,PLOOPBK,00,PPWRSV,00,PDPXMD    //full duplex actual transmit
//    phy_byte_high = 0x41;    //PRST,PLOOPBK,00,PPWRSV,00,PDPXMD    //full duplex loopback
phy_byte_low = 0x00;    //0000 0000
write_phy(PHCON1);

phy_byte_high = 0x00;        // normal operation
phy_byte_low = 0x00;
write_phy(PHCON2);

cs_spi = 0;
TXSPI(bit_field_set | EIE);
TXSPI(0xC0);
cs_spi = 1;
nRBPU = 0;        // pull up enabled
TRISB0 = 1;        // interrupt input
INTEDG = 0;        //falling edge
INTF = 0;
GIE = 1;

// writting arp request packet
enc_bank_sel(0);
write_enc(EWRPTL,(arp_request_start & 0x00FF));    write_enc(EWRPTH,(arp_request_start >> 8));    // write pointer at arp reply location
cs_spi = 0;
TXSPI(write_buffer_memory);
for(i=0;i<43;i++)
{
TXSPI(arp_request[i]);
}
cs_spi = 1;

// writting arp reply packet
enc_bank_sel(0);
write_enc(EWRPTL,(arp_reply_start & 0x00FF));    write_enc(EWRPTH,(arp_reply_start >> 8));    // write pointer at arp reply location
cs_spi = 0;
TXSPI(write_buffer_memory);
for(i=0;i<43;i++)
{
TXSPI(arp_reply[i]);
}
cs_spi = 1;

__delay_ms(10000);    // connection detection delay

// sending arp request
enc_bank_sel(0);
write_enc(ETXSTL,(arp_request_start & 0x00FF));    write_enc(ETXSTH,(arp_request_start >> 8));
write_enc(ETXNDL,(arp_request_end & 0x00FF));    write_enc(ETXNDH,(arp_request_end >> 8));

cs_spi = 0;
TXSPI(bit_field_set | ECON1);
TXSPI(0x0C);
cs_spi = INTE = 1;
while(packeti==0);    // waiting for arp reply to get MAC address

TMR1ON = 1; // TMR1 start, fosc/4
while(1)
{
if(adc_complete)
{
write_packet();
adc_complete = 0;

enc_bank_sel(0);
write_enc(ETXSTL,send_packet_start & 0x00FF);    write_enc(ETXSTH,send_packet_start >> 8);
write_enc(ETXNDL,send_packet_end & 0x00FF);        write_enc(ETXNDH,send_packet_end >> 8);

cs_spi = 0;
TXSPI(bit_field_set | ECON1);
TXSPI(0x0C);
cs_spi = INTE = 1;
}
}
}

void interrupt packet_interrupt(void)
{
if(INTE && INTF)
{
INTF = 0;
enc_bank_sel(1);
while(read_enc(EPKTCNT)>0)
{
enc_bank_sel(0);
write_enc(ERDPTL,(received_packet_adr & 0x00FF));        write_enc(ERDPTH,(received_packet_adr >> 8));        // 1010 read pointer
read_packet();
for(i=0;i<read_packet_len;i++)
{
TX(received_packet[i]);
}
write_enc(ERXRDPTL,received_packet[0]);    write_enc(ERXRDPTH,received_packet[1]);    // at last.. hardware writes upto ERXRDPT – 1
received_packet_adr = received_packet[0] + (((unsigned int)(received_packet[1]))<<8);    // dont change this logic

if((received_packet[19]==0x06) && (received_packet[27]==0x02) && (received_packet[44]==0x0A) && (received_packet[45]==0x9C) && (received_packet[46]==0x01) && (received_packet[47]==0xC8))
{
// arp reply has came so read mac address
for(i=12;i<18;i++)
{
transmit_packet[i-11] = received_packet[i];
}

// writting arp reply packet  with the received mac address
enc_bank_sel(0);
write_enc(EWRPTL,arp_reply_start & 0x00FF);        write_enc(EWRPTH,arp_reply_start>> 8);        // 1010 write pointer
cs_spi = 0;
TXSPI(write_buffer_memory);
for(i=0;i<43;i++)
{
if(i>0 && i<7)
{
TXSPI(transmit_packet[i]);
}
else if(i>32 && i<39)
{
TXSPI(transmit_packet[i-32]);
}
else
{
TXSPI(arp_reply[i]);
}
}
cs_spi = 1;
packeti = 1;    // indication of mac address received
}
else if((received_packet[19]==0x06) && (received_packet[27]==0x01) && (received_packet[45]==0x9C) && (received_packet[47]==0xC8))
{
// arp request has came so send arp reply
enc_bank_sel(0);
write_enc(ETXSTL,(arp_reply_start & 0x00FF));    write_enc(ETXSTH,(arp_reply_start >> 8));
write_enc(ETXNDL,(arp_reply_end & 0x00FF));        write_enc(ETXNDH,(arp_reply_end >> 8));

cs_spi = 0;
TXSPI(bit_field_set | ECON1);
TXSPI(0x0C);
cs_spi = 1;
}
else if((received_packet[19]==0x00) && (received_packet[29]==0x11) && (received_packet[6]==0x00))
{
TMR1ON = 0;
if((received_packet[45]==0x0C))
{
CCPR1L = received_packet[48];
CCPR1H = received_packet[49];

eeprom_write1(1,CCPR1H);
eeprom_write1(2,CCPR1L);
}
else
{
for(i=52;i<(received_packet[45]+40);i++)    // 40 = 52 – 0x0C    // 0x0D means one byte
{
eeprom_write1(i-49,received_packet[i] – 0x30);
}
eeprom_write1(i-49,0xFF);
}
EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];

ADIF = 0;
adc_complete = 0;
GODONE = 1;
CCP1IF = 0;
TMR1ON = 1;
}

//packet decrement
cs_spi = 0;
TXSPI(bit_field_set | ECON2);
TXSPI(0x40);
cs_spi = 1;

cs_spi = 0;
TXSPI(bit_field_clear | EIR);
TXSPI(0x40);
cs_spi = 0;
enc_bank_sel(1);    // while loop EPKTCNT read
}
}
else if(ADIE && ADIF)
{
adc_last_channel = EEDATA;
EEADR++;
RD = 1;
if(EEDATA == 0xFF)
{
EEADR = 3;
RD = 1;
}
ADCON0 = ADCON0_value[EEDATA];
ADIF = 0;
adc_complete = 1;
}
else if(CCP1IE && CCP1IF)
{
GODONE = 1;
CCP1IF = 0;
}
}

void read_packet(void)
{
cs_spi = INTE = 0;
TXSPI(read_buffer_memory);
for(i=0; i<read_packet_len; i++)
{
received_packet[i] = TXSPI(0x00);
}
cs_spi = 1;
}

void write_packet(void)
{
enc_bank_sel(0);
write_enc(ETXSTL,send_packet_start & 0x00FF);        write_enc(ETXSTH,send_packet_start>> 8);        // 1010 transmit packet pointer to pp control byte
write_enc(EWRPTL,send_packet_start & 0x00FF);        write_enc(EWRPTH,send_packet_start>> 8);        // 1010 write pointer

// packet formation
// all bytes except  identification, ip checksum, udp checksum, data
for(packeti=0;packeti<43;packeti++)
{
if(i>0 && i<7)    continue;
transmit_packet[packeti] = udp_packet[packeti];
}

transmit_packet[packeti++] = ADRESL;
transmit_packet[packeti++] = ADRESH | (adc_last_channel << 4);

// Identification number
transmit_packet[20]++;
if(CARRY)
{
transmit_packet[19]++;
}

//checksum calculation of ip header
for(packeti=15; (packeti<34); packeti++)
{
if((packeti == 25) || (packeti == 26))    continue;
transmit_packet[25] + = transmit_packet[packeti];
if(CARRY)
{
transmit_packet[26]++;
}
packeti++;
transmit_packet[26] + = transmit_packet[packeti];
if(CARRY)
{
transmit_packet[25]++;
}
}
transmit_packet[25] = ~transmit_packet[25];
transmit_packet[26] = ~transmit_packet[26];
// ip header checksum ready.

// 41 42 checksum bytes,   udp protocol byte 0x11, and len 0x0A are already added.
//checksum calculation of udp header    ip, port,len,data
for(packeti=27; packeti<45; packeti++)
{
if((packeti == 41) || (packeti == 42))    continue;
transmit_packet[41] + = transmit_packet[packeti];
if(CARRY)
{
transmit_packet[42]++;
}
packeti++;
transmit_packet[42] + = transmit_packet[packeti];
if(CARRY)
{
transmit_packet[41]++;
}
}
transmit_packet[41] = ~transmit_packet[41];
transmit_packet[42] = ~transmit_packet[42];
// udp header check sum ready.

cs_spi = 0;
TXSPI(write_buffer_memory);
for(packeti=0;packeti<45;packeti++)
{
TXSPI(transmit_packet[packeti]);
}
cs_spi = 1;
}

void write_phy(unsigned char PHY_ADR)    //it changes bank
{
enc_bank_sel(3);
while(read_enc(MISTAT) & 0x01); // wait until MISTAT.BUSY = 1
enc_bank_sel(2);
write_enc(MIREGADR,PHY_ADR);
write_enc(MIWRL,phy_byte_low);
write_enc(MIWRH,phy_byte_high);
__delay_us(50);
}

void read_phy(unsigned char PHY_ADR)    // changes the bank selection
{
enc_bank_sel(3);
while(read_enc(MISTAT) & 0x01); // wait until MISTAT.BUSY = 1
enc_bank_sel(2);
write_enc(MIREGADR,PHY_ADR);
write_enc(MICMD, 0x01);            // MICMD.MIIRD = 1;
__delay_us(11);
enc_bank_sel(3);
while(read_enc(MISTAT) & 0x01); // wait until MISTAT.BUSY = 1
enc_bank_sel(2);
write_enc(MICMD, 0x00);            // MICMD.MIIRD = 0;
phy_byte_low = read_enc(MIRDL);
phy_byte_high = read_enc(MIRDH);

}
void write_enc(unsigned char REG_ADR, unsigned char REG_DATA)
{
cs_spi = INTE = 0;
TXSPI(write_control_register | REG_ADR);
TXSPI(REG_DATA);
cs_spi = 1;
}
unsigned char read_enc(unsigned char REG_ADR_DATA)
{
cs_spi = INTE = 0;
TXSPI(REG_ADR_DATA);
REG_ADR_DATA = TXSPI(0x00);
cs_spi = 1;
return REG_ADR_DATA;
}

void enc_bank_sel(unsigned char BANK_SEL)
{
cs_spi = INTE = 0;
TXSPI(bit_field_clear | ECON1);    // 101 bit field clear , 1 1111 ECON1
TXSPI(0x03);    // clear to return to bank 0
cs_spi = 1;

cs_spi = 0;
TXSPI(bit_field_set | ECON1);    // 100 bit field set , 1 1111 ECON1
TXSPI(BANK_SEL);
cs_spi = 1;
}
void SPI_init()
{
TRISC3=0;
TRISC4=1;
TRISC5=0;

SSPSTAT = 0x00;
SMP = 0;       // Input data is sampled at middle of o/p time
CKE = 1;

SSPCON = 0x00; // spi mode , Fspi = Fosc/4
CKP = 0;
SSPEN = 1;
}

unsigned char TXSPI(unsigned char TX_BYTE)
{
SSPBUF = TX_BYTE;
while(!BF);
TX_BYTE = SSPBUF;
return TX_BYTE;
}
void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data)
{
GIE = 0;
EEADR = eeprom_add;
EEDATA = eeprom_data;
WREN = 1;
EECON2 = 0x55;
EECON2 = 0xAA;
WR = 1;
WREN = 0;
while(WR == 1);
//    GIE = 1;
}
void uart_init(void)
{
TRISC7 = 1;
TRISC6 = 0;
SPBRG = 5;     // 115200 BRGH = 1; 11.0592 Mhz
//    SPBRG = 129; // 9600 brgh = 1; 20 Mhz
//    SPBRG = 64;  // 19200 brgh = 1; 20 Mhz
TXSTA = 0x24;
//    RCIE =1 ; GIE =1; PEIE =1;
RCSTA = 0x90;
}
void TX(unsigned char TX_BYTE)
{
while(!TRMT);
TXREG = TX_BYTE;
}

************************END OF PROGRAM**************************

******************************************************************************************

DOWNLOAD GUI DEVELOPED IN VB 6.0

******************************************************************************************

GUI - ETHERNET ADDED SnapShot

Advertisements

(12) Data Acquisition System using PIC16F877A with serial interface and onboard configuration and data storage capability:

15/04/2012 1 comment

Till now we have seen serial communication, ADC, use of internal EEPROM of PIC16F877A, Use of CCP module in compare mode to get desired sampling rate, Data acquisition system with serial interface, GUI in Visual Basic 6.0, Interfacing 16×2 LCD, 4×4 Keyboard, and SPI EEPROM 25LC1024.

That’s it. we have gained knowledge of each and every components. Now its time to combine every part and make final Data Acquisition System.

System will be acquiring data from various signals and/or transducers.

  • Channel 0 – Not used
  • Channel 1 – 4 to 20 mA. (Signal conditioning is required to convert it into 1 to 5 V).
  • Channel 2 – Temperature measurement with thermistor ( There are thermistors with different β values and they have different R0 – Resistance at 0 ⁰C, But the design of signal conditioning and program will gives user to use any thermistor by just providing β and R0 values either from keyboard or from GUI)
  • Channel 3 – Temperature measurement with thermocouple (There are standard thermocouples are available B, E, J, R, S, T etc. Any thermocouple can be used by just selecting the thermocouple type from 4×4 keyboard or from GUI)
  • Channel 4 – Displacement measurement using strain gauge. (Strain gauge are mounted on a plate with one fixed end and one free end. A semi active bridge method is used – It measures the displacement of free end of plate from the normal position).
  • Channel 5 -±10 V. (signal conditioning required to convert it into 0 to 5 V).

DATA ACQUISITION SYSTEM

*******************************************************************************************

Program

*******************************************************************************************

#include<htc.h>
#include<math.h>

__CONFIG(0X3F3A);

#define _XTAL_FREQ 11059200

// prescaler byte 00 1, 10 2, 20 4, 30 8
__EEPROM_DATA(0x30,0xFF,0xFF,0x01,0x02,0x03,0x04,0x05); // 0x00 0x01 0x30
__EEPROM_DATA(0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0x00);

#define LCD_RS         RB2                //port e 2 for rs
#define LCD_EN         RB3                // port r for enable
#define data         PORTB
#define data_tris     TRISB

#define cursor_hide             0x0c
#define cursor_show             0x0e
#define cursor_left             0x10
#define cursor_right             0x14
#define cursor_underline         0x0e
#define cursor_blinking         0x0f
#define display_right             0x1c
#define display_left             0x18
#define lcdclear                 0x01
#define dcr_cursor                 0x04
#define inr_cursor                 0x06
#define disoff                     0x08
#define display_off_cursor_on     0x0A
#define putline1                 0x80
#define putline2                 0xc0

#define col0 RD0
#define col1 RD1
#define col2 RD2
#define col3 RD3

#define row0 RD4
#define row1 RD5
#define row2 RD6
#define row3 RD7

#define READ_SPI_EEPROM     0x03
#define WRITE_SPI_EEPROM     0x02
#define WREN_SPI_EEPROM     0x06
#define RDSR_SPI_EEPROM     0x05

#define serial_memory         RCIE

#define cs_spi RC2
unsigned char spi_eeprom_addressa = 255, spi_eeprom_addressb = 255,spi_eeprom_addressc = 254;
unsigned char spi_eeprom_read_addressa = 0,spi_eeprom_read_addressb = 0,spi_eeprom_read_addressc = 0;
unsigned char spi_eeprom_adc_channel = 0;
unsigned int spi_eeprom_data=0;
void SPI_init(void);
unsigned char TXSPI(unsigned char TX_BYTE);

unsigned const char key_comb[4][4] = {“123O”,”456B”,”789E”,”.0LR”};
unsigned char waitforakey(void);
unsigned char row,col;

void delay_5us(unsigned int delay_us1);
//void delay_ms(unsigned int delay_ms1);
void lcd_strob(void);
void lcd_write(unsigned char);
void lcd_cmd(unsigned char i);
void lcd_string(unsigned char s[],unsigned char len);
void lcd_stringc(void);
void lcd_config(void);

void uart_init(void);
void TX(unsigned char TX_BYTE);
bit channel_receive = 0, ccp_receive = 0, config = 0;
unsigned char rx_data=0,eeprom_address = 0;

void voltage2pv(void);
void get_input(void);

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

const char ADCON0_value[8] = {0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39};
unsigned char adc_last_channel=0,adc_complete=0;

float voltage;
unsigned char pv[8];
unsigned const char daq_str[][32] = {    “DATA ACQUISITIONSYSTEM     -IDDC”,
“2.MONITR 3.RATE 4.SEQ 5.OP 6.MEM”,
“CHANNEL#:       PV:             “,
“SAMPLING RATE:                  “,
“SET CHANNEL SEQ:                “,
“1.MEM 2.SERIAL ?                “,
“CH   DATA   UP:7                “,
“0.B 1.E 2.J 3.K 5.R 6.S 7.T     “,
“BETA Value :                    “,
“0 C Resistance:                 ”    };
unsigned const char message[][16] = {    “MEMORY STORAGE  “,
“SERIAL INTERFACE”,
“IS SELECTED.    “,
“FULL            “,
“UPLOADING   DATA”    };

unsigned const char unit[][3] = {    ” V “,
” mA”,
{‘ ‘,’C’,’ ‘},
{‘ ‘,’C’,’ ‘},
” mm”,
” V “,};

unsigned char input[16];
unsigned char disp_index=0;
unsigned char key;
unsigned int i;
unsigned char show_pv = 0,view_channel = 0;
//0 -> VOLTAGE, 1 –> CURRENT, 2–>THERMISTOR, 3–> TC, 4 –> STRAIN GAUAGE , 5 –> VOLTAGE
const float conversion_divisor[8] = {51.15, 50.9454 , 20.771574    , 0.2046    ,204.6    , 51.15    , 204.6,204.6};
const float conversion_offset[8] =  {-10  , 0         , -9.850    , 0            ,5        , -10    , 0,0};
const float TC_sensitivity[8] =    {    0.7133333333333, //B
70.02,           //E
53.4,            //J
43.6,            //K
46,              //LAB
6.94,            //R
6.86,            //S
44.693333333333};//T
unsigned char TC_index = 3;
float Beta = 3657, R0 = 30.50373;
void resistance_to_temp(void);

void main()
{
uart_init();
serial_memory = 1;
cs_spi = 1;
TRISC2 = 0;
SPI_init();

EEPGD = 0;    // 0 means EEPROM read write .. 1 means Program data
T1CON = 0x30;

EEADR = 1;
RD = 1;
CCPR1H=EEDATA;

EEADR = 2;
RD = 1;
CCPR1L=EEDATA;

EEADR = 3;
RD = 1;
TRISA = 0xff;
TRISE = TRISE | 0X07;
ADCON1=0x80; // data right justified. 8 adc channels

ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
ADIE =1;

lcd_config();
TRISD = 0xf0;
PORTD = 0X0F;

GIE =1; PEIE =1;

CCP1IE =0; // AVOID FALSE INTERRUPT WHILE CHANGING CAPTURE MODE
CCP1CON = 0X0B; // CCPxIF sets, ADC conversion starts,TMR1 resets.
CCP1IE =1;

TMR1ON = 1; // TMR1 start, fosc/4

lcd_cmd(cursor_underline);
disp_index = 0;
lcd_stringc();

while(1)
{
key = waitforakey();
show_pv = 0;
if(disp_index == 2)
{
if(key == ‘O’ || key == ‘B’)
{
disp_index = 1;
}
else if(key == ‘L’)
{
if(view_channel>0)     view_channel–;
else view_channel = 7;
}
else if(key == ‘R’)
{
if (view_channel<7) view_channel++;
else view_channel = 0;
}
else if(key == ‘E’)
{
if(view_channel == 3)
{
disp_index = 7;
}
else if(view_channel == 2)
{
disp_index = 8;
}
}
lcd_stringc();
if(disp_index == 7 || disp_index == 8)
{
get_input();
lcd_stringc();
if(disp_index==9)
{
get_input();
}
}
lcd_stringc();
}
else if(disp_index == 6)
{
if(key == ‘O’ || key == ‘B’)
{
disp_index = 1;
}
else if(key == ‘L’)
{
if(spi_eeprom_read_addressc>1 || spi_eeprom_read_addressa == 2)
{
GIE = 0;
spi_eeprom_read_addressc–;    spi_eeprom_read_addressc–;
if(!CARRY)
{
spi_eeprom_read_addressb–;
if(!CARRY)
{
spi_eeprom_read_addressa–;
}
}
GIE = 1;
}
}
else if(key == ‘R’)
{
if(spi_eeprom_read_addressa != 2)
{
GIE = 0;
spi_eeprom_read_addressc++;    spi_eeprom_read_addressc++;
if(CARRY)
{
spi_eeprom_read_addressb++;
if(CARRY)
{
spi_eeprom_read_addressa++;
}
}
GIE = 1;
}
}
else if(key == ‘7’)
{
lcd_cmd(putline1);
for(key = 0; key<17; key++)
{
lcd_write(message[4][key]);
}
TMR1ON = 0; GIE = 0;

do
{
cs_spi = 1;
cs_spi = 0;
TXSPI(RDSR_SPI_EEPROM);
}

while(TXSPI(0x00) & 0x01);
cs_spi = 1;

spi_eeprom_read_addressa = spi_eeprom_read_addressb = 255;
spi_eeprom_read_addressc = 254;

cs_spi = 0;
TXSPI(READ_SPI_EEPROM);
TXSPI(0x00);
TXSPI(0x00);
TXSPI(0x00);
// spi_eeprom_address is address pointing the last written sample… next sample will be stored at spi_eeprom_address+2
while( (spi_eeprom_read_addressa != spi_eeprom_addressa) || (spi_eeprom_read_addressb != spi_eeprom_addressb) || (spi_eeprom_read_addressc != spi_eeprom_addressc) )
{
spi_eeprom_read_addressc++;    spi_eeprom_read_addressc++;
if(CARRY)
{
spi_eeprom_read_addressb++;
if(CARRY)
{
spi_eeprom_read_addressa++;
}
}
TX(TXSPI(0x00));
TX(TXSPI(0x00));
}
cs_spi = TMR1ON = GIE = 1;
spi_eeprom_addressa = spi_eeprom_addressb = 255;
spi_eeprom_addressc = 254;
spi_eeprom_read_addressa = spi_eeprom_read_addressb = spi_eeprom_read_addressc = 0;
disp_index = 1;
lcd_stringc();
}
}
else    // main display
{
if(key>0x2f && key<0x37)
{
disp_index = key – 0x30;
}
lcd_stringc();
if(disp_index==3 || disp_index == 4 || disp_index == 5)
{
get_input();
}

}
if(disp_index == 2)
{
lcd_cmd(putline1+9);
lcd_write(view_channel+0x30);
show_pv = 1;
}
else if(disp_index == 6)
{
do
{
cs_spi = 1;
cs_spi = 0;
TXSPI(RDSR_SPI_EEPROM);
}
while(TXSPI(0x00) & 0x01);
cs_spi = 1;

cs_spi = 0;
TXSPI(READ_SPI_EEPROM);
TXSPI(spi_eeprom_read_addressa);
TXSPI(spi_eeprom_read_addressb);
TXSPI(spi_eeprom_read_addressc);
spi_eeprom_data = TXSPI(0x00);
spi_eeprom_data + = TXSPI(0x00)<<8;
cs_spi = 1;

spi_eeprom_adc_channel = spi_eeprom_data >> 12;
voltage =(spi_eeprom_data & 0x0FFF)/conversion_divisor[spi_eeprom_adc_channel] + conversion_offset[spi_eeprom_adc_channel];

if(spi_eeprom_adc_channel == 3)
{
voltage = voltage/TC_sensitivity[TC_index];
}
else if(spi_eeprom_adc_channel == 2)
{
resistance_to_temp();
//voltage =-273 + 1/( (1/Beta)*log(voltage/R0)+ 0.003663);
}
voltage2pv();
lcd_cmd(putline2+1);
lcd_write(spi_eeprom_adc_channel+0x30);
lcd_cmd(putline2+3);
lcd_string(pv,8);
for(key = 0; key<3; key++)
{
lcd_write(unit[spi_eeprom_adc_channel][key]);
}
}
}
}
void get_input(void)
{
unsigned char pos = 0;
unsigned char in_len;
unsigned int ccp;
TMR1ON = 0;
lcd_cmd(putline2);
if(disp_index == 7)
{
lcd_cmd(putline2+13);
}
key = waitforakey();
while(key != ‘O’ && key != ‘E’)
{
if(key == ‘B’ && pos>0) // OUT
{
lcd_cmd(cursor_left);
lcd_write(‘ ‘);
lcd_cmd(cursor_left);
pos–;
}
else if(key == ‘L’ && pos>0)
{
lcd_cmd(cursor_left);
pos–;
}
else if(key == ‘R’)
{
lcd_cmd(cursor_right);
pos++;
}
else
{
lcd_write(key);
input[pos] = key;
pos++;
}
key = waitforakey();
}
in_len = pos;
if(key==’E’)
{
if(disp_index == 4)
{
eeprom_address = 0x03;
for(pos = 0; pos < in_len ; pos++)
{
if(input[pos]>’7′) continue;
eeprom_write1(eeprom_address,input[pos] – 0x30);
eeprom_address++;
}
eeprom_write1(eeprom_address,0xFF);
disp_index = 2;
}
else if(disp_index == 3)
{
ccp = 0;
for(pos = 0; pos< in_len; pos++)
{
ccp  = (ccp*10) + (input[pos]-0x30);
}
if(ccp<6)
{
ccp = 6;
}
else if (ccp > 57600)
{
ccp = 57600;
}

ccp = ((unsigned long int)345600)/(unsigned long int)ccp;    // 11.0592
CCPR1H = ccp >>8;
CCPR1L = ccp & 0xff;
eeprom_write1(1,CCPR1H);
eeprom_write1(2,CCPR1L);
disp_index = 2;
}
else if(disp_index == 5)
{
lcd_cmd(putline1);
input[0] – = 0x31;
if(input[0] == 1 || input[0] == 0)
{
RCIF = 0;
serial_memory = input[0];
for(pos = 0; pos<17 ; pos++)
{
lcd_write(message[input[0]][pos]);
}
lcd_cmd(putline2);
for(pos = 0; pos<17 ; pos++)
{
lcd_write(message[2][pos]);
}
__delay_ms(1000);
}
disp_index = 1;
}
else if(disp_index == 7)
{
TC_index = input[0] – 0x31;
disp_index = 2;
}
else if(disp_index == 8)
{
Beta = 0;
for(pos = 0; pos< in_len; pos++)
{
Beta  = (Beta*10) + (input[pos]-0x30);
}
disp_index = 9;
}
else    // disp_index ==9
{
R0 = 0;
for(pos = 0; pos< in_len; pos++)
{
R0  = (R0*10) + (input[pos]-0x30);
}
R0 = R0/1000;
disp_index = 2;
}

EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
GODONE = 1;
TMR1ON = 1;
}
lcd_stringc();
}

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data)
{
GIE = 0;
EEADR = eeprom_add;
EEDATA = eeprom_data;
WREN = 1;
EECON2 = 0x55;
EECON2 = 0xAA;
WR = 1;
WREN = 0;
while(WR == 1);
GIE = 1;
}
unsigned char waitforakey(void)
{
unsigned int key_debounce;

while(row0==1 || row1==1 || row2==1 || row3==1) /// wait until all key release….
for(key_debounce=0;key_debounce<1000;key_debounce++);
while(row0==0 && row1==0 && row2==0 && row3==0)  /// wait until any key pressed….
{
//write routine to execute while waiting for key..
if(adc_complete && config == 0)
{
if(serial_memory)
{
TX(ADRESL);
TX(ADRESH | (adc_last_channel << 4));
}
else
{
if(spi_eeprom_addressa != 2)
{
GIE = 0;
spi_eeprom_addressc++;    spi_eeprom_addressc++;
if(CARRY)
{
spi_eeprom_addressb++;
if(CARRY)
{
spi_eeprom_addressa++;
}
}
GIE = 1;
do
{
cs_spi = 1;
cs_spi = 0;
TXSPI(RDSR_SPI_EEPROM);
}
while(TXSPI(0x00) & 0x01);
cs_spi = 1;

cs_spi = 0;
TXSPI(WREN_SPI_EEPROM);
cs_spi = 1;

cs_spi = 0;
TXSPI(WRITE_SPI_EEPROM);
TXSPI(spi_eeprom_addressa);
TXSPI(spi_eeprom_addressb);
TXSPI(spi_eeprom_addressc);
TXSPI(ADRESL);
TXSPI(ADRESH | (adc_last_channel << 4));
cs_spi = 1;
}
else
{
show_pv = 0;
TMR1ON = 0;
lcd_cmd(putline1);
for(key = 0; key <17 ; key++)
{
lcd_write(message[0][key]);    // “MEMORY STORAGE”
}
lcd_cmd(putline2);
for(key = 0; key <17 ; key++)
{
lcd_write(message[3][key_debounce]);    // “FULL”
}
}
}
if(show_pv && adc_last_channel == view_channel)
{
voltage = (((ADRESH<<8)+ADRESL)/conversion_divisor[view_channel]) + conversion_offset[view_channel];

if(view_channel == 3)
{
voltage = voltage/TC_sensitivity[TC_index];
}
else if(view_channel == 2)
{
resistance_to_temp();
//voltage =-273 + 1/( (1/Beta)*log(voltage/R0)+ 0.003663);
}
voltage2pv();
lcd_cmd(putline2+3);
lcd_string(pv,8);
for(key = 0; key<3; key++)
{
lcd_write(unit[view_channel][key]);
}
}
adc_complete = 0;
}
}
for(key_debounce=0;key_debounce<2500;key_debounce++);

if(row0 == 1)
{
row = 0;
}
else if(row1 == 1)
{
row = 1;
}
else if(row2 == 1)
{
row = 2;
}
else if(row3 == 1)
{
row = 3;
}
//col0=1;    col1=0;    col2=0;    col3=0;
PORTD = 0X01;
if(PORTD != 0x01)
{
col = 0;
}
else
{
//col0=0;    col1=1;    col2=0;    col3=0;
PORTD = 0X02;
if(PORTD != 0x02)
{
col=1;
}
else
{
//col0=0;    col1=0;    col2=1;    col3=0;
PORTD = 0x04;
if(PORTD != 0x04)
{
col=2;
}
else
{
//col0=0;    col1=0;    col2=0;    col3=1;
PORTD = 0x08;
if(PORTD != 0x08)
{
col=3;
}
}
}
}
//col0=1;    col1=1;    col2=1;    col3=1;
PORTD = 0X0F;
return key_comb[row][col];
}

void resistance_to_temp(void)
{
voltage =-273 + 1/( (1/Beta)*log(voltage/R0)+ 0.003663);
}
void interrupt receive(void)
{
if(RCIE && RCIF)
{
RCIF = 0;
rx_data = RCREG;
if(rx_data == 17 && !channel_receive)
{
ADIE = 0;
TMR1ON = 0;
channel_receive = 1;
config = 1;
eeprom_address = 3;
}
else if(rx_data == 17 && channel_receive)
{
eeprom_write1(eeprom_address,0xFF);
EEADR = 0x03;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
channel_receive = 0;
config = 0;
ADIE = 1;
TMR1ON = 1;
}
else if(rx_data == 0x55 && !ccp_receive)
{
ADIE = 0;
TMR1ON = 0;
ccp_receive = 1;
config = 1;
eeprom_address = 1;
}
else if(ccp_receive)
{
eeprom_write1(eeprom_address,rx_data);
eeprom_address++;
if(eeprom_address == 3)
{
EEADR = 1;
RD = 1;
CCPR1H = EEDATA;

EEADR = 2;
RD = 1;
CCPR1L = EEDATA;

TMR1ON = 1;

EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
ccp_receive = 0;
config = 0;
ADIE = 1;
TMR1ON = 1;
}
}
else if(channel_receive)
{
eeprom_write1(eeprom_address,rx_data);
eeprom_address++;
}
else if(rx_data == 0xff)
{
GIE = 0;

EEADR = 0;
RD = 1;
TXREG = 0xF1;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 1;
RD = 1;
TXREG = 0xF2;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 2;
RD = 1;
TXREG = 0xF3;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;

TMR1ON = 1;
GIE = 1;
}
}
if(!channel_receive && !ccp_receive)
{
if(ADIE && ADIF)
{
adc_last_channel = EEDATA;
EEADR++;
RD = 1;
if(EEDATA == 0xFF)
{
EEADR = 3;
RD = 1;
}
ADCON0 = ADCON0_value[EEDATA];
ADIF = 0;
adc_complete = 1;
}
else if(CCP1IE && CCP1IF)
{
GODONE = 1;
CCP1IF = 0;
}
}
}

void voltage2pv(void)
{
unsigned char n;
n=0;
if(voltage<0)
{
pv[n] = ‘-‘;
voltage = -voltage;
}
else
{
pv[n] = ‘+’;
}
n++;
pv[n] = (int)(voltage/100);
voltage – = pv[n]*100;
pv[n] + = 0x30;

n++;
pv[n] =(int)(voltage/10);
voltage – = pv[n]*10;
pv[n] + = 0x30;

n++;
pv[n] = (int)voltage;
voltage – = pv[n];
pv[n] + = 0x30;

n++;
pv[n] = ‘.’;

while(n<7)
{
n++;
voltage = voltage*10;
pv[n] = (int)voltage;
voltage – = pv[n];
pv[n] + = 0x30;
}
}

void uart_init(void)
{
TRISC7 = 1;
TRISC6 = 0;
SPBRG = 5;     // 115200 BRGH = 1; 11.0592 Mhz
//    SPBRG = 129; // 9600 brgh = 1; 20 Mhz
//    SPBRG = 64;  // 19200 brgh = 1; 20 Mhz
//    SPBRG = 25;     // 9600 BRGH = 1; 4.0 Mhz
//    SPBRG = 8;     // 128000 BRGH = 1 18.432 Mhz
TXSTA = 0x24;
RCIE =1 ; GIE =1; PEIE =1;
RCSTA = 0x90;
}
void TX(unsigned char TX_BYTE)
{
while(!TRMT);
TXREG = TX_BYTE;
}

void lcd_strob(void)
{
LCD_EN=1;
delay_5us(2);
LCD_EN=0;
}

void lcd_config(void)
{
data_tris = 0x00;
__delay_ms(5);

LCD_EN=0;                    //enable lcd
LCD_RS=0;                    //set to instuction mode

lcd_cmd(0x38);
__delay_ms(5);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);

lcd_cmd(0x01);            //clear lcd scren
delay_5us(25);
lcd_cmd(0x0f);            //set entry mode
}

void lcd_write(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 1;
delay_5us(25);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp)|(0x04);

lcd_strob();
delay_5us(100);

data_temp = data & 0x03;
data = (i<<4) |(data_temp)|(0x04);

lcd_strob();
}
void lcd_cmd(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 0;
delay_5us(30);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp);

lcd_strob();
delay_5us(150);

data_temp = data & 0x03;
data = (i<<4) |(data_temp);

lcd_strob();
}

void lcd_string(unsigned char s[],unsigned char len)
{
unsigned char k;
for(k=0;k<len;k++)
{
lcd_write(s[k]);
}
}

void lcd_stringc(void)
{
unsigned char k;
lcd_cmd(putline1);
for(k=0;k<32;k++)
{
if(k==16) lcd_cmd(putline2);
lcd_write(daq_str[disp_index][k]);
}
}

void delay_5us(unsigned int delay_us1)
{
unsigned int ui,um;
for(ui = 0; ui<delay_us1; ui++);
}
void SPI_init(void)
{
TRISC3=0;
TRISC4=1;
TRISC5=0;

SSPSTAT = 0x00;
SMP = 0;       // Input data is sampled at middle of o/p time
CKE = 1;

SSPCON = 0x00; // spi mode , Fspi = Fosc/4
CKP = 0;
SSPEN = 1;
}

unsigned char TXSPI(unsigned char TX_BYTE)
{
SSPBUF = TX_BYTE;
while(!BF);
TX_BYTE = SSPBUF;
return TX_BYTE;
}

*************************END OF PROGRAM**************************

<<previous                                                                                                                     Next>>

(11) Interfacing SPI EEPROM 25LC1024

Many times experimental setup is located such that we cant have PC anywhere near. Data acquisition system must have an on board data storage capability to store the sampled data in case if user do not have computer at the time of acquisition. Later, user can upload the acquired sample data and analyze it.

We are interfacing 25LC1024 EEPROM to PIC16F877A. It has SPI interface to the host controller. Its and 131072 bytes of EEPROM. Our one sample requires two bytes of data. So we can store 65536 samples in a single 25LC1024. To increase the memory storage capacity of our system we can cascade two or more 25LC1024 by having different Chip Select pin connection to PIC.

Connections are very simple. PIC16F877A has a MSSP module. This MSSP module is used for SPI data transfer.

Interfacing 25LC1024 to PIC16F877A

Following program will write two bytes at a time to 25LC1024. Once all memory locations are written it will read the data from 25LC1024 and send that data to PC via serial.

************************************************************************

Program

************************************************************************

#include<htc.h>

#define _XTAL_FREQ 20000000
__CONFIG(0x3f3a);

unsigned char i;
unsigned char spi_eeprom_addressa = 255, spi_eeprom_addressb = 255,spi_eeprom_addressc = 254; // address where the L is stored then at next location H is stored
unsigned char spi_eeprom_read_addressa = 0,spi_eeprom_read_addressb = 0,spi_eeprom_read_addressc = 0; // address from where L is read, then from next location H is read
unsigned int spi_eeprom_data=0;

unsigned char L=0,H=0;    //data which is to be stored at two consecutive location

// 25LC1024 spi commands
#define READ_SPI_EEPROM 0x03
#define WRITE_SPI_EEPROM 0x02
#define WREN_SPI_EEPROM 0x06
#define RDSR_SPI_EEPROM 0x05

void uart_init(void);
void TX(unsigned char TX_BYTE);

#define cs_spi RC2
void SPI_init(void);
unsigned char TXSPI(unsigned char TX_BYTE);
void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

unsigned char data;
void main()
{
cs_spi = 1;
TRISC2 = 0;

uart_init();
SPI_init();

// complete address where the data is getting stored is of three bytes
// spi_eeprom_addressa, spi_eeprom_addressb, spi_eeprom_addressc

// address range of 25LC1024 is from 000000 -> 01FFFF,  means spi_eeprom_addressa should never be > 1
// so we need to stop writting data when spi_eeprom_addressa = 2;
// writting data to 25LC1024
while(spi_eeprom_addressa != 2)
{
spi_eeprom_addressc++;    spi_eeprom_addressc++;
if(CARRY)
{
spi_eeprom_addressb++;
if(CARRY)
{
spi_eeprom_addressa++;
}
}

do
{
cs_spi = 1;
cs_spi = 0;
TXSPI(RDSR_SPI_EEPROM);    // read status register
}
while(TXSPI(0x00) & 0x01);    // wait until write instruction gets completed
cs_spi = 1;

cs_spi = 0;
TXSPI(WREN_SPI_EEPROM);    // always required to set write enable bit in control register of 25LC1024
cs_spi = 1;

cs_spi = 0;
TXSPI(WRITE_SPI_EEPROM);    // write instruction
TXSPI(spi_eeprom_addressa);    // address byte
TXSPI(spi_eeprom_addressb);    // address byte
TXSPI(spi_eeprom_addressc);    // address byte
TXSPI(L);                    // data byte
TXSPI(H);                    // data byte for next location
cs_spi = 1;

// decrement data by 1
L–;
if(L==255)
{
H–;
}
}

do
{
cs_spi = 1;
cs_spi = 0;
TXSPI(RDSR_SPI_EEPROM);
}
while(TXSPI(0x00) & 0x01);
cs_spi = 1;

// reading data in 25LC1024
while(spi_eeprom_read_addressa != 2)
{
spi_eeprom_read_addressc++;    spi_eeprom_read_addressc++;
if(CARRY)
{
spi_eeprom_read_addressb++;
if(CARRY)
{
spi_eeprom_read_addressa++;
}
}

cs_spi = 0;
TXSPI(READ_SPI_EEPROM);
TXSPI(spi_eeprom_read_addressa);
TXSPI(spi_eeprom_read_addressb);
TXSPI(spi_eeprom_read_addressc);
TX(TXSPI(0x00));    // read L data and transmit to uart to see data on comport tool kit
TX(TXSPI(0x00));    // read H data and transmit to uart to see data on comport tool kit
cs_spi = 1;
}

while(1);
}

void SPI_init()
{
TRISC3=0;
TRISC4=1;
TRISC5=0;

SSPSTAT = 0x00;
SMP = 0;       // Input data is sampled at middle of o/p time
CKE = 1;

SSPCON = 0x00; // spi mode , Fspi = Fosc/4
CKP = 0;
SSPEN = 1;
}

unsigned char TXSPI(unsigned char TX_BYTE)
{
SSPBUF = TX_BYTE;
while(!BF);
TX_BYTE = SSPBUF;
return TX_BYTE;
}

void uart_init(void)
{
TRISC7 = 1;
TRISC6 = 0;
SPBRG = 5;     // 115200 BRGH = 1; 11.0592 Mhz
//    SPBRG = 129; // 9600 brgh = 1; 20 Mhz
//    SPBRG = 64;  // 19200 brgh = 1; 20 Mhz
TXSTA = 0x24;
RCIE =1 ; GIE =1; PEIE =1;
RCSTA = 0x90;
}
void TX(unsigned char TX_BYTE)
{
while(!TRMT);
TXREG = TX_BYTE;
}

<<Previous                                                                                                    Next>>

(10) Interfacing 4×4 matrix keyboard and showing pressed key on 16×2 LCD:

In previous post LCD interfacing is discussed. As i mentioned earlier for on board configuration of our Data acquisition system we need a keyboard.

let name our keys like this:

1    2   3   O

4    5   6   B

7    8   9   E

.     0   L   R

There is reason why i named like this, Each key will have its own operation on our final data acquisition system and depending up on that operation key identifier character is assigned :  ‘O’ -> Out, ‘B’-> Backspace, ‘E’-> Enter, ‘R’-> Scroll right, ‘L’-> Scroll left, ‘.’ put decimal point.

16x2 LCD and 4x4 Keyboard with PIC16F877A

In program first PORTD0-> PORTD3(columns) are made high and used as output pins, PORTD4-> PORTD7(rows) are used as input pins.

programs monitors status at all rows. when no key is pressed row pins remains low because of 10k pull down resistor.

when any key is pressed. that particular row becomes high and controller will identifies row number.

Now to identify the column number we will make columns high one by one, one at a time and check the row status. when the row is found high for a particular column high, thats our column number. Now from row and col number we can identity that which key was pressed.

Once the key is identified program will show it on LCD’s first line first position.

************************************************************************

Program

************************************************************************

#include<htc.h>

__CONFIG(0X3F3A);

#define _XTAL_FREQ 11059200

// prescaler byte 00 1, 10 2, 20 4, 30 8
__EEPROM_DATA(0x30,0xFF,0xFF,0x01,0x02,0xFF,0xFF,0xFF); // 0x00 0x01 0x30
__EEPROM_DATA(0x05,0x06,0x07,0xFF,0xFF,0x00,0xFF,0x00);

#define LCD_RS RB2                //port e 2 for rs
#define LCD_EN RB3                // port r for enable
#define data PORTB
#define data_tris TRISB

#define cursor_hide 0x0c
#define cursor_show 0x0e
#define cursor_left 0x10
#define cursor_right 0x14
#define cursor_underline 0x0e
#define cursor_blinking 0x0f
#define display_right 0x1c
#define display_left 0x18
#define lcdclear 0x01
#define dcr_cursor 0x04
#define inr_cursor 0x06
#define disoff 0x08
#define display_off_cursor_on 0x0A
#define putline1 0x80
#define putline2 0xc0

void delay_5us(unsigned int delay_us1);
//void delay_ms(unsigned int delay_ms1);
void lcd_strob(void);
void lcd_write(unsigned char);
void lcd_cmd(unsigned char i);
void lcd_string(unsigned char s[],unsigned char len);
void lcd_stringc(void);
void lcd_config(void);

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

unsigned const char daq_str[][32] = {    “DATA ACQUISITIONSYSTEM     -IDDC”,
“2.MONITR 3.RATE 4.SEQ 5.OP 6.MEM”,
“CHANNEL#:       PV:             “,
“SAMPLING RATE:                  “,
“SET CHANNEL SEQ:                “,
“1.MEM 2.SERIAL ?                “,
“CH   DATA   UP:7                ”    };
unsigned const char message[][16] = {    “MEMORY STORAGE  “,
“SERIAL INTERFACE”,
“IS SELECTED.    “,
“FULL            “,
“UPLOADING   DATA”    };
unsigned char input[16];
unsigned char disp_index=0;
unsigned int i;

#define col0 RD0
#define col1 RD1
#define col2 RD2
#define col3 RD3
#define row0 RD4
#define row1 RD5
#define row2 RD6
#define row3 RD7
unsigned char key;
unsigned const char key_comb[4][4] = {“123O”,”456B”,”789E”,”.0LR”};
unsigned char waitforakey(void);
unsigned char row,col;

void main()
{
TRISD = 0xF0;        //Rows as input, and columns as output
PORTD = 0X0F;        // all columns = 1 initially.
lcd_config();    // initialise lcd  in 4 bit

lcd_cmd(cursor_underline);    // cursor will be displayed as underline not blinking
while(1)
{
lcd_cmd(putline1);
waitforakey();
{
lcd_write(key);
}
}
}

unsigned char waitforakey(void)
{
unsigned int key_debounce;

while(row0==1 || row1==1 || row2==1 || row3==1) /// wait until all key release….
for(key_debounce=0;key_debounce<1000;key_debounce++);
while(row0==0 && row1==0 && row2==0 && row3==0)  /// wait until any key pressed….
{
//write routine to execute while waiting for key..
// program will stuck here when no key is pressed ..
// so put the code here which is to be executed
}
for(key_debounce=0;key_debounce<2500;key_debounce++);

if(row0 == 1)
{
row = 0;
}
else if(row1 == 1)
{
row = 1;
}
else if(row2 == 1)
{
row = 2;
}
else if(row3 == 1)
{
row = 3;
}
//col0=1;    col1=0;    col2=0;    col3=0;
PORTD = 0X01;
if(PORTD != 0x01)
{
col = 0;
}
else
{
//col0=0;    col1=1;    col2=0;    col3=0;
PORTD = 0X02;
if(PORTD != 0x02)
{
col=1;
}
else
{
//col0=0;    col1=0;    col2=1;    col3=0;
PORTD = 0x04;
if(PORTD != 0x04)
{
col=2;
}
else
{
//col0=0;    col1=0;    col2=0;    col3=1;
PORTD = 0x08;
if(PORTD != 0x08)
{
col=3;
}
}
}
}
//col0=1;    col1=1;    col2=1;    col3=1;
PORTD = 0X0F;
return key_comb[row][col];
}

void lcd_strob(void)
{
LCD_EN=1;
delay_5us(2);
LCD_EN=0;
}

void lcd_config(void)
{
data_tris = 0x00;
__delay_ms(5);

LCD_EN=0;                    //enable lcd
LCD_RS=0;                    //set to instuction mode

lcd_cmd(0x38);
__delay_ms(5);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);

lcd_cmd(0x01);            //clear lcd scren
delay_5us(25);
lcd_cmd(0x0f);            //set entry mode
}

void lcd_write(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 1;
delay_5us(25);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp)|(0x04);

lcd_strob();
delay_5us(100);

data_temp = data & 0x03;
data = (i<<4) |(data_temp)|(0x04);

lcd_strob();
}
void lcd_cmd(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 0;
delay_5us(30);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp);

lcd_strob();
delay_5us(150);

data_temp = data & 0x03;
data = (i<<4) |(data_temp);

lcd_strob();
}

void lcd_string(unsigned char s[],unsigned char len)
{
unsigned char k;
for(k=0;k<len;k++)
{
lcd_write(s[k]);
}
}

void lcd_stringc(void)
{
unsigned char k;
lcd_cmd(putline1);
for(k=0;k<32;k++)
{
if(k==16) lcd_cmd(putline2);
lcd_write(daq_str[disp_index][k]);
}
}

void delay_5us(unsigned int delay_us1)
{
unsigned int ui,um;
for(ui = 0; ui<delay_us1; ui++);
}

*************************END OF PROGRAM**************************

<<Previous                                                                                                                    Next>>

(9) Interfacing 16×2 LCD to PIC16F877A

Up to last post we already built a data acquisition system with GUI interface in VB. In that design we must have to have laptop or PC with us to use data acquisition system otherwise its of no use. So as to overcome this factor, we want to have a on board display, on board keys to give channel sequence inputs, on board memory storage to store the sampled data.

Lets start with interfacing 16×2 LCD display to PIC16F877A.

It can be interfaced in 8 bit or in 4 bit mode.

  • 8 bit interface –> 8 pins for data, 1 pin  for RS, 1 pin  for EN  ==> total 10 pins of microcontroller will get used.
  • 4 bit interface –> 4 pins for data, 1 pin  for RS, 1 pin  for EN  ==> total 6 pins of microcontroller will get used.

So as to save controller pins we will use 4 bit interface.

In 4 bit mode the 8 bit data is given in two parts :  First higher nibble then after lower nibble.

  • RS pin is for register select.

RS = 0 –> byte given to LCD is understood as command byte. Command register is selected.

RS = 1 –> byte given to LCD is understood as data byte and its ASCII character will be shown on LCD.

  • RW pin is for Read/Write, In our case LCD is used in Write operation only. So we keep RW = 0.
  • EN pin: We must apply a pulse on EN whenever we want to give data.

************************************************************************

Circuit Connections

************************************************************************

Connections of 16x4 LCD to PIC16F877A

Following program shows the “DATA ACQUISITION SYSTEM  -IDDC” on LCD display.

For ease of use of LCD, Program is divided into simple subroutines.

First of all lcd_config() must be called. before using any other lcd routine functions.

Then after you can use lcd_cmd(), lcd_write(), lcd_stringc(), lcd_string() functions to do various operations.

  • lcd_cmd(unsigned char i)  –> byte i is send to LCD as a command.
  • lcd_write(unsigned char i)  –> byte i is send to LCD as a data byte. and its ASCII character will be displayed after this routine gets executed.
  • lcd_string(unsigned char s[],unsigned char len) –> characters from string s will get written on LCD. len is the number of characters from the string s to be written.
  • lcd_stringc() –> This function is used to write the 32 characters of daq_str[][32],daq_str is an array of string, disp_index is used to specify which string is to be displayed.

************************************************************************

Program

************************************************************************

#include<htc.h>

__CONFIG(0X3F3A);

#define _XTAL_FREQ 11059200

#define LCD_RS RB2                //port B2 for RS
#define LCD_EN RB3                // port B3for EN
#define data PORTB
#define data_tris TRISB

#define cursor_hide 0x0c
#define cursor_show 0x0e
#define cursor_left 0x10
#define cursor_right 0x14
#define cursor_underline 0x0e
#define cursor_blinking 0x0f
#define display_right 0x1c
#define display_left 0x18
#define lcdclear 0x01
#define dcr_cursor 0x04
#define inr_cursor 0x06
#define disoff 0x08
#define display_off_cursor_on 0x0A
#define putline1 0x80
#define putline2 0xc0

void delay_5us(unsigned int delay_us1);
//void delay_ms(unsigned int delay_ms1);
void lcd_strob(void);
void lcd_write(unsigned char);
void lcd_cmd(unsigned char i);
void lcd_string(unsigned char s[],unsigned char len);
void lcd_stringc(void);
void lcd_config(void);

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

unsigned const char daq_str[][32] = {    “DATA ACQUISITIONSYSTEM     -IDDC”,
“2.MONITR 3.RATE 4.SEQ 5.OP 6.MEM”,
“CHANNEL#:       PV:             “,
“SAMPLING RATE:                  “,
“SET CHANNEL SEQ:                “,
“1.MEM 2.SERIAL ?                “,
“CH   DATA   UP:7                ”    };
unsigned const char message[][16] = {    “MEMORY STORAGE  “,
“SERIAL INTERFACE”,
“IS SELECTED.    “,
“FULL            “,
“UPLOADING   DATA”    };
unsigned char input[16];
unsigned char disp_index=0;

unsigned int i;

void main()
{

lcd_config();    // initialise lcd  in 4 bit

lcd_cmd(cursor_underline);    // cursor will be displayed as underline not blinking
disp_index = 0;
lcd_stringc();   // DISPLAY THE daq_str[disp_index] string on lcd

while(1);
}

void lcd_strob(void)
{
LCD_EN=1;
delay_5us(2);
LCD_EN=0;
}

void lcd_config(void)
{
data_tris = 0x00;
__delay_ms(5);

LCD_EN=0;                    //enable lcd
LCD_RS=0;                    //set to instuction mode

lcd_cmd(0x38);
__delay_ms(5);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);
lcd_strob();

lcd_cmd(0x28);
delay_5us(45);

lcd_cmd(0x01);            //clear lcd scren
delay_5us(25);
lcd_cmd(0x0f);            //set entry mode
}

void lcd_write(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 1;
delay_5us(25);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp)|(0x04);

lcd_strob();
delay_5us(100);

data_temp = data & 0x03;
data = (i<<4) |(data_temp)|(0x04);

lcd_strob();
}
void lcd_cmd(unsigned char i)
{
unsigned char data_temp;
LCD_RS = 0;
delay_5us(30);

data_temp = data & 0x03;
data = (i & 0xf0)|(data_temp);

lcd_strob();
delay_5us(150);

data_temp = data & 0x03;
data = (i<<4) |(data_temp);

lcd_strob();
}

void lcd_string(unsigned char s[],unsigned char len)
{
unsigned char k;
for(k=0;k<len;k++)
{
lcd_write(s[k]);
}
}

void lcd_stringc(void)
{
unsigned char k;
lcd_cmd(putline1);
for(k=0;k<32;k++)
{
if(k==16) lcd_cmd(putline2);
lcd_write(daq_str[disp_index][k]);
}
}

void delay_5us(unsigned int delay_us1)
{
unsigned int ui,um;
for(ui = 0; ui<delay_us1; ui++);
}

*************************END OF PROGRAM**************************

<<previous                                                                                                                    Next>>

(8) GUI of DATA ACQUISITION SYSTEM in Visual Basic that can communicate with our hardware through serial port

So far from the post(1) to post(7) I gave you the idea how one can proceed to design a data acquisition system with serial interface.

Now, Our system needs the Graphical User Interface.

I have developed a GUI in visual basic 6.0.  To download the GUI click here

Extract the GUI DATA ACQUISITION SYSTEM.RAR file.You must have Visual Basic installed in your system. Open Project1 and Run this project by pressing F5.

You will see following window on your computer screen.

GUI Snap Shot

When our hardware is connected to serial port. First select the comport and press “Start” button. Then Switch on the hardware.

The PIC16F877A will start sampling data from the channels specified at internal EEPROM (locations : 0x03 onwards) at the sampling rate determined by the CCPR1 value (loaded from EEPROM locations 0x01, 0x02).

From controller side, the sampled data is continuously via serial interface. every sample is sent to GUI as two bytes. Firstly ADRESL and then (ADRESH | adc_last_channel).

At the other end GUI will identifies channel number and also calculates the actual value of signal and updates the appropriate channel viewer part in GUI.

Up on reception of every sample GUI will

  1. Updates value in Present Value Box.
  2. Updates Current trend (graph of recent 50 samples).
  3. Appends the new value in file Database.mdb.
  4. Checks if it has crossed any limits. If it is above high limit or below low limit then it flash the alarm indicator and also generates alarm sound if you have connected speaker to your computer.

History Trend button is provided to see graph of entire database.

You can adjust channel sequence and send new sequence by clicking on send button (->). On clicking send button it will automatically send 0x11, channel numbers you provide (if you provided 1234 then 0x01,0x02,0x03,0x04), 0x11. This is the rules by which our hardware understands that coming data is to change the sampling sequence(As discussed in previous post). At controller side, channel numbers  (0x01,0x02,0x03,0x04) are stored in EEPROM at address starting at 0x03 and after storing last channel number it puts 0xff value in next location.

You can adjust sampling rate of ADC and send it to controller. On clicking send button it will automatically calculates the required value of CCPR1 to achieve the sampling rate specified. It displays the actual rate achieved next to it. Three bytes : 0x55 , value for CCPR1H , Value for CCPR1L are sent to PIC16F877A(Rules we defined in previous post). At controller side, values of CCPR1H, CCPRL are stored at locations 0x01 and 0x02. and also loaded to CCPR1H and CCPR1L of controller so as to take effect immediately.

We now finished the data acquisition and serial transmission and GUI parts of project. Now its time to move on the next part. Suppose we dont have computer at the time of acuisition. Then we need to have on board memory storage to store the sampled data, on board LCD and Keyboard to configure Acquisition parameters and interact with user.

In next post, we will see the interfacing of 16×2 LCD display to PIC16F877A.

<<previous                                                                                                      Next>>

(7) Data acquisition program using PIC16F877A, Sampling rate and Sampling sequence can be configured via serial commands.

As we discussed in previous post, we already developed a program that is taking the CCPR1H and CCPR1L values for sampling rate , and the channel sequence in which they are scanned are taken from internal eeprom of PIC16F877A.

Only change required to make a complete Data Acquisition System which can be set to sample at any desired sampling rate and channel sequence is that we should be able to modify the data in the internal eeprom from some serial commands.

T1CON value is loaded from location 0x00.

CCPR1H value is loaded from location 0x01.

CCPR1L value is loaded from location 0x02.

Channel sequence will be stored from location 0x03 onwards with 0xFF value after last channel number to specify repeatation.

Here we are keeping T1CON value fixed to 0x30 –> Timer 1 prescaler is set to 1:8.

Lets make certain rules through which it accept serial data and interpret it correctly.

To change CCPR1H and CCPR1L value from serial –> send 0x55 first, then value of CCPR1H, then finally CCPR1L.

To change channel sequence –> First send 0x11 to specify the start of receiving channel numbers, then one bye one send the channel numbers in order in which they needs to be scanned, then at the end send ox11 again to specify end of reception of channel sequence.

************************************************************************

Program

************************************************************************

#include<htc.h>

__CONFIG(0X3F3A);

#define _XTAL_FREQ 11059200

// prescaler byte 00 1, 10 2, 20 4, 30 8
__EEPROM_DATA(0x00,0x0f,0xff,0x00,0xFF,0xFF,0xFF,0xFF); // 0x00 0x01 0x30
void uart_init(void);
void TX(unsigned char TX_BYTE);
bit channel_receive = 0, ccp_receive = 0, config = 0;
unsigned char rx_data=0,eeprom_address = 0;

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data);

const char ADCON0_value[8] = {0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39};
unsigned char adc_last_channel=0,adc_complete=0;

unsigned int i;
unsigned char show_pv = 0,view_channel = 0;

void main()
{
uart_init();

EEPGD = 0;    // 0 means EEPROM read write .. 1 means Program data
EEADR = 0;
//    EEPGD = 0;
RD = 1;
T1CON = EEDATA;

EEADR = 1;
RD = 1;
CCPR1H=EEDATA;

EEADR = 2;
RD = 1;
CCPR1L=EEDATA;

EEADR = 3;
RD = 1;
TRISA = 0xff;
TRISE = TRISE | 0X07;
ADCON1=0x80; // data right justified. 8 adc channels

ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
ADIE =1;

TRISD = 0xf0;
PORTD = 0X0F;

GIE =1; PEIE =1;

CCP1IE =0; // AVOID FALSE INTERRUPT WHILE CHANGING CAPTURE MODE
CCP1CON = 0X0B; // CCPxIF sets, ADC conversion starts,TMR1 resets.
CCP1IE =1;

TMR1ON = 1; // TMR1 start, fosc/4

while(1)
{
if(adc_complete && config == 0)
{
TX(ADRESL);
TX(ADRESH | (adc_last_channel << 4));
adc_complete = 0;
}
}
}

void eeprom_write1(unsigned char eeprom_add, unsigned char eeprom_data)
{
GIE = 0;
EEADR = eeprom_add;
EEDATA = eeprom_data;
WREN = 1;
EECON2 = 0x55;
EECON2 = 0xAA;
WR = 1;
WREN = 0;
while(WR == 1);
GIE = 1;
}
void interrupt receive(void)
{
if(RCIE && RCIF)
{
RCIF = 0;
rx_data = RCREG;
if(rx_data == 17 && !channel_receive)
{
ADIE = 0;
TMR1ON = 0;
channel_receive = 1;
config = 1;
eeprom_address = 3;
}
else if(rx_data == 17 && channel_receive)
{
eeprom_write1(eeprom_address,0xFF);
EEADR = 0x03;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
channel_receive = 0;
config = 0;
ADIE = 1;
TMR1ON = 1;
}
else if(rx_data == 0x55 && !ccp_receive)
{
ADIE = 0;
TMR1ON = 0;
ccp_receive = 1;
config = 1;
eeprom_address = 1;
}
else if(ccp_receive)
{
eeprom_write1(eeprom_address,rx_data);
eeprom_address++;
if(eeprom_address == 3)
{
EEADR = 0;
RD = 1;
T1CON = EEDATA;

EEADR = 1;
RD = 1;
CCPR1H = EEDATA;

EEADR = 2;
RD = 1;
CCPR1L = EEDATA;

TMR1ON = 1;

EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;
ccp_receive = 0;
config = 0;
ADIE = 1;
TMR1ON = 1;
}
}
else if(channel_receive)
{
eeprom_write1(eeprom_address,rx_data);
eeprom_address++;
}
else if(rx_data == 0xff)
{
GIE = 0;

EEADR = 0;
RD = 1;
TXREG = 0xF1;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 1;
RD = 1;
TXREG = 0xF2;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 2;
RD = 1;
TXREG = 0xF3;    while(!TRMT);//    TXIF =0;
TXREG = EEDATA;    while(!TRMT);//    TXIF =0;
for(i=0;i<1000;i++);

EEADR = 3;
RD = 1;
ADCON0 = ADCON0_value[EEDATA];
ADIF =0;

TMR1ON = 1;
GIE = 1;
}
}
if(!channel_receive && !ccp_receive)
{
if(ADIE && ADIF)
{
adc_last_channel = EEDATA;
EEADR++;
RD = 1;
if(EEDATA == 0xFF)
{
EEADR = 3;
RD = 1;
}
ADCON0 = ADCON0_value[EEDATA];
ADIF = 0;
adc_complete = 1;
}
else if(CCP1IE && CCP1IF)
{
GODONE = 1;
CCP1IF = 0;
}
}
}

void uart_init(void)
{
TRISC7 = 1;
TRISC6 = 0;
SPBRG = 5;     // 115200 BRGH = 1; 11.0592 Mhz
//    SPBRG = 129; // 9600 brgh = 1; 20 Mhz
//    SPBRG = 64;  // 19200 brgh = 1; 20 Mhz
TXSTA = 0x24;
RCIE =1 ; GIE =1; PEIE =1;
RCSTA = 0x90;
}
void TX(unsigned char TX_BYTE)
{
while(!TRMT);
TXREG = TX_BYTE;
}

****************************END OF PROGRAM********************************************

You can simulate this program using PIC SIMULATOR IDE. Try sending 0x55 , 0x40, 0x00 to change sampling rate.

and try sending 0x11, 0x00, 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x11. to change channel sampling sequence. and see what happens.

You can also test this program in hardware. The following is the circuit diagram. I am using channel 0 and channel 2. you can use any channel. just you need to configure the system through serial commands as mentioned above.

Data Acquisition System

The above code is compiled with HiTech C compiler and is tested with the above hardware in real time.

In my post we will discuss about GUI of DATA ACQUISITION SYSTEM in Visual Basic that can communicate with our hardware through serial port. This GUI will automatically generates the commands to to change the sampling rate and sampling sequence. So our system will be very very easy to use.

<<previous                                                                                                          Next>>