ATmega8a & Python serial communication problem

I’ve written a C++ application to transmit a character from my PC to ATmega8A and from it to my PC once again using USB to serial cable. I’ve attached LCD HD44780 to the microcontroller to display the sent and received characters.

The connection between the two devices is established successfully, but I have a problem in encoding and decoding the character. For example:

  • If I send (using serial terminal) from PC the character ‘1’, it displays ‘g’ on LCD and once received by my PC again as ‘L’.
  • Send from PC the character ‘A’ it displays ‘_’ on LCD and once received by my PC again as ‘P’.
  • Send from PC the character ‘a’ it displays ‘o’ on LCD and once received by my PC again as ‘x’.

And so on, I tried different serial terminal apps and got the same result, I’ve tried many times to make it work but without success. So here’s my code:

#define DP4 PC5
#define DP5 PC4
#define DP6 PD7
#define DP7 PD4
#define DE  PD6    //! Display Enable pin
#define DRS PB0    //! Display Registers select pin
#define DRW PD5    //! Display Read/Write pin 
#define BAUD_RATE 19200

#include "KH_Atmega8.hpp"
#include <Arduino.h>
#include "KH_USART_CPP.hpp"
#include "LCDHD44780_AVRLib.hpp"

// LCD Setup
 LCD_HD44780 * ptrLCD;
 LineNumber myLine ;   //Line number to write in
 Page myPage=Page_1;   //The page number
 char pos =1 ;      // //chacter postion on the LCD 

//Setup output file stream
FILE Usart_WR_Stream;
int  WriteByteToStdout(char u8Data, FILE *stream);
char strStream[25]={' '};

int main()
{
  LCD_HD44780 myDisplay (DP4,DP5,DP6,DP7,PORT_C_,PORT_C_,PORT_D_,PORT_D_,DRS,DE,DRW,PORT_B_,PORT_D_,PORT_D_);   
  ptrLCD = &myDisplay;
 //baud rate 19200 ,8 data bits no parity, 1 start bit, 1 stop bit 
  ATMG8A_USART my_Serial(BAUD_RATE,true,true);  //(Baud rate , Enable Rx,Enable Tx)
  char cv = 'V' ;
   
  Usart_WR_Stream.put = WriteByteToStdout;
  Usart_WR_Stream.flags = _FDEV_SETUP_WRITE;
  Usart_WR_Stream.buf=strStream;
  stdout = &Usart_WR_Stream;
   
  myDisplay.LCD_SHOW_String(Page_1,6,Line_1,"Welcome PIO");
  _delay_ms(300);
  myDisplay.LCD_Clear();
  myDisplay.LCD_SHOW_String(Page_1,1,Line_1,"Tx: ");
  myDisplay.LCD_SHOW_String(Page_1,1,Line_2,"Rx: ");
  
  while(1)
  {
   //If there is a received data
      if (UCSRA & (1 << RXC))  
       {   
          //! Receive char
             my_Serial.Receive_Char(cv);
             myLine= Line_2;
             pos =5;
             printf("%d  : %c  ",cv,cv);
            _delay_ms(700) ;
       
           //!Send char
            my_Serial.Transmit_Char(cv); 
            myLine= Line_1;
            pos =5;
            printf("%d : %c ",cv,cv);
          
      }
  return 0;
}
 
int  WriteByteToStdout(char u8Data, FILE *stream)//(char u8Data, __file *stream)//int  ATMG8A_USART::USART_SendByte(char u8Data, FILE *stream)
{
      if( pos<17)
     
    {  
    
       ptrLCD-> LCD_Show_Character (Page_1,pos,myLine,u8Data);
       pos+=1;
     }
     return pos;
}

and my serial class definition

#include "KH_Atmega8.hpp"
#include "KH_USART_CPP.hpp"
#include "util/delay.h"
#include <stdlib.h>

  ATMG8A_USART::ATMG8A_USART (unsigned long ubrr,bool en_tx,bool en_rx)
    {  
          
           Rx_Tx_BufferPtr= Rx_Tx_Buffer;
           index=0;
            #define MYUBRR   ((F_CPU/(ubrr * 16UL))-1)
    //Set the Baud rate
        UBRRH = (unsigned char ) (MYUBRR >> 8);
        UBRRL = (unsigned char ) MYUBRR;

    

     //Set data frame formate 8 Data bits 1 stop pits , no parity check
       UCSRC= 0b10000110; 
    
    // Enable Transmitter
      if(en_tx) UCSRB |= (1 << TXEN);
      
    //Enable Receiver 
       if(en_rx)  UCSRB |= (1 << RXEN) ;  
      
     // General index variable to store the current index
       index=0;
      
           DDRC |= 1 << DDC0; //set for led tx
           DDRD |= 1<< PD2; // utpur for the led rx
          
    }
   void ATMG8A_USART::Clear_RX_TX_Buffer()
   {
      for(uint8_t i=0;i<=19;i++)
      {
         Rx_Tx_Buffer[0]='\0';
      }
   }
   void ATMG8A_USART::ResetPtr()
     {
        Rx_Tx_BufferPtr = Rx_Tx_Buffer;
     }

    ATMG8A_USART::~ATMG8A_USART()
    {
    }
   //! For test
  bool ATMG8A_USART::Transmit_Char ( char & data)
    {
       //$ Wait for Empty Transmit buffer (UDR)/ UDRE UART Data Transmit Buffer empty flag
        while (! (UCSRA & (1 << UDRE)));       //Do nothing
          //  return false;
         UDR = data;
         PORTC ^= 1<< PC0;
         return true;  
    }
    
bool ATMG8A_USART::Receive_Char( char & data) 
    {
        //wait for data to be received
        while (! (UCSRA & (1 << RXC)));
          //  return false;
        data = (unsigned char)UDR;
        PORTD ^= 1 << PD2;
        return true;
    }

and my python script is

import serial
import keyboard
import time
import kh_Serial_comm_Py as kh_ser
import Py_AVR_DecIncod as kh_avr
#import My_Py_Functions.py as mfn

#Setup the serial port
my_SPort = serial.Serial()
my_SPort.port = kh_ser.Select_Ser_Port()  #mpf.Select_Ser_Port()
my_SPort.baudrate = 19200
my_SPort.parity = 'N'
my_SPort.stopbits = 1
my_SPort.bytesize = 8
try:
    my_SPort.open()
except:
    pass
#Store read data
In_Data_List = []

#source of sent data
#out_Data=[]
out_Data =[b'A',b'a',b'B',b'b',b'C',b'c',b'D',b'd']

indx=0

if my_SPort.is_open :
    print("Port: {0} is opend".format(my_SPort.port))
    while 1:
        while my_SPort.in_waiting:              # a received data is unread yet
            print('reciving bytes in ' )
            data_In = my_SPort.read()
            In_Data_List.append((data_In))
            print('\t',"Data recived --> ",(data_In))
        else:
            print(f'Sending data {out_Data[indx]})
            my_SPort.write(out_Data[indx]          
            if indx <7:
                indx+=1
            if indx==7 :
                indx =0
                break
                
        if keyboard.is_pressed('q'):
            my_SPort.close()
            print("Port is closed")
            break
        time.sleep(3)
       
else:
    print(f"Can't open port {my_SPort.port}")
    #keyboard.parse_hotkey_combinations({'Ctrl','C'})    
print('Sent Charcters','\n',out_Data ,'\n','Received charcaters',"\n",In_Data_List)

Tx_Rx = [out_Data,In_Data_List]
datafile = open("SavedData.txt",mode='w')

datafile.write(str(Tx_Rx))
datafile.close()
print('SavedData.txt has been created','\n',Tx_Rx)

When using the Serial class in Python, you’d normally pass arguments to the constructor like this:

my_SPort = serial.Serial(port=kh_ser.Select_Ser_Port(), baudrate = 19200, ...)

Opening the port in a bare try...except block like you’re doing is a very bad idea because it’ll catch and ignore any error. Did it open the serial port? Don’t care! Just keep going!

Also, aren’t my_SPort.is_open and my_SPort.in_waiting methods? Which serial module are you using anyway? The one I’m familiar with has my_SPort.isOpen() and my_SPort.inWaiting(), and if you don’t include the parentheses, it’ll simple check whether the methods themselves are ‘truish’ (my_SPort.isOpen is always treated as true, whereas my_SPort.isOpen() calls the method to check whether the port is open).

isOpen and similar methods have been deprecated for some time, with is_open (which is a regular member variable, not a method) and co. replacing them.

I have pyserial installed, and although it does have an in_waiting property, it doesn’t have is_open.

Anyway, the first code has a missing } and the third has a missing ). Also, the third has a while...else loop with no break in the while part, so the else part will never be run.

is_open was added in pyserial 3.0, released in 2015. For some reason it’s an instance variable, not a property, so you won’t see it if you just look at the serial.Serial class itself.

You have it backwards. The else clause of a while ... else statement will run when the while condition becomes False unless the loop is exited via break.

Oops, you’re correct about the while...else loop. It’s still strange, though!

I’ve found a post on StackOverflow that might be helpful:

atmega - How to do hardware UART using Atmega8 - Stack Overflow

Dears
thanks for your answers,
I worked around this by making a dictionary to map the transmitted character and the received one,
each time I send or receive a character I must search the dictionary and get the supposed correct character.
I know it’s not efficient solution but temporary solve my problem till I discover the cause of the problem which made me very wonder !!!.

In terms of looking for the cause, my personal suspicion woul be a
mismatch in the serial protocol. Your original code has this comment:

 baud rate 19200 ,8 data bits no parity, 1 start bit, 1 stop bit

I’d check carefully:

  • does your pyserial open call actually establish that?
  • is that actually what the device at the far end is using as well?

Getting these mismatched can cause no end of data transmission
confusion, not to mention making finding other bugs next to impossible.

Cheers,
Cameron Simpson cs@cskk.id.au

Have you tried dropping the baud rate? It might be that it can’t get close enough to that baud rate with the given clock frequency, as mentioned in the StackOverflow post.