hey,

Ik heb hier 2 breadboardjes met attiny2313 opgemaakt. 1tje (A) met een 4 segment's lcd display wat de seconden telt (tot en met 59:59) en 1tje (B) met een lcd display dat (hoofdzakelijk) tekst weergeeft.
Het punt is nu dat ik probeerde data via usart te verzenden van A naar B met usart. Ik heb een ifje gezet bij het tijd dingetje waardoor ik bij elke 10 seconden een bitje met de hoeveelheid aantal 10 seconden. Dat houdt in, als het dan bijv. 20:30 is, dan verstuurt hij 3. Ik probeer dit op mijn B setup te ontvangen, doormiddel van 2 draadjes die in een full handshake op tx en rx staan verbonden (txA naar rxB en rxA naar txB). systeem A draait op een 11.0592mhz kristal en systeem B op de interne oscillator van de attiny. Probleem is nu dat ik volgens mij wel data verstuur (ik zie op m'n scoop een kort dipje tijdens het versturen, en het UDR register is daarna leeg). Maar ik ontvang niks.

Mijn code voor het initieren en versturen op A:


void setusart() {
	//set usart baud rate register 
	int baudrate = 250000;
	UBRRH = (unsigned char)(baudrate>>8);
	UBRRL = (unsigned char)baudrate;
	
	//set control and status register A 
	//UCRSA = std;
	
	//set control and status register B
	UCSRB = 8;
	
	//set control and status register C
	UCSRC = 2+4+32;
	
	
}
void sendusart(int data) {
	//wait until data register is empty:
	while(!(UCSRA & (1<<UDRE)));
	
	UDR=data;
	lightnumber(10,1);
	delay_10us(1000);
}

code van B:


/*************************************************************************
Title:    testing output to a HD44780 based LCD display.
Author:   Peter Fleury  <pfleury@gmx.ch>  http://jump.to/fleury
File:     $Id: test_lcd.c,v 1.6 2004/12/10 13:53:59 peter Exp $
Software: AVR-GCC 3.3
Hardware: HD44780 compatible LCD text display
          ATS90S8515/ATmega if memory-mapped LCD interface is used
          any AVR with 7 free I/O pins if 4-bit IO port mode is used
**************************************************************************/
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "lcd.h"
#include <util/delay.h>
#include <avr/interrupt.h>

ISR(USART_RX_vect) {
	//update();
	lcd_clrscr();
	lcd_puts("boe!\n");
	int blaat = UDR;
	lcd_puts(blaat);
	
}
	
/*
** constant definitions
*/

// function prototypes

void wait_until_key_pressed(void);
void setusart(void);
void update(void);
void usart_receive();

//variables:
int x = 0;
int main(void)
{
	
    int x = 0;
    
    
    DDRD = 0;;        /* Pin PD2 input              */
    PORTD = 4;        /* Pin PD2 pull-up enabled    */


    /* initialize display, cursor off */
    lcd_init(LCD_DISP_ON);

        /* clear display and home cursor */
        lcd_clrscr();
        
        /* put string to display (line 1) with linefeed */
        lcd_puts("Waiting for incoming data...\n");
        sei();    
        usart_receive();
              
    
}

void wait_until_key_pressed(void)
{
    unsigned char temp1, temp2;
    unsigned int i;
    
    do {
        temp1 = PIND;                  // read input
        for(i=0;i<65535;i++);
        temp2 = PIND;                  // read input
        temp1 = (temp1 & temp2);       // debounce input
    } while ( temp1 & _BV(PIND2) );
    
    loop_until_bit_is_set(PIND,PIND2);            /* wait until key is released */
}
void delay_ms(unsigned int t)
{
  while(t > 0)
  {    
    _delay_loop_2(250);
    t--;
  }  
}

void setusart(void) {
	//set usart baud rate register 
	int baudrate = 250000;
	UBRRH = (unsigned char)(baudrate>>8);
	UBRRL = (unsigned char)baudrate;
	
	//set control and status register A 
	//UCRSA = std;
	
	//set control and status register B
	UCSRB = 16+128;
	
	//set control and status register C
	UCSRC = 2+4+32;
	
}

void update(void) {
	x++;
	lcd_gotoxy(0,1);
	lcd_puts(x);
}

void usart_receive() {
	lcd_puts("gaap...");
	while (!(UCSRA & (1<<RXC)));
	lcd_clrscr();
	lcd_puts("boe");
	delay_ms(1000);
}

.
het lcd geeft wel waiting for incoming data weer en "gaap", maar verder niks :(. Iemand enig idee wat hier misgaat? of moet ik de baudrate maar is drastisch omlaag brengen?

//edit: ook met baudrate 2400 (op beide) werkt 't niet :(.

Je moet in UBRRH/UBRRL niet de baudrate plaatsen, maar een deelfactor. Iets als dit, dus:


#defineF_CPU 14745600UL
#define BAUD 9600UL

UBRRH = 0;	// Meestal 0, tenzij bij extreem lage baudrate						
UBRRL = (F_CPU / (16 * BAUD)) - 1;

hey, thx.
Ik heb de baudrate van A op 287 gezet, en de baudrate van B op 103 (uit de tabelletjes van de datasheet gevist). Helaas gebeurt er nog niks :(.

Laat A constant een 'U' verzenden, en hang je scoop aan TXD. Daar moet een nette blokgolf te zien zijn. Als je B hetzelfde laat doen, kan je alvast nagaan of de frequenties overeenstemmen.

En gebruik verder de namen van de bits. Iets als

UCSRC = 2+4+32;

zegt me niets. En ik ben te lui om uit te zoeken wat het zou kunnen betekenen...

ik vindt die (1<<XXX) notatie niet zo prettig.. Maargoed, zal het er zometeen even bijzetten voor je. Maar hoe verzend ik een karakter? moet ik dan de buffer versturen of kan ik gewoon met chars werken?

//edit: ik verstuur nu het getal 11 met A, en daarbij krijg ik een signaal dat bestaat uit 3 "drops" in spanning van versch. lengte, lijkt een "normaal" usart signaal, maar B reageert er nog steeds niet op :(.

owja:
van bit 0 t/m 7
UCSRB = TXB8, RXB8, UCSZ2, TXEN, RXEN, UDRIE, TXCIE, RXCIE
UCSRC = UGPOL, UCSZ0, UCSZ1, UCBS, UPM0, UPM1, UMSEL, -

dat zou genoeg moeten zijn.

[Bericht gewijzigd door pcnerd op (17%)]

lol, volgens mij heb ik de fout al gevonden, ik ben vergeten setusart(); te doen in B :P.

het werkt, wel mooi dat ik hierdoor achter dat baud gebeuren kwam. Nog 1 ding, ik zit te stoeien met variabelen in de avr, hoe maak ik iets "global" zegmaar? ik wil namelijk bij elke interrupt 1 optellen bij een variabele die elke functie moet kunnen gebruiken.

//edit:

shit, ik wou editen, sorry mods, voel je vrij om de posts bij elkaar te voegen..

[Bericht gewijzigd door pcnerd op (15%)]

Plaats ergens aan het begin van je code iets als


volatile int weetikveel;

Die "volatile" geeft je de zekerheid dat avr-gcc hem niet negeert.

zijn er ook nettere manieren of niet?

//edit:
nog een vraagje, ik probeer met deze code de verzonden informatie te op m'n lcd te laten verschijnen:


ISR(USART_RX_vect) {
	char buffer[20];
	//update();
	lcd_clrscr();
	lcd_puts("boe!\n");
	int blaat = UDR;
	itoa(blaat, buffer, 10);
	lcd_puts(buffer);
	
}

maar ik krijg getallen als 30, 120 en 6. Terwijl ik getallen van 1 tot 9 verstuur..

ligt dit aan mij ofzo?

[Bericht gewijzigd door pcnerd op (85%)]

Als je enkel getallen van 0 tot 9 wil versturen en op het LCD tonen, kan je beter zoiets doen:


ISR(USART_RX_vect) {
   lcd_putchar(UDR + '0');
}

nee, ook hogere (later), kun je ook gewoon cast'en?

blijft wel 8 bits als 't goed is...

Hoger dan 9 lukt niet. 10 + '0' geeft immers ':'

zo ver was ik al, ik vroeg dus of er een manier was om hogere getallen te doen..

Waarom stuur je getallen niet door als een ascii-string, netjes afgesloten met een '\n'? Dat is toch veel logischer?

misschien wel, als ik wist hoe dat moest xD. gewoon 1 char doorsturen ofniet?

Stuur een serie karakters ('0' ... '9') van A naar B, gevolgd door een '\n'. B hoeft niets anders te doen dan ze in een string op te slaan, de '\n' te vervangen door een '\0' en atoi() aan het werk te zetten als hij de waarde wil kennen, of de string simpelweg naar het LCD te sturen.

dus eerst een char versturen naar UDR, dan wachten en \n versturen.

bij B dit in binnenkomende volgorde versturen, en dan doen zoals jij zegt?

A:


void uart_sendchar(unsigned char c)
{
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;
}


// send string to the rs232
void uart_sendstr(char *s)
{
    while (*s) {
	uart_sendchar(*s);
	s++;
    }
}

int main(void)
{
    // init...
    uart_sendstr{"12345\n");
    // ...
}

B kan nu één voor één de ontvangen karakters in een buffer plaatsen, en --als er een '\n' binnenkomt-- een '\0' op het einde v/d string plaatsen en main() waarschuwen.

vreemd, ik gebruik nu deze code (verkorte versie van die van jou):


void sendusart(char *data) {
	
	while (*data) {
		//wait until data register is empty:
		while(!(UCSRA & (1<<UDRE)));
		UDR=*data;
		data++;
	}
	
	
	
}

in A.
Maar ik kom er maar niet uit hoe ik hem op moet vangen met B...

ik heb nu het volgende in m'n interrupt staan:


char buffer[7];
	//update();
	lcd_clrscr();
	lcd_puts("number: \n");
	itoa(x,buffer,10);
	x++;
	lcd_puts(buffer);
	delay_ms(500);
	lcd_clrscr();
	
	
	lcd_puts("data: \n");
	itoa(UDR,buffer,10);
	lcd_puts(buffer);
	delay_ms(500);

en verstuur getallen (d0h), maar de getallen worden niet juist weergegeven, de optelgetallen echter wel (voor elke nieuwe rij usart gegevens). probleem in het verzenden?

Ik heb die rare itoa() nog nooit gebruikt. Maar iets zegt me dat er een (16-bits) int verwacht wordt als argument. Misschien loopt het mis bij

itoa(UDR,buffer,10);

; 'k zou 't niet weten...

Stuur gewoon alle data (tekst, getallen) als een serie ascii-tekens over de RS232-lijn. Dan heb je toch meer grip op het gebeuren?

maar dan lukt het ook niet (het versturen volgens mij wel, maar het ophalen gaat ergens fout...). Het lukt me niet een 8bits int naar char om te zetten en weer te geven op 't display.

Misschien ben je hier iets mee. De eerste is de UART-RX interrrupt-routine. De tweede vertaalt ascii naar een unsigned int. D'r zit wat oubollig spul in, maar ik reken er op, dat zulks voor een 60-plusser door de vingers wordt gezien... :-)


static char uart_outbuf[UART_RX_BUFFER_SIZE + 1];
static char uart_rxbuf[UART_RX_BUFFER_SIZE + 1];
volatile static unsigned char uart_rx_pos;			// end of string in rx
volatile static unsigned char uart_rx_linecomplete;		// one complete line in buffer


/* Deze functie wordt aangeroepen, telkens er een karakter ontvangen werd */
SIGNAL(SIG_UART_RECV)
{
    unsigned char c;
    unsigned char *p1, *p2;

    c = UDR;
    uart_rxbuf[uart_rx_pos] = c;				// vb. uart_rx_pos = 2 (M=\n)
    if ((c == '\n') || (uart_rx_pos > UART_RX_BUFFER_SIZE - 1)) {
	p1 = uart_outbuf;
	p2 = uart_rxbuf;
	for (c = 0; c < uart_rx_pos; c++) {			// vb. 0 en 1
	    *p1 = *p2;
	    p1++;
	    p2++;
	}
	*p1 = 0;						// vb. uart_outbuf[2] = 0
	uart_rx_linecomplete = 1;
	uart_rx_pos = 0;
    } else {
	uart_rx_pos++;
    }
}



unsigned int get_data(char *ptr)
{
    int result = 0;

    while ((*ptr == ' ') || (*ptr == '\t'))
	ptr++;							// spaties en tabs overslaan

    if (*ptr == '0') {
	ptr++;
	if (*ptr == 'x') {					// hexadecimaal
	    ptr++;
	    while (1) {
		if ((*ptr > '/') && (*ptr < ':')) {		// een decimaal karakter
		    result *= 16;
		    result += (*ptr - '0');
		} else if ((*ptr > '@') && (*ptr < 'G')) {
		    result *= 16;				// 'A' = 65, 'A' - 55 = 10
		    result += (*ptr - 55);
		} else if ((*ptr > '`') && (*ptr < 'g')) {
		    result *= 16;				// 'a' = 97, 'a' - 87 = 10
		    result += (*ptr - 87);
		} else {
		    return (result);
		}
		ptr++;
	    }
	} else if ((*ptr > '/') && (*ptr < ':')) {		// decimaal
	    return (atoi(ptr));
	} else {
	    return (0);
	}
    } else if (*ptr == '%') {					// binair
	ptr++;
	while ((*ptr == '0') || (*ptr == '1')) {
	    result = (result << 1) + (*ptr - '0');
	    ptr++;
	}
	return (result);
    } else if ((*ptr > '/') && (*ptr < ':')) {			// decimaal
	return (atoi(ptr));
    } else {
	return (0);
    }
}

De interrupt-routine, die aangeroepen wordt als de UART een karakter heeft onvangen, werkt me 2 string-buffers. De eerste (uart_rxbuf) is voor eigen gebruik. Daar worden de karakters één na één opgelagen. Zodra de buffer vol is, of er een '\n' te voorschijn komt, wordt uart_rxbuf gecopieerd naar uart_outbuf, en wordt er een vlag geset (uart_rx_linecomplete = 1;) zodat de hoofdroutine weet dat er werk aan de winkel is.

Je kan uiteraard het formaat aanpassen naar wens...

Ik probeer het zelf te maken..
maar ik verstuur nu bij A gewoon dom het getal 104 doormiddel van:
UDR = 104;
maar met de interruptcode:


ISR(USART_RX_vect) {
	
	char buffer[7];
	char vaag = 'h';
	char blaat[2] = {(int)vaag, '\0'};
	char blaat2[2];
	lcd_clrscr();
	lcd_puts("s");
	lcd_puts(":");
	lcd_puts("\n");
	lcd_puts(blaat);
	lcd_puts("\n");
	lcd_puts("number: \n");
	itoa(x,buffer,10);
	x++;
	lcd_puts(buffer);
	delay_ms(1500);
	lcd_clrscr();
		
	
	
	lcd_puts("data: \n");
	blaat2[0] = UDR;
	blaat2[1] = '\0';
	lcd_puts(blaat2);
	delay_ms(1500);
	
	
	
}

wat het karakter h zou moeten weergeven op het display (als 104 wordt verzonden, ascii 104 is nl. h volgens http://cwashington.netreach.net/main/library/ascii_chart.html ).
punt is alleen dat er niks komt te staan, en de interrupt 2 keer wordt getriggert. Het laatste kan ik echt niet bij komen, want op de scoop zie ik maar 1 serie "downfalls"...

nou, ik ben alweer een stapje verder (trial and error) en ben erachter dat het verzenden op zich fout gaat. Ik heb een 2e setuptje gemaakt met een attiny2313 met ook een interne oscillator, en met 3 verschillende baud rate settings geprobeerd, ze werkten allebei 50/50. eens goed, dan eens fout etc. De error wordt wel gedetecteerd door UCRSA maar het zou leuk zijn als het gewoon tegen de 100% goed ging (dat is nodig voor het uiteindelijke doel namelijk). Ligt het aan de interne oscillator en moet ik een kristalletje plaatsen, of is een kabeltje van 20 cm in 2 verschillende breadboardjes van tx->rx niet goed genoeg?