• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

dsPIC30F6014a ADC

frahman3

Member
Hi,
I attached the program and changes made by considering inputs from members. Thank you so much. However, how can I avoid overflow for 12-bit ADC for voltage[value]=(ADC_value[value]/4095)*5?


Regards
FR
118301Hi,
CSS:
#use rs232(baud=9600,UART2)
#include <float.h>
#fuses HS, NOWDT, NOPROTECT, PUT64, BORV27
//correct - Power On Reset Timer value 64ms, Brownout reset at 2.7V
#use delay(clock=20000000)  //20 MHz crystal
#use rs232(baud=9600,UART2)
#define LED PIN_B10
//#define VSS_VDD
#define WDT_OFF=0



void main()
{

   setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3 | sAN4 | sAN5 | sAN6 | sAN7 | sAN8 | sAN9 | sAN10 | sAN11 | sAN12 | sAN13 | sAN14 | sAN15, VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_2);
  
   setup_adc_ports(ALL_ANALOG); 
   // Built-in A/D setup function
   setup_adc(ADC_CLOCK_INTERNAL); 
   // Built-in A/D setup function
 
   const int8 channel_1[]=1,2,3,4,5,6,7,8,9,10,11,12,13;       
   int16 ADC_value1[sizeof(channel_1)];   
   int16 value;
   float voltage[sizeof(channel_1)];

   //I/O ports configurations(1:input, 0:output)
   set_tris_a(0x0000);     //set port_a as output
   set_tris_b(0xFFFF);     //set port_b as analog input/ADC
   set_tris_c(0x0000);     //set port_c as output
   set_tris_d(0x0000);     //set port_d as output
   set_tris_f(0x0000);     //set port_f as output
   set_tris_g(0x0000);     //set port_g as output
  
  
   output_a(0x0000);       //clear port_a to all 0s
   output_c(0x0000);       //clear port_c to all 0s
   output_d(0xFFFF);       //clear port_d to all 1s-portD dafault at HIGH state
   output_f(0x0000);       //clear port_f to all 0s
   output_g(0x0000);       //clear port_g o all 0s

   while(TRUE)
   {
//pair 16_1
//sample start
            
//Excitation_pair 16_1 (+I)
      output_high(pin_G15);
      output_low(pin_A15);
//excitation_pair 16_1 (-I)
      output_low(pin_F0);
      output_high(pin_G0);
      delay_ms(2.5);
      
//S&H
      output_d(0b1100000000000001);
      
      for (value=0;value<sizeof(channel_1);value++)
      {
        set_adc_channel(channel_1[value]);
        ADC_value1[value]=read_adc();
        voltage[value] = (ADC_value1[value]/4095.0) * 5.0;
      }
      for(value=0;value<sizeof(channel_1); value++)
      {
      printf("%4.3f\r\n", voltage[value]);
      }
      printf("9.999\r\n");
      
   }
}
 

Pommie

Well-Known Member
Most Helpful Member
Use a 32 bit variable.
Code:
int32 newVar;
        newVar=ADC_value1[value];
        newVar*=5000;
        newVar/=4096;                    //note not 4095
        voltage[value] = newVar;        //voltage = 0 to 5000 I.E. mV
Mike.
Edit, Tided up code. Just out of bed and not had coffee yet so not got code head on!!!
if you want it as a float then add float volts=voltage[n]/1000.0;
 

Pommie

Well-Known Member
Most Helpful Member
You may need to cast some values.
Code:
int32 newVar;
        newVar=(int32)ADC_value1[value];
        newVar*=5000;
        newVar/=4096;                        //note not 4095
        voltage[value] = (int16) newVar;    //voltage = 0 to 5000 I.E. mV
Mike.
 

frahman3

Member
Hi,

This morning i encountered a problem with the hyper terminal which I'm using to display ADC data from dspic. Last Friday I tried to read the data from dspic with labview using port COM3 and it was able to display on the front panel in labview. For your information, I closed and exit the hyper terminal program before I opened labview and vice versa. Now both program are unable to display the data. In hyper terminal the message displayed "Another program is using the selected telephony device. Try again after the program completes". I exit all programs and restart my laptop several times but the message remains. Can anyone guide me how to solve this problem? I'm using windows 10.

Regards

FR
 

rjenkinsgb

Well-Known Member
Most Helpful Member
Check in device manager to make sure COM3 has no driver errors?

I've had similar errors in Realterm a couple of times when I've managed to crash it, but they can often be fixed by opening and closing the program & attempting to reconfigure the com port a couple of times, or simply rebooting.

A fault that persists through reboots and power cycling seems like a driver or hardware problem...

What is COM3? A plug-in serial card or a USB adapter?


Edit - if it is a USB device, check in device manager if the driver has auto updated. If t has, roll it back to the previous version.
There was a similar problem a few years ago with some USB serial devices..

If it's a USB serial adapter, is it a genuine FTDI type or a clone?
 

frahman3

Member
Hi,
Thank you for the reply. The devices i referring to is a USB serial adapter and its genuine FTDI type. What I did i clicked on control panel> hardware&sound> device and printer> FT232R usb uart> (right click) troubleshoot> follow instructions on screen. It works. Thanks for the guide.

Regards

FR
 

frahman3

Member
HI,

I have some other problem when read ADC data from the PIC. I created a program using for loop because I want to make sure I received all data according to how many loops i wanted. For example if I set the for loop to run 3 times (0,1,2) than on the hyper terminal I will received 3x9 data including 9.999 (marked as end of data for each iteration). But the problem is at the last iteration the data displayed less than 9. IS it because of the ADC
CSS:
#include <18F4580.h>
#device ADC=8
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define button (PIN_B0)

void main()
{
  setup_adc_ports(ALL_ANALOG); 
  setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_8);
  set_TRIS_B(0x0F);
 
  const int8 channel_1[] = 0,1,2,3,4,5,6,7;
 
  int start;
  int16 ADC_value1[sizeof(channel_1)];
  //int16 ADC_value[sizeof(channel_1)];
 
  int32 value1;
  int32 voltage[sizeof(channel_1)];
 
 
  SETUP_ADC_PORTS(ALL_ANALOG);
 
  //while(TRUE)
  for(start=0; start<=2;start++)// acquire 8 measurements in 10 ONLY
  {       
    LOOP1:
    if(input_state(PIN_B2) ==0)//if not pres==0, LED ON/OFF 0.5sec
    {
    delay_ms(100);
    output_b(00000000);
    delay_ms(100);
    output_b(11000000);
    
    goto LOOP1;
    //break;
    }
    else // if pressed (HIGH) start acquisition
    {
        
      // Collect ADC_DATA IN CHANNEL_1
      for(value1 = 0; value1 < sizeof(channel_1); value1++)
      // Read from 8 adc channels
      {
        
        set_adc_channel(channel_1[value1]);
        ADC_value1[value1] = read_adc();  // ADC readings
        delay_ms(500);
        voltage[value1] = ADC_value1[value1] * (5 / 4096);       
        // Convert ADC data to mV
        
      }

      // Print all ADC data
      for(value1 = 0; value1 < sizeof(channel_1); value1++)         
      // Display 8 voltage values
      {
        printf("%4.3w\r\n", voltage[value1]);
        
      }
        printf("9.999\r\n");
              
  }

  }
 
}
buffer? First I set iteration to 10 and the problem occurs. Later, I change iteration to 3 the problem remains. 118356Can anyone help me.

Regards
FR
 

rjenkinsgb

Well-Known Member
Most Helpful Member
I suspect the compiler is using buffered I/O and there are a few characters still in the transmit buffer when the program quits.

Try adding a dummy printf() after the output loop that eg. prints a block of 20 space characters, just to ensure all wanted data has been flushed through the serial buffers.
 

Pommie

Well-Known Member
Most Helpful Member
The reason you're getting zero is because, in integer maths, (5/4096)=0. Which is why I separated the calculations.

Mike.
Edit, it also needs to be 5000 (not 5) to get mV or you need to use fp variables.
 

frahman3

Member
Hi,

I take your advice. However I am facing error which says "Previous identifier must be a pointer" and it refers to the 'value'. I'm a bit confusing with the error statement. What does pointer mean in this situation? Sorry for my knowledge in C is bad. Pls advice.

Regards
FR

CSS:
#include <30F6014A.h>
#include <float.h>
#include <string.h>
#fuses HS, NOWDT, NOPROTECT, PUT64, BORV27
//correct - Power On Reset Timer value 64ms, Brownout reset at 2.7V
#use delay(clock=20000000)  //20 MHz crystal
//#use rs232(baud=9600,UART2)
#define LED PIN_B10
//#define VSS_VDD
#define WDT_OFF=0
#use rs232(baud=9600,UART2)
void main()
{

   setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3 | sAN4 | sAN5 | sAN6 | sAN7 | sAN8 | sAN9 | sAN10 | sAN11 | sAN12 | sAN13 | sAN14 | sAN15, VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_2);
  
   setup_adc_ports(ALL_ANALOG); 
   // Built-in A/D setup function
   setup_adc(ADC_CLOCK_INTERNAL); 
   // Built-in A/D setup function
  
   const int8 channel_1[]=1,2,3,4,5,6,7,8,9,10,11,12,13;
    
   int16 ADC_value1[sizeof(channel_1)];
  
   int16 value;
   int16 voltage;
   int32 newVar;
        newVar=(int32)ADC_value1[value];
        newVar*=5000;
        newVar/=4096;                        //note not 4095
        voltage[value] = (int16) newVar;    //voltage = 0 to 5000 I.E. mV
  
      //I/O ports configurations(1:input, 0:output)
   set_tris_a(0x0000);     //set port_a as output
   set_tris_b(0xFFFF);     //set port_b as analog input/ADC
   set_tris_c(0x0000);     //set port_c as output
   set_tris_d(0x0000);     //set port_d as output
   set_tris_f(0x0000);     //set port_f as output
   set_tris_g(0x0000);     //set port_g as output
  
  
   output_a(0x0000);       //clear port_a to all 0s
   output_c(0x0000);       //clear port_c to all 0s
   output_d(0xFFFF);       //clear port_d to all 1s-portD dafault at HIGH state
   output_f(0x0000);       //clear port_f to all 0s
   output_g(0x0000);       //clear port_g o all 0s

   while(TRUE)
   {
      //read from chnnel 0, 0++ (1,2,3...13)
      for (value=0;value<sizeof(channel_1);value++)
      {
        set_adc_channel(channel_1[value]);
        ADC_value1[value]=read_adc();
        voltage[value] = (ADC_value1[value]*5000/4096);
      }
      //display value from channels 0...7
      for (value=0;value<sizeof(channel_1);value++)
       {
       //printf("%4.3f",voltage[value]);
       printf("%4.3f\r\n",voltage[value]);
      
       }
       //printf("9.999");
       printf("9.999\r\n");
  }
}
 

Pommie

Well-Known Member
Most Helpful Member
It's (I think) the * in the line newVar*=5000; Try changing it to newVar= newVar*5000;

That's the problem when adlibbing.

Mike.
 

frahman3

Member
Hi,
Thanks Mike. But the problem remains. The errors are pointing to the term 'value' which the error says 'Previous identifier must be a pointer'.

FR
 

Pommie

Well-Known Member
Most Helpful Member
Which line is the problem on?

Mike.
Edit, why is value sometimes blue? Is it a reserved word? I don't know or use CSS.
Edit2, why isn't voltage an array anymore? I think this is your problem
 
Last edited:

frahman3

Member
Hi,

I think for the time being I stick with the command voltage[value] = (ADC_value1[value]). I'll recheck it. Other options for the mv conversion I will use the labview to do it. In the time being I tried to try to read dc voltage 4.788V from multichannel ADCs but only channel AN0 seems working, others it display -16.000 Why is this happening? Does the dspic require delay to read from other ADCs? or I missed to declare/ insert include files in the code? Here is what I received in the hyper terminal. Any suggestions?

Regards
FR

4752.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
-16.000
9.999
 

Nigel Goodwin

Super Moderator
Most Helpful Member
In the time being I tried to try to read dc voltage 4.788V from multichannel ADCs but only channel AN0 seems working, others it display -16.000 Why is this happening? Does the dspic require delay to read from other ADCs?
I can't comment on your exact situation, but essentially it's a VERY common rookie mistake.

There's usually only one ADC in a microcontroller, which is switched between the different input pins. When you switch channels the capacitor in the sample and hold has to charge/discharge, and this takes time, in particular it's EXTREMELY dependent on the source impedance feeding the pins, and the specification of the ADC specifies the minimum source impedance for fast switching.

Mostly though, speed isn't an issue, so you switch channels, wait a while (dependent on source impedance), and then take the reading.

However, I wouldn't expect that to give -16 readings, the reading will normally be somewhere between the previous pin, and the one you've switched to (as the capacitor has finished charging/discharging before the reading).
 

rjenkinsgb

Well-Known Member
Most Helpful Member
In the code with the error - this section

int16 value;
int16 voltage;
int32 newVar;
newVar=(int32)ADC_value1[value];
newVar*=5000;
newVar/=4096; //note not 4095
voltage[value] = (int16) newVar; //voltage = 0 to 5000 I.E. mV

You are using variables without initialising them; is that chunk of code in the wrong place, or was it intended to be a comment block?


In next example, it is as Nigel says, you need a delay for the analog input sample & hold time after each change of channel.
A 10uS delay is advised as being safe, you may be able to use less if you check the device data sheet.
 

Nigel Goodwin

Super Moderator
Most Helpful Member
A 10uS delay is advised as being safe, you may be able to use less if you check the device data sheet.
As long as you've got a nice low source impedance 10uS is probably fine, but you need considerably longer delays if your source impedance is higher - usually 2K is the maximum suggested source impedance for most PIC's.
 

rjenkinsgb

Well-Known Member
Most Helpful Member
As long as you've got a nice low source impedance 10uS is probably fine, but you need considerably longer delays if your source impedance is higher - usually 2K is the maximum suggested source impedance for most PIC's.
Very true; I'm thinking of my hardware designs, without allowing for other possibilities.
10uS is just the advised delay in the CCS compiler manual.

(Also, I never use inline delays so I'm not used to thinking in those terms; for ADC inputs, I use a sequencer that alternately reads the ADC result then selects a new input channel, or starts a new conversion, based on an incrementing state variable.
That's called from a regular clock interrupt at whatever frequency the project needs for that and other background functions).
 

frahman3

Member
Hi,

Sorry for my incompetent in c programming. I'm in learning process and asking some guidance from the experts. I have rewritten the program and now it can read from ADC (single & multi-channel). Attached are the codes for single channel ADC. I encounter problem when I pump-in dc voltage to the channel 0. The results displayed are different from what have been measured. Below are the results:-
Vdc ADC(mV)
1.03 1334
2.01 2542
3.01 3731
4.01 4981
5.01 4998

Can advice regarding the errors?

Regards
FR


CSS:
#include <30F6014A.h>
#device ADC=12
#fuses HS, NOWDT, NOPROTECT, PUT64, BORV27
//correct - Power On Reset Timer value 64ms, Brownout reset at 2.7V
#use delay(clock=20000000)  //20 MHz crystal
#use rs232(baud=9600,UART2,ERRORS)


void main()
{
   SETUP_ADC(adc_OFF);
   setup_adc_ports(sAN0 | sAN1 | sAN2 , VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_2);
   setup_adc(ADC_CLOCK_INTERNAL); 
   // Built-in A/D setup function
 
   setup_adc_ports(ALL_ANALOG); 
   // Build-in A/D setup function
   signed int32 ert_adc_value_0;
   signed int32 ert_voltages_0;
    
   while(true)
   {
    
   //sample at Channel_0
   set_adc_channel(0);  //read from channel 0
   delay_us(10);        //delay is required after setting channel and bef.read
   ert_adc_value_0=read_adc();    //starts conversion & stored
   ert_voltages_0=(ert_adc_value_0)*5000/4096;// last result of last conversion
   printf("Ch0=%u\r\n",ert_voltages_0);
        
  
   }
}
 

Latest threads

EE World Online Articles

Loading

 
Top