another strange problem with USART on atmega324

Go To Last Post
46 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello everyone.
i have a system which consists of 2 atmega324 mcu (i will say it as mcu A and mcu B), connected each other through USART, and mcu A is connected to other devices using same protocol, and i program my system using codevision. Both of them use interrupt-driven USART on RX side.

btw, the problem is when mcu B send 4 packets in sequence(0x01, 0x02, 0x03, and 0x04) to mcu A, mcu A respond it by sending return packets but seems like mcu B respond the return packets in incorrect order (0x01 i send first returns a packet that is supposed to be a return packet of 0x04, but when i probe it using computer and do the same thing, it returns packets correctly....

can you help me solve this annoying problem? thx for replying :)

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

your help is very appreciated :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

e0ne199 wrote:
your help is very appreciated :D

Thank you. :D

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

larryvc wrote:
e0ne199 wrote:
your help is very appreciated :D

Thank you. :D

you don't even help me :p
btw do you know how to solve my problem? :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am going to look at your code later tonight.

My last post was for the sake of humor. :D

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How many bytes in each packet? Is there a format or protocol for each packet, like flag, opcode, bytecount, databytes, checksum? Can you just send individual characters from A to B and print them out? Are you using 0-5V or +-12V on the serial cable?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your programs are complex. To save time can you post here only the code for the packet transfer and receive routines of mcu A and mcu B?

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the packet transfer and receive routines are all already included in the code, and the problems are when my mcus are trying to send an array of packets and receive it in master side ...the transmit code on the slave is like this :



interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status,data;
status=UCSR1A;
data=UDR1;
request_=data;
 
  

  if(request_==0x20) { putchar1(real_packet[1]);}
  if(request_==0x30) { putchar1(real_packet[2]);}
  if(request_==0x40) { putchar1(real_packet[3]);}      
  if(request_==0x60) { putchar1(real_packet2[0]);}
  if(request_==0x70) { putchar1(real_packet2[1]);}   
  if(request_==0x80) { putchar1(real_packet2[2]);}
  if(request_==0x90) { putchar1(real_packet2[3]);};
  ........

btw, when i try to compile my program (slave side) with codevision AVR by enabling 2 non-default warnings i have just set recently, after compilation i receive a message "possible loss of precision" on lines containing commands to send the array of packets...do you know how to solve this??
looks like the transmitted packet on slave side is distorted or something like that..

before that, thx for helping :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello, anyone?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Before I downloaded it your file above had been downloaded 12 times yet none of the down-loaders responded. Having now looked at it I totally agree with Larry:

Quote:

Your programs are complex.

No one is going to wade through code of that complexity to find the bit you are talking about (and some comments would have helped!). Try cutting this down to the minimal subset for each micro that still demonstrates the issue and post that. (90% of the time doing this kind of cutting down leads to the source of the issue in a "slaps forehead" moment anyway ;-)).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here is the problem :

interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status,data;
status=UCSR1A;
data=UDR1;
request_=data;
 
 
  if(request_==0x10) { putchar1(real_packet[0]);}
  if(request_==0x20) { putchar1(real_packet[1]);}
  if(request_==0x30) { putchar1(real_packet[2]);}
  if(request_==0x40) { putchar1(real_packet[3]);}     
  if(request_==0x60) { putchar1(real_packet2[0]);}
  if(request_==0x70) { putchar1(real_packet2[1]);}   
  if(request_==0x80) { putchar1(real_packet2[2]);}
  if(request_==0x90) { putchar1(real_packet2[3]);};
  ........ ( 

when i try to compile it, i get 8 warning messages that say "possible loss of precision"...do you know how to handle this problem?

btw, 2 USARTS (with only RX interrupt on USART1) are enabled when this code is running..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

btw does anyone here knows how to make a packet with checksum, or something like encapsulation on TCP?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Having now looked at it I totally agree with Larry:

I am definitely going to buy a lotto ticket today!!! :wink:

"I may make you feel but I can't make you think" - Jethro Tull - Thick As A Brick

"void transmigratus(void) {transmigratus();} // recursio infinitus" - larryvc

"It's much more practical to rely on the processing powers of the real debugger, i.e. the one between the keyboard and chair." - JW wek3

"When you arise in the morning think of what a privilege it is to be alive: to breathe, to think, to enjoy, to love." -  Marcus Aurelius

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How is "real_packet" declared?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You appear to have a regular CodeVision program. The CodeWizard will write your interrupt code for you. There is no need to fiddle with this at all.

Then you call putchar() or getchar() from the foreground as required. Note that you always want to check that there is data available before you call getchar().
Hint. Read rx_counter0 or rx_counter1.

As a general rule you should never call putchar() from inside an ISR().

No. I have not downloaded your whole code.

It is more important to get your program structure designed properly in the first place. Then ask specific questions about specific sequences, having reduced the code down to a minimal size that illustrates your problem.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You appear to have a regular CodeVision program. The CodeWizard will write your interrupt code for you. There is no need to fiddle with this at all.

Then you call putchar() or getchar() from the foreground as required. Note that you always want to check that there is data available before you call getchar().
Hint. Read rx_counter0 or rx_counter1.

As a general rule you should never call putchar() from inside an ISR().

No. I have not downloaded your whole code.

It is more important to get your program structure designed properly in the first place. Then ask specific questions about specific sequences, having reduced the code down to a minimal size that illustrates your problem.

David.

i am now trying to use usart interrupt with buffer as you advised, but do you know how to clear interrupt buffer on codevision? i have tried to disable the receiver but still the buffer contains garbage data...

or maybe can you explain how to use usart buffer in codevision? i have some difficulties when trying it....the packet i get from the buffer is always wrong...thx 4 the advise before :)

Last Edited: Tue. May 22, 2012 - 10:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

but do you know how to clear interrupt buffer on codevision?

Keep calling getchar() until it returns -1 perhaps?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

but do you know how to clear interrupt buffer on codevision?

Keep calling getchar() until it returns -1 perhaps?

wew i am not sure about that...i have tried it but the result was the same...
btw can you explain how to use packets in the buffer?
when i try to use that i always get a wrong packet anyway...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To clear receive buffer:

while (rx_counter0)     // anything there ?
   getchar();           // eat it.

Depending on which channel you are using, you might test rx_counter1 and call getchar1().

Personally, I call this test kbhit().
You will use exactly the same functions whether you use polling or interrupts. The only 'difference' is the kbhit() function.

If your application would benefit from fully interrupt driven putchar() and getchar(), you just tell the CodeWizard.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
To clear receive buffer:

while (rx_counter0)     // anything there ?
   getchar();           // eat it.

Depending on which channel you are using, you might test rx_counter1 and call getchar1().

Personally, I call this test kbhit().
You will use exactly the same functions whether you use polling or interrupts. The only 'difference' is the kbhit() function.

If your application would benefit from fully interrupt driven putchar() and getchar(), you just tell the CodeWizard.

David.

thx for the help :)
but, btw do you know how to get desired packets in buffer?
i read previous thread that i have to include "header" or something, but still i can't figure it out how to use it, i just afraid the code will be more complicated and will give more burden to mcu...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I presume that you have a full CodeVision license. And the CodeWizard will create your interrupt code.

The mcu is used more efficiently with interrupts. It only executes instructions when required.
When you poll, you sit in a tight loop doing nothing apart from wait for a bit to be set.

Yes, the interrupt handling is more complex than polling. The CodeWizard writes it for you. Or you can use Atmel app notes. Or any code written for any cpu ever invented.

Before you can use any functions, you must #include

printf("Hello World\r\n");
while (1) {
    if (kbhit()) {
        putchar(getchar());
    }
}

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

btw kbhit() that you mean is this :

//special macro
#define kbhit()    (rx_counter!= 0)

or this?


while (rx_counter0)     // anything there ?
   getchar();           // eat it. 

thx 4 the previous help again :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have used the word "packet" several times. I think we have some confusion of the use of this word. If you fill out your city and country in your profile, it will help the English speakers to recognize translation problems. I might respectfully suggest that you use a slightly more normal text style to improve the understandability of your messages. All thos lowercase abbreviations are hard to read. No need to save characters. You didn't respond to my question in a previous message. Some might regard this as an affront.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
You have used the word "packet" several times. I think we have some confusion of the use of this word. If you fill out your city and country in your profile, it will help the English speakers to recognize translation problems. I might respectfully suggest that you use a slightly more normal text style to improve the understandability of your messages. All thos lowercase abbreviations are hard to read. No need to save characters. You didn't respond to my question in a previous message. Some might regard this as an affront.

ah sorry my bad, i'm still learning how to type in english well :( , and sometimes i get internet connection problems so the comment i submit is sometimes not displayed correctly (or even failed to submit) and it will take time to edit it again :(

actually i did respond your comments on here:

Quote:
e0ne199 wrote:
the packet transfer and receive routines are all already included in the code, and the problems are when my mcus are trying to send an array of packets and receive it in master side ...the transmit code on the slave is like this :



interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status,data;
status=UCSR1A;
data=UDR1;
request_=data;
 
  

  if(request_==0x20) { putchar1(real_packet[1]);}
  if(request_==0x30) { putchar1(real_packet[2]);}
  if(request_==0x40) { putchar1(real_packet[3]);}      
  if(request_==0x60) { putchar1(real_packet2[0]);}
  if(request_==0x70) { putchar1(real_packet2[1]);}   
  if(request_==0x80) { putchar1(real_packet2[2]);}
  if(request_==0x90) { putchar1(real_packet2[3]);};
  ........

btw, when i try to compile my program (slave side) with codevision AVR by enabling 2 non-default warnings i have just set recently, after compilation i receive a message "possible loss of precision" on lines containing commands to send the array of packets...do you know how to solve this??
looks like the transmitted packet on slave side is distorted or something like that..

before that, thx for helping :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off. How can anyone work with unformatted code?
Secondly. You have fiddled with the RX_USART ISR()

You appear to be peeking into a transitory value 'packet'
Instead you should read a whole sequence of bytes with getchar(). The whole point of buffered interrupts is that you will catch EVERY byte regardless of whether your robot is busy.

If you replace your 'packet' with getchar() you will process each byte in the correct order that it was received. (you can just do 4 getchar()s if you know there are 4 chars available otherwise you test rx_counter0)

David.;;

/*****************************************************
Project : automatic system for final project
Version : 1.0
Date    : 4/20/2012
Author  : E-1 
Company : E-1 Engineering Inc.
Comments: Simple implementation of my program model for my main system :)


Chip type               : ATmega324PA
Program type            : Application
AVR Core Clock frequency: 18.432000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 512
*****************************************************/

#include 
#include 
#include 
#include 


#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

//PWM
#define left_pwm OCR1BL
#define right_pwm OCR1AL


//global variables
char start, packet, val1, val2, val3, val4, val5, val6, val7, val8;
eeprom char id[3];
eeprom char location[4][3] = { {0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
};
int id_count = 0, count = 0, soft_left, soft_right, row = 0, line = 0;

// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 32
char rx_buffer0[RX_BUFFER_SIZE0];

#if RX_BUFFER_SIZE0 <= 256
unsigned char rx_wr_index0, rx_rd_index0, rx_counter0;
#else
unsigned int rx_wr_index0, rx_rd_index0, rx_counter0;
#endif

// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;


// USART0 Receiver interrupt service routine
interrupt [USART0_RXC] void usart0_rx_isr(void)
{
    char status, data;
    status = UCSR0A;
    data = UDR0;
    start = data;
    packet = data;

    if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0) {
        rx_buffer0[rx_wr_index0++] = data;
#if RX_BUFFER_SIZE0 == 256
        // special case for receiver buffer size=256
        if (++rx_counter0 == 0) {
#else
        if (rx_wr_index0 == RX_BUFFER_SIZE0)
            rx_wr_index0 = 0;
        if (++rx_counter0 == RX_BUFFER_SIZE0) {
            rx_counter0 = 0;
#endif
            rx_buffer_overflow0 = 1;
        }
    }
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
    char data;
    while (rx_counter0 == 0);
    data = rx_buffer0[rx_rd_index0++];
#if RX_BUFFER_SIZE0 != 256
    if (rx_rd_index0 == RX_BUFFER_SIZE0)
        rx_rd_index0 = 0;
#endif
#asm("cli")
    --rx_counter0;
#asm("sei")
    return data;
}

#pragma used-
#endif

// Get a character from the USART1 Receiver
#pragma used+
char getchar1(void)
{
    char status, data;
    while (1) {
        while (((status = UCSR1A) & RX_COMPLETE) == 0);
        data = UDR1;
        if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)) == 0)
            return data;
    }
}

#pragma used-

// Write a character to the USART1 Transmitter
#pragma used+
void putchar1(char c)
{
    while ((UCSR1A & DATA_REGISTER_EMPTY) == 0);
    UDR1 = c;
}

#pragma used-


inline void init()
{

    // Crystal Oscillator division factor: 1
#pragma optsize-
    CLKPR = 0x80;
    CLKPR = 0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif


    // Port B initialization
    PORTB = 0x0F;
    DDRB = 0x00;

    //Port C initialization
    PORTC = 0x00;
    DDRC = 0xF0;

    //Port D initialization
    PORTD = 0x30;
    DDRD = 0x30;

    //for dynamixel
    PORTD.7 = 0;
    DDRD.7 = 1;


    //motor config
    //using OCR1AL & OCR1BL
    TCCR1A = 0xF1;
    TCCR1B = 0x02;
    TCNT1H = 0x00;
    TCNT1L = 0x00;
    ICR1H = 0x00;
    ICR1L = 0x00;
    OCR1AH = 0x00;
    OCR1AL = 0x00;
    OCR1BH = 0x00;
    OCR1BL = 0x00;


    // USART0 initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART0 Receiver: On
    // USART0 Transmitter: On
    // USART0 Mode: Asynchronous
    // USART0 Baud Rate: 115200
    UCSR0A = 0x00;
    UCSR0B = 0x98;
    UCSR0C = 0x06;
    UBRR0H = 0x00;
    UBRR0L = 0x09;

    // USART1 initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART1 Receiver: On
    // USART1 Transmitter: On
    // USART1 Mode: Asynchronous
    // USART1 Baud Rate: 115200
    UCSR1A = 0x00;
    UCSR1B = 0x18;
    UCSR1C = 0x06;
    UBRR1H = 0x00;
    UBRR1L = 0x09;




}

void packet_received()
{

    putchar(0x10);
    val1 = packet;
    putchar(0x20);
    val2 = packet;
    putchar(0x30);
    val3 = packet;
    putchar(0x40);
    val4 = packet;

}

//motor movement---------------------
void forward(int left, int right)
{

    left_pwm = left;
    right_pwm = right;
    PORTC.7 = 1;
    PORTC.6 = 0;
    PORTC.5 = 1;
    PORTC.4 = 0;
};
void backward(int left, int right)
{

    left_pwm = left;
    right_pwm = right;
    PORTC.7 = 0;
    PORTC.6 = 1;
    PORTC.5 = 0;
    PORTC.4 = 1;
};
void left(int left, int right)
{

    left_pwm = left;
    right_pwm = right;
    PORTC.7 = 1;
    PORTC.6 = 0;
    PORTC.5 = 0;
    PORTC.4 = 1;
};
void right(int left, int right)
{

    left_pwm = left;
    right_pwm = right;
    PORTC.7 = 0;
    PORTC.6 = 1;
    PORTC.5 = 1;
    PORTC.4 = 0;
};
void stop()
{
    PORTC.7 = 0;
    PORTC.6 = 0;
    PORTC.5 = 0;
    PORTC.4 = 0;
}

//-----------------------------------------
void arrange_position()
{
    while (val4 > 77) {
        putchar(0x40);
        val4 = packet;
        right(254, 250);
    };
    while (val4 > 50) {
        putchar(0x40);
        val4 = packet;
        left(254, 250);
    };
}

void dynamixel_push()
{
    putchar1(0xFF);
    putchar1(0xFF);
    putchar1(0x00);
    putchar1(0x07);
    putchar1(0x03);
    putchar1(0x1E);
    putchar1(0x10);
    putchar1(0x03);
    putchar1(0x00);
    putchar1(0x03);
    putchar1(0xC1);
    delay_ms(1000);
}

void dynamixel_pull()
{
    putchar1(0xFF);
    putchar1(0xFF);
    putchar1(0x00);
    putchar1(0x07);
    putchar1(0x03);
    putchar1(0x1E);
    putchar1(0xFE);
    putchar1(0x01);
    putchar1(0x00);
    putchar1(0x03);
    putchar1(0xD5);
    delay_ms(1000);
}

void preliminary()
{
    while (1) {


        if (start == 0xFF) {
            break;
        };
        if (packet == 0xAA) {
            id[id_count] = getchar();

            switch (id[id_count]) {
            case '9':
                location[1][1] = 1;
                break;
            case 'F':
                location[2][1] = 1;
                break;
            case '%':
                location[1][2] = 1;
                break;
                //some extra books
            case '3':
                location[2][2] = 1;
                break;
            case '<':
                location[1][1] = 1;
                break;
            default:
                break;
            };


            id_count++;
            if (id_count == 2) {
                id_count = 0;
            };
        };
        if (PINB.0 == 0) {
            putchar(0x01);
            delay_ms(250);
        };
        if (PINB.1 == 0) {
            putchar(0x02);
            delay_ms(250);
        };
        if (PINB.2 == 0) {
            putchar(0x03);
            delay_ms(250);
        };
        if (PINB.3 == 0) {
            putchar(0x04);
            delay_ms(250);
        };

    }
}
void transmit()
{
    PORTD.7 = 1;
    DDRD.7 = 1;
}

void receive()
{
    PORTD.7 = 0;
    DDRD.7 = 1;
}

void soft_start()
{
    soft_left = soft_right = 0;
    while (soft_left < 255 || soft_right < 255) {
        forward(soft_left, soft_right);
        soft_left++;
        soft_right++;
        delay_ms(5);
    }
}
void straight()
{
    while (1) {

        packet_received();
        forward(255, 255);


        if (val1 < 45) {
            forward(254, 255);
            delay_ms(60);

        };
        if (val1 > 76 && val1 < 86) {
            forward(255, 250);
            delay_ms(80);
        };
        if (val4 == 0) {
            forward(255, 255);
            delay_ms(1200);
            stop();
            break;
        };

        delay_ms(5);

    }

}
void turn_left()
{
    left(254, 250);
    delay_ms(800);
    while (val4 < 45) {
        packet_received();
        left(254, 250);
        delay_ms(250);
    }

    stop();
}

void turn_right()
{
    right(254, 250);
    delay_ms(800);
    while (val4 > 50) {
        packet_received();
        left(254, 250);
        delay_ms(250);
    }

    stop();
}

void main(void)
{
    init();
#asm("sei")

    preliminary();

    while (1) {
        // soft_start();  //'heating' the system ^_^
        //straight(); 
        //turn_left();
        while (1) {
            packet_received();
            forward(0, 255);
            if (val1 < 45) {
                break;
            };

            delay_ms(1);
        }
        stop();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
First off. How can anyone work with unformatted code?
Secondly. You have fiddled with the RX_USART ISR()

You appear to be peeking into a transitory value 'packet'
Instead you should read a whole sequence of bytes with getchar(). The whole point of buffered interrupts is that you will catch EVERY byte regardless of whether your robot is busy.

If you replace your 'packet' with getchar() you will process each byte in the correct order that it was received. (you can just do 4 getchar()s if you know there are 4 chars available otherwise you test rx_counter0)

David.;;

[HUGE requote of entire previous post removed - moderator]

i'm afraid if i change it become getchar() the process will be halted because getchar() will loop until the packet is received...CMIIW..and if i do so, the interrupt will be useless, or?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The interrupt reads the char from the uart and puts it in an array/buffer/queue (my mental model is an array. Old basic and fortran habit). Kbhit() returns true if there is something in the array (input index has been incremented), getchar pulls out a char from the output index. The indexes chase each other from 0 up to max then back to zero.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off. Please edit your last post to remove the COPY of my post. Long stretches of code are ok as one-offs. It serves no purpose to repeat them verbatim. [done that for him - moderator]

Quote:

i'm afraid if i change it become getchar() the process will be halted because getchar() will loop until the packet is received...CMIIW..and if i do so, the interrupt will be useless, or?

Read any book on C. Think about your PC. Think about most things in life. Your PC receives all your key-presses via interrupts. Even if it was busy writing to disk, reading a DVD, downloading from the internet.

You call getchar() when you want to see the next key in the queue. If there is not one available, it waits until there is.
This is why you call kbhit() to check first. Only call getchar() when kbhit() says there is something to get.

Try any of the CodeVision examples with buffered RX interrupts. You will see that nothing is lost. (unless you are silly, a 64 byte buffer is fine for most AVR projects)

I am still fascinated by whether people really do work with unformatted code. And if so, how do you do it ?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am still fascinated by whether people really do work with unformatted code.

Or comments. :shock:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can cope without the comments. If you choose your names wisely, a formatted listing can be understood.

Mind you, I have a pretty good idea what opinion the OP's teacher will have.

Even if the code does not work, if she has documented it well, the student is more likely to impress an employer.

Quote:
I am still fascinated by whether people really do work with unformatted code.

It is a genuine question. When I used to write 6502 ASM, my editor formatted automatically. What was stored on disk was without any indentation.

Are there C editors that do this ?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

When I used to write 6502 ASM, my editor formatted automatically. What was stored on disk was without any indentation.

Are there C editors that do this ?

I'll bet the editor was forced to do that in the days when every byte on disk was a precious resource! I doubt that modern C editors have the same impetus to implement such a feature.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, Cliff. I wrote the editor!

Yes, when I started to use PCs with more RAM and more disk, there was little point in continuing with compressed code.

All the same, modern PCs could quite easily format automatically. Personally I am happy with a specific 'format' command. Any auto-anything makes me feel uncomfortable.

Hand-formatting takes very little brain power. The average student could come home drunk. Format her assignment. Collapse in a heap. Still gain a reasonable mark even if the assignment does not 'work' perfectly.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
The interrupt reads the char from the uart and puts it in an array/buffer/queue (my mental model is an array. Old basic and fortran habit). Kbhit() returns true if there is something in the array (input index has been incremented), getchar pulls out a char from the output index. The indexes chase each other from 0 up to max then back to zero.

thx for the detail explanation, i have tested it and it did hold the values first in the buffer before it is called :)

david.prentice wrote:
First off. Please edit your last post to remove the COPY of my post. Long stretches of code are ok as one-offs. It serves no purpose to repeat them verbatim. [done that for him - moderator]

Quote:

i'm afraid if i change it become getchar() the process will be halted because getchar() will loop until the packet is received...CMIIW..and if i do so, the interrupt will be useless, or?

Read any book on C. Think about your PC. Think about most things in life. Your PC receives all your key-presses via interrupts. Even if it was busy writing to disk, reading a DVD, downloading from the internet.

You call getchar() when you want to see the next key in the queue. If there is not one available, it waits until there is.
This is why you call kbhit() to check first. Only call getchar() when kbhit() says there is something to get.

Try any of the CodeVision examples with buffered RX interrupts. You will see that nothing is lost. (unless you are silly, a 64 byte buffer is fine for most AVR projects)

I am still fascinated by whether people really do work with unformatted code. And if so, how do you do it ?

David.

still not understand with the unformatted code you're talking about. :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

about this code :

interrupt [USART1_RXC] void usart1_rx_isr(void)
{
char status,data;
status=UCSR1A;
data=UDR1;
request_=data;
 
 

  if(request_==0x20) { putchar1(real_packet[1]);}
  if(request_==0x30) { putchar1(real_packet[2]);}
  if(request_==0x40) { putchar1(real_packet[3]);}     
  if(request_==0x60) { putchar1(real_packet2[0]);}
  if(request_==0x70) { putchar1(real_packet2[1]);}   
  if(request_==0x80) { putchar1(real_packet2[2]);}
  if(request_==0x90) { putchar1(real_packet2[3]);};
  ........ 

i deliberately place my own code into the codevision ISR() so that i can get direct response when the packet is requested from other devices / mcu...or do anyone have a better way to get a direct response just like what i did with this code anyway? :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You normally have short ISR()s that simply fill buffers or set a simple flag.

Your foreground code examines any flags or empties a buffer as a separate operation.

There is no right and wrong way in software. There are often efficient and inefficient or better and worse techniques.

By all means choose your own approach to interrupts and definitely your own approach to formatting.

Incidentally, atomiczombie apparently writes ASM code in a single monster file with no indentation.
Yet he produces some impressive software and hardware.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You normally have short ISR()s that simply fill buffers or set a simple flag.

Your foreground code examines any flags or empties a buffer as a separate operation.

There is no right and wrong way in software. There are often efficient and inefficient or better and worse techniques.

By all means choose your own approach to interrupts and definitely your own approach to formatting.

Incidentally, atomiczombie apparently writes ASM code in a single monster file with no indentation.
Yet he produces some impressive software and hardware.

David.

thx for the response.. btw i have 2 last question :

1) Do you know how to flush USART rx if it is not interrupt-driven?

2) btw if i use kbhit(), will the rx receive the data from outside in correct order?

thx before :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For buffered input, you examine whether there is anything in the buffer.

// for interrupt-driven RX on USART0:
#define kbhit()    (rx_counter0 != 0)

For polling, you check the USART itself.

// for polled RXC
#define kbhit()    (UCSR0A & (1<<RXC0))

You flush a buffer in exactly the same way for either method. i.e.

while (kbhit()) getchar();

kbhit() is just a common name for a function/macro that tests whether there is a byte available.

Since you have CodeVision with its very capable CodeWizard, you might just as well try your own experiments. e.g.

#include 

char c;
printf("type away regardless.   Typing 'S' will sleep the display for a second\r\n");
while (1) {
    if (kbhit()) {
        c = getchar();
        if (c == 'S') delay(1000);
        putchar(c);
    }
}

If you use interrupts, you will not lose any characters at all. If you use polling, any keys typed while the AVR is 'delaying' will be lost.

As I tried to explain earlier, your PC does not lose characters when the disk is running or you are playing a CD. Your PC works like the Wizard interrupt.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
For buffered input, you examine whether there is anything in the buffer.

// for interrupt-driven RX on USART0:
#define kbhit()    (rx_counter0 != 0)

For polling, you check the USART itself.

// for polled RXC
#define kbhit()    (UCSR0A & (1<<RXC0))

You flush a buffer in exactly the same way for either method. i.e.

while (kbhit()) getchar();

kbhit() is just a common name for a function/macro that tests whether there is a byte available.

Since you have CodeVision with its very capable CodeWizard, you might just as well try your own experiments. e.g.

#include 

char c;
printf("type away regardless.   Typing 'S' will sleep the display for a second\r\n");
while (1) {
    if (kbhit()) {
        c = getchar();
        if (c == 'S') delay(1000);
        putchar(c);
    }
}

If you use interrupts, you will not lose any characters at all. If you use polling, any keys typed while the AVR is 'delaying' will be lost.

As I tried to explain earlier, your PC does not lose characters when the disk is running or you are playing a CD. Your PC works like the Wizard interrupt.

David.

wew, what a great explanation! :)
thx for your help, i'll test it soon :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oh yah, one more question... :D
@bobgardner said that i may not put my modified code inside codevision's ISR() and what he said is right, if i put my modified code inside ISR() it will hang my mcu...btw do you know how to do a fast call without using ISR()? at least it wouldn't take time more than 500ms on each call, thx again for the help :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suggest that you leave the ISR() unchanged. The Wizard creates perfectly correct code.

You should put any program logic into the foreground code (which will call getchar() as required)

Since you never lose any keypresses, you can process at whatever speed you like. In fact the AVR will be able to do more work because it is never waiting for hardware.

Have you tried my example program?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
I suggest that you leave the ISR() unchanged. The Wizard creates perfectly correct code.

You should put any program logic into the foreground code (which will call getchar() as required)

Since you never lose any keypresses, you can process at whatever speed you like. In fact the AVR will be able to do more work because it is never waiting for hardware.

Have you tried my example program?

David.

yup i have tried it (although i tried it using my own code but it was still based on your concept), it seems like the packets are buffered first and they will be all pulled out on next getchar() call...but the weakness is that the mcu have to wait for the next getchar() call in order to get new packets...it doesn't matter if the delay is less than 300ms, but the delay i found is longer than 700ms, so the response of my system become so slow once it gets some new packets.....unlike when i put my modified code inside ISR()...

now i am thinking about how to trick that limitation but i am still unable to find the solution...maybe another small-but-extremely-helpful advice from you and others can help me continue my project again :D :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A command language generally has a fixed number of bytes or a terminator character. e.g.

"F123"
"left 2, forward 5, right 4, fire\n"

The first example is 4 bytes. You simply wait till you have received 4 bytes. Then execute the command.

The second example may have two strategies.
1. Read the whole line up to the '\n' newline. Then execute the whole list of commands.
2. Read up to a comma or newline. Execute one command at a time.

Your foreground code simply reads commands and your robot moves accordingly.

You should never get stuck in a loop because you only read a command that is available. e.g. you check kbhit()

I really don't understand how you should have any problems. But quite honestly I can't see how your commands are structured (if at all).

My example program will simply echo your typing. If you type an 'S' the echoing stops for a second. Then all the silently typed characters are displayed at once. And the regular echoing continues. (exactly as happens on your multitasking PC)

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
A command language generally has a fixed number of bytes or a terminator character. e.g.

"F123"
"left 2, forward 5, right 4, fire\n"

The first example is 4 bytes. You simply wait till you have received 4 bytes. Then execute the command.

The second example may have two strategies.
1. Read the whole line up to the '\n' newline. Then execute the whole list of commands.
2. Read up to a comma or newline. Execute one command at a time.

Your foreground code simply reads commands and your robot moves accordingly.

You should never get stuck in a loop because you only read a command that is available. e.g. you check kbhit()

I really don't understand how you should have any problems. But quite honestly I can't see how your commands are structured (if at all).

My example program will simply echo your typing. If you type an 'S' the echoing stops for a second. Then all the silently typed characters are displayed at once. And the regular echoing continues. (exactly as happens on your multitasking PC)

David.


i don't want to say my system as "robot", since "robot" is undoubtedly smarter than the system i created, so i prefer "automatic machine" as the name of my system instead :)

btw i have several improvements in my code, which is the main problem i'm talking about :

while (1)  // the automatic machine is started
      {   
      lcd_track(track,track2,buff,buff2);  
     cam_receive();   
      while(count<3){          //line
       tracking();
       count++;
       delay_us(500);
       }  ;   
      real_packets();
      count=0; 
  
      cam_receive();  
      while (count<3){              //other colors
       tracking2();
       count++;   
       delay_us(500);
        } ; 
      real_packets2();
      count=0; 
      cam_receive();   
      
        if (request_==0x50) { goto main_menu;}; 
       delay_ms(1);         
         }  

cam_receive() on the code above will receive request packet from outside and simply send the requested packet, and its receiver is interrupt-driven. As you can see, in order to execute cam_receive(), it has to wait for other code to finish first. I hope this code will make the problems clearer.... :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want help, explain in plain English what you want to do.

An ordinary AVR is quite capable of receiving commands, parsing them, executing them, monitoring sensors, playing a tune, calculating the meaning of life, ... and many other tasks.

No one is going to read through uncommented code. Mind you, an English explanation would make all the difference.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
If you want help, explain in plain English what you want to do.

An ordinary AVR is quite capable of receiving commands, parsing them, executing them, monitoring sensors, playing a tune, calculating the meaning of life, ... and many other tasks.

No one is going to read through uncommented code. Mind you, an English explanation would make all the difference.

David.

wew, i have tried my best to explain it in English but my explanation is still quite hard to understand. :D

do you mean plain English = simple English?

....................
....................
void main(){
...........//initializing
...........
main_menu:
menu();

while (1)  // main code
      {   
      lcd_track(track,track2,buff,buff2); 
     cam_receive();   // for receiving request data and send the requested data back

      while(count<3){   //----->processing the data
       tracking();      //|   
       count++;         //| 
       delay_us(500);   //|--->delay (more than 1sec)
       }  ;             //|
      real_packets();   //|
      count=0;          //|
 //------------------------------------------------
      cam_receive(); // same as cam_receive() above
      while (count<3){  //-->processing the 2nd data
       tracking2();     //|
       count++;         //|
       delay_us(500);   //|--->delay (more than 1sec)
        } ;             //|  
      real_packets2();  //| 
      count=0;          //| 
     cam_receive();// same as cam_receive()above     
//-------------------------------------------------        
     if (request_==0x50) { goto main_menu;};
     delay_ms(1);         
         } 
}

real_packets() and real_packets2() are the data that will be sent by cam_receive(), if they are requested. The problem is, cam_receive() has to wait for about a second or more in order to get it processed.

just tell me if it is still hard to understand, i really need some useful solution (or inspiration at least) to make my code work well...:)

*oh yeah don't mind criticizing my English, i also need several improvements for my English too :D *

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hello?
anyone?