|
|
View previous topic :: View next topic |
Author |
Message |
jaethelegend Guest
|
MCP4921 showing weird behavior |
Posted: Mon Jun 15, 2009 12:07 am |
|
|
Please note that I have posted same problem to microchip forum.
I'm experimenting with the MCP4921 chip.
The code is supposed to copy the input voltage in B0 port and output the same voltage through DAC.
With Vss to Ground, Vref to 5V, LDAC to ground,
It shows strange behavior.
When I am expecting 5V, the output is 5V.
However, When I am expecting 0V, I get 2.5V.
In other words, the output range is pretty much halved.
With playing with Vref, I found out that the output voltage range is 0.5Vref~Vref with 12bit resolution.
So, with Vref = 5, and when I enter code for 1V output, I get 2.5+2.5/5 = 3V
Below is the coding
Code: |
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\Header\16f886.h>
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\Header\def_16f886.h>
#use delay(clock = 1000000)
#fuses INTRC_IO
#define CS PORTC6
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\project1\ADC2DAC\16by2flex_lcd.h>
int16 adc_in = 0;
int16 dac_out = 0;
int16 one_digit = 0;
int16 ten_digit = 0;
int16 hund_digit = 0;
int16 thou_digit = 0;
int16 disp_number = 0;
int8 high_byte = 0;
int8 low_byte = 0;
int8 dummy = 0;
void init_rtn(){
setup_adc(ADC_CLOCK_DIV_32);
ANSEL = 0x00;
ANSELH = 0x00;
SETUP_ADC_PORTS(SAN13);
TRISB5 = 1;
set_adc_channel(13);
lcd_init();
lcd_send_byte(1,CURSOR_OFF_BLINK_OFF);
lcd_gotoxy(1,1);
LCD_putc("Incoming Voltage");
lcd_gotoxy(7,2);
lcd_putc(".");
lcd_gotoxy(9,2);
lcd_putc("V");
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
TRISC6 = 0;
LDAC = 1;
CS = 1;
}
void bcd_rtn(int16 buffer){
thou_digit = buffer/1000;
buffer-=thou_digit*1000;
hund_digit = buffer/100;
buffer-=hund_digit*100;
ten_digit = buffer/10;
}
void disp_rtn(int16 buffer){
bcd_rtn(buffer);
lcd_gotoxy(6,2);
lcd_putc(ascii_num_tbl[thou_digit]);
lcd_gotoxy(8,2);
lcd_putc(ascii_num_tbl[hund_digit]);
lcd_gotoxy(9,2);
lcd_putc(ascii_num_tbl[ten_digit]);
}
void main(void){
init_rtn();
while(1){
adc_in = READ_ADC();
disp_number = adc_in*5;
disp_rtn(disp_number);
CS = 0;
dac_out = adc_in*4;
dummy = dac_out>>8;
dummy &= 0x0f;
high_byte = dummy|0x70;
low_byte = dac_out;
SPI_WRITE(high_byte);
SPI_WRITE(low_byte);
LDAC = 0;
delay_ms(100);
CS = 1;
}
}
|
Note that I have tried entering values directly in place of high_byte and low_byte for example,
Code: |
SPI_WRITE(0x70);
SPI_WRITE(0x00);
|
With this coding in place of
Code: |
SPI_WRITE(high_byte);
SPI_WRITE(low_byte);
|
I don't get 0V as an output but get 2.5V instead.
Anybody have idea??
Thanks |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Mon Jun 15, 2009 10:07 am |
|
|
This does not look correct:
Code: |
set_adc_channel(13);
|
How do you get 13 when this part only has 11 A/D channels? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 15, 2009 11:09 am |
|
|
Quote: | #use delay(clock = 1000000) |
Do you really want to run the internal oscillator at 1 MHz ?
Quote: | setup_adc(ADC_CLOCK_DIV_32); |
If so, 1/32 is not the correct divisor value for the ADC. Look in the
ADC section of the 16F886 data sheet to see the correct divisor.
Look in the 16F886.h file to see the list of divisor constants.
Quote: | setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4); |
You have setup the SPI module to use Mode 1. See the list below:
Code: | // SPI mode definitions.
#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) |
But the MCP4921 data sheet clearly says that it only supports
modes 0 or 3. It won't work correctly in Mode 1. Look on pages
18 or 19 of the data sheet to see this:
http://ww1.microchip.com/downloads/en/DeviceDoc/21897B.pdf
Also, your MCP4921 code is written "inline" instead of being made into
functions, so it's not easy to understand and it's also easy to make errors. |
|
|
jaethelegend Guest
|
Another question. |
Posted: Thu Jun 18, 2009 8:38 am |
|
|
Quote: | How do you get 13 when this part only has 11 A/D channels? |
It is true that there are only 11 channels for 16f886 but with 3 missing channels for corresponding channel numbers.
Another question for pcm programmer,
Using internal ADC doesn't seem to yield the expected value.
For example, with Vdd=5 as a reference, if I put in 2.5V, i do not get 1023*0.5 but something else.
Also, even after I switched the ADC frequency accordingly(actually, i have tried all different ADC clock frequencies), my incoming AD converted signal is very noisy(swings rapidly) even when the voltage is fed through precision calibrator.
The situation doesn't show improvement, when I change the reference voltage to external(which is also stable).
What is the problem? would using external ADC solve it? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 18, 2009 10:42 am |
|
|
Quote: | Using internal ADC doesn't seem to yield the expected value. |
Post a test program that shows how you are testing this. Example:
http://www.ccsinfo.com/forum/viewtopic.php?t=32168&start=1
Also post a description of the circuit which is driving the ADC input pin.
How do you know the voltage is 2.5 volts ? Have you used an
oscilloscope to look at the pin's voltage ? Is the voltage a DC level ?
Is it a steady level ? (always at 2.5 volts) |
|
|
jaethelegend Guest
|
|
Posted: Thu Jun 18, 2009 9:42 pm |
|
|
Here is the coding
Code: |
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\Header\16f886.h>
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\Header\def_16f886.h>
#use delay(clock = 1000000)
#fuses INTRC_IO
#define CS PORTC6
#define VinRef 1
#define VoutRef 2
#include<C:\Documents and Settings\Microsoft\My Documents\PIC\project1\ADC2DAC\16by2flex_lcd.h>
int16 adc_in = 0;
int16 dac_out = 0;
int8 one_digit = 0;
int8 ten_digit = 0;
int8 hund_digit = 0;
int8 thou_digit = 0;
int16 disp_number = 0;
int8 high_byte = 0;
int8 low_byte = 0;
int8 dummy = 0;
int8 counter = 0;
void init_rtn(){
//A/D converter initiation.
setup_adc(ADC_CLOCK_DIV_2);
ANSEL = 0x00;
ANSELH = 0x00;
SETUP_ADC_PORTS(SAN1);// Analog input is RA1 pin
TRISA1 = 1;
VCFG0 = 1; //External Vref+
set_adc_channel(1);
//LCD initiation.
lcd_init();
lcd_send_byte(1,CURSOR_OFF_BLINK_OFF);
lcd_gotoxy(1,1);
LCD_putc("Incoming Voltage");
lcd_gotoxy(7,2);
lcd_putc(".");
lcd_gotoxy(9,2);
lcd_putc("V");
//SPI Module initiation.
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_4); //Using SPI MODE 0
//Chip select initiation.
TRISC6 = 0;
CS = 1;
}
void bcd_rtn(int16 buffer){
thou_digit = (int16)buffer/1000;
buffer-=(int16)thou_digit*1000;
hund_digit = (int16)buffer/100;
buffer-=(int16)hund_digit*100;
ten_digit = buffer/10;
}
void disp_rtn(int16 buffer){
bcd_rtn(buffer);
lcd_gotoxy(6,2);
lcd_putc(ascii_num_tbl[thou_digit]);
lcd_gotoxy(8,2);
lcd_putc(ascii_num_tbl[hund_digit]);
lcd_gotoxy(9,2);
lcd_putc(ascii_num_tbl[ten_digit]);
}
void DAC_RTN(void){
CS = 0;
dac_out = adc_in*4;
dummy = dac_out>>8;
dummy &= 0x0f;
high_byte = dummy|0x70;
low_byte = dac_out;
SPI_WRITE(high_byte);
SPI_WRITE(low_byte);
CS = 1;
}
void main(void){
init_rtn();
while(1){
adc_in = READ_ADC();
disp_number = adc_in*5;
disp_rtn(disp_number);
DAC_RTN();
}
}
|
I am certain that the input voltage is 2.5V since it is generated by FLUKE 702 calibrator. I also measured it using another calibrator, while the voltage is fed through the voltage input. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 18, 2009 11:13 pm |
|
|
Post your compiler version. |
|
|
jaethelegend Guest
|
Compiler version |
Posted: Fri Jun 19, 2009 2:47 am |
|
|
It is 4.057. (PC B,M,H,D) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 19, 2009 2:57 pm |
|
|
I installed vs. 4.057 and compiled the test program shown below.
I set the AN0 pin to 2.50 volts, and checked it with a voltmeter.
The voltage is set with a 5K trimpot, with the knob set in the middle
position. The A/D converter is setup for default 8-bit output mode.
The program gives the following results, and it's correct:
Quote: | 127
127
127
127
127
127
127
127 |
You wanted to use INTRC at 1 MHz, so I did the same thing.
I had to reduce the baud rate to 4800, because 9600 will not give good
results with a 1 MHz clock.
Code: | #include <16F886.h>
#fuses INTRC_IO, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=1000000)
#use rs232(baud=4800, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//====================================
void main()
{
int8 result;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_2);
set_adc_channel(0);
delay_us(20);
while(1)
{
result = read_adc();
printf("%u \n\r", result);
delay_ms(500);
}
} |
|
|
|
|
|
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
|