Archive for Data Acquisition

Analog to Digital Signal Rectification

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

Hello,

Often in my projects i need to detect the signal level and then feed it to an A/D Converter. Since Digital circuitry operate on a single rail power supply usually from 1.8V to 5V you cannot feed the analog signal to the ADC’s input referenced to digital ground because the negative polarity will be ignored or worse, could damage the ADC.

One way is to use an analog rectifier and convert this output to digital. This requires some extra components though and depending on maximum frequency of the signal can be expensive.

In audio domain I usually rectify it in software and I provide a DC offset on the ADC input in order to keep both positive and negative side of the signal within the ADC’s input range.

To have a symmetric voltage swing the offset is VDD/2. This of course gives a first limitation of peak input voltage of VDD/2 but it can be easily resolved by attenuating the signal first and keeping the attenuation level in mind in software side. This way we can scale the signal to fit our input requirements.

Digital Rectifier ADC Software signal rectifier

 

 

In the picture above (a) shows you the signal with a VDD/2 offset presented at the input of our A/D converter. We will sample this signal in time as shown on the x axis. and the black lines represent the result after sampling

(b) shows how to reconstruct the analog signal. You can see that for values above the VDD/2 line the green part exists in our sample value from (a) and for samples below VDD/2 line we need to add the green part.

Looking at our analog input signal and samples in (a) and looking at the green parts in (b) we can say that the signal value v(t) for each sample s[n] is:

v(t1) = s[1]-VDD/2

v(t2) = s[2]-VDD/2

v(t3) = s[3]-VDD/2

v(t4) = s[4]-VDD/2

v(t5) = s[5]-VDD/2

…..

What the above list describes are actually the green parts in (b). The problem that remains is that v(t3) and v(t4) (corresponding for the negative voltage swing in the input signal) are negative because sample 3 and 4 are lower in value than VDD/2.

What we did so far is eliminate the input offset and now in order to rectify it we need to make all the negative values positive. This is simply done this way:

v(t1) = s[1]-VDD/2

v(t2) = s[2]-VDD/2

v(t3) = VDD/2-s[3]

v(t4) = VDD/2-s[4]

v(t5) = s[5]-VDD/2

…..

Now the signal is rectified. v(t3) and v(t4) are positive and the list above describes now figure (c), the rectified output.

There are a couple of drawbacks in using this technique. First is the stability of the offset VDD/2. This voltage will need to be extremely stable for accurate result. If offset fluctuates then sample values will fluctuate too. If you can eliminate drift caused by temperature, load fluctuations etc then you can have a very accurate and fast rectifier.

There is a way to make this problem disappear by using a second A/D converter channel. And this is the second drawback if your number of channels is very limited. When using a microcontroller this isnt really a problem as usually there are a sufficient number of channels available.

I usually use the second solution and i always get the VDD/2 value from the second ADC channel and then get the input signal value. Lets look below at at example on how to do this;

/* we will use channel 0 for VDD/2 input and channel 1 for signal input */

int READ_ADC(int channel); //function prototype to read ADC value on channel 

int RECTIFY(void)

{

int INPUT_OFFSET, SAMPLE_VALUE;

INPUT_OFFSET = READ_ADC(0);

SAMPLE_VALUE = READ_ADC(1);

if(SAMPLE_VALUE >= INPUT_OFFSET)

  SAMPLE_VALUE = SAMPLE_VALUE – INPUT_OFFSET;

else

  SAMPLE_VALUE = INPUT_OFFSET – SAMPLE_VALUE;

return SAMPLE_VALUE;

}

 

Output of RECTIFY function can then be stored into a vector and perform various calculations to get your desired result. I usually average the values:

#define SUM_LENGTH 512 //how many samples you want to average

int AVERAGE(void)

{

double SUM=0; // depending on the ADC resolution choose the data type

int RESULT, i;

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

{

  RESULT = RECTIFY();

  SUM = SUM + RESULT;

}

RESULT = SUM/SUM_LENGTH;

return RESULT;

}

To choose the SUM_LENGTH you should consider the speed of the A/D conversion and the lowest frequency of the input signal so that you can capture an entire period. This, of course is application dependant but you can play around with the values and check the result.

Holding the RECTIFY value in a vector you can then get max value which is peak value or RMS, envelope and so many more things.

I hope this will be useful and if there is anything you want to ask go ahead and leave a comment.

Thank you for visiting.

Implementing Software SPI for PIC 2 PIC Communication

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

Hello,

In one of my projects i had to transmit some data between two PIC microcontrollers. The data represented some sensor values and it was important to know which value corresponded to which sensor.

This can be tricky if you don’t have free peripherals so i will present a way to implement SPI style communication by bit-banging any pin/port available. As with most SPI you will need 4 wires representing Clock, MISO (Master In Slave Out), MOSI (Master Out Slave In) and CS (Chip Select or Slave Select or Data Enable….).

Scenario is like this PIC1 MCU converts analog value of a few sensors with a 16bit resolution and then sends the data to PIC2 MCU for further processing. PIC2 needs to know that the data that was just received corresponds to a certain sensor. When can achieve this simply by letting PIC2 make a data request to PIC1.

E.g.

PIC2: [SEND DATA OF SENSOR 3]—————->:PIC1

PIC1:[SENDING SENOR 3 DATA]——————>:PIC2

PIC2: [SEND DATA OF SENSOR 7]—————->:PIC1

PIC1:[SENDING SENOR 7 DATA]——————>:PIC2

This way PIC2 will always associate the received data with the right sensor. It seems natural that PIC2 will be the SPI Master and PIC1 will be the slave. The Master is the one initiating the communication by first setting CS line to logic low and then starting the clock. It will then send the sensor address to the slave and receive the value from the slave. Once value was read it will stop the clock and set CS to logic high.

I assigned each sensor an address, 8 bit is enough allowing basically for 256 sensors. The received data is 16 bits long.

1. SPI MASTER program

/* I will use delay functions which you will need to define according to your compiler

and your Fcy settings. */

//Defining Signal Lines, replace “x” chars with your port/pin numbers

#define DCLK PORTxbits.Rxx
#define DIN PORTxbits.Rxx //MISO
#define DOUT PORTxbits.Rxx //MOSI
#define CS PORTxbits.Rxx

//Function to configure the data direction

//If you add these functions after main() remember to add prototype before main()

void Init_MSPI(void)

{

TRISxbits.TRISxx = 0; // clock
TRISxbits.TRISxx = 1; // DIN
TRISxbits.TRISxx = 0; // DOUT
TRISxbits.TRISxx = 0; // CS

//look in your MCU h file to get the actual TRIS struct parameters

CS=1;
DCLK=1;

}

UINT16 Get_Value_SSPI(char ADDRESS)

{

char temp; //used to serialize data

UINT16 in=0x0000; //will hold received 16bit data, initialize with 0

CS=0;

__delay_us(50);

//CS Line set to logic low

//begin serializing ADDRESS and sending it via DOUT from MSB to LSB

for(i=0;i<8;i++)
{
temp=ADDRESS&0x80; //Keep the MSB, ignore the rest of the bits
if(temp) // if MSB is 1 put 1 on DOUT and cycle clock 
{
DOUT = 1;
DCLK = 0;
__delay_us(50);
DCLK = 1;
__delay_us(50);
}
else //if MSB is 0 put 0 on DOUT and cycle clock
{
DOUT = 0;
DCLK = 0;
__delay_us(50);
DCLK = 1;
__delay_us(50);
}
ADDRESS <<=1; // Shift data to the right to get the next bit in MSB position
}

//cycle clock again, prepare to receive
DCLK = 0;
__delay_us(50);
DCLK = 1;
__delay_us(50);

//receiving the data
for(i=0;i<16;i++)
{
DCLK = 0; //activate clock
if(DIN) // if on DIN line we have 1 we put 1 in LSB position of “in” variable
in|=0x0001;
__delay_us(50);
DCLK = 1;
__delay_us(50);

//if DIN 0 leave variable unchanged, cycle clock
in<<=1; // shift LSB to right and prepare to receive the next bit
}

 //reception of last bit needs to be out of for loop so it wont get shifted to the right

if(DIN)
in|=0x0001;
DCLK = 0;
__delay_us(50);
DCLK = 1;
__delay_us(50);

//cycle clock and close communication by putting CS line to logic high

CS=1;
__delay_us(50);

}

// to call the function in main

UINT16 Sensor_Value;

Sensor_Value = Get_Value_SSPI(ADDRESS);

2. SPI Slave Program

//Defining Signal Lines, replace “x” chars with your port/pin numbers

#define DCLK PORTxbits.Rxx
#define DIN PORTxbits.Rxx //MISO
#define DOUT PORTxbits.Rxx //MOSI
#define CS PORTxbits.Rxx

//Function to configure the data direction

//If you add these functions after main() remember to add prototype before main()

void Init_SSPI(void)

{

TRISxbits.TRISxx = 1; // clock
TRISxbits.TRISxx = 1; // DIN
TRISxbits.TRISxx = 0; // DOUT
TRISxbits.TRISxx = 1; // CS

//notice clock and CS are inputs on slave MCU

}

void Send_Value_MSPI(void)

{

char address=0x00; //variable to hold sensor address

UINT16 out,temp; //out holds the sensor value, temp used to serialize data

while(!CS);
while(CS);

//wait for CS line to cycle to logic low

//this prevents the Slave to start its routine in the middle of communication

//start receiving Master data on DIN
for(i=0;i<8;i++)
{
if(DIN) //if DIN is 1 put 1 in data as LSB if 0 leave data unchanged
data|=0x01;
data<<=1; //shift LSB to the right, wait for clock and prepare for new bit
while(!DCLK);
while(DCLK);
}
if(DIN)//last bit must be out of for loop to prevent shifting it to the right
data|=0x01;

/*wait 2 clock periods in here you should get the value corresponding to the received address */
while(!DCLK);
while(DCLK);
while(!DCLK);
while(DCLK);

// serialize the value and send it bit by bit on DOUT

for(j=0;j<16;j++)
{
temp = out&0x8000;// keep MSB and ignore the res
if(temp) //toggle DOUT depending on MSB
DOUT=1;
else
DOUT=0;
out<<=1;//shift data to the right prepare next bit as MSB and wait for clock
while(!DCLK);
while(DCLK);
}
DOUT=0; // once all bits are sent put DOUT to 0 and wait final clock
while(DCLK);
while(!DCLK);

}

Ran the software on 2 PIC24FJ128GA010 devices and below you can see the signals. Remember DOUT form Master goes to DIN on Slave and DIN from Master Goes to DOUT on Slave. From top to bottom 1st signal = Clock, 2nd signal = Master DOUT, 3rd signal = Master DIN, 4th signal = CS

ADDRESS = 0xC2 Sensor_Value = 0xF10F

SPI Communication PIC

 

 

to see if each PIC MCU will interpret the data correctly i added a verification point on both programs by making a pin go high if the data is verified. Below you can see the signals.

SPI Communication PIC

showing control output and data lines

SPI Communication PIC

Showing control output with Clock and CS lines

 

You can change delay values in the Master program for faster or slower transmission, just make sure you have the same value everywhere. The beauty part is that you can use it with any ports/pins and not worrying about your peripherals.

Thank you for visiting.

LM35温度センサー / LM35 Temperature Sensor

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

 

LM35温度センサー。摂氏で温度を測定することができ、安価で信頼性の高いセンサーです。
TEAで使用するDB9プラグに接続されています。

LM35 temperature sensor. A cheap and reliable sensor that can measure temperature on Celsius scale. Connected to a DB9 plug to be used with TEA.

lm35

Temperature Effect Analysis Tool

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather

 

こんにちは,

私は、スピーカーに対する温度の影響を監視するために開発したツールをご紹介したいと思います。これは、Microchip社のPIC18F4550マイクロコントローラーを中心に構築されており、
USBポート経由でPCに接続されています。デスクトップアプリケーションは、私のパートナーがC#でプログラムをしました。

 

Hello everyone,

I want to present a tool I developed for monitoring temperature effects on loudspeaker performance. It is built around PIC18F4550 microcontroller from Microchip and it connects to a PC via USB port. Desktop application was programmed in C# by one of my partners.

DSC03402

The tool uses a reference resistor to calculate the changes in field coil and voice coil resistance. The voltage captured is fed into the 10 bit ADC on the microcontroller. It is also equipped with a LM35 temperature sensor in order to calculate the voice coil’s temperature coefficient. This parameter can be used to predict power compression.

DSC03388 DSC03389 DSC03390

 

The Desktop application will display graphs showing the time variation of four parameters. Data can also be saved for further processing.

tea