0

I expect from the following program serial.c to light the led on if I send key 1 from terminal, and light the led off when I send key 0 from terminal:

#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
char data;
void main(void) {
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B |= (1<<RXEN0);
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
  DDRB |= (1<<PB1);
  while(1) {
    while(!(UCSR0A&(1<<RXC0)));
    data = UDR0;
    if (data=='0') PORTB &= ~(1<<PB1);
    if (data=='1') PORTB |= (1<<PB1);
  }
}

I use the following commands to compile and burn all the programs:

avr-gcc -Os -mmcu=atmega328p -c -o serial.o serial.c
avr-ld -o serial.elf serial.o
avr-objcopy -O ihex serial.elf serial.hex
avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

The output of avrdude is the following:

$ avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "serial.hex"
avrdude: input file serial.hex auto detected as Intel Hex
avrdude: writing flash (12 bytes):

Writing | ################################################## | 100% 0.03s

avrdude: 12 bytes of flash written
avrdude: verifying flash memory against serial.hex:
avrdude: load data flash data from input file serial.hex:
avrdude: input file serial.hex auto detected as Intel Hex
avrdude: input file serial.hex contains 12 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.02s

avrdude: verifying ...
avrdude: 12 bytes of flash verified

avrdude: safemode: Fuses OK (E:07, H:DE, L:FF)

avrdude done.  Thank you.

For serial connection I tried PL2302 and FT232RL usb-com adapters - the effect is always the same.

Terminal settings on the computer are correct (9600,8N1).

avr-gcc version 4.8.1 avrdude version 6.1

Why the very first program in this question does not work as needed and what should be changed in it to achieve the desired behavior?

11
  • How is the LED wired to the ATMega?
    – Majenko
    Nov 6, 2015 at 15:54
  • @Majenko: one led is built-in from the arduino duemilanove board (PB5), another is an ordinary led directly connected to GND and PB1. Nov 6, 2015 at 15:57
  • So no resistor on the PB1 LED then?
    – Majenko
    Nov 6, 2015 at 15:58
  • @Majenko: no resistor. I'll try with 270 ohm between GND and led (right?) and report in a minute.... Nov 6, 2015 at 16:00
  • 1
    But an LED has a fixed forward voltage of say 2V. With no resistance the current drawn by the LED is theoretically infinite. That can cause all sorts of issues, including power supply droop and general crashes and resets even with brownout disabled. With it enabled it just reboots cleanly. With it disabled it just crashes messily. The good news is I can replicate the symptoms of your first bit of code on my Uno quite happily, so I can diagnose the problem now.
    – Majenko
    Nov 6, 2015 at 16:31

1 Answer 1

1

The problem you have is that your baud rate is not being set right.

You only have part of the settings you need. There is a third macro in the setbaud.h file that you need to take account of: USE_U2X.

That defines whether or not you need to set or clear the U2X0 bit of UCSRA0. If that is set wrong then your baud rate will be either twice or half what you want it to be - in this case it's coming out as twice.

Modify your code to assign the baud rate like this:

#include <util/setbaud.h> 
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_U2X
UCSR0A |= (1<<U2X0);
#else
UCSR0A &= ~(1<<U2X0);
#endif
UCSR0B |= (1<<RXEN0);
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);

Then you should be able to receive characters.

In the actual header file in question there is a large number of comments and instructions, including this:

Assuming that the requested BAUD is valid for the given F_CPU then the macro UBRR_VALUE is set to the required prescaler value. Two additional macros are provided for the low and high bytes of the prescaler, respectively: UBRRL_VALUE is set to the lower byte of the UBRR_VALUE and UBRRH_VALUE is set to the upper byte. An additional macro USE_2X will be defined. Its value is set to 1 if the desired BAUD rate within the given tolerance could only be achieved by setting the U2X bit in the UART configuration. It will be defined to 0 if U2X is not needed.

My resulting UART configuration, which may be being affected by the bootloader, is:

UBRR0H: 0x00
UBRR0L: 0x67
UCSR0A: 0x20
UCSR0B: 0x10
UCSR0C: 0x06

That equates to data register empty, RX enabled, 8-bit.

To my mind that is equal to the values being manually set in the code, so shouldn't be a problem.

14
  • No, it changes anything - still the program does not work as needed. With F_CPU = 16MHz and BAUD = 9600 it leaves U2X0 setting in the default value (I already checked this before). Nov 6, 2015 at 16:43
  • Then there must be something else unrelated that is stopping it from working. This code works, I tested it on an Uno.
    – Majenko
    Nov 6, 2015 at 16:45
  • What could this be? I've been fighting with this all the week... Nov 6, 2015 at 16:46
  • By the way, did you say you didn't have a bootloader installed, because you had BOOTRST enabled? With BOOTRST turned on (hf=0xDE) you boot into the bootloader. With it turned off (hf=0xDF) you boot into your code.
    – Majenko
    Nov 6, 2015 at 16:47
  • With it "enabled" (=0) you boot the bootloader. With it "disabled" (=1) you boot your code. Make sure you have it set right if you don't have a bootloader installed.
    – Majenko
    Nov 6, 2015 at 16:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.