Jump to content

16F876

EstablishedMember
  • Content Count

    10
  • Joined

  • Last visited

Posts posted by 16F876

  1. Finally got this thing to work. Problem is threefold.

    1) The AD7706 needs a reset in the beginning. RB2 is tied to the reset and kept low for a while(reset) and then brought high to activate the chip again.

    2) Polling the DRDY bit I could not get to work. So finally I polled the DRDY pin on the AD7706 and that worked.

     

    This I thought would work, but it did not:

    void DRDYX(void)						//Data from ADC Ready?
    {	delay_ms(1);
    SpiSend(0x08);						//08h, Write to Comm register to read(poll) DRDY(Bit7)in comm register
    SpiSend(0x0);
    while(sspbuf&0x80)		        //Constantly poll com reg to see when write done(bit 7=0)
    	{SpiSend(0x08);				//08h, Next operation a read from COM register
    	 SpiSend(0x0);
    	}
    }

    This did work by polling the actual pin and not reading the registry.

    void DRDY(void)						//Data from ADC Ready?
    {	delay_ms(1);
    while (portb&0x02)				//portb,1 as input, DRDY goes low when ready
    ;	
    }

     

    3) It seems like the channel that is to be enquired needs to be calibrated before every enquiry.

     

    void serial (void)					//RS232's 'send' of a character- used by outserial()
    {	while( pir1&0x10==0 )			//Test bit 4
             {  nop();}
    	txreg=send;
    	break;
    
    }
    
    void outserial (void)				//RS232 Serial out
    {	unsigned char zz;
    for ( zz=0; zz<7;zz++ )
    {send=out[zz];					
    serial();
    } 
    }
    
    void CheckBF (void)					//Check if data was sent and answer received(Buffer Full)
    {while(sspstat&0x01==0)				//BF bit(0) is set once data was sent and new data received
    ;
    }
    
    void SpiSend (unsigned char SendA)	 	//Send SPI command and get answer-8 bit
    { 	sspbuf=SendA;					//Send command
    CheckBF();						//Check buffer full
    }
    
    
    
    void DRDY(void)						//Data from ADC Ready?
    {	delay_ms(1);
    while (portb&0x02)				//portb,1 as input, DRDY goes low when ready
    ;	
    }
    
    void SetupAD77061(void)
    {SpiSend(00100000b);   		 //(20h)(32 dec) Write to Clock Register, Chan0
    SpiSend(00000100b);		//(04h)(4 dec)-0,0,0,0,CLK=1(bit2), rest zero,50HZ filter 
    SpiSend(00010000b);		//(10h)(32 dec)Write operation to setup register,Channel 1
    SpiSend(01000100b);		//(46h)(70 dec)(0,1)Self Calibration, (0,0,0)gain=1, (1)Unipolar, UNbuffered
    DRDY();					//Test to see when calibration complete
    }
    
    void SetupAD77062(void)
    {SpiSend(00100001b);    //(21h)(33 dec) Write to Clock Register, Chan1
    SpiSend(00000100b);		//(04h)(4 dec)-0,0,0,0,CLK=1(bit2), rest zero,50HZ filter 
    SpiSend(00010001b);		//(11h)(33 dec)Write operation to setup register,Channel 2
    SpiSend(01000100b);		//(46h)(70 dec) (0,1)Self Calibration, (0,0,0)gain=1, (1)Unipolar, UNbuffered
    DRDY();					//Test to see when calibration complete
    }
    
    void SetupAD77063(void)
    {SpiSend(00100011b);    //(23h)(35 dec) Write to Clock Register
    SpiSend(00000100b);		//(04h)(4 dec)-0,0,0,0,CLK=1(bit2), rest zero,50HZ filter 
    SpiSend(00010011b);		//(13h)(35 dec)Write operation to setup register,Channel 3
    SpiSend(01000100b);		//(46h)(70 dec) (0,1)Self Calibration, (0,0,0)gain=1, (1)Unipolar, UNbuffered
    DRDY();					//Test to see when calibration complete
    }
    
    void ADC (void)	 	//Send SPI command and get answer-8 bit
    { 	SpiSend(0x0);
    out[3]=sspbuf;
    SpiSend(0x0);
    out[4]=sspbuf;
    }
    
    void Whatisthevalue (void)	 	//
    { 	SetupAD77061();
    SpiSend(0x38);
    ADC();
    outserial();
    SetupAD77062();
    SpiSend(0x39);
    ADC();
    outserial();
    SetupAD77063();
    SpiSend(0x3B);
    ADC();
    outserial();
    }
    
    
    
    void main (void)
    {	setup ();
    Whatisthevalue();	
    sleep();
    }

  2. I am getting there slowly.

     

    Because the SPI is hardware driven I was under the impression that the chip would know when to receive answers or that the slave chip would tell the main chip to receive data. Well it does not work that way.

     

    After the chip is asked a question of which you want an answer, the data has to be "clocked out" of the chip being interrogated. This can be done by sending a dummy data to the chip.

     

    By sending a zero(0) by hardware SPI, clock cycles will be provided in exactly the same way to the slave chip, as it would if you where to "clock out"(bit bang) an answer in software.

     

    Previously I did not notice that the SPI clock was working because the burst of the clock is so quick. Not until I put the SPI in a loop did I see on the scope that the clock signal is operating.

     

    The code is still not working, but I am getting closer I think. If anybody can give me a clue as to what I am doing wrong it will be great.

     

    Thank you.

    Louis

     

    void SerialReset(void)     //This part is supposed to reset the AD7706- provides 32 clock cycles
    {set_bit(portc,3);		//Clock High
    set_bit(portc,5);		//SDO high
    unsigned char j;
    for ( j=0; j<64;j++ )
    {
    clear_bit(portc,3);					
    set_bit(portc,3);
    }
    clear_bit(portc,5);
    } 
    {set_bit(portc,3);		//Clock High
    set_bit(portc,5);		//SDO high
    unsigned char j;
    for ( j=0; j<64;j++ )
    {
    clear_bit(portc,3);					
    set_bit(portc,3);
    }
    clear_bit(portc,5);
    } 
    
    void CheckBF (void)					//Check if data was sent and answer received(Buffer Full)
    {while(sspstat&0x01==0)			//BF bit(0) is set once data was sent and new data received
    ;
    }
    void SpiA (unsigned char SAnsw)	 		//Send SPI command and get answer-8 bit
    { 	dummy=sspbuf;					//Clear trash
    WCOL=0;							//Clear Write collision
    sspbuf=SAnsw;
    CheckBF();						//Check buffer full
    sspbuf=0;						//Dummy data clocks out answer
    CheckBF();	
    }
    void DRDY(void)						//Data from ADC Ready?
    {	SpiA(0x08);			//08h, Write to Comm register to read(poll) DRDY(Bit7)in comm register
    while(sspbuf&0x80)		        //Constantly poll com reg to see when write done(bit 7=0)
    	{SpiA(0x08);		//08h, Next operation a read from COM register
    	}
    }
    
    void SpiCommand (unsigned char SAnsw)	//Send SPI command and expect no answer
    { 	dummy=sspbuf;						//Clear trash
    WCOL=0;								//Clear Write collision
    sspbuf=SAnsw;
    CheckBF();
    }
    
    
    void SpiChan (unsigned char SAnsw)	//Send SPI command for channel and clock out 16bit answer
    { 	dummy=sspbuf;					//Clear trash
    WCOL=0;							//Clear Write collision
    sspbuf=SAnsw;					//Write channel number to Data register
    CheckBF();						//Check buffer full after channel selected?
    DRDY();							// Is data ready?
    sspbuf=0;						//Dummy data clocks out first 8 bits
    CheckBF();
    out[3]=sspbuf;					//MSB
    sspbuf=0;						//Provides clock cycles to clock out last 8 bits
    CheckBF();						//Check buffer full
    out[4]=sspbuf;					//LSB	
    }
    
    void SetupAD7706(void)
    {SpiCommand(00100000b);   	 //(20h) Write to Clock Register
    SpiCommand(00000100b);			//(04h)-0,0,0,0,CLK=1(bit2), rest zero,50HZ filter 
    SpiCommand(00010000b);			//(10h)Write operation to setup register,Channel 1
    SpiCommand(01000110b);			//(44h) (0,1)Self Calibration, (0,0,0)gain=1, (1)Unipolar, buffered
    DRDY();						//Test to see when calibration complete
    }
    
    void SPIADC (void)					//Read Data from channel x
    {	SpiChan(0x38);			//00111000b 38h, Bit3=1(read), data register 
    outserial();			//Data sent to PC via RS232
    }
    
    void GoMeasure (void)					//Normal display
    { 	while (1)
    {SPIADC();
    }
    
    void main (void)
    {	setup ();                                                 //Setup PIC
    SerialReset();					//Routine to reset chip
    SetupAD7706();
    GoMeasure();	
    sleep();
    }

  3. Hi

     

    I disabled the RS232 before the use of SPI with no success.

     

    At http://forum.microchip.com/tm.asp?m=48978&...32&anchor#48978 is says "The I2C/SPI interface, and the USART are totally seperate, and do not affect each other." So far I have not found any other reference to disabling the RS232 before SPI use, but then there is very little information on using both at the same time.

     

    What did you mean by

    because no specified in DS
    ?

     

    The Slave Select(SS) method is not used because the slave chip is hardwired as being selected.

     

    Thank you for your help I appreciate it.

  4. Hi there

     

    I am having trouble getting ADC values from an external AD7706( very similar to AD7705) IC to a PIC16F876 via SPI. The PIC is running at 4MHZ and the AD7706 is running at 2.4578 MHZ.

     

    I want to use the hardware SPI function(no bit banging) of the PIC and no interupts.

     

    I am trying to communicate to the external IC via SPI and want to report back to the computer via RS232. At the moment all the readings I get is zero and with my picoscope scope there seems to be no SPI data coming from the 16F876.

     

     

     

    void setup (void)
    {
    /* Setup*/
    trisa=101111b;				//make all portA input except RA4 output
    trisb=0;					//All output
    trisc=10010000b;			// make just RC7 input for RS232, RC5(SDO)=0,RC4(SS)=1,RC3(SCK)=0 and RC4 for SDI
    clear_bit (option_reg,NOT_RBPU);	// portb pullups enabled - normally set 
    clear_bit (pie1,7);			// Disables AD convert interupt 
    adcon1=10000000b; 			//Justify right,FOSC/8(0),(00), Set all to analogue input
    /*SetBaud for RS232*/
    clear_bit (intcon, GIE);		//disables global interupt
    clear_bit (intcon, PEIE);		// disables peripheral interupts
    clear_bit (intcon, INTE);      // disables all external interupts
    clear_bit (intcon, RBIE);		// disables all RB port interupts
    clear_bit (pie1,TXIE);			// clears interupt bit 
    portb=0;						//Clear port B outputs
    portc=0;						//clear portc
    spbrg=25;
    txsta=00000100b;				//Sync=0(bit4), brgh=1(bit2)
    rcsta=10010000b;  /*enables serial port, SPEN bit set-enables reception */
    set_bit (txsta, TXEN);			/* enables transmission */
    temp=rcreg;						//Clear receive register
    /* Setup SPI */
    pie1=0;				//Just to make sure all interupts are off
    intcon=0;			//Just to make sure all interupts are off
    sspcon=00110000b;	//SSPEN(5)=1,CKP(4) =1,Fosc/4(0001)
    sspstat=00000000b;          //CKE=0    
    dummy=sspbuf;				//Clear buffer
    }

    That was the setup part of the deal.

     

    Here follows the SPI nitty gritty.

    void CheckBF (void)					//Check if data was sent and answer received(Buffer Full)
    { while ((sspstat&0x01)==0)			//BF bit(0) is set once data was sent and new data received
    	{;}
    }
    
    void SendSpiA (unsigned char SAnsw)    //Send SPI command, keep answer
    { 	WCOL=0;	                              //Clear Write collision
    sspbuf=SAnsw;                         //Put command in sspbuf and send
    CheckBF();				//Check buffer full
    }
    
    void DRDY(void)					//AD7706 stuff -Data from ADC Ready?
    {	SendSpiA(00001000b);			//08h, Write to Comm register to read(poll) DRDY(Bit7)in comm register
    while(sspbuf&0x80)		        //Constantly poll communication register to see when write done(bit 7=0)
    {SendSpiA(00001000b);         	 //08h, Next operation a read from COM register
    	}
    }
    
    void SPIADC (void)					//Read Data from channel one
    {	DRDY();		                                   // Data ready?					
    SendSpiA(00111000b);		                //00111000b 38h, Bit3=1(read), data register 
    out[3]=sspbuf;
    out[4]=sspbuf;
    }
    
    void SetupAD7706(void)          //AD7706 setup stuff which does not seem to be sent
    {SendSpiA(00100000b);   	 //(20h) Write to Clock Register
    SendSpiA(00000100b);		//(04h)-0,0,0,0,CLK=1(bit2), rest zero,50HZ filter 
    SendSpiA(00010000b);		//(10h)Write operation to setup register,Channel 1
    SendSpiA(01000100b);		//(44h) (0,1)Self Calibration, (0,0,0)gain=1, (1)Unipolar
    Alive4();					//LED routine to confirm that we got this far
    }
    
    Void Testing(void)
    {//Code here that calls SPIADC and sends data via RS232
    }
    
    void main (void)
    {	setup ();
    SetupAD7706();
    Testing();	
    }

     

    The RS232 part works fine, but the SPI does not seem to work. Any help and clues will be appreciated.

  5. Dear nic_steph

     

    Data can be read when a command was written to read data ie you send the command to read something, and right after it was sent the answer should be available.

     

     

    uchar SpiRead(uchar value){
    uchar tmp;
    sspbuf = readcom; /*you put in here the command to read from certain register*/
    while(bf == 0); /*wait for transmission completed and answer received*/
    tmp = sspbuf; /*answer goes into tmp*/
    }

     

    Depending on the device you might have to send quite a few commands before a read, but as soon as the final read command was sent and BF is set then the answer should be in sspbuf and can be read,

     

    I am struggling with something similar so I hope that at least this little of what think I know is right.

  6. U = Uinput * 5 / 1,024

     

    You could multiply by 44, then divide by 9 to get a value that's roughly 0-5000 mV.

     

    My solution is so complicated that I would have gone with Steve's solution, but here goes:

     

    I get the ADC value in int multi.

     

    I multiply the value by 4.882 ( comes from 5000/1024, therefor 1023(+1) will be 5000) as follows:

     

    void Voltage (void)

    { multi=multi+1; // add one

    temp=multi*4;

    temp0=(multi*8)/10;

    temp1=(multi*8)/100;

    temp2=(multi*2)/1000;

    multi=temp+temp0+temp1+temp2;

    }

     

    Then I do the BCD extraction:

     

    void bcdext (void)

    {

    thou=multi/1000;

    multi=multi%1000;

    hund =(multi/100);

    multi=multi%100;

    tens=(multi/10);

    ones=(multi%10);

    thou=thou+48; //the 48 gets added to get the LCD value

    hund=hund+48;

    tens=tens+48;

    ones=ones+48;

    }

     

    Then I do rounding of the value so a ADC value of 1023 will show 5000 while a value of zero will still show 0.

     

    void roundd (void)

    {if (ones>(4+48)) //ie ones +48(to get LCD value)>4

    {tens=tens+1;

    /*if the LCD value for 9 increases by one it becomes the value for character ':' */

    if (tens>(9+48))

    {tens=(0+48);

    hund=hund+1;

    if (hund>(9+48))

    {hund=(0+48);

    thou=thou+1;}}}}

     

    This gives an adc value of 1023 a value of 5000.

  7. This following program does not compile with Sourceboost C2C Plus 5.3. It gives the error : Error: General error in function definition on line 72 which is exacltly the same as the code on line 78 namely, clear_bit (portc,RS) ;

     

    I have tried, output_low_port_c (RS); and clear_bit (portc,5); with no success. In general the code may be wrong for what I am trying to do, but it is the syntax that seems to be the problem. I have tried using hex instead of my prefered binary in some statements, but with no success.

     

    Please help me get this going.

     

     

    /* Trying to get to grips with this */

     

    #include <system.h>

    #define ebit 00010000b /*bit4*/

    #define RS 00100000b /*bit5*/

    #define rsmask 00110000b

    #define lcdstart_delay 1 /* 2500 */

    #define stndwrite_delay 1 /* 100 */

    #define clrlcd_delay 1 /*2000 */

     

    unsigned int place, celsius, ones, tens, hund, thou, tenk, temp0, temp1;

    unsigned int temp2, temp3, temp4, progno, ahi, amd, alo, bhi, bmd, blo, a1hi;

    unsigned int a1lo, b1hi, b1lo, multi0, multi1, h0, h1, h2;

    unsigned int sign, rscom, aargb2, aargb1, aargb0, factor, divide2;

    unsigned int divide3, product, product1, product2, product3, product4, product5;

    unsigned int zoom0, zoom1, loopcount, bargb0, bargb1, multipland, multipland1;

    unsigned int multipland2, multi2, c1hi, c1lo, d1lhi, d1lo, cntr1, x, y;

    unsigned int Zero, answer, Ba, avg ;

    unsigned char temp, disp;

     

    const unsigned char lcd_init [5] =

    {

    /* Display off */

    0x08,

    /* Display clear */

    0x01,

    /* Entry mode set */

    0x06,

    /* Display on/underline off-Blink off */

    0x0C,

    /* Function set big display */

    0x2C

     

    };

    const unsigned char message [5] =

    {

    'H', 'E', 'L', 'L', 'O'

    } ;

     

    void E (void)

    { portc=portc^0x08;

    stndwrite_delay();

    portc=portc^0xEF;

    }

    void IN (void)

    { temp=disp; /* move display to temporary */

    asm swapf(temp);

    temp= temp&0x0f;

    portc=temp;

    portc=portc^11100000b ;

    E();

    temp=disp;

    temp=temp&0x0F;

    portc =portc^0xE0;

    E();

    }

     

    void lcdstart (void)

    {

     

    clear_bit (portc,ebit); /* Clear Ebit */

    output_high_port_c (0x01); /* Function set--4 bits */

    E(); /* call E */

    stndwrite_delay();

     

    unsigned char i ;

    for ( i=0 ; i<5 ;i++ )

    {

    disp=lcd_init;

    IN();

    stndwrite_delay();

    }

    clear_bit (portc,RS) ; /* !!!!! Line 72 !!!!!! */

    }

     

     

    void display (void)

    {

    clear_bit (portc,RS); /* !!!!! Line 78 !!!!!!!!*/

    disp=0xC0; /* Display address 40 */

    IN();

    set_bit (portc,RS);

     

    unsigned char j ;

    for ( j=0 ; j<5 ;j++ )

    {

    disp=message[j];

    IN();

    stndwrite_delay();

    }

    output_low_port_c(RS);

    }

     

     

     

     

    void setup (void)

    {

     

    /* Setup*/

    trisa=0x17 ; /* make all port a except TA4 input*/

    trisb=0x1F ;

    clear_bit (option_reg,RBPU); /* portb pullups enabled - normally set */

    clear_bit (pie1,PSPIE); /* Disables AD convert interupt */

    trisc=0x80; /* make just RC7 input for RS232 */

    /*SetBaud*/

    clear_bit (intcon, gie); /*disables global interupt*/

    clear_bit (intcon, t0ie); /* disables peripheral interupts */

    clear_bit (intcon, inte) ; /* disables all external interupts*/

    clear_bit (intcon, rbie); /* disables all RB port interupts */

    portc=0; /*clear portc*/

    spbrg=0x19 ;

    txsta=0x04 ;

    clear_bit (pie1,txie) ; /* clears interupt bit */

    rcsta=0x90; /*enables serial port, SPEN bit set-enables reception */

    set_bit (txsta, txen); /* enables transmission */

    }

     

    void main (void)

     

    { setup () ;

    lcdstart ();

    display();

     

    }

×
×
  • Create New...