pcnerd
Take a parachute, and jump!
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
.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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;
pcnerd
Take a parachute, and jump!
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
.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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...
pcnerd
Take a parachute, and jump!
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%)]
pcnerd
Take a parachute, and jump!
pcnerd
Take a parachute, and jump!
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%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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.
pcnerd
Take a parachute, and jump!
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%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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');
}
pcnerd
Take a parachute, and jump!
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
pcnerd
Take a parachute, and jump!
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Waarom stuur je getallen niet door als een ascii-string, netjes afgesloten met een '\n'? Dat is toch veel logischer?
pcnerd
Take a parachute, and jump!
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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.
pcnerd
Take a parachute, and jump!
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?
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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.
pcnerd
Take a parachute, and jump!
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...
pcnerd
Take a parachute, and jump!
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?
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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?
pcnerd
Take a parachute, and jump!
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.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
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...
pcnerd
Take a parachute, and jump!
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"...
pcnerd
Take a parachute, and jump!
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?
.