1

I first used the Arduino IDE but now I'm using PlatformIO which is awesome. But I have some big trouble with Serial.print() and Serial.println(). To show this error I have the following example code:

#include <avr/io.h>
#include <util/delay.h>
#include "Arduino.h"
#include "main.h"

int main(int argc, char const *argv[]) {
  Serial.begin(9600);

  section5ex34();

  return 0;
}

void section5ex34() {
  // Initialization
  DDRC = 0b00000100; // Port C2 as output and the rest (including Port C3) as input. (Port C2 is used for a led that indicates when en bit is being read)

  uint8_t b = 0b00000000;

  // here the code reads bits from PORTC3
  for (int i = 0; i < 8; i++) {
    _delay_ms(1000);
    PORTC |= _BV(PORTC2); // Make Port C2 high (indicates a bit will be read)

    if ((PINC & (0b1 << 3)) != 0) {
      b |= (1 << i);
    }

    _delay_ms(100); // Wait for the user to prepare the next bit (because this is now done by hand)
    PORTC &= ~_BV(PORTC2); // Then make Port C2 low
  }

  Serial.println(b, HEX);
}

When I have the code like this, it prints the right Hexadecimal value corresponding with the 8 read bits.

When I add Serial.println("test"); after the print, it doesn't print that.

Or when I change Serial.println(b, HEX); to Serial.println(b, BIN); it prints 11.

When I replace those 2 prints with Serial.println("Hi test test."); it prints Hi, so it seems like it can only print 2 characters.

When I add Serial.println("Hello world . hello . hi"); four times after Serial.begin(9600);, it prints Hello world . h and nothing more. So here it seems like it can print more than 2 characters, but not all. If I wait a few seconds it adds ello to this, so it says Hello world . hello.

In the initial code, when I replace the if-statement with

if ((PINC & (0b1 << 3)) != 0) {
  b |= (1 << i);
  Serial.println("1");
} else {
  Serial.println("0");
}

and when the input is connected to 5v (so high) it prints a 1 once and nothing else, not even a hexadecimal value when the reading is finished.

This problem drives me crazy.

I have an Arduino Uno and use a baudrate of 9600 , 8,N,1.

I hope someone can help me out with this.

4

You have two issues here:

The first is that you are using the Arduino core library and failed to initialize it. This is done automatically if you rely on the core's supplied main(), i.e. you stick with the setup()/loop() style of coding. If you write your own main(), you should start by calling init() to initialize the core.

Edit: In this particular instance, you could get away by just enabling interrupts with sei(). But I consider it good practice to initialize the core if you are ever going to use it.

The second issue is the abrupt termination of main: Serial.print() and println() do not really print to the serial port. Instead, they put the characters to be printed in the output buffer, and let an interrupt take care of actually sending them through the UART.

Your program ends with

return 0;

This will stop it. It will stop the whole program, including interrupt-driven tasks. So you will see whatever characters did make it to the UART, and nothing more.

If you instead end the program with and endless loop

for (;;) ;

it should work as expected.

| improve this answer | |
  • Hmm. I was very hopeful when I saw this. It made some sense. But unfortunately it changes nothing .. – JeroenJK Sep 19 '16 at 17:35
  • @JeroenJK: Indeed, I forgot to tell you about initializing the core. See amended answer. – Edgar Bonet Sep 19 '16 at 17:57
  • Yes, sei(); works together with the endless loop. Thanks! – JeroenJK Sep 19 '16 at 18:22
1

Arduino main() is not so simple as you think. If you use standard Arduino loop() and setup() functions it might be working much better.

But if you're not allowed to use Arduino libraries, you can use this:

src/main.cpp

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

void section5ex34();
int uart_putchar(char c, FILE *stream);
void uart_init (unsigned long int baud);

int main(void) {
  uart_init(9600U);

  while(1) section5ex34();
  return 0;
}

void section5ex34() {
  // Initialization
  DDRC = 0b00000100; // Port C2 as output and the rest (including Port C3) as input. (Port C2 is used for a led that indicates when en bit is being read)
  PORTC = 0b11111011; 

  uint8_t b = 0b00000000;

  // here the code reads bits from PORTC3
  for (int i = 0; i < 8; i++) {
    _delay_ms(100);
    PORTC |= _BV(PORTC2); // Make Port C2 high (indicates a bit will be read)

    if ((PINC & (0b1 << 3)) != 0) {
      b |= (1 << i);
    }

    _delay_ms(100); // Wait for the user to prepare the next bit (because this is now done by hand)
    PORTC &= ~_BV(PORTC2); // Then make Port C2 low
  }
  printf("0x%02X and something loooooooooooong\n",b);
}

int uart_putchar(char c, FILE *stream) {
  if (c == '\n') uart_putchar('\r', stream);
  loop_until_bit_is_set(UCSR0A, UDRE0);
  UDR0 = c;
  return 0;
}

// function to initialize UART
void uart_init (unsigned long int baud) {
    unsigned int baudrate = F_CPU/(baud*16UL)-1;
    UBRR0H = (baudrate>>8);             // shift the register right by 8 bits
    UBRR0L = baudrate;                  // set baud rate
    UCSR0B|= (1<<TXEN0)|(1<<RXEN0);     // enable receiver and transmitter
    UCSR0C|= (1<<UCSZ00)|(1<<UCSZ01);   // 8bit data format

    //// with static FILE variable:
    // static FILE uart0fd;
    // fdev_setup_stream((&uart0fd), uart_putchar, NULL,  _FDEV_SETUP_WRITE);
    // stdout = &uart0fd;

    //// or directly by using dynamically allocated FILE struct:
    stdout = fdevopen(uart_putchar,NULL); // uses malloc/calloc, it might be inconvenient
}
| improve this answer | |
  • Well, the thing is, this is an exercise for school. I submitted it because the right HEX-value is displayed, so good enough for now, but we are not allowed anymore to use loop and setup. So if there is another way to make it work, it would be nice. – JeroenJK Sep 19 '16 at 17:57
  • @JeroenJK: You are not allowed to write setup() and loop() and yet you can use Serial? This makes little sense to me: if any functionality of Arduino core is OK, then setup() and loop() are the most standard way to use it. Anything else, including my answer, is just a hack. – Edgar Bonet Sep 19 '16 at 18:04
  • @JeroenJK Well, if I use initVariant() build fails on multiple definitions of main. So you have to skip whole arduino.h and use old school registers and so on. Or printf, but it's not so easy... – KIIV Sep 19 '16 at 18:10
  • @EdgarBonet You are totally right here. I think that in a later class they will explain USART to us. But we may use other Arduino.h functionalities throughout the entire course, which is strange, yes. I first used crosspack which couldn't include Arduino.h easily, but that wasn't sufficient .. – JeroenJK Sep 19 '16 at 18:24
  • @JeroenJK see updated code, it doesn't even need anything from arduino – KIIV Sep 19 '16 at 18:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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