uart on avr328p returns strange characters

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
i am just starting with microcontrollers so i don't know much about them to begin with.but as of now i am learning to configure uart hardware registers for serial communication and i seem to be stuck with weird strange characters being printed on my serial terminal. I am using avr328p-pu(extracted from an arduino uno board) with an external 16mhz oscillator and a usb to ttl converter(5V) for usb to serial conversion. I'm not using the power supply that comes with the usb-ttl adaptor instead i am using the powerline pins on arduino board as for the circuit diagram i will upload it and the code that i am using as well.
Initially i thought that my baud rate is messed up somehow because of that i hardcoded the baud rate in the registers using a baud rate calculator for 16mhz clock cycle you will see that in the code. could it be that i am using long jumper wires which could cause some noise?
can anyone help with this another thing that i noticed was when i unplug the power from the board the chip is still powered from the usb-ttl adaptor even though i am not using it's 5V power supply pin can anyone look at the circuit and explain that to me as well.
i am using coolTerm for serial Terminal and it is set to 9600
Screenshot 2023-12-07 at 7.45.46 PM.png
serialCom.c:
#include<avr/io.h>
#include<util/delay.h>
#include "USART.h"

int main(void){
    char serialcharacter;

    DDRB|=(1<<0)|(1<<1)|(1<<2);
    initUSART();


    while(1){
        serialcharacter = receiveByte();
        transmitByte(serialcharacter);
        PORTB=serialcharacter&(255>>5); /*get the 3 most significant bits*/
    }
}
USART.h:
/* Functions to initialize, send, receive over USART

   initUSART requires BAUD to be defined in order to calculate
     the bit-rate multiplier.
*/

#ifndef BAUD                          /* if not defined in Makefile... */
#define BAUD  9600                     /* set a safe default baud rate */
#endif

                                  /* These are defined for convenience */
#define   USART_HAS_DATA   bit_is_set(UCSR0A, RXC0)
#define   USART_READY      bit_is_set(UCSR0A, UDRE0)

/* Takes the defined BAUD and F_CPU,
   calculates the bit-clock multiplier,
   and configures the hardware USART                   */
void initUSART(void);

/* Blocking transmit and receive functions.
   When you call receiveByte() your program will hang until
   data comes through.  We'll improve on this later. */
void transmitByte(uint8_t data);
uint8_t receiveByte(void);

void printString(const char myString[]);
             /* Utility function to transmit an entire string from RAM */
void readString(char myString[], uint8_t maxLength);
/* Define a string variable, pass it to this function
   The string will contain whatever you typed over serial */

void printByte(uint8_t byte);
                  /* Prints a byte out as its 3-digit ascii equivalent */
void printWord(uint16_t word);
        /* Prints a word (16-bits) out as its 5-digit ascii equivalent */

void printBinaryByte(uint8_t byte);
                                     /* Prints a byte out in 1s and 0s */
char nibbleToHex(uint8_t nibble);
char nibbleToHexCharacter(uint8_t nibble);
void printHexByte(uint8_t byte);
                                   /* Prints a byte out in hexadecimal */
uint8_t getNumber(void);
/* takes in up to three ascii digits,
converts them to a byte when press enter */
USART.c:
#include <avr/io.h>
#include "USART.h"
#include <util/setbaud.h>

void initUSART(void) {                                /* requires BAUD */
  UBRR0H = 0x00;                        /* defined in setbaud.h */
  UBRR0L = 0x67;
#if USE_2X
  UCSR0A |= (1 << U2X0);
#else
  UCSR0A &= ~(1 << U2X0);
#endif
                                  /* Enable USART transmitter/receiver */
  UCSR0B = (1 << TXEN0) | (1 << RXEN0);
  UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);   /* 8 data bits, 1 stop bit */
}


void transmitByte(uint8_t data) {
                                     /* Wait for empty transmit buffer */
  loop_until_bit_is_set(UCSR0A, UDRE0);
  UDR0 = data;                                            /* send data */
}

uint8_t receiveByte(void) {
  loop_until_bit_is_set(UCSR0A, RXC0);       /* Wait for incoming data */
  return UDR0;                                /* return register value */
}


                       /* Here are a bunch of useful printing commands */

void printString(const char myString[]) {
  uint8_t i = 0;
  while (myString[i]) {
    transmitByte(myString[i]);
    i++;
  }
}

void readString(char myString[], uint8_t maxLength) {
  char response;
  uint8_t i;
  i = 0;
  while (i < (maxLength - 1)) {                   /* prevent over-runs */
    response = receiveByte();
    transmitByte(response);                                    /* echo */
    if (response == '\r') {                     /* enter marks the end */
      break;
    }
    else {
      myString[i] = response;                       /* add in a letter */
      i++;
    }
  }
  myString[i] = 0;                          /* terminal NULL character */
}

void printByte(uint8_t byte) {
              /* Converts a byte to a string of decimal text, sends it */
  transmitByte('0' + (byte / 100));                        /* Hundreds */
  transmitByte('0' + ((byte / 10) % 10));                      /* Tens */
  transmitByte('0' + (byte % 10));                             /* Ones */
}

void printWord(uint16_t word) {
  transmitByte('0' + (word / 10000));                 /* Ten-thousands */
  transmitByte('0' + ((word / 1000) % 10));               /* Thousands */
  transmitByte('0' + ((word / 100) % 10));                 /* Hundreds */
  transmitByte('0' + ((word / 10) % 10));                      /* Tens */
  transmitByte('0' + (word % 10));                             /* Ones */
}

void printBinaryByte(uint8_t byte) {
                       /* Prints out a byte as a series of 1's and 0's */
  uint8_t bit;
  for (bit = 7; bit < 255; bit--) {
    if (bit_is_set(byte, bit))
      transmitByte('1');
    else
      transmitByte('0');
  }
}

char nibbleToHexCharacter(uint8_t nibble) {
                                   /* Converts 4 bits into hexadecimal */
  if (nibble < 10) {
    return ('0' + nibble);
  }
  else {
    return ('A' + nibble - 10);
  }
}

void printHexByte(uint8_t byte) {
                        /* Prints a byte as its hexadecimal equivalent */
  uint8_t nibble;
  nibble = (byte & 0b11110000) >> 4;
  transmitByte(nibbleToHexCharacter(nibble));
  nibble = byte & 0b00001111;
  transmitByte(nibbleToHexCharacter(nibble));
}

uint8_t getNumber(void) {
  // Gets a numerical 0-255 from the serial port.
  // Converts from string to number.
  char hundreds = '0';
  char tens = '0';
  char ones = '0';
  char thisChar = '0';
  do {                                                   /* shift over */
    hundreds = tens;
    tens = ones;
    ones = thisChar;
    thisChar = receiveByte();                   /* get a new character */
    transmitByte(thisChar);                                    /* echo */
  } while (thisChar != '\r');                     /* until type return */
  return (100 * (hundreds - '0') + 10 * (tens - '0') + ones - '0');
}
Screenshot 2023-12-07 at 6.47.20 PM.png
 

MrChips

Joined Oct 2, 2009
30,805
Do not connect LED loads directly to logic outputs. It will distort the output.
I know that this is not your problem but it is something that you should know.

Your circuit does not show the frequency of the quartz crystal. The first item to check is the baud. Other items to check are number of bits, parity setting, and the logic LO/HIGH requirements of the receiver.

1701961367858.png
 

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
Do not connect LED loads directly to logic outputs. It will distort the output.
I know that this is not your problem but it is something that you should know.

Your circuit does not show the frequency of the quartz crystal. The first item to check is the baud. Other items to check are number of bits, parity setting, and the logic LO/HIGH requirements of the receiver.

View attachment 309386
in regards to the led you are saying i should use a resistor with it right?(i am using one but forgot to put in the circuit diagram)
frequency of crystal oscillator is 16mhz
are you asking me to check all those thing in coolTerm or in my program that i have uploaded and could you please elaborate on low/high requirement of the receiver cause i didn't get that one?thanks for helping
 

MrChips

Joined Oct 2, 2009
30,805
Do you have access to an oscilloscope?
If you plan on getting serious with any kind of MCU development then an oscilloscope is an essential tool.
 

Jon Chandler

Joined Jun 12, 2008
1,051
"Strange characters" is a little vague, but if all you're getting is gibberish, start with baud rate, data bits and stop bits. If these don't match on both ends, you get garbage. Line termination (CR, LF) matter too.
 

tumbleweed

Joined Jun 27, 2023
15
when i unplug the power from the board the chip is still powered from the usb-ttl adaptor even though i am not using it's 5V power supply pin
A UART TX line idles in the high state when there's no data being transmitted, so the TX output of the USB-UART adapter is powering the uC through the input protection diodes on its RX input pin.

You can see this if you measure the chip VCC supply voltage when power is unplugged but still connected to the usb adapter
 

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
Do you have access to an oscilloscope?
If you plan on getting serious with any kind of MCU development then an oscilloscope is an essential tool.
no i don't have an oscilloscope and can't buy one at the moment because i am just a student i don't have resources to buy it. can i use a logic analyzer?
 

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
"Strange characters" is a little vague, but if all you're getting is gibberish, start with baud rate, data bits and stop bits. If these don't match on both ends, you get garbage. Line termination (CR, LF) matter too.
i have checked baud rate,data bits and stop bit multiple times and all of them align both sides but i am not sure about line termination how do you tell which one to select?
 

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
A UART TX line idles in the high state when there's no data being transmitted, so the TX output of the USB-UART adapter is powering the uC through the input protection diodes on its RX input pin.

You can see this if you measure the chip VCC supply voltage when power is unplugged but still connected to the usb adapter
should i do something about this like place a transistor or something or should i just leave it?
 

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
"Strange characters" is a little vague, but if all you're getting is gibberish, start with baud rate, data bits and stop bits. If these don't match on both ends, you get garbage. Line termination (CR, LF) matter too.
yup i am getting garbage values but sometimes i get the right one
 

Dave Lowther

Joined Sep 8, 2016
225
i seem to be stuck with weird strange characters being printed on my serial terminal.
If I were you I'd try something simpler at this point. I'd have the 328p code just transmitting the same character (e.g. 'A') forever with a delay of e.g. 1 second between transmits. The resulting code would be much simpler to debug. When you have that working you could then move on to adding the receive / echo code.
can i use a logic analyzer?
If the simple tx code I proposed doesn't work then you could use a logic analyser to look at what is being output on the tx pin, but it would be better to output something where the bit sequence from the character alternates between 0 and 1, e.g. 'U' = 0x55
Also the 10pF capacitor should be much higher, typically 100nF should be used, but I don't think that's causing your current problem.
 

MrChips

Joined Oct 2, 2009
30,805
no i don't have an oscilloscope and can't buy one at the moment because i am just a student i don't have resources to buy it. can i use a logic analyzer?
If you don’t have resources to buy an oscilloscope then you won’t have resources to buy a logic analyzer. Even a DSO138 is better than no oscilloscope. You would use this to check the correct transmission of “U”.
 

tumbleweed

Joined Jun 27, 2023
15
should i do something about this like place a transistor or something or should i just leave it?
If you're going to have the adapter connected without powering the uC it's best to isolate that TX signal since it can cause startup problems, but you might find a simple way to do this is to insert a series resistor, say 10K or so in the TX line and enable the BOD brown out reset detection of the uC. Not a 100% cure but it's simple and usually "works most of the time", if you're ok with that.
 

Dave Lowther

Joined Sep 8, 2016
225
i am not sure about line termination how do you tell which one to select?
At this stage I don't think it matters. It would only matter if either or both the following were true:
a) You were using some code in the 328p to receive whole lines of input characters or detect end of line character(s).
b) You wanted to break up what the 328p is sending into separate lines on your terminal display.
If / when you get to the stage where it does matter then ask again.
 

Dave Lowther

Joined Sep 8, 2016
225
i seem to be stuck with weird strange characters being printed on my serial terminal.
I copied your code into the Arduino IDE. I didn't modify USART.h or USART.c (other than renaming it to .cpp). I modified serialCom.c, but only to fit in with setup() and loop(). I also modfied the line "transmitByte(serialcharacter)" to add 1 to the character to be output, so I was sure I wasn't seeing an echo done by the terminal itself.
1702051853289.png
It works running on an Uno. When I type "ABC" and then click on 'send' it outputs "BCD".
1702051997691.png

1702052039164.png
I don't know if there's something in the hardware setup done by an Arduino sketch by default that has fixed the problem. I didn't expect it to work so easily first time. It only took me about 10 minutes to try this.
[Edit added the following text] I thought it would be easy to Google and find out what the IDE terminal expects for number of data bits, parity bit, and number of stop bits. I couldn't find a spec for the terminal, but for Serial.begin() the default is 8 data bits, no parity, one stop bit. So it seems reasonable to assume that the IDE terminal uses those settings. Your code must also be using the same settings, otherwise it wouldn't have displayed "BCD" correctly.
[Edit added the following text and CoolTerm image] It works with CoolTerm too.
1702058920045.png
 
Last edited:

Thread Starter

pointdexter16

Joined Oct 31, 2023
28
I copied your code into the Arduino IDE. I didn't modify USART.h or USART.c (other than renaming it to .cpp). I modified serialCom.c, but only to fit in with setup() and loop(). I also modfied the line "transmitByte(serialcharacter)" to add 1 to the character to be output, so I was sure I wasn't seeing an echo done by the terminal itself.
View attachment 309495
It works running on an Uno. When I type "ABC" and then click on 'send' it outputs "BCD".
View attachment 309496

View attachment 309497
I don't know if there's something in the hardware setup done by an Arduino sketch by default that has fixed the problem. I didn't expect it to work so easily first time. It only took me about 10 minutes to try this.
[Edit added the following text] I thought it would be easy to Google and find out what the IDE terminal expects for number of data bits, parity bit, and number of stop bits. I couldn't find a spec for the terminal, but for Serial.begin() the default is 8 data bits, no parity, one stop bit. So it seems reasonable to assume that the IDE terminal uses those settings. Your code must also be using the same settings, otherwise it wouldn't have displayed "BCD" correctly.
[Edit added the following text and CoolTerm image] It works with CoolTerm too.
View attachment 309510
does that mean there is problem with the serial adapter or the circuitry? let me get DSO138 and check
 

Dave Lowther

Joined Sep 8, 2016
225
does that mean there is problem with the serial adapter or the circuitry? let me get DSO138 and check
Either a problem with the way you built your code or a hardware problem.
You could find out which by:
- Take your 328p off the patch board and put it back in the Arduino board.
- Does it work now?
-- If yes then there's a problem with your patchboard hardware set up
-- If no then continue with steps below
- Do what I did with the Arduino IDE and check it works (I assume this will work)
- Plug the 328p back into the patch board
- Does it work now?
-- If yes then there's a problem with your code build
-- If no then I'd be a bit puzzled.

Suspected hardware problems:
- Long jumper wires, depending on what they are connecting.
- That 10pf decoupling capacitor should be replaced with 100nF
- Something about the way you have the USB-serial adaptor wired. It might be better to use the power from the adaptor and remove the other power from the Arduino 5V pin
 

Dave Lowther

Joined Sep 8, 2016
225
let me get DSO138 and check
Although you may not need it for debugging this, it would be a good investment if you can afford it. There are so many cases where having a look with a scope can shed light on how something works, or why something isn't working. I have the cheapest Picoscope. Although I don't need to use it often, when I do need to look at something that's not working it can save me a lot of frustration. I found the scope useful when I was learning how I2C works.
 

Dave Lowther

Joined Sep 8, 2016
225
I'm not using the power supply that comes with the usb-ttl adaptor instead i am using the powerline pins on arduino
I didn't spot one implication of what you said when I first read that. I just assumed you were taking the 5V power from the Arduino board. You said "powerline pins". So now I'm thinking maybe you didn't connect the gnd pin of the adaptor to the 0V rail of your breadboard. I note there is a gnd connection to the adaptor shown on your schematic so maybe you do have the gnd to 0V connection.
If you haven't made that connection then your setup may not have a common 0V between the USB adaptor and your bread board power supply. This would be the most likely cause of the problem.
 
Last edited:
Top