TheAptKid
TheAptKid

Reputation: 1571

Delayed uart command execution

I'm writing a small embedded program, where I send some commands over uart to the atmega328p chip. The commands start with the character $ and end with the character # (so I know when to perform the parsing). Upon receiving the command I parse it and turn the device on (COMMAND:TURN_ON_I1) or off (COMMAND:TURN_OFF_I1). The application currently looks like this:

// ------- Defines -------- //
#define F_CPU 8000000UL 

#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include "pinDefines.h"
#include "USART.h"

#define RECEIVE_BUFFER_SIZE 100

// Control output value
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)

// Set pin mode (input or output)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)

// The DDRD port contains only two pins:
#define REL_BTN_SIM_2 PD6 // PD6 = REL_BTN_SIM_2

void initUSART(void) {                                /* requires BAUD */
  UBRR0H = UBRRH_VALUE;                        /* defined in setbaud.h */
  UBRR0L = UBRRL_VALUE;
#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 printString(const char myString[]) {
  uint8_t i = 0;
  while (myString[i]) {
    transmitByte(myString[i]);
    i++;
  }
}

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

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

int main(void) {

    //$COMMAND:TURN_ON_I1#
    //$COMMAND:TURN_OFF_I1#

    char s[RECEIVE_BUFFER_SIZE];
    char readSerialCharacter;

    // -------- Inits --------- //
    DDRB = 0b00000111;
    DDRC = 0b00001000;
    DDRD = 0b11000000;

    initUSART();

    // ------ Event loop ------ //
    while (1) {

        printString("Waiting for the start of string (char $).\r\n");
        do { } while ( receiveByte() != '$'); // Wait for start of string.

        // Fill the array until the end of transmission is received
        int i=0;

        do {

            // If nearing end of buffer, don't fill the buffer and exit the loop
            if(i<RECEIVE_BUFFER_SIZE-1){
                readSerialCharacter = receiveByte();
                s[i++] = readSerialCharacter;
            }else
                break;
        } while (readSerialCharacter != '#');   // Wait for end of string.

        s[i] ='\0'; // Terminate the string

        printString("The whole received command:\r\n");
        printString(s);
        printString("\r\n");

        // Other commands (temperature, relay control)

        // REL_BTN_SIM_2
        else if(strstr(s, "COMMAND:TURN_ON_I1") != NULL)
        {
            printString("Will set I1 on!");
            output_high(PORTD, REL_BTN_SIM_2);
        }
        else if(strstr(s, "COMMAND:TURN_OFF_I1") != NULL)
        {
            printString("Will set I1 off!");
            output_low(PORTD, REL_BTN_SIM_2);
        }

        else
            printString("Unknown command.\r\n");

        // Clear the buffer
        memset(s,'\0', sizeof(s));

        } 
        /* End event loop */
        return (0);
    }

I noticed that after I send a command around seven or eight times (or more), the serial communication is interrupted or that the command is executed with a delay. I can also see, that the debug strings "Will set I1 off!", "Will set I1 on!" are printed, but the state of the outputs are not changed (or are changed with a delay of a couple of seconds).

I was wondering if someone would know, what I'm doing wrong?

Thanks.

Upvotes: 1

Views: 160

Answers (1)

Stefan Bormann
Stefan Bormann

Reputation: 693

You have a nice definition of set_output(), but you are not using it. So I suspect that you never enabled the output driver. By setting the port register, you just enable the weak pull-up. Maybe that is not strong enough to switch on your relay driver fast. Do you have a capacitor in that driver circuit?

Upvotes: 1

Related Questions