Sending binary data from built in ADC in Atmega8 to USART

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,
My task in my miniproject is obtain analog signal from a function generator and convert the analog signal to digital using ADC. Then the converted data need to send to the computer.

After the analog data is converted , I need to send out the data of ADC(in binary) through TXD to the computer. I've written my program here but there is still error exist. I'm using 16MHz crystal .My program is shown below:

#include
#include

void InitADC()
{
//Aref= AVcc and ADC become 8 bit resolution
ADMUX|= (1<<REFS0)|(1<<ADLAR);

//Enable ADC and prescalar div factor 128
ADCSRA|= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

uint8_t ReadADC()
{
// Channel ADC0 is selected, so no need to set MUX3 to MUX0 in ADMUX

// Start single conversion
ADCSRA|= (1<<ADSC);

//Wait for conversion to complete
while (!(ADCSRA & (1<<ADIF)));

// Clear bit ADIF
ADCSRA|= (1<<ADIF);

return (ADCH);
}

void InitUSART(uint16_t ubrr_value)
{
// Set baud rate[
UBRRL= ubrr_value;
UBRRH= (ubrr_value >>8);

// Set frame format,i.e. asynchronous mode, no parity, 1 stopbit, char size= 8
UCSRC= (1<<URSEL)|(3<<UCSZ0);

// Enable the transmitter
UCSRB= (1<<TXEN);
}

void USARTWriteChar(int data)
{
// Wait until the transmitter is ready
while(!(UCSRA & (1<<UDRE)))
{
// Do nothing
}

// Clear bit TxC
UCSRA|= (1<<TXC);

// Write data to USART buffer
UDR= data;
}

void main()
{
int data;

// Initialize the USART
InitUSART(51);

// Initialize ADC
InitADC();

while(1)
{
// Read data from ADC
data= ReadADC(0);

// Send data from ADC out through TxD
USARTWriteChar(data);
}
}

Is there any problem on my programming? I've looking for it for so long time but I still cannot solve the problem. Thanks for helping me.

SongYing

Last Edited: Tue. Oct 5, 2010 - 03:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

See what the forum software did to your code? All indentation lost. Some characters replaced by a smiley.

Make your post more attractive, making more gurus here interesting in reading and perhaps answering/helping: Go back and edit you post surround the code with code tags.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:
Is there any problem on my programming?

the main loop looks reasonable - just make sure that the uart-related settings, like baud rate, etc., are consistent between the chip and your uart receiver (pc).

I would send a fixed char over to start the code to make sure that at least the uart portion of the code works.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t ReadADC() 
{ 
 // Channel ADC0 is selected, so no need to set MUX3 to MUX0 in ADMUX 
  
 // Start single conversion 
 ADCSRA|= (1<<ADSC); 

 //Wait for conversion to complete 
 while (!(ADCSRA & (1<<ADIF))); 

 // Clear bit ADIF 
 ADCSRA|= (1<<ADIF); 
  
 return (ADCH); 
}

If you block on ADSC not ADIF there's no need to clear it as ADSC returns to 0. That is:

uint8_t ReadADC() 
{ 
 // Channel ADC0 is selected, so no need to set MUX3 to MUX0 in ADMUX 
  
 // Start single conversion 
 ADCSRA|= (1<<ADSC); 

 //Wait for conversion to complete 
 while ((ADCSRA & (1<<ADSC))); 

 return (ADCH); 
}

Cliff

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

Ok. Thanks for replying^^

SongYing

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

Hi all,

My task is to convert analog signal to digital data and those data need to send to USART of Atmega8.
Now I encounter a big problem. The rate of data conversion for ADC is 104us (I use 16 MHz crystal) BUT the rate of data transfer for USART is 520.833us for 10 bits(8 bit data with 1 stop bit , 1 start bit), my baud rate is 19200.

So, I solve this problem by changing the 16MHz crystal to 8MHz crystal. For the baud rate, I set to 38400. But still, the ADC conversion time is still faster than data transfer of USART for about 52 us. Therefore, I put a delay loop in my source code(the words in bold). I’d like to ask, am I putting the delay loop at the right place?

#include 
#include 
#include 

void InitADC()
{
 //Aref= AVcc and ADC become 8 bit resolution
 ADMUX|= (1<<REFS0)|(1<<ADLAR); 

 //Enable ADC and prescalar div factor 128
 ADCSRA|= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 
}


uint8_t ReadADC()
{
 // Channel ADC0 is selected, so no need to set MUX3 to MUX0 in ADMUX
 
 // Start single conversion 
 ADCSRA|= (1<<ADSC); 

 //Wait for conversion to complete
 while (!(ADCSRA & (1<<ADIF)));

 // Clear bit ADIF
 ADCSRA|= (1<<ADIF);
  
 return (ADCH);
}


void InitUSART(uint16_t ubrr_value)
{
 // Set baud rate
 UBRRL= (unsigned char)ubrr_value;
 UBRRH= (unsigned char)(ubrr_value >>8);
 

 // Set frame format,i.e. asynchronous mode, no parity, 1 stopbit, char size= 8
 UCSRC= (1<<URSEL)|(3<<UCSZ0);

 // Enable the transmitter
 UCSRB= (1<<TXEN);
}


void USARTWriteChar(unsigned char data)
{
 // Wait until the transmitter is ready
 while(!(UCSRA & (1<<UDRE)))
 {
  // Do nothing
 }

 // Write data to USART buffer
 UDR= data;
 }



 void main()
{
 unsigned char data;

 // Initialize the USART
 InitUSART(12);

 // Initialize ADC
 InitADC();

 while(1)
 {

  // Read data from ADC 
  data= ReadADC(0);

  _delay_ms(0.06);  

// Send data from ADC out through TxD
  USARTWriteChar(data);
  }
}

But I also encounter another problem is, the analog input is from function generator, which mean that the input is continuously enter the ADC. I think that if I put delay loop, the input signal that enters the ADC won’t paused there. Cauz if the input signal doesn’t pause, I think that my data that send out are surely troublesome cause the group after me need to use these sent data to calculate the frequency of the input analog signal. So they need to reform the analog signal using my sent out data. If the analog input continuously enter the input but I don’t convert the data continuously and send it out due to the present of delay loop, I think they sure cannot reform the shape of input analog wave qnd thus the calculated frequency is wrong.
How can I solve this problem?

[moderator: [code] tags added to increase readability - please do this yourself next time]

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

Why don't you put either the UART send or the ADC reading on an interrupt? As it stands you have two delays (plus the one you added). One is the wait for ADIF and the other the wait for UDRE. The reading and the transmission could be done in parallel.

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

Use a 14.7456mhz xtal. Runthe uart at 115200 bps. You can send 11K bytes per sec at this rate. Set the a/d to free run. If you have a loop where you grab a byte from the a/d, send it out the uart, loop back, this loop will send 11K samples/sec back over the wire. No interrupts needed!

Imagecraft compiler user

Last Edited: Fri. Oct 22, 2010 - 12:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dear Bobgardner, thanks for your advices. I forgot to tell that the maximum baud rate i can set is 38400 due to some factors. Thanks for your help.

Dear Clawson, I'd like to ask,how do i put the UART or ADC reading on an interrupt?
Cause I know nothing about it as I ignored it when i read on ADC and USART. Is it just need to set a certain bit(s) to do it?Actually what's the function of these interrupts? I've read the datasheet but i can't understand it.
From the forum post, did you mean that by putting an interrupt at either UART or ADC reading, I don need to put delay loops anymore?

Thanks for replying.

Songying

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

Quote:

Actually what's the function of these interrupts? I've read the datasheet but i can't understand it.

Suggest you read through the tutorial forum paying particular attention to anything with "interrupt" in the title.

It's basically the ability to tell the UART or ADC (or whatever) to "just get on and do your job as soon as you can and when it's complete call a routine I provide to let me know it's complete"

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

school project ???????

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

I would like to see the full spec for this "mini-project". If I was going to start a new design, I would need more information than what we have been given.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Actually, the whole thing is like this. Our project is made up of 5 groups and each group need to incharge on 1 part of the project. Later when every group finish their own part, we will combine all together. Below is the task of every group:
Group 1 : Build a circuit that can produce an analog signal.
Group 2(MY GROUP) : Receive the analog signal then convert to digital form and lastly send the digital data
Group 4: Do programming so that the computer is able to receive the data and use the sent data to calculate the frequency of the analog signal. Then they need to send this value of frequency to Group 5
Group 5: Receive the data using USB and display the frequency value on LCD display.

So,I'm in Group 2.

I have a few questions:
Now my original program is shown below:

#include 
#include 

void InitADC()
{
 //Aref= AVcc and ADC become 8 bit resolution
 ADMUX|= (1<<REFS0)|(1<<ADLAR); 

 //Enable ADC and prescalar div factor 128
 ADCSRA|= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 
}

uint8_t ReadADC()
{
 // Channel ADC0 is selected, so no need to set MUX3 to MUX0 in ADMUX
 
 // Start single conversion 
 ADCSRA|= (1<<ADSC); 

 //Wait for conversion to complete
 while (!(ADCSRA & (1<<ADIF)));

 // Clear bit ADIF
 ADCSRA|= (1<<ADIF);
  
 return (ADCH);
}

void InitUSART(uint16_t ubrr_value)
{
 // Set baud rate
 UBRRL= ubrr_value;
 UBRRH= (ubrr_value >>8);
 

 // Set frame format,i.e. asynchronous mode, no parity, 1 stopbit, char size= 8
 UCSRC= (1<<URSEL)|(3<<UCSZ0);

 // Enable the transmitter
 UCSRB= (1<<TXEN);
}

void USARTWriteChar(unsigned char data)
{
 // Wait until the transmitter is ready
 while(!(UCSRA & (1<<UDRE)))
 {
  // Do nothing
 }

  // Clear bit TxC
  UCSRA|= (1<<TXC);

 // Write data to USART buffer
 UDR= data;
 }

 void main()
{
 unsigned char data;

 // Initialize the USART
 InitUSART(51);

 // Initialize ADC
 InitADC();

 while(1)
 {

  // Read data from ADC 
  data= ReadADC(0);
  
  // Send data from ADC out through TxD
  USARTWriteChar(data);
  }
}

As you can see, after the ADC finish converting the data, only the USART will send the data and after the USART finish sending it, ADC will only start to convert. This process repeats.

So now, I’d like to ask for interrupt, if I write the code below, what does it means?

void main()
{
 unsigned char data;

 // Initialize the USART
 InitUSART(12);

 // Initialize ADC
 InitADC();

ReadADC(0);

 while(1)
 {
  // Read data from ADC 
  data= ReadADC(0);
    }
}

ISR(ADC_vect)
{
Data=ReadADC(0);
USARTWriteChar(data);
}

From my understanding, does it means that when ADC complete convert the data, the ISR function will be run. and at the same time,it will run the while(1) loop again and after that it runs the ISR function. This process that runs the while loop and ISR repeats.
Am I right?
But if I write like this, the problem still cannot be solve as the speed of ADC convert data is still faster than USART. Although the ADC converts data continuously and send the data continuously to the USART, but when USART is sending a data and a new data is given to it, it will ignore the new data too.

Thanks for replying.

songying

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

Quote:
Receive the analog signal then convert to digital form and lastly send the digital data

What does "convert to digital form" mean. Does it mean you need to preserve the waveform ie. amplitude vs time? Complex waveform?
What is the maximum frequency to be generated by Team 1 or the bandwidth for the overall system.

Simplistically, one could assume that since Team 5 only needs to show the frequency, that all your team needs to do is to measure "the period" of the incoming signal (assuming it to be an sine or square wave within the audio range) which is sent to Team 3 (In which case the analog will be more useful)

Unless you have a detailed specification set in concrete, each team could be making huge guesses on what they expect from the preceding team and what the next team requires.
Once you have the overall specification, you can then have the specifications for each team, which will ensure that all the collars & cuffs match.
Once you know exactly what your team spec is you can come up with the most appropriate solution for your task. Your problem may also not be as huge as what you think it is!

Reading between the lines, I would say your lecturer has set up up to fail, in order to teach the importance of specifications & effective communication between teams. :)
I may be wrong, they could be pure academics who have have never worked in the real world before.

Attachment(s): 

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

Dear Ldveries,

The maximum freq that the 1st group can provide is about 600Hz only.

Actually, my part is to convert analog signal to digital data using ADC. For me I use built in ADC of Atmega8. After that, i need to send the digital data to the next group.The group after me recieve my data and display those data 1st before calculating the frequency for me to hav a look at those data. As the data sent out is in binary form, they convert my data to decimal form so that i can read the data easier.

Actually, my part works BUT the data sent have wide range between them.For e.g, the 1st data is 1, then 49,125,200,234,255 143 0 sth like that.
So i go back & think and i found out that the speed of ADC is faster than the speed of USART. As we know that, USART will ignore the new data given to it if it is transmitting one data. That's my problem.

And 1 more thing, the way of the group after me calculate the frequenct is by just taking two maximum value of my data.I think that it's not only me need to make my data better but i think that they also need to improve their way to calculae.What's your opinion?

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

Quote:
I think that it's not only me need to make my data better but i think that they also need to improve their way to calculae.What's your opinion?

Yes!
Why not measure the period of the waveform.
Why not use comparator instead of ADC?

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

it's a must to use ADC, the lec told us.

1 question, can i write like this if i wan to put data inside the general purpose registers for Atmega8?

R0= ADCH;
R1= data;

somehing like that?

Thanks for replying

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

Quote:

1 question, can i write like this if i wan to put data inside the general purpose registers for Atmega8?

If you want to control the general purpose register contents explicitly yourself then program in assembler. If you program in C, then let the compiler decide on how the CPU resources will be used.

Again: With the correct setup you can have the ADC doing a conversion while the USART sends a character. In principle it could look like this:

void main()
{
   // Initialize the USART
   InitUSART(12);

   // Initialize ADC
   InitADC();

   while(1)
   {
   }
}

ISR(ADC_vect)
{
   unsigned char data;
   data = ReadADC();
   USARTWriteChar(data);
}

Where
ReadADC i) waits for a conversion to finish, ii) reads the conversion result, iii) triggers a new (one-shot) conversion and iv) exits returning the conversion result from step iii.

USARTWriteChar i) waits for a previous USART transmision to finish, ii) places the data in the USART transmission register thereby triggering a transmision of it, and iii) exits.

Now go print out the data sheet, make a big pot of tea or coffee and plan to sit down for the next day or so and read the ADC and USART section of the sheet. You need to work out the details of the i)s, ii)s etc above.

Also, try not to solve the whole problem in one big leap. Maybe start by learning how to send character repeatedly with the USART. Instead of using ADC data, how about sending some constant character? OR maybe a string in an array? At the other end, set up a PC with a good terminal program to verify that your string arrives OK. Do not leave testing to the point where you integrate with the other teams. That is a sure recipe for disastrous failure.

If you want to go from A to B then taking many small steps repeatedly is likely to bring you to a successful end. Attempting one giant leap will fail.

EDIT: FYI: The solution that I sketch does not use interrupts at all.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:
it's a must to use ADC, the lec told us.

I assume then that he actually taught you something, you should continue to use his wise council.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?