ATMEGA48 Serial communication

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

Hi, it has been sometime since I last programmed for serial communication. I have an ATMEGA48 and I want to communicate via serial with another device (Suprema fingerprint scanner) which supports the following communication interface:

UART
-3.3V CMOS level
-Baud rates up to 921.6kbps
(factory default: 115.2kbps)
-RS232/422/485 supported via
additional level converter

And has the following packet structure:

Start | Command | Param | Size | Flag | Checksum | End

1byte | 1byte |4bytes | 4bytes | 1byte | 1byte |1byte

I am using AVR Studio to write my code and am stuck. Can I just use USART for my communication? I want to achieve the simplest configuration and avoid a level converter. Also, I am not sure how to set baud rates in AVR code.

If anyone has any sample code that they can come up with to get me started that would be awesome, I am at the point where I am pulling out my hair!!! All I need to do is send simple HEX commands to the fingerprint scanner. Thanks in advance. Rob

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

If you are running your mega48 at 3.3V then yes, you can just connect the two via the USART. If you are running the mega48 at a different voltage, then you will need a buffer IC to translate the voltage levels, you do not necessarily need to use an RS232 level converter here. (you'll need 2 of them if you do use them)

Check the tutorials section for tutorials/examples on how to use the USART. The USART's on all the AVR's work pretty much the same, the only thing that might change is the register names slightly, and the UBRR register. But those differences should be pretty easy to figure out via the datasheets.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Thanks for the quick reply. I have a few more questions if you don't mind.

1) How do I set the voltage levels of the AVR chip to 3.3v, so I can not use a level converter?

2) When setting the baud rate, how do I determine the F_CPU? Is it 1.8432 MHz?

Thanks

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

1) The voltage level of the AVR is determined by the VCC you feed it. That is if VCC is 5V then the VIO of the AVR is 5V, if the VCC is 3.3V then the VIO is 3.3V.

2) F_CPU is whatever you clock the chip at. By default AVR's come from the factory running on the internal 1MHz oscillator. This oscillator however, is not accurate enough for reliable UART communications, without some additional calibration. If you attach an external crystal, and set the fuses appropriately, then F_CPU will need to be set to whatever the crystal frequency is (divided by whatever you set the prescaler to)

Based on your questions, it is apparent that you need to spend some time with your AVR's datasheet. All of this is explained in the datasheet.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

If the OP is talking about RS-232 levels, then I am thinking that the processor voltage should not matter?

I'll believe corporations
are people when Texas executes one.

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

tubecut wrote:
If the OP is talking about RS-232 levels, then I am thinking that the processor voltage should not matter?

note the specs that the OP listed.

Quote:

UART
-3.3V CMOS level
...
-RS232/422/485 supported via
additional level converter

So all that is needed is logic level translators, if the AVR and the module are running at different voltages. If they are at the same voltage, nothing additional is required, they can be directly connected.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Ok, well I spent all day reading the datasheet...

Here is what i have come up with...

#include

#define fosc 1843200 //clock speed
#define baud 9600 //baud rate
#define baudnum fosc/16/baud-1 //baud number

int main(void);
void usart_init(unsigned int);
void usart_transmit(unsigned char);

int main(void)
{
usart_init(baudnum);
usart_transmit(0x05);
}

void usart_init(unsigned int ubrr)
{
//Set baud rate
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;

//Enable receiver and transmitter
UCSR0B = (1<<RXEN0)|(1<<TXEN0);

//Set frame format: 8data, 2stop bit
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void usart_transmit(unsigned char data)
{
//Wait for empty transmit buffer
while ((UCSR0A & (1 << UDRE0)) == 0);
//Put data into buffer, sends the data
UDR0 = data;
}

The command I want to send to the other device is 0x05. If you look at the first posting above, i have listed the frame format for the device that I am sending the command to. For example to send the command I want, the string will be 0x40 0x05 0x29 0x99 0x00 0x00 0x07 0x0A (this is from the frame format above). My question is, do I need to send each byte seperatly by loading it to the UDR0? Is there a way to send this as a string?

Thanks a lot

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

well at the lowest level you can only send one byte at a time. But you usually wrap this into a function that will send a string of bytes sequentially.

However, since in this case you need to transmit NUL's your function will not be able to do the normal, transmit until NUL loop to send all the bytes. Instead, you will need to give it the number of bytes to transmit.


// normal string function
void send_string(char *str)
{
  while(*str) usart_transmit(*str++);
}

// send bytes function
void send_bytes(char *str, int len)
{
  while(len--) usart_transmit(*str++);
}

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

So how is the checksum to be calculated? There could be a zillion ways of doing it and if it does not match the rest of the packet then the packet will be rejected by the receiving end.

Have you changed the scanner's default settings of 115.2K to 9600?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

The checksum is computed by summing each byte of the packet and then dividing that sum by 0x100.

EX:
0x40 0x05 0x29 0x99 0x00 0x00 0x07 0x0A = 0x107
0x107/0x100 = 0x07

Yes, I manually changed the baud rate from default to 9600. Are you familiar with the Suprema fingerpring scanners?

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

Quote:
The checksum is computed by summing each byte of the packet and then dividing that sum by 0x100.
So it's just modulo 0xff. However the way it's calculated above cannot be right as you cannot add the checksum 0x07 to the sum as you don't know it's going to be 0x07. I would think you need to add all bytes before the checksum. ie 0x40 0x05 0x29 0x99 0x00 0x00=0x0107

and no I'm not familiar with the Suprema fingerpring scanners unfortunately.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Yes, my mistake, you are right. The checksum is computed by adding the bytes BEFORE the checksum byte.

I think solved my problems sending out a string of bytes. I am a little hung up on the clocking frequency that calcualtes the baud. Is it necesary that I attached an external crystal or can I get away with using the internal RC oscillator?

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

robtotoreb wrote:
Is it necesary that I attached an external crystal or can I get away with using the internal RC oscillator?

see answer #2 in my second post.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Ok, so if I went to digikey and bought a 1.8432MHz crystal oscillator and connected it as described in the data sheet (XTAL1 XTAL2), the clock frequency will be set to that. And that will be sufficient for most USART baud rates?

Im sorry if I am asking to many question... I have no other place to turn to, I am ALONE!

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

Quote:
the clock frequency will be set to that

It will once the fuses have been programmed to tell the AVR to start using the crystal and 1.8432 is one of the "magic crystals" that are perfect for UART use as it gives 0% error at all common baud rates.

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

I am looking through the data sheet for fuse settings. Should I use the low power crystal oscillator settings instead of the full swing settings? If I choose to use a 1.8432MHz, 13pf load capacitance and a +/- 30 ppm crystal from digikey. Would this oscillator be consider a fast, slow or BOD enabled type (for SUT1..0 fuse setting)?

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

You only need "full swing" above 8MHz

(also BOD is completely unrelated to the crystal setting so "fast, slow or BOD" does not make sense)

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

Note that you still need load capacitors on the crystal, in case you missed that point.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Yea, I figure I will use 2 15pf caps...

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

Refering to the following code below: When I load UDR0 (USART I/O Data Register) with a certain HEX value, does that automaticaly transmit out the serial line or does it just load that register and awaits another commnd to send it out(PD1/TXN)?

void usart_transmit(unsigned char c) {
// wait until UDR ready
while(!(UCSR0A & (1 << UDRE0)));
// send character
UDR0 = c;
}

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

It starts to transmit as soon as you load UDR.

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

So...I got it to work!!!!!!!!!!! My commands are being send via USART to the scanner, awesome. The weird thing is that I set up the crystal I bought and set the fuses for external low frequency crystal and programed the chip and everything started working. When I removed the crystal and tried it again, it still worked. Is this because the programming board (STK500)I am using has an external oscillator? I couldn't find any documentation about an external oscillator on this board although.

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

If you are placing the chip in the stk500, then yes. Otherwise if it is still working then you must still be running on the internal oscillator.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

If you are placing your crystal in the "CRYSTAL" socket on the STK500 and have set up your chip for external crystal but have not moved the jumper "OSCSEL" to the correct position then you are running off the software clock of the STK500 (why you can remove the crystal and it still runs).