Witam, mam problem z kodem ( no właśnie, to sie okaże
):
problem polega na tym, że w części:
warunek jest zawsze prawdziwy ( zmienne zawsze są równe / wskaźniki wskazują na to samo miejsce ) pomimo zwiększenia "rxbufptrwrite" tutaj:
czyli w kolejności wykonania kodu:
w pętli main prosimy o znak ( fgetc ), który pozyskiwany jest przez "USART_Receive()"
a w tejże funkcji zatrzymujemy się na "while( rxbufptrwrite == rxbufptrread );"
do tego miejsca jest ok. Ale gdy przez UART przychodzi znak i trafia do przerwania "ISR( USART_RXC_vect )" zmienna "rxbufptrwrite" jest zwiększana a wspomniana pętla while tego nie zauważa i dla niej "rxbufptrwrite" jest cały czas równe "rxbufptrread" natomiast w bloku przerwania ta zmienna się ładnie przesuwa i wskazuje na kolejne znaki co widać za pomocą
Prawdopodobnie zrobiłem jakiś strasznie głupi błąd, bo tylko z takimi mam problem ponad cały dzień
kod miał buforować znaki przychodzące z UART ponieważ są one bardzo wolno przetwarzane... Dodam że kod działał na 100% bez przerwania ze zwyczajnym oczekiwaniem na znak w "USART_Receive"...
Pomóżcie bo mi ręce opadają już...
#define F_CPU 16000000UL
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#define UART_BAUD 115200 //prędkość transmisji
#define UART_CONST (F_CPU/((16*UART_BAUD)-1))
#define rxbufsize 64
char * rxbuf;
volatile char * rxbufptrwrite;
volatile char * rxbufptrread;
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) );
/* Put data into buffer, sends the data */
UDR = data;
}
unsigned char USART_Receive( void )
{
while( rxbufptrwrite == rxbufptrread );
char c = *rxbufptrread;
++rxbufptrread;
if( rxbufptrread == rxbufptrwrite )
{
rxbufptrwrite = rxbuf;
rxbufptrread = rxbuf;
}
return c;
}
void USART_Init( unsigned int ubrr)
{
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Enable receiver and transmitter / rx interrupt */
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
ISR( USART_RXC_vect ) // USART RX interrupt
{
if( (rxbufptrwrite - rxbuf) < rxbufsize )
{
USART_Transmit('z');
*rxbufptrwrite = UDR;
++rxbufptrwrite;
USART_Transmit( *rxbufptrread );
USART_Transmit( *(rxbufptrwrite-1) );
}
else
{
//ignoring input
char c = UDR;
}
}
void mshort()
{
PORTC |= ( 1 << PC5 ); // dioda on
_delay_ms( 70 );
PORTC &= !( 1 << PC5 ); // dioda off
_delay_ms( 50 );
}
void mlong()
{
PORTC |= ( 1 << PC5 ); // dioda on
_delay_ms( 200 );
PORTC &= !( 1 << PC5 ); // dioda off
_delay_ms( 50 );
}
void moff()
{
PORTC &= !( 1 << PC5 ); // dioda off
_delay_ms( 250 );
}
int main(void)
{
DDRD=0x02;
PORTD=0x00;
USART_Init( UART_CONST );
rxbuf = malloc( rxbufsize );
rxbufptrwrite = rxbuf;
rxbufptrread = rxbuf;
FILE mystdout = FDEV_SETUP_STREAM( USART_Transmit, NULL, _FDEV_SETUP_WRITE );
FILE mystdin = FDEV_SETUP_STREAM( NULL, USART_Receive, _FDEV_SETUP_READ );
stdout = &mystdout;
stdin = &mystdin;
sei();
for(;;)
{
static char c;
while ( c = fgetc( stdin ) )
{
switch( c )
{
case 'a': { mshort(); mlong(); break; }
case 'b': { mlong(); mshort(); mshort(); mshort(); break; }
case 'c': { mlong(); mshort(); mlong(); mshort(); break; }
case 'd': { mlong(); mshort(); mshort(); break; }
case 'e': { mshort(); break; }
case 'f': { mshort(); mshort(); mlong(); mshort(); break; }
case 'g': { mlong(); mlong(); mshort(); break; }
case 'h': { mshort(); mshort(); mshort(); mshort(); break; }
case 'i': { mshort(); mshort(); break; }
case 'j': { mshort(); mlong(); mlong(); mlong(); break; }
case 'k': { mlong(); mshort(); mlong(); break; }
case 'l': { mshort(); mlong(); mshort(); mshort(); break; }
case 'm': { mlong(); mlong(); break; }
case 'n': { mlong(); mshort(); break; }
case 'o': { mlong(); mlong(); mlong(); break; }
case 'p': { mshort(); mlong(); mlong(); mshort(); break; }
case 'q': { mlong(); mlong(); mshort(); mlong(); break; }
case 'r': { mshort(); mlong(); mshort(); break; }
case 's': { mshort(); mshort(); mshort(); break; }
case 't': { mlong(); break; }
case 'u': { mshort(); mshort(); mlong(); break; }
case 'v': { mshort(); mshort(); mshort(); mlong(); break; }
case 'w': { mshort(); mlong(); mlong(); break; }
case 'x': { mlong(); mshort(); mshort(); mlong(); break; }
case 'y': { mlong(); mshort(); mlong(); mlong(); break; }
case 'z': { mlong(); mlong(); mshort(); mshort(); break; }
}
if( 0 /*isalpha( c )*/ )
{
fputc( (((c - 'a')+13)%('z'-'a'))+'a', stdout );
}
else
{
fputc( c, stdout );
}
moff();
}
}
return 0;
}
problem polega na tym, że w części:
unsigned char USART_Receive( void )
{
while( rxbufptrwrite == rxbufptrread );
warunek jest zawsze prawdziwy ( zmienne zawsze są równe / wskaźniki wskazują na to samo miejsce ) pomimo zwiększenia "rxbufptrwrite" tutaj:
ISR( USART_RXC_vect ) // USART RX interrupt
{
if( (rxbufptrwrite - rxbuf) < rxbufsize )
{
USART_Transmit('z');
*rxbufptrwrite = UDR;
-------> ++rxbufptrwrite;
USART_Transmit( *rxbufptrread );
USART_Transmit( *(rxbufptrwrite-1) );
}
czyli w kolejności wykonania kodu:
w pętli main prosimy o znak ( fgetc ), który pozyskiwany jest przez "USART_Receive()"
a w tejże funkcji zatrzymujemy się na "while( rxbufptrwrite == rxbufptrread );"
do tego miejsca jest ok. Ale gdy przez UART przychodzi znak i trafia do przerwania "ISR( USART_RXC_vect )" zmienna "rxbufptrwrite" jest zwiększana a wspomniana pętla while tego nie zauważa i dla niej "rxbufptrwrite" jest cały czas równe "rxbufptrread" natomiast w bloku przerwania ta zmienna się ładnie przesuwa i wskazuje na kolejne znaki co widać za pomocą
USART_Transmit( *rxbufptrread );
USART_Transmit( *(rxbufptrwrite-1) );
Prawdopodobnie zrobiłem jakiś strasznie głupi błąd, bo tylko z takimi mam problem ponad cały dzień
kod miał buforować znaki przychodzące z UART ponieważ są one bardzo wolno przetwarzane... Dodam że kod działał na 100% bez przerwania ze zwyczajnym oczekiwaniem na znak w "USART_Receive"...
Pomóżcie bo mi ręce opadają już...