CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Need Help Programming PIC16F877 for MCP3202
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dam5091



Joined: 05 Apr 2009
Posts: 5

View user's profile Send private message Send e-mail

Need Help Programming PIC16F877 for MCP3202
PostPosted: Wed Apr 08, 2009 9:28 pm     Reply with quote

I am having a problem trying to access my A/D converter over the bus. I'm using a MCP3202 A/D converter and a PIC16F877 controller. If there is anyone who can help this would be greatly appreciated. I did reference another code using the spi function. http://www.ccsinfo.com/forum/viewtopic.php?p=72138
Code:

void main()                               
{
   int8 msb,lsb;
   int16 result;
   float ad_pct;
   char string [4];

   setup_psp(PSP_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   
   output_high(PIN_B4);               //output high channel select
   setup_spi(SPI_MASTER|0x4000|SPI_CLK_DIV_16);   
   output_low(PIN_B4);                //output low channel select
   spi_write(192);                    //modify a/d Din
   delay_ms(30);

   while(TRUE)
   {
     msb = spi_read();
     lsb = spi_read();
     output_high(PIN_B4);               //output high channel select
     result = make16(msb, lsb);
     result &= 0x1FFE;
     result >>= 1;

     itoa (result , 16 , string);
     output_char(string[0], DIGIT_1);
     output_char(string[1], DIGIT_2);
     output_char(string[2], DIGIT_3);
     output_char(string[3], DIGIT_4);
     delay_ms(1000);
     
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Apr 09, 2009 11:52 am     Reply with quote

RW Young has posted a software SPI driver for the MCP3202 here:
http://www.ccsinfo.com/forum/viewtopic.php?t=7316&start=3

Take his code and put the following 3 lines at the start of it, and
then save it all as the file "mcp3202.c". Put the mcp3202.c file in
your project directory.
Code:

int16 read_mcp3202(int8 channel);
void write_spi_byte(int8 data, int8 num_bits);
int8 read_spi(int8 num_bits);


Then in your main source file for your project, put in the following code.
Make sure the hardware connections between your PIC and the MCP3202
are the same as is shown below.

I haven't tested this code in hardware, but it will probably work.
The code that you posted definitely will not work, so you should
try this code.
Code:

#include <16F877.H>
#device *=16
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define SPI_CLK  PIN_C3   // Connect to pin 7 (CLK) on MCP3202
#define SPI_DIN  PIN_C5   // Connect to pin 5 (Din) on MCP3202
#define SPI_DOUT PIN_C4   // Connect to pin 6 (Dout) on MCP3202
#define ADC_CS   PIN_B4   // Connect to pin 1 (\CS) on MCP3202

#include "mcp3202.c"

//====================================
void main()
{
int16 result;

// Read ADC channel 0 every 1/2 second and
// display the result in Hex format.
while(1)
  {
   result = read_mcp3202(0);   
   printf("%LX\n\r", result);
   delay_ms(500);
  }

}
dam5091



Joined: 05 Apr 2009
Posts: 5

View user's profile Send private message Send e-mail

PostPosted: Sat Apr 11, 2009 2:41 pm     Reply with quote

Quote:

Then in your main source file for your project, put in the following code.
Make sure the hardware connections between your PIC and the MCP3202
are the same as is shown below.

I haven't tested this code in hardware, but it will probably work.
The code that you posted definitely will not work, so you should
try this code.
Code:

#include <16F877.H>
#device *=16
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define SPI_CLK  PIN_C3   // Connect to pin 7 (CLK) on MCP3202
#define SPI_DIN  PIN_C5   // Connect to pin 5 (Din) on MCP3202
#define SPI_DOUT PIN_C4   // Connect to pin 6 (Dout) on MCP3202
#define ADC_CS   PIN_B4   // Connect to pin 1 (\CS) on MCP3202

#include "mcp3202.c"

//====================================
void main()
{
int16 result;

// Read ADC channel 0 every 1/2 second and
// display the result in Hex format.
while(1)
  {
   result = read_mcp3202(0);   
   printf("%LX\n\r", result);
   delay_ms(500);
  }

}



this code didn't work for us, but we don't know if our setup_spi() function is correct...any insight on this?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Apr 12, 2009 2:09 pm     Reply with quote

Your SPI mode value of 0x4000 gives you SPI Mode 0, which is correct
for the MCP3202. However, it's best not to use magic numbers.
It's better to put these constants above main(), and then delete the
0x4000 and put in SPI_MODE_0 instead.
Code:

#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)



Quote:
while(TRUE)
{
msb = spi_read();
lsb = spi_read();
output_high(PIN_B4); //output high channel select

You have to give spi_read() a parameter, to get the SCLK to be
generated. This is the CCS manual. Normally a parameter of 0 is used.

The MCP3202 has both "MSB first" and "LSB first" output formats
available. There might also be problems with your masking and bit-
shifting, depending on which format you're using. I didn't look at that
part of the problem.
dam5091



Joined: 05 Apr 2009
Posts: 5

View user's profile Send private message Send e-mail

PostPosted: Tue Apr 14, 2009 12:49 pm     Reply with quote

I tried the code posted and could not get it to work so i tried using the code below and got an output on the display. At 0V it will read 0 then count its way up to around 8000 bits then back down to 1000 up to 3840 when you vary the power supply up to 5V. We are referring to figure 6-1 and 6-2 on the MCP 3202 data sheet. If there is anyway you can help with this problem that would be very appreciated. We are trying to read from 0 to 4096 at 0 to 5V.

Data sheet for MCP3202 http://ww1.microchip.com/downloads/en/DeviceDoc/21034e.pdf

Code:
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_spi(SPI_MASTER|SPI_MODE_0| SPI_CLK_DIV_64);   
 
   while(TRUE)
   {
   output_high(PIN_B4);
   delay_ms(4);
   output_low(PIN_B4);
   spi_write(00000001);
   msb=spi_read(0x00);
   spi_write(10000000);
   
   lsb=spi_read(0x00);
   output_high(PIN_B4);
 
   
   
   result= make16(msb,lsb);
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 14, 2009 1:04 pm     Reply with quote

Quote:
while(TRUE)
{
output_high(PIN_B4);
delay_ms(4);
output_low(PIN_B4);
spi_write(00000001);

What is the purpose of writing 00000001 to the chip ?

Quote:
msb=spi_read(0x00);
spi_write(10000000);

lsb=spi_read(0x00);
output_high(PIN_B4);

Here, you're attempting to write 10 million to the chip.
If you want binary notation, you must prefix the number with "0b".

You should be trying to make your bit protocol look like this timing
diagram in the MCP3202 data sheet:
Quote:
FIGURE 5-1: Communication with the MCP3202 using MSB first format only.

You are trying to use hardware SPI with this chip. The data sheet doesn't
say that you do leading or trailing zero-bits in the 4-bit command word.
But that's what you're trying to do. The software based driver that I
gave you a link to, does follow the data sheet.
dam5091



Joined: 05 Apr 2009
Posts: 5

View user's profile Send private message Send e-mail

PostPosted: Tue Apr 14, 2009 1:19 pm     Reply with quote

Figure 6.1 and 6.2 of page 15 of the datasheet show the configuration needed for programming using a microcontroller. We also added the 0b in front of the binary input and we still get the same result. We also tried the driver that you had previously posted and it gave us nothing for an output.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 14, 2009 1:23 pm     Reply with quote

You're right. I didn't see that part. I'll study it.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 14, 2009 1:41 pm     Reply with quote

I assume you are using Single-ended mode. Which channel do you
have connected to your analog signal on the MCP3202. Is CH0 or CH1 ?
Guest








PostPosted: Tue Apr 14, 2009 2:12 pm     Reply with quote

Channel 0 in single ended mode.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 14, 2009 3:14 pm     Reply with quote

I think this code will match the protocol shown in Figure 6-1 in the
MCP3202 data sheet:
Code:
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

#define MCP3202_CS  PIN_B4

int16 read_mcp3202(int8 channel)
{
int8 lsb, msb;
int8 cmd;
int16 result;

// In single-ended mode, the Odd/Sign bit selects the channel.
if(channel)
   cmd = 0xE0;  // SGL = 1, CH = 1, MSBF = 1
else
   cmd = 0xA0;  // SGL = 1, CH = 0, MSBF = 1

output_low(MCP3202_CS);
spi_write(0x01);       // Send start bit
msb = spi_read(cmd);
lsb = spi_read(0x00);
output_high(MCP3202_CS);

result = make16(msb, lsb);
return(result);
}

//====================================
void main()
{
int16 result;

output_high(MCP3202_CS);
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_16);
delay_ms(10);

// Read ADC channel 0 every 1/2 second and
// display the result in Hex format.
while(1)
  {
   result = read_mcp3202(0);   
   printf("%LX\n\r", result);
   delay_ms(500);
  }

}
Guest








PostPosted: Wed Apr 15, 2009 2:56 pm     Reply with quote

Here is my complete code. I am trying to read 0 to 4096 bits over the spi bus when varying a 0 to 5V input. The other part is using a zero pushbutton holding it in for 10 seconds and then displaying the number 500 to varify that the push button works. I tried implimenting your code and something is not right, I am not getting any output on the display at all when adding your code. Im sorry for the bother and posting the entire thing, but I would like you to see what I am doing completely and see if there is anything you can catch that I am doing wrong. Thanks again.
Code:
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use spi (DI=PIN_C5, DO=PIN_C4, CLK=PIN_C3)

#include <stdlib.h>
#define DIGIT_1 PIN_B3
#define DIGIT_2 PIN_E0
#define DIGIT_3 PIN_E1
#define DIGIT_4 PIN_E2
#define DECIMAL PIN_D0
#define ZERO_PB PIN_C1
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#define SPI_CLK PIN_C3
#define SPI_DIN PIN_C5
#define SPI_DOUT PIN_C4
#define ADC_CS PIN_B4
#define MCP3202_CS  PIN_B4 //might not need
//#include "mcp3202.c"

void output_char(char c, int8 digit)
{
  if (c == 'e') // 'e' == empty, aka don't output anything
  {
   output_low(digit);
   return;
  }
  if (digit == DIGIT_1)
   {
      output_low (DIGIT_2);
      output_low (DIGIT_3);
      output_low (DIGIT_4);
   }
   if (digit == DIGIT_2)
   {
      output_low (DIGIT_1);
      output_low (DIGIT_3);
      output_low (DIGIT_4);
   }
   if (digit == DIGIT_3)
   {
      output_low (DIGIT_1);
      output_low (DIGIT_2);
      output_low (DIGIT_4);
   }
   if (digit == DIGIT_4)
   {
      output_low (DIGIT_1);
      output_low (DIGIT_2);
      output_low (DIGIT_3);
   }
   output_high(digit);
   if (c == '0')            //Digit0
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_low(PIN_D3);   //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_high(PIN_D1);  //SegmentG
   }
   
   if (c == '1')            //Digit1
   {
      output_high(PIN_D7);  //SegmentA 
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_high(PIN_D4);  //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_high(PIN_D2);  //SegmentF
      output_high(PIN_D1);  //SegmentG
   }
   
   if (c == '2')            //Digit2
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_high(PIN_D5);  //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_low(PIN_D3);   //SegmentE
      output_high(PIN_D2);  //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '3')            //Digit3
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_high(PIN_D2);  //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '4')            //Digit4
   {
      output_high(PIN_D7);  //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_high(PIN_D4);  //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '5')            //Digit5
   {
      output_low(PIN_D7);   //SegmentA
      output_high(PIN_D6);  //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '6')            //Digit6
   {
      output_low(PIN_D7);   //SegmentA
      output_high(PIN_D6);  //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_low(PIN_D3);   //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '7')            //Digit7
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_high(PIN_D4);  //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_high(PIN_D2);  //SegmentF
      output_high(PIN_D1);  //SegmentG
   }
   
   if (c == '8')            //Digit8
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_low(PIN_D3);   //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
   
   if (c == '9')            //Digit9
   {
      output_low(PIN_D7);   //SegmentA
      output_low(PIN_D6);   //SegmentB
      output_low(PIN_D5);   //SegmentC
      output_low(PIN_D4);   //SegmentD
      output_high(PIN_D3);  //SegmentE
      output_low(PIN_D2);   //SegmentF
      output_low(PIN_D1);   //SegmentG
   }
}

void test_display()
{
   char flip [11] = {"0123456789"};
   int8 index = 0;
   while(TRUE)
   {
      delay_ms(1000);
      output_char(flip[index], PIN_E0);
      if (index < 10)
         index++;
      else
         index = 0;
   }
}
char *i32toa(int32 n, char *s) {
  int8 i,j;                    //decade counter
  int8 idx=0;                  //string index     
  int32 const Div[10] = {      //decades table
    1000000000L,100000000L,10000000L,1000000L
    100000L,10000L,1000L,100L,10L,1};   
  int32 b;                     //i32 to hold table read                           
  int fdd;                     //first digit detect (suppress leading zero function)
 
  fdd=0;                       //clear detection
  if (bit_test(n,31)) {        //T: n=negative
    n=(~n)+1;                  //convert to positive
    s[0]='-';                  //mark the negative number
    idx++;
  } 
 
 
  for (i=0; i<10;i++) {        //do all the decades, start with biggest
    j=0;                       //clear the decimal digit counter
    b=Div[i];                  //read the table once;
    while (n>=b) {             //T: "left-over" still bigger then decade; substr. and count
      j++;
      n-=b;
    } 
    if ((j)||(fdd)) {          //T: decade count!=0 or first digit has been detected
      fdd=1;
      s[idx++]='0'+j;          //..then add the decade count
    } 
  }

  if (!fdd) s[idx++]='0';      //dont suppress zero when n==0!
  s[idx]=0;                    //end the string
  return(s+idx);               //return last written pointer
}

void pretty_print(int16 output_integer , char string[])
{
   // case 1: 3 digits, shift everyone right 1 spot and
   // fill first position with 'e' (empty)
   if (output_integer < 10)
      {
      string[3] = string[0];
      string[2] = 'e';
      string[1] = 'e';
      string[0] = 'e';
      }
   else if (output_integer < 100)
      {
      string[3] = string[1];
      string[2] = string[0];
      string[1] = 'e';
      string[0] = 'e';
   }

   else if (output_integer < 1000)
   {
      string[3] = string[2];
      string[2] = string[1];
      string[1] = string[0];
      string[0] = 'e';
   }

}
int16 read_mcp3202(int8,channel)
{
   int lsb,msb;
   int8 cmd;
   int16 result;
   float ad_pct;
   char string [5]={"eeee"};
   
// In single-ended mode, the Odd/Sign bit selects the channel.
if(channel)
   cmd = 0xE0;  // SGL = 1, CH = 1, MSBF = 1
else
   cmd = 0xA0;  // SGL = 1, CH = 0, MSBF = 1
   
output_low(PIN_B4);
spi_write(0x01);  // Send start bit
delay_ms(4);
msb=spi_read(cmd);         
lsb=spi_read(0x00);         
output_high(PIN_B4);
result= make16(msb,lsb); 
string[0]='e';
string[1]='e';
string[2]='e';
string[3]='e';   
delay_ms(500);
return(result);
}

void main()                               
{
//initialize all variables here before setup functions or will not work
 
   int16 result;
   int32 zero_count = 0, zero_point = 0;
   float ad_pct;
   char string [5]={"eeee"};
   

   output_high(PIN_B4); 
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);

   setup_spi(SPI_MASTER|SPI_MODE_0| SPI_CLK_DIV_16);
   delay_ms(10);
   
 
   while(TRUE)
   {
      result = read_mcp3202(0,0);
      delay_ms(500);
   }

 ///This is the loop for processing the zero push button   
     while (!input(ZERO_PB))
     {
        // turn all digits off
        output_low(DIGIT_1);
        output_low(DIGIT_2);
        output_low(DIGIT_3);
        output_low(DIGIT_4);
        while (zero_count < 49)   //Waits 10 seconds
        {
            delay_ms(1000);  // wait 1 sec
            zero_count++;
        }
        if (zero_count >= 49) 
            {
              zero_point = 500;  // set zero point based on our spi read value
              i32toa(zero_point, string);
              pretty_print (zero_point,string);
              output_char(string[0], DIGIT_1);
              delay_ms(5);
              output_char(string[1], DIGIT_2);
              delay_ms(5);           
              output_char(string[2], DIGIT_3);
              delay_ms(5);
              output_char(string[3], DIGIT_4);
              delay_ms(5);
            }
               }
                  zero_count = 0;
                  i32toa (result , string);
                  output_char(string[0], DIGIT_1);
                  delay_ms(5);
                  output_char(string[1], DIGIT_2);
                  delay_ms(5);
                  output_char(string[2], DIGIT_3);
                  delay_ms(5);
                  output_char(string[3], DIGIT_4);
                  delay_ms(5);
               
             
}
dam5091



Joined: 05 Apr 2009
Posts: 5

View user's profile Send private message Send e-mail

PostPosted: Wed Apr 15, 2009 2:58 pm     Reply with quote

That was my code...sorry I forgot to log on
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Apr 15, 2009 3:23 pm     Reply with quote

Quote:
int16 read_mcp3202(int8,channel)
{

result = read_mcp3202(0,0);

You have changed the parameter list in my routine to use two parameters
by adding a comma unnecessarily. I don't know why you did this.

You have added tons of application code when you don't even have
basic operation of the device.

Basically, whenever code that has a good chance to work, doesn't work,
instead of looking for reasonable problem such as bad connections,
you instead switch to your own very large buggy code, which has no
chance to work.

I don't want to work on this anymore.
Guest








PostPosted: Wed Apr 15, 2009 3:35 pm     Reply with quote

i think your code just does not work. Thanks for the help d-bag
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group