Search code examples
ccygwinatmegamicrochiptermios

Transmission and receiving of data through serial(in C)


I'm trying to write a program where one part—and the most important part—of the program is to establish communication of transmission and reception through the serial port file "dev/ttyS2" using termios and a microship controller(Atmega169P). I am doing this in C.

The program has two sides. One side is the simulation side, where I run a main file through the Cygwin terminal. The file contains simple transmission and reception termios code(see figure 1). The code is expected to communicate this through the serial file "dev/ttyS2". I'm using a physical serial cable with a converter to have it plugged into my laptop(the other end is connected to the microchip controller). The second side of the program is the controller side. This side has the function of reading the file through the USART register UDR0 (see figure 2). It has a simple USART_Init() finction to initialize the port for proper transmission ad reception of data. The data being transmitted is simple bit configurations(e.g 0b0101).

Figure 1 (simulation side)

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void sendChar(int fd){

    char input = getchar();

    if (input == 'n') {
        uint8_t out = 0b0001;
        write(fd, &out, 1);
    }

    if (input == 's') {
        uint8_t out = 0b0100;
        write(fd, &out, 1);
    }

    if (input == 'e') {
        printf("You have exited the simulation");

    }
    close(fd);
}

void main() {

    int fd;
    fd = open("/dev/ttyS2",  O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd==-1) {printf("Couldn't open specified file");}

    struct termios tty;

    tcgetattr(fd, &tty);
    cfsetospeed(&tty, B9600);
    cfsetispeed(&tty, B9600);
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;
    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tcsetattr(fd, TCSANOW, &tty);

    sendChar(fd);
    }

Figure 2 (controller side)

#include <avr/io.h>
#include <stdio.h>
#define BAUD 9600
#define F_CPU 8000000UL
#define UBRR_VALUE (F_CPU / (BAUD * 16UL) )

void USART_init(void)
{   // Set baud rate prescaler
    UBRR0H = (UBRR_VALUE >> 8);
    UBRR0L = UBRR_VALUE;
    // Enable receiver and transmitter
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
    // Set frame format: 8 data bits, no parity, 1 stop bit
    UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
}

unsigned char USART_Receive(void) {
    // Wait for data to be received
    while(!(UCSR0A & (1<<RXC0))); 
    // Get and return received data from buffer
    volatile uint8_t data = UDR0;
    if (UDR0 == 0b0001) {
        writeChar('1',1);
    }
}

int main(){

        USART_init();
    LCD_init();
    
    USART_Receive();
    writeChar('1',5);
            
}

My first test was to see whether the transmission from the simulation side worked. To test this I put the block of code seen in fig:2 that checks whether the register has the value "UDR0 == 0b0001". And if this is the case, the program would write to the(fully functional) write_char() function that writes a "1" to position 1 on the microchip controller display(hence also the LCD_Init function in main). As you probably could've guessed, the intented does not happen. Nothing seems to appear on the LCD display apart from the (also test) code that calls write_char() to write "1" on position 5.

What should be happening—If you haven't already gathered it from the above—is that the controller side should write "1" on position 1 of the LCD diaplay to indicate that the transmission and reception is connected and communicating correctly between the controller and the simulation side.


Solution

  • So, am I reading this right... You see a value of '1' in position 5 on the LCD?

    If so, in the following code the value that is being read from the USART isn't 0b0001 (rather the UDR0 isn't 0b0001):

       unsigned char USART_Receive(void) {
            // Wait for data to be received
            while(!(UCSR0A & (1<<RXC0))); 
            // Get and return received data from buffer
            volatile uint8_t data = UDR0;
            if (UDR0 == 0b0001) {
                writeChar('1',1);
            }
        }
    

    You may be getting "spurious" data on the UART when it is first read. I've had this on Microchip controllers before, I've had to perform a dummy read initally and discard the value.

    It looks like you maybe read a "spurious" value, this would get you out of the following loop:

    while(!(UCSR0A & (1<<RXC0)));
    

    But the value isn't 0b0001. Can you put a breakpoint on the following line:

    if (UDR0 == 0b0001) {
    

    and see what is in the variable data?

    The code is then carrying on to eventually put the value of '1' in position 5.

    int main(){
    
            USART_init();
        LCD_init();
        
        USART_Receive(); //Coming out of this function
        writeChar('1',5); //Displaying the value of '1' in position 5
                
    }