Go Down

Topic: Aggiornare valore di una variabile *byte (Read 1 time) previous topic - next topic

Licius1991

Dec 01, 2013, 12:21 am Last Edit: Dec 01, 2013, 01:43 am by UweFederer Reason: 1
Ciao a tutti. Mi sono imbattuto in un problema apparentemente facilissimo ma che (sarà che è mezzanotte passata) non riesco a risolvere. Il codice è di una banalità imbarazzante eppire non riesco a capire perchè la variabile byte *inData non venga aggiornata dopo il primo ciclo loop().  Sullo schermo mi viene printato :
0
0
0
0
......

Aiutatemi perchè non so più che pesci piogliare vista la banalità del codice.


Code: [Select]
byte *inData= 0;

void setup() {  
 Serial.begin(9600);  
}

void loop() {  
 *inData = *inData + 1;
 Serial.println(*inData);
 delay(1000);   
}

uwefed

Non capisco cosa vuoi fare coi puntatori.
Ciao Uwe

PaoloP

#2
Dec 01, 2013, 08:36 am Last Edit: Dec 01, 2013, 08:38 am by PaoloP Reason: 1
Elimina l'asterisco e vedrai che funziona.
In qual modo sposti il puntatore alla variabile e non incrementi il valore della variabile stessa.
Puoi comunque scrivere al posto di
Code: [Select]
inData = inData + 1;
direttamente
Code: [Select]
inData++;
oppure eliminando quella riga
Code: [Select]
Serial.println(inData++);

Se devo incrementare o decrementare di valori più grandi di 1, quindi senza utilizzare ++ o -- puoi usare, ad esempio
Code: [Select]
inData += 5;
o
Code: [Select]
inData -= 3;

Licius1991


Elimina l'asterisco e vedrai che funziona.
In qual modo sposti il puntatore alla variabile e non incrementi il valore della variabile stessa.
Puoi comunque scrivere al posto di
Code: [Select]
inData = inData + 1;
direttamente
Code: [Select]
inData++;


Hai ragione ma a me serve che inData sia un type *byte. Sto implementando un sistema di comunicazione laser basato su due stazioni entrambe in grado di ricevere e trasmettere. dotate di tastierino alfa numerico e display, con funzioni uguali a quelle per mandare messaggi con un comunissimo cellulare. Ogni carattere viene ricodificato in 7 bit, il most significant bit lo uso come bit di parità. quindi ogni carattere occupa un byte alla fine. Quindi premendo il tasto INVIA il laser inizia a trasmettere bit per bit: 1 --> laser completamente acceso. 0-->laser completamente spento. Quando invece non sta trasmettendo il laser è a metà potenza. Il lato trasmettitore è completato e funziona.

Ora devo implmentare il ricevitore. lofarei con un fotodiodo e una resistenza in serie, connessi tra 5 V e massa. la resistenza l'ho scelta in modo che il nodo tra il fotodiodo e la resistenza sia a metà dinamica quando illuminato a mezza potenza (l'ho fatto leggendo i valori dirrettamente da anlogRead) e vada a 0 o 1023 (5V o più) a seconda se si tratti di 1 o 0. Il ricevitore deve poter raccogliere i dati senza interferire con le operazioni del trasmettitore (per esempio voglio poter ricevere un messaggio e immagazzinarlo in memoria per futura lettura mentre sto scrivendo un altro messaggio o lo sto trasmettendo ecc...). Avevo quindi pensato di ricorrere agli interrupt: Ogni volta che il pin 2 (corrispondente all'interrupt 0 di ARDUINO UNO) cambia stato si attiva un interrupt, che scrive un 1 o 0 in "inData" nella posizione "inputIndex" attraverso la funzione bitWrite(). quindi aggiorno il valore di inputIndex e se inputIndex è multiplo di 8 (cioè ho esaurito il byte in cui stavo scrivendo i bit ricevuti). rialloco inData aggiungendo un ulteriore byte. In pratica:

Code: [Select]
unsigned short i, j;

volatile const int photoPin = 2;

volatile unsigned short inputIndex = 0;

volatile byte *inData, *rec;

void setup() {
 
  Serial.begin(9600);
  attachInterrupt(photoPin, inComingMessage, CHANGE);
  *inData = 0;
  *rec = 0;
 
}

void loop() {
 
  for(i = 0; i < (trunc(inputIndex / 8) + 1); i++) {
   
    for(j = 8; j > 0; j--) {
     
      Serial.print(bitRead(inData[i], j - 1), BIN);
     
    } //Con questi cicli di for scrivo a schermo, in binario, il dato
   
  }
  Serial.println();
  delay(1000);
 
}



void inComingMessage() {
 
  detachInterrupt(photoPin); //non voglio che altre occorrenze dell'interrupt
                             //creino problemi
  pinMode(photoPin, INPUT);
  if(digitalRead(photoPin) == HIGH) {
 
    bitWrite(inData[(volatile unsigned short)trunc(inputIndex / 8)], inputIndex % 8, 1);
    //trunc(inputIndex / 8) serve a identificare il byte corretto.
   // inputIndex % 8 serve a identificare il corretto bit.
  }
  else {
 
    bitWrite(inData[(volatile unsigned short)trunc(inputIndex / 8)], inputIndex % 8, 1); 
 
  }
  inputIndex++;
  if(inputIndex % 8 == 0) { //Realloco inData aggiungendo un byte
 
  volatile byte *rec = (volatile byte*) realloc((byte*) inData, (volatile unsigned short) sizeof(byte) * (trunc(inputIndex / 8) + 1));
  inData = rec;
  inData[(unsigned short) trunc(inputIndex / 8)] = 0;
 
  } 
  attachInterrupt(photoPin, inComingMessage, CHANGE);
 
}


Tralasciando il fatto che in questo modo stringhe di 1 o di 0 vengono codificate come un unico bit (ci penserò dopo ad aggiustare questo problema) e altre piccole cose.  Il problema è che inData non viene aggiornato correttamente. Quindi ho ridotto fino all'osso il problema e sono arrivato al codice esposto nel primo post. Ecco perchè mi serve che inData sia un puntatore a byte.

PaoloP

#4
Dec 01, 2013, 11:05 am Last Edit: Dec 01, 2013, 11:12 am by PaoloP Reason: 1

Code: [Select]
 *inData = 0;
 *rec = 0;



Questo è un errore anche se il compilatore non lo segnale.
Non assegni un indirizzo di memoria al puntatore prima di utilizzarlo.

Ad esempio con
Code: [Select]
int *x;
int y;
x=&y;
*x=100;


oppure con
Code: [Select]
int *p;
p = (int *) malloc(20);

Poi puoi usare realloc.

Occhio a scrivere
Code: [Select]
p = (int *) malloc(20);
e non
Code: [Select]
*p = (int *) malloc(20);
con l'asterisco davanti. (errore)

EDIT
Proseguendo con l'esempio, conviene controllare l'esisto di malloc.
Code: [Select]
p = (int *) malloc(20);
if ( p==NULL) {
 Serial.println(F("E' finita la memoria :-("));
 while(1);
 }



nid69ita

Leggi bene quello che @PaoloP ti scrive.

In sintesi nel tuo primo esempio manca questo:
Code: [Select]

byte Var=0;
byte *inData= &Var;   // declare a pointer to byte and initialize to point Var


Var è la variabile che contiene un byte e attraverso il puntatore contenuto dentro a  inData puoi modificare il contenuto di Var.
my name is IGOR, not AIGOR

astrobeed


Leggi bene quello che @PaoloP ti scrive.


Aggiungiamo pure che nel caso specifico, ma anche in generale (salvo casi particolari), non ha alcun senso usare un puntatore su una variabile a singolo byte.
Scientia potentia est

Licius1991

#7
Dec 01, 2013, 01:49 pm Last Edit: Dec 01, 2013, 01:51 pm by Licius1991 Reason: 1
Grazie mille Paolo. ho rimediato al problema. Però ho ancora problemi con la funzione di chiamata dell'interrupt.  In pratica il valore di una variabile non mi si aggiorna correttamente. Posto qui il codice (estremamente semplice) che non sta funzionando.

Code: [Select]

volatile int contatore = 0;

void setup()
{
 Serial.begin(9600);
 attachInterrupt(0, blink, RISING);
}

void loop()
{
 Serial.println(contatore);
}

void blink()
{
 
 contatore++;
 
}


L'interrupt è azionato per il momento tramite un push-botton in serie a una resistenza da 5 KOHM, posti tra VDD e massa. Il pin 2 associato all'interrupt 0 è collegato al nodo centrale (tra push-botton e resistenza).

Il valore della variabile contatore non incrementa correttamente quando premo il push-botton. innanzi tutto il più delle volte si aggiorna anche durante il FALLING-EDGE. poi a volte incrementa di 3, 4 valori o anche più inspiegabilmente. QUalcuno saprebbe dirmi dove sto sbagliando?

PaoloP

E' colpa del rimbalzo del pulsante che fa scattare l'interrupt un paio di volte di seguito.
Devi usare una tecnica per l'antirimbalzo (debounce).

Questo è quello che succede quando rilasci il pulsante


Con un semplice digital.read si aggiunge un delay per eliminare gli effetti del transitorio, ma dentro l'interrupt il delay non funziona (e non avrebbe neanche senso utilizzarlo)

gpb01

#9
Dec 01, 2013, 02:12 pm Last Edit: Dec 01, 2013, 02:13 pm by gpb01 Reason: 1

Devi usare una tecnica per l'antirimbalzo (debounce).


@ Licius1991 : ... e, dato che in una ISR, come giustamente segnala Paolo, non puoi inserire ritardi ... la devi realizzare in HW ... cerca su google "hardware debouncing" ed avrai vari schemi e soluzioni ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

Go Up