Baud rate and ADC sampling frequency

Go To Last Post
65 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks,

I am using a M128 with ADC on channel 5. I am using the UART for an RS232 connection to my PC. I am trying to see a sampled sine wave on my PC. Sine wave frequency is 100Hz which I have confirmed with an O scope. Amplitude is about 700 mV. Xtal frequency is 8MHz. CLKDIV8 fuse is selected. UART baud rate is 1200 baud.

I am getting the instantaneous voltage values on the hyperterminal but I am getting multiple zeroes between the values. Could this be because of a wrong baud rate? Do I have to average the samples? Here is a part of my code:

I am using a timer to display the ADC values every second on my PC.


#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((8000000/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR

unsigned int a;
unsigned int b;
volatile unsigned char flag;

static int UART_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry 
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
   stdout = &mystdout; //Required for printf init

}


static int UART_putchar(char c, FILE *stream)
{
    if (c == '\n') UART_putchar('\r', stream);
  
    while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

    UDR0 = c;
    
    return 0;
}


char UART_getchar()
  {
   while((UCSR0A & (1 << RXC0)) == 0) {};
   return UDR0;
  }


void ADC_init()

{
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); // Set ADC prescaler to 128   ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
   DIDR0 = (1 << ADC5D); //turn off the digital driver
   ADCSRA |= (1 << ADEN);  // Enable ADC
}


ISR(TIMER1_COMPA_vect)
{

PORTD ^= (1 <<PORTD7);
flag = 1;
}

/************MAIN**************/
int main (void)
    {

       
	   DDRC = 0x0F;
	   DDRD = 0xC0; 
	   DDRB = 0xFF;
	   PORTD = 0x00;
	   PORTB = 0x01; 
           USART0_init();
	   ADC_init(); 
	   timer_init();

          for(;;)
            {
			  	  
		 _delay_ms(100);

			  
                  ADCSRA |= (1 << ADSC); 
		  while((ADCSRA & _BV(ADIF)) != 0);
                  ADC_dummy = ADC;
						                       ADC_buffer_dummy =   ADC_dummy * 5;
		  a = ADC_buffer_dummy/1000;
                  b = ADC_buffer_dummy(percent)1000;

                 if(flag==1)
		      {

        		 printf("#d.#d\n",a,b); //percent sign replaced due to posting bug
		         flag = 0;
						 

                        }
               }
      }

So, with the /8 CLKDIV8 fuse, Xtal frequency of 8MHz ,13 cycles/sample and prescalar of 128 I should be getting a sample rate of about 600 sps. This should satisfy Nyquist for a 100Hz signal. I am using a baud rate of 1200 baud to display these samples on my PC. Does this mean I will get 1200 bps which is nearly twice my ADC sampling frequency?

What could be missing? Is it the averaging?

Appreciate your thoughts on this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

At 1200 Baud,you have only 1200 raw bits per second. This is 120 bytes per second. Even sending the data in binary form this is not enought to get a 100 Hz singal in real time. If you send the data as the ASCII output from floats it gets even worse: probably 6 or 7 bytes per sample.

So with binary data the minium baudrate is about 4800, with ascii data as in the programm its about 34 kBaud.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am using a baud rate of 1200 baud to display these samples on my PC.

Kind of a mess.

Your code is taking 10 samples per second.

The message sent to the PC is, say, 10 characters long. At 1200bps and 10-bit character frames, that allows 120 characters per second. So you can get about 10 messages/second through your link. (It is an estimate because the message size is not deterministic.)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
CLKDIV8 fuse is selected

I don't have AVR Studio or a board where I am right now, but isn't this backwords? Selecting, (marking, ticking), the box activates the divide by 8, and gives you a 1 MHz clock.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I don't have AVR Studio or a board where I am right now, but isn't this backwords? Selecting, (marking, ticking), the box activates the divide by 8, and gives you a 1 MHz clock.

The OP says he is using 1200 baud and 8MHz with div 8 on (so 1MHz final). The code says 9600 baud with 8MHz final. Both would require a UBRR value of 51.

@npat_avr: at no time are you clearing the ADIF flag, so after the first conversion (ADCSRA & _BV(ADIF)) != 0 will always be true. Either clear the flag or check for the ADSC bit to be low instead.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could make a sample buffer, and when full then send the data to the PC.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the feedback, guys.

First of all I had a typo in my first post. I am using an M168 not M128.

JC, Steve is correct, I will need an UBRR of 51.

Quote:

at no time are you clearing the ADIF flag, so after the first conversion (ADCSRA & _BV(ADIF)) != 0 will always be true. Either clear the flag or check for the ADSC bit to be low instead.

I want to run the ADC in a free running mode. Looking at the M168 datasheet page 248 timing diagram, I see that ADIF is always high after the 13th clock cycle.

@Kleinstein,
I will try the higher baud rate, it just seems too much horsepower to display the very slow 100 Hz signal.

I will also try to go to a lower frequency and see what I get.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I want to run the ADC in a free running mode

To what advantage? - you can only sample at 15.3KHz so just have the ADC interrupt each time a conversion is complete, initiate UART transmission (don't wait for completion) and set ADSC again. I guess it's true this does "cost" the time into/out of the ISR?

But your bandwidth limit here has already been identified as the 1200 baud comms. As a UART frame is 10 bits (8N1) this is 120 bytes per second. If you are making 10 bit reading you need to send a minimum of 2 bytes each time to encompass the 10 bits (with a 6 bit waste each time). So you can take a maximum of 60 readings per second if you really stuff the UART. That is what is going to determine how often you take ADC readings - nothing else - the ADC is more than capable of stuffing this pipe at 60Hz!

I'd consider moving to a clock source for the AVR that could support an accurate 115,200 baud so you can sens about 11KHz bytes. The ADC (assuming 2 bytes per reading) is still capable of feeding 5.5kHz as it's max rate is 15.3kHz as previously noted.

When doing a design like this you need to work through a similar "time budget" calculation to identify whether all parts of the system can run at sufficient speed and if not, do something about it (the ultimate is trading up to a faster CPU or ADC!). You choice of 1200baud here was a bad one given what you are trying to achieve. If you'd done a time budget you'd have known this from the outset.

In a similar vein the initial design phases should include a rough "space budget" too to determine whether you have sufficient of each type of used storage (flash, SRAM, EEPROM, external SRAM, external flash, etc etc). Add/change chips until you know what you propose is "do-able"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So you can take a maximum of 60 readings per second if you really stuff the UART.

But the fragment showed a printf() string being produced and sent--perhaps 10 characters and 100+us. That brings it down even further, to like 12 reports per second.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I agree that my main limitation is the UART but I need to display the real time data on my PC.

@Cliff,
I will change my logic so it is ADC interrupt driven. I agree it does not make sense to use a free running mode.

Bear with me here, so if it is 12 reports/ second from the UART with 1200 bps, if I go to a 115200 bps should I get about 1152 reports/second?

If that is true, for a 100 cycles/second sine wave, should I get about 11.52 samples/cycle of the 100Hz sine wave?

If this is right, what crystal should I use? If I use 8MHz, I will get my UBRR value with 115200 bps as 3? Will that work?

Also right now I am connecting my signal generator straight to ADC input through a 10K input resistor. The GND of the signal generator goes to my breadboard ground. I am going to put a scope to see what the ADC is seeing but is there something I am missing hardware wise?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your signal will have to be centered between ground and Vref. If not, it will be "clipped". You might handle this in one of several ways:

1) If the signal generator has a DC offset control, then set it so that the zero-amplitude output is close to Vref/2

2) Build a resistive voltage divider to bias the ADC input. Then, capacitor couple the signal to the ADC input. If you do this, beware of that 10K series resistor. You could loose a LOT of amplitude, depending on the size of the resistors in your bias network.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
what crystal should I use?

There are certain frequencies that are "Baud Rate Friendly". I believe 14.7456 MHz is one such frequency.

I think AVRCalc, (and Kevin's, I'm blanking on the name...), will show the errors for given xtals and baudrates.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I see that ADIF is always high after the 13th clock cycle.

Which was my point. It is always high regardless of whether or not a new conversion has been completed.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

It is always high regardless of whether or not a new conversion has been completed.

... which can well explain
Quote:

I am getting multiple zeroes between the values.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you want to use 8mhz because you just have a 168 dip on a white board and no xtal. Seems like one could buy a bd with a 20mhz 168 with an 18.432mhz xtal, and you could run the serial at 115.2 or 230.4 kbits to the host computer. 115.2 is about 83usec per char, so you could send a 3 char report of ascii digits (maybe set the 0x80 bit on the 1st char so you know its the 1st char). You could send 4k reports per sec. Way faster than you could read. You could avg 4 readings and send the avg maybe.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, Jim. I will try point 1). I may have an offset on the signal.

@JC thanks for the AVRCalc idea.

I used Kevin Rosenberg's tool and found that the error for an 8MHz crystal @ 115200 baud is 8.5%.

Does this mean that if I have 11.52 samples/cycle, I will loose about 1 sample/cycle? Even with about 10 samples/cycle I should be able to get the 100 Hz sampled wave right?

Bob, I am using an 8MHz crystal for my board.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
the error for an 8MHz crystal @ 115200 baud is 8.5%.

One often sees a figure of Max of 2% error for baud rates for reliable communications, but I don't have a reference for that handy.

What 8.5% tells you is that you can't do that baud rate with that crystal when communicating with a PC, or other device which will have an accurate baud rate at its end. You need to pick a clock frequency which will give you much tighter accuracy in your baud rate.

There are other threads which discuss tweaking the baud rate to make it work. One can measure the incoming serial signal and calibrate the baud rate against that incoming signal, for example. One could also calibrate against a clock crystal. Much easier, in my mind, to just pick the correct crystal to begin with.

The XMegas have a much tighter tolerance on their internal clock, and may well be able to give one reliable serial comms without an external crystal.

Note that if you had two boards with AVRs with that crystal frequency they could communicate with each other just fine, as they both would be equally off of the true baud rate.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lose.... not the winner. loose..... not tight

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Quote:

It is always high regardless of whether or not a new conversion has been completed.

... which can well explain
Quote:

I am getting multiple zeroes between the values.

Ok I tried to use interrupt driven ADC, and I am still getting zeroes. Here is my code:

volatile unsigned int ADC_dummy;
volatile unsigned int ADC_buffer_dummy;
volatile unsigned int a;
volatile unsigned int b;
volatile unsigned char flag;


static int UART_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry 
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
   stdout = &mystdout; //Required for printf init

}


static int UART_putchar(char c, FILE *stream)
{
    if (c == '\n') UART_putchar('\r', stream);
  
    while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

    UDR0 = c;
    
    return 0;
}


char UART_getchar()
  {
   while((UCSR0A & (1 << RXC0)) == 0) {};
   return UDR0;
  }

void ADC_init()

{
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); 
   ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
   DIDR0 = (1 << ADC5D); //turn off the digital driver

    ADCSRA |= (1 << ADEN);  // Enable ADC
    ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
    sei();   // Enable Global Interrupts
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions 
}

ISR(ADC_vect)
{

  						             flag = 1;
						             ADC_dummy = ADC;
						              ADC_buffer_dummy = ADC_dummy * 5;
	 a = ADC_buffer_dummy/1000;
         b = ADC_buffer_dummy#1000;//percent sign replaced
}

int main (void)
    {

       

	   DDRB = 0xFF;
	   PORTD = 0x00;
	   PORTB = 0x01;
           USART0_init();
	   ADC_init(); 
	   timer_init();

            for(;;)
             {	
                 if(flag==1)
	             {
			 printf("#d.#d\n",a,b);
			 flag = 0;
						 
                      }
            }

    }



I am setting a flag in my ADC interrupt routine, update my a and b values and then send them to the UART in the main for loop.

Are the zeroes due to the wrong crystal used?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

no one ever mentioned a sampling theorem like Nyquist-Shannon... Please sample at least 10 times your input signal so at 100 Hz bare min should be 1000... if you want it to look like a sine wave not aliased garbage.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am setting a flag in my ADC interrupt routine, update my a and b values and then send them to the UART in the main for loop.

The one thing you are not doing in the ISR is triggering the next conversion each time. Try adding a:

ADCSRA |= (1<<ADSC);

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
lose.... not the winner. loose..... not tight

DefinItely, they are two sepArate words.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Cliff,
I tried adding that in my ADC ISR but I still get random zeroes.

I tried a few things:

1. I checked my sine wave and there is no offset.
2. When I power off the signal generator, and have it connected to my ADC input, I get all zeroes.
3. When I remove my signal generator connection to my ADC input and connect the ADC input to 5V, I get 5V.
4. When I leave my ADC input floating, I get random (noise) values but no zeroes.

Could this be a signal generator GND problem?

Or do I need an internal/external pull up on my ADC input pin?

I understand that this could still be because of the wrong crystal values and the undersampling, but would I get zeroes due to that? I would expect some garbage similar to the noise I see when I keep my ADC input floating.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

random zeroes

An extremely interesting oxymoron. Wonder what it means?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:) What I mean by that is I get two non zero values then a zero value and at other times I get one non zero value and then a zero value.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you get steady readings at the pc when avr a/d is converting dc from a pot across the 5v?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

What I mean by that is I get two non zero values then a zero value and at other times I get one non zero value and then a zero value.

Capture some output in your terminal and post it here. Maybe include the raw ADC reading as well as the processed 'a' and 'b'?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I discovered that I accidentally had turned on the AM on my signal generator. When I turned it off, I saw that the zeroes in my data were gone but I still don't get a sine wave. I also tried a 1N4001 diode (didn't have a pot) connected from ADC input to GND with a 10K pull up from ADC input to VCC and I got voltage values from 0.515V to about 0.645V so I have quite a bit of variation (about 25%)here.

I have attached the raw data output files. In the files the first value is the raw ADC value and then a comma and then the a and the b values as a.b.

The AC signal has the following:

Type: Sine wave
Amplitude: 539 mVpp
Frequency: 101.84 Hz
DC Offset: 76 mV

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just out of curiosity, I changed the input frequency only to 1Hz. Attached is a waveform I got. I think I will need a positive bias on my ADC pin to prevent the clipping for the negative voltages.How can I prevent the spikes at each zero crossing? Do I need a filter at the input?

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That actually looks awfully like the positive part of a sine wave if you discount the peaks as it transitions the 0 boundary. Consider the following small bit of image editing:

(did you edit that post while I was doing this I wonder? Anyway we agree - that just needs pulling up into the +ve domain at which point the 0 crossing peaks will likely cease to be a problem anyway)

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes I noticed the same thing. Two questions:

1. I am applying a 1Hz sine wave at the ADC input.I am getting 54 samples in one cycle (or one second). I am using 9600 baud with a 8MHz crystal and a prescalar of 128. How can I confirm that I am getting 1 Hz on my PC?

2. How can I remove the spikes at the zero crossings? Will I need a filter?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) thread search/Google "zero crossing". Time between the zero crossing is the period and 1/period is the frequency.

2) wait and see if you still have the spikes when you've applied a DC offset. I'm no h/w engineer but I think I've read enough threads here to know you are going to need an op-amp for that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
         o 5v
         |
         \
         / 5k
         \
    10k  |
o-/\/\/\-+----o  0-5v
+-10v    |
         \
         / 10k
         \
         /
         |
         V

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks like overflow, are some of the numberes signed and some unsigned ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, Bob.

I will try that cricuit, although as Jim mentioned I may be faced with too much voltage drop due to the 10K series resistor? I will also try an OPAMP based offset adder circuit.

@sparrow2:
All my ints are unsigned but you may be right, I may be getting an overflow because it does seem to coincide with the zero crossings.

How do I verify if the frequency of the signal I get on my PC is 1 Hz?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr wrote:
How do I verify if the frequency of the signal I get on my PC is 1 Hz?

Just look at the byte locations that correspond to your zero crossing a/d values. If the a/d values that correspond to zero crossing occur every 0.5 second, then you have 1Hz (a sine wave has two zero crossings per period).

To know the time between zero crossings, you use the byte count, the byte rate, and the number of bytes sent per a/d value.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd get it rigged up with a pot so a nice slow turn from 0v to 5v gives a nice smooth linear increase from 0x000 to 0x3ff. Then you can put any old shape signal into it with harmonics less than 4.5khz, and sample it at 9k samples per sec to a buffer, then print it out with a bunch of spaces and a * like a teletype with the ***s scrolling up the screen.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I got it working with an 18.432 MHz crystal, 115200 baud and 100 Hz.Waveform is attached.

I am getting 6 samples/cycle in my captured waveform. I am trying to figure out how this is possible and how I can calculate the frequency to be 100 Hz.I am not sure if the captured signal on my PC is really 100 Hz. Any ideas? Appreciate your patience.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well the horizontal axis of that graph is your "timebase". It's not clear from the diagram what the units are. But lets say it's 1 second. I see about 9.5 cycles in that so I guess it's 9.5Hz if the timebase really was 1 second. The bottom line is that one cycle looks like:

  +
 + +
+   +
+   +
    +   +
    +   +
     + +
      +

So just measure the time between the zero crossings as noted previously - you know how often the AVR is sending samples.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

make a autocorrelation on the signal.

Edit and find the peak.

Can you have more that 1 freq. at the time ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Should be able to convert 10k samples per sec at 18.4mhz. and should be able to send 11.5k bytes per sec at 115.2kbps. The problem MIGHT be your pc cant receive serial at 115200 bps without missing chars? Did you write the program?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr wrote:
I am getting 6 samples/cycle in my captured waveform.
Assuming that each "bar" in your plot is one sample, I agree that it is close to 6. My money is that it is either 6.06 or 5.76. You'll see why in a moment.
Quote:
I am trying to figure out how this is possible
How many bytes are sent for each sample?
Quote:
and how I can calculate the frequency to be 100 Hz.
If you know the number of bytes per sample and the number of bytes per unit of time, it's easy.

Your period is 6 bars. You claim there is one bar for each sample received via serial. Your serial rate is 11,520 [bytes/second]. Divide that by the number of bytes per sample and by 6 samples per period. If you get something close to 100[cycle/sec], then the frequency is 100 Hz.

Are there between 19 and 20 bytes sent for each sample? If so, you're there. 19 bytes sent per sample would yield 5.76 samples per cycle. 20 bytes sent per sample would yield 6.06.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

The problem MIGHT be your pc cant receive serial at 115200 bps without missing chars? Did you write the program?

I think you may be right. I wrote the AVR code but I am using hyperterminal to see the output.

Quote:

How many bytes are sent for each sample?

I am sending 2 bytes/sample.

printf("#d,#d",a,b);

So am I losing 17-18 bytes/sample because of a serial comm. issue?
I will check my hyperterminal settings to see if there is something missing/wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like you are printing the 10 bit integer as 'decimal', so it can be 1 to 4 ascii chars.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Disclaimer: The HUGE assumption here is that your device is continuously sampling and sending with no delay between bytes or messages.

Can you be sure that there is no delay between messages?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

npat_avr wrote:
I am using hyperterminal to see the output.
Does hyperterminal show the total byte count received? If so, that would be a sanity check. Have your device run for x seconds and see how many total bytes are rx'ed by hyperterminal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I always test my ad converter setups with a pot. Read a sample, print it out with a %4d\r so it doesnt walk back and forth on the line. With the pot down, should get 0. With the pot up should get 1023. What would I expect at halfway? Does your rig work like this? (I've asked this questiuon twice before already....)

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I fixed it. Actually I was sending "RAW ADC = 499,2.5" which of course was too many bytes. I changed it to just 2.5 and it works like a charm. Now I get about 19 samples/cycle.

My input signal is about 500 mVpp but I am getting only about 140 mVpp and also the signal does not look symmetrical. Could it be due to the resistive divider? Also I checked and the offset measures almost zero (a few mV) on my scope. Like suggested I will try the opamp circuit.

@Bob,
I will also try the potentiometer expt.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What is generating the 500mv ptop sine wave? Usually the idea is to get the input signal to use as much of the whole a/d range as possible. That circuit I posted to convert +-10 to 0-5 would work on 2.5v too... that would cvt +-5v to 0-2.5. Then you put the 2.5V on the a/d vref pin, and the range of the a/d converter is 0-2.5v. That should give a much prettier picture, because there will be twice as many vertical steps.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so now I am using 7.3278MHz (I am limited to using this crystal) and trying to capture 1kHz at 115200 bps.

#define USART_BAUDRATE 115200
#define BAUD_PRESCALE (((7327800/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR

unsigned int a;
unsigned int b;
volatile unsigned char flag;

static int UART_putchar(char c, FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
   stdout = &mystdout; //Required for printf init

}


static int UART_putchar(char c, FILE *stream)
{
    if (c == '\n') UART_putchar('\r', stream);
 
    while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

    UDR0 = c;
   
    return 0;
}


char UART_getchar()
  {
   while((UCSR0A & (1 << RXC0)) == 0) {};
   return UDR0;
  }


void ADC_init()

{
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADATE); // Set ADC prescaler to 128   ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
   DIDR0 = (1 << ADC5D); //turn off the digital driver
   ADCSRA |= (1 << ADEN);  // Enable ADC
}


ISR(TIMER1_COMPA_vect)
{

PORTD ^= (1 <<PORTD7);
flag = 1;
}

/************MAIN**************/
int main (void)
    {

       
      DDRC = 0x0F;
      DDRD = 0xC0;
      DDRB = 0xFF;
      PORTD = 0x00;
      PORTB = 0x01;
           USART0_init();
      ADC_init();
      timer_init();

          for(;;)
            {
               
       _delay_ms(100);

          
                  ADCSRA |= (1 << ADSC);
        while((ADCSRA & _BV(ADIF)) != 0);
                  ADC_dummy = ADC;
                                         ADC_buffer_dummy =   ADC_dummy * 5;
        a = ADC_buffer_dummy/1000;
                  b = ADC_buffer_dummy(percent)1000;

                 if(flag==1)
            {

               printf("#d.#d\n",a,b); //percent sign replaced due to posting bug
               flag = 0;
                  

                        }
               }
      } 

I think I am sending 7 bytes/sample i.e.two integers,a and b (4 bytes), one dot (1 byte), one newline (1 byte) and one CR (1 byte).

Is my printf adding overhead? How can I get rid of my printf statement? Can I use a char instead of an integer to capture my ADC data?

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want to get the data from the AVR to the PC quicker then why not send it in (human non-readable) binary rather than doing the binary to ASCII conversion on the AVR. Literally just send ADCH and ADCL readings each time to the PC - so 2 bytes per reading then do the float conversion and binary to ASCII at the PC end.

(though I believe you are using these to plot a graph so ASCII need never be involved).

If always sending 2 fixed bytes you needn't bother with '\n' delimiters. Just read 2 bytes every time though I guess you could waste a byte and send 0x00 or '\n' or ',' or something?

Pages