|
|
View previous topic :: View next topic |
Author |
Message |
dam5091
Joined: 05 Apr 2009 Posts: 5
|
Need Help Programming PIC16F877 for MCP3202 |
Posted: Wed Apr 08, 2009 9:28 pm |
|
|
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
|
|
Posted: Thu Apr 09, 2009 11:52 am |
|
|
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
|
|
Posted: Sat Apr 11, 2009 2:41 pm |
|
|
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
|
|
Posted: Sun Apr 12, 2009 2:09 pm |
|
|
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
|
|
Posted: Tue Apr 14, 2009 12:49 pm |
|
|
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
|
|
Posted: Tue Apr 14, 2009 1:04 pm |
|
|
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
|
|
Posted: Tue Apr 14, 2009 1:19 pm |
|
|
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
|
|
Posted: Tue Apr 14, 2009 1:23 pm |
|
|
You're right. I didn't see that part. I'll study it. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 14, 2009 1:41 pm |
|
|
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
|
|
Posted: Tue Apr 14, 2009 2:12 pm |
|
|
Channel 0 in single ended mode. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 14, 2009 3:14 pm |
|
|
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
|
|
Posted: Wed Apr 15, 2009 2:56 pm |
|
|
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
|
|
Posted: Wed Apr 15, 2009 2:58 pm |
|
|
That was my code...sorry I forgot to log on |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 15, 2009 3:23 pm |
|
|
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
|
|
Posted: Wed Apr 15, 2009 3:35 pm |
|
|
i think your code just does not work. Thanks for the help d-bag |
|
|
|
|
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
|