Concurso de fotografía AM

Temática: «Una panorámica de tu acuario».
Ya esta abierto el plazo para presentar fotografías.

Más info
image01

¿Aún no conoces AMA?

Hazte socio de Acuariofilia Madrid Asociación.
CERRADO EL PLAZO DE INSCRIPCIÓN

Más info
image01

Atlas de peces de AM

¡Hemos alcanzado las 800 fichas! Visita nuestro atlas de peces actualizado.

Más info
image01

Cardúmenes y sociabilidad

Nueva actualización de la tabla con una extensa relación de peces, donde podrás conocer qué entorno necesita cada especie, su sociabilidad y si convive o no en cardumen. ¡Pasa a descubrirla!

Mas info
image01
Programación C desde Cero.
Respuestas: 135    Visitas: 48007
#76
El tema de los bit y bytes es sencillo una vez explicado fácil.

El bit es el mínimo valor binario es decir como un interruptor o una bombilla o está encendido (1) o esta apagado (0), es decir solo puede almacenar dos valores. Que matemáticamente se puede expresar como 2^1

Un Byte son un conjunto de 8 bits que puede almacenar desde 00 00 00 00 hasta 11 11 11 11 y cuanto valores pueden tener: 2^8 es decir 256 valores (0..255)

Una variable int utiliza 2 bytes de memoria luego puede almacenar 2^16=65536 si fuera unsigned (sin signo), si es signed (admite negativos y positivos), como para el signo se gasta un bit, signed int va de -32768 a +32767

En arduino Uno los pin analógicos se dice que tienen una resolución normal de 10 bits por lo que 2^10 = 1024 valores, es decir que a la hora de medir el voltaje que recibe el pin va a dar un valor entre 0 y 1023, como el rango de voltaje está entre 0 a 5 Vcc, es capaz de medir variaciones 5/1024 = 0.00488 V: 0.005 V o 5 mV aprox

En el código que has puesto calcula el voltaje en función del valor facilitado por el pin para un potenciometro y una RTC

Es muy bueno meter mucho comentario en los códigos porque ya sea para cuando lo lea otro o tu mismo dentro de unos meses quedará mas claro que se quería hacer. Cuando el programa se compila, todos los comentarios no se tienen en cuenta, se eliminan, por lo que no afecta al rendimiento del programa la cantidad de literatura que le hubieras añadido.

Analiza esto que has puesto, y comenta porqué:

Código:
int sender=analogRead(A1);
//.....
sender = (5.0 * sender * 100)/1023.0;
#77
(09-01-2016, 04:23 PM)ArturoS escribió: Analiza esto que has puesto, y comenta porqué:

Código:
int sender=analogRead(A1);
//.....
sender = (5.0 * sender * 100)/1023.0;
esto no es mas que la formula que permite transformar el dato que da el programa en un dato que podamos entender, teniendo en cuenta que estamos midiendo temperaturas y queremos verla en el monitor o en este caso en el serial.
Como he escrito en el primer comentario del código si yo lo he entendido creo que cualquiera lo entenderá.
Tambien he estado pensando que quizás se pueda simplificar la formula Dodgy pero quien soy yo para rebatir en este campo-no2.gif
#78
(09-01-2016, 06:06 PM)pedmar escribió:
(09-01-2016, 04:23 PM)ArturoS escribió: Analiza esto que has puesto, y comenta porqué:

Código:
int sender=analogRead(A1);
//.....
sender = (5.0 * sender * 100)/1023.0;
esto no es mas que la formula que permite transformar el dato que da el programa en un dato que podamos entender, teniendo en cuenta que estamos midiendo temperaturas y queremos verla en el monitor o en este caso en el serial.
Como he escrito en el primer comentario del código si yo lo he entendido creo que cualquiera lo entenderá.
Tambien he estado pensando que quizás se pueda simplificar la formula Dodgy pero quien soy yo para rebatir en este campo-no2.gif

Te lo comentaba porque veo un acierto y un error:

El error:
Usas la variable para capturar el nivel analógico del pin que tiene un rango de 0 a 1023 y después la reutilizas para almacenar el voltaje x 100 (rango 0 a 500)
No es bueno usar una variable para dos conceptos, puede generar errores ya que puedes creer que tiene almacenado de un tipo y realmente tener del otro (a nada que el código se complique)

Aparte haces dos lecturas del analog: int sender=analogRead(A1); puedes declararla sin darle valor o obviarse la posterior lectura

El Acierto:
Realizas una operación matemática que incluye divisiones y los valores constantes los pones con decimal (n.0) con lo que consigues que la operación se realice con float, evitando truncados. Aunque al final se almacene en una variable entera donde solo se trunca el resultado final, es este caso concreto no influye ya que es sencilla, pero en operaciones mas retorcidas puede ser un error y de los que cuesta identificar.

Aunque he leido a los expertos sobre ciertas pajas mentales que se hace el arduino operando con float, ya que operar lo que se dice operar solo lo hace en binario.

Puestos a simplificar, esto sería mas corto:
int v_temp = (5.0 * analogRead(A1) * 100)/1023.0;
#79
¿Me podrías dar un ejemplo de como como harías el código?
#80
(09-01-2016, 06:27 PM)ArturoS escribió:
(09-01-2016, 06:06 PM)pedmar escribió:
(09-01-2016, 04:23 PM)ArturoS escribió: Analiza esto que has puesto, y comenta porqué:

Código:
int sender=analogRead(A1);
//.....
sender = (5.0 * sender * 100)/1023.0;
esto no es mas que la formula que permite transformar el dato que da el programa en un dato que podamos entender, teniendo en cuenta que estamos midiendo temperaturas y queremos verla en el monitor o en este caso en el serial.
Como he escrito en el primer comentario del código si yo lo he entendido creo que cualquiera lo entenderá.
Tambien he estado pensando que quizás se pueda simplificar la formula Dodgy pero quien soy yo para rebatir en este campo-no2.gif

Te lo comentaba porque veo un acierto y un error:

El error:
Usas la variable para capturar el nivel analógico del pin que tiene un rango de 0 a 1023 y después la reutilizas para almacenar el voltaje x 100 (rango 0 a 500)
No es bueno usar una variable para dos conceptos, puede generar errores ya que puedes creer que tiene almacenado de un tipo y realmente tener del otro (a nada que el código se complique)

Aparte haces dos lecturas del analog: int sender=analogRead(A1); puedes declararla sin darle valor o obviarse la posterior lectura

El Acierto:
Realizas una operación matemática que incluye divisiones y los valores constantes los pones con decimal (n.0) con lo que consigues que la operación se realice con float, evitando truncados. Aunque al final se almacene en una variable entera donde solo se trunca el resultado final, es este caso concreto no influye ya que es sencilla, pero en operaciones mas retorcidas puede ser un error y de los que cuesta identificar.

Aunque he leido a los expertos sobre ciertas pajas mentales que se hace el arduino operando con float, ya que operar lo que se dice operar solo lo hace en binario.

Puestos a simplificar, esto sería mas corto:
int v_temp = (5.0 * analogRead(A1) * 100)/1023.0;

En efecto se puede simplificar y para que se entienda se explica en un comentario de donde viene.

int v_temp = analogRead(A1) * 0.4888; // 0.4888 = (5.0*100.0)/1023.0


El tema de los bytes tiene que ver con la forma en que trabajan los ordenadores.
Los humanos tenemos 10 dedos y usamos un sistema decimal.

Los ordenadores trabajan con estados lógicos que pueden ser alto o bajo (HIGH / LOW). En Arduinos que trabajan a 5v los estados son 0v y 5v.

Para guardar datos numéricos se usan agrupaciones de bits. Se usa mucho el término byte que no son más que 8 bits.

Eso es porque internamente los primeros procesadores se diseñaron con unidades aritmético lógicas (el corazon del micro) cuyos acumuladores (el registro principal) para hacer operaciones trabajaban con bytes.

Existen unidades de 4 bits llamadas Nibbles pero nadie se acuerda de ellas. No son nada interesantes. Ni siquiera se puede guardar un carácter en ellas.

El código ASCII capaz de codificar 128 caracteres se diseñó inicialmente para 7 bits y permitía codificar 128 carateres diferentes incluidos caracteres no imprimibles usados como caracteres de control (2⁷ = 128) y la pregunta es ¿por qué no se eligió 7 bits como unidad de información?

La respuesta es porque para hacer operaciones aritmético lógicas viene muy bien usar datos con un número de bits que sean potencias de 2 y por eso el octeto o byte se hizo muy popular.

Los datos en memoria d un procesador de 8 bits se cargará en grupos de 8.

Los Arduinos más normalitos, como Arduino UNO, trabajan con 8 bits, pero Arduino DUE es especial y trabaja con 32 bits.

Dependiendo del procesador algunos tipos de datos pueden usar más o menos memoria.

No existe ningún tipo de dato que ocupe menos de un byte. Parece un despercicio pero se hace para agilizar las operaciones. Por ejemplo, las variables lógicas (booleanas) son capaces de almacenar únicamente dos valores (cierto/falso), pero se guardan en un byte completo cuando en realidad un byte puede guardar muchos más valores. Concretamente valores entre 0 y 127.

Lo que se hace es que el valor cero significará false (falso) y cualquier otro valor significará true (cierto) .
#81
(09-01-2016, 03:40 PM)pedmar escribió: La verdad es que quizás meto mucho testo en los códigos,¿?¿?¿?¿? pero este me ayuda a entender el paso a paso.
Acepto como siempre cualquier tipo de critica sobre mi intento de entender todo este mundo. Pero por favor ser benévolos con mi ignorancia; y que sepáis que aunque cada vez entiendo mas lo que comentáis...Aún paso un buen rato leyendo y desglosando las repuestas de algunos-pardon.gif...

Lo que tú llamas testeo, se llama poner trazas, y es imprescindible poner todas las que hagan falta para lograr salir de dudas y comprender el funcionamiento del programa.

Si tú vieras la cantidad de trazas que puedo llegar a poner yo en una parte cuando me da problemas alucinarías.

Ya que ahora estas con el tema de los datos te informo que existe una función interesante que sirve para obtener el número de bytes que ocupa un tipo de dato cualquiera, como por ejemplo (bool, char, byte, int, long, float, ...) o tambien lo que ocupa una variable.

Un trozo de programa de ejemplo sería:

Código:
char Var_Caracter;
int Var_Entero;
float Var_ValorRealEnComaFlotante;

Serial.println(sizeof(char));
Serial.println(sizeof(Var_Caracter));
Serial.println(sizeof(int));
// etc...



Usando un valor constante para mostrarlo en diferentes sistemas de numeración, un ejemplo sería:

Serial.print(78, BIN) daría "1001110"
Serial.print(78, OCT) daría "116"
Serial.print(78, DEC) daría "78" // De este estoy especialmente seguro.
Serial.print(78, HEX) daría "4E"

Las constante no solo se pueden usar en notación decimal.

Por ejemplo en Binario:
Serial.print(B1001110, BIN) daría "1001110"
Serial.print(B1001110, OCT) daría "116"
Serial.print(B1001110, DEC) daría "78" // De este estoy especialmente seguro.
Serial.print(B1001110, HEX) daría "4E"

Por ejemplo en Octal:
Serial.print(0116, BIN) daría "1001110"
Serial.print(0116, OCT) daría "116"
Serial.print(0116, DEC) daría "78" // De este estoy especialmente seguro.
Serial.print(0116, HEX) daría "4E"

Por ejemplo en Hexadecimal:
Serial.print(0x4E, BIN) daría "1001110"
Serial.print(0x4E, OCT) daría "116"
Serial.print(0x4E, DEC) daría "78" // De este estoy especialmente seguro.
Serial.print(0x4E, HEX) daría "4E"

Para los sistemas de numeración lo interesante sería usar una variable que valla incrementando su valor desde cero. Basta programar un bucle y mostrar un valor creciente en binario, en octal, en decimal y en hexadecimal.
#82
he dejado el intento de comprensión de vuestras respuestas a la mañana por que ayer estaba un poco colapsado.
aun así no te creas que he entendido muy bien todo-pardon.gif
pero he modificado y simplificado el codigo.

1.void setup() {
2. Serial.begin(9600); //algo así como dar de alta el puerto serie???
3. pinMode(13,OUTPUT);//declaro el pin 13 como salida
4. }
5.void loop() {
6. int potencio=analogRead(A0);//variable de potenciometro
7. analogRead(A1);//¿¿Declaramos A1 como analog??????¿¿¿¿
8. digitalWrite(13,HIGH);//encendemos el led
9.delay(500);//
10. Serial.println(potencio);//envia el dato en bits de 0-1023
11. delay(2000);
12. int v_temp = analogRead(A1) * 0.4888;
/*A1 X 0.4888 =A1 X 5 X 100 /1023 consegimos pasar de bits a ºC*/
13. Serial.println(v_temp);//envia datos del sensor al monitor serial
14. delay(2000);
15.}


he eliminado la variable anterior que llame (sender)
He aplicado la formula que me has dado para transformar el dato bits a ºc

¿no es necesario declarar el pin (A1) en el setup? de echo he declarado en el setup pinMode(A1,IMPUT) y me daba error Huh
#83
(10-01-2016, 12:56 PM)pedmar escribió: he dejado el intento de comprensión de vuestras respuestas a la mañana por que ayer estaba un poco colapsado.
aun así no te creas que he entendido muy bien todo-pardon.gif
pero he modificado y simplificado el codigo.

1.void setup() {
2. Serial.begin(9600); // Inicializa el puerto serie a una velocidad de 9600 baudios
3. pinMode(13,OUTPUT);//declaro el pin 13 como salida
4. }
5.void loop() {
6. int potencio=analogRead(A0);//variable de potenciometro
7. analogRead(A1);// Esto lee la entrada analógica A!, pero al no guardar el resultado en ninguna variable, ese valor se perderá sin que se pueda usar en el resto del programa.
8. digitalWrite(13,HIGH);//encendemos el led
9.delay(500);//
10. Serial.println(potencio);// Envía el dato como valor entero entrea 0..1023 al puerto Serial
11. delay(2000);
12. int v_temp = analogRead(A1) * 0.4888;
/* Leemos la entrada A1 y multiplicamos ese valor por la constante 0.4888 para pasarlo a ºC*/
13. Serial.println(v_temp);//envia datos del sensor al monitor serial
14. delay(2000);
15.}


he eliminado la variable anterior que llame (sender)
He aplicado la formula que me has dado para transformar el dato bits a ºc

¿no es necesario declarar el pin (A1) en el setup? de echo he declarado en el setup pinMode(A1,IMPUT) y me daba error Huh

He editado tu respuesta para corregir algunas inexactitudes. Me resultan muy útiles tus comentarios para darme cuenta de lo que vas captando y lo que no. No te desesperes por vas bastante bien.

Hay conceptos que no tienes claros pero es normal.

Te diré que absolutamente todo lo que pongas en un programa, sin excepción alguna, será transformado en bits. Cuando hablamos específicamente de bits es para poder entender el dato usando... digamoslo así "unas gafas diferentes" que nos permiten mirar como lo haría el ordenador. En la memoria de un ordenador solo hay ceros y unos. Pero al compilador le puedes decir que trate el dato como si fuera un entero sin signo, un entero con signo, un carácter, etc.


Respecto a la declaración de A1. Primero no sería IMPUT sino INPUT y segundo A! no tiene ambigüedad y Arduino ya sabe que al usar ese valor nos estamos refiriendo a un puerto de entrada analógico y por eso hace falta avisarle de como lo vamos a usar. Uso la palabra avisar porque tampoco es exactamente una declaración, pero está bien visto porque sería algo parecido.

Respecto a las cosas que puse y no entendiste, hay cosas que puedes copiar y ejecutar para ver que sale.

Una tabla con valores en tres formatos diferentes.
Código:
Dec.Hex.  Binario

0 ,  0x0 ,  0b0
1 ,  0x1 ,  0b1
2 ,  0x2 ,  0b10
3 ,  0x3 ,  0b11
4 ,  0x4 ,  0b100
5 ,  0x5 ,  0b101
6 ,  0x6 ,  0b110
7 ,  0x7 ,  0b111
8 ,  0x8 ,  0b1000
9 ,  0x9 ,  0b1001
10 ,  0xa ,  0b1010
11 ,  0xb ,  0b1011
12 ,  0xc ,  0b1100
13 ,  0xd ,  0b1101
14 ,  0xe ,  0b1110
15 ,  0xf ,  0b1111
16 ,  0x10 ,  0b10000
17 ,  0x11 ,  0b10001
18 ,  0x12 ,  0b10010
19 ,  0x13 ,  0b10011
20 ,  0x14 ,  0b10100
21 ,  0x15 ,  0b10101
22 ,  0x16 ,  0b10110
23 ,  0x17 ,  0b10111
24 ,  0x18 ,  0b11000
25 ,  0x19 ,  0b11001
26 ,  0x1a ,  0b11010
27 ,  0x1b ,  0b11011
28 ,  0x1c ,  0b11100
29 ,  0x1d ,  0b11101
30 ,  0x1e ,  0b11110
31 ,  0x1f ,  0b11111
32 ,  0x20 ,  0b100000
33 ,  0x21 ,  0b100001
34 ,  0x22 ,  0b100010
35 ,  0x23 ,  0b100011
36 ,  0x24 ,  0b100100
37 ,  0x25 ,  0b100101
38 ,  0x26 ,  0b100110
39 ,  0x27 ,  0b100111
40 ,  0x28 ,  0b101000
41 ,  0x29 ,  0b101001
42 ,  0x2a ,  0b101010
43 ,  0x2b ,  0b101011
44 ,  0x2c ,  0b101100
45 ,  0x2d ,  0b101101
46 ,  0x2e ,  0b101110
47 ,  0x2f ,  0b101111
48 ,  0x30 ,  0b110000
49 ,  0x31 ,  0b110001
#84
Vamos a hablar ahora de una serie de tipos que vamos a encontrarnos tales como uint8_t, int16_t, etc.

Estos son tipos donde se menciona el número de bits que ocupan. De esa forma, nos garantizamos que al compilarse el programa en una máquina diferente, ese tipo de datos va a ocupar la misma cantidad de memoria en cualquier máquina, cosa que no ocurre cuando usamos los tipos que no llevan el numerito. En estos para averiguar cuantos bytes ocupan en la memoria necesitamos preguntar con sizeof().

Código:
Serial.print("sizeof(byte)="); Serial.println(sizeof(byte));
  Serial.println();
  Serial.print("sizeof(char)="); Serial.println(sizeof(char));
  Serial.println();
  Serial.print("sizeof(short)="); Serial.println(sizeof(short));
  Serial.println();
  Serial.print("sizeof(int)="); Serial.println(sizeof(int));
  Serial.println();
  Serial.print("sizeof(long)="); Serial.println(sizeof(long));
  Serial.println();
  Serial.print("sizeof(long long)="); Serial.println(sizeof(long long));
  Serial.println();
  Serial.print("sizeof(bool)="); Serial.println(sizeof(bool));
  Serial.println();
  Serial.print("sizeof(boolean)="); Serial.println(sizeof(boolean));
  Serial.println();
  Serial.print("sizeof(float)="); Serial.println(sizeof(float));
  Serial.println();
  Serial.print("sizeof(double)="); Serial.println(sizeof(double));
  Serial.println();
  Serial.print("sizeof(char*)="); Serial.println(sizeof(char*));
  Serial.println();

Para verificar lo que ocupan los datos que usan el numerito haríamos lo mismo pero el resultado en cualquier plataforma será invariable.

Código:
Serial.print("sizeof(int8_t)="); Serial.println(sizeof(int8_t));
  Serial.println();
  Serial.print("sizeof(int16_t)="); Serial.println(sizeof(int16_t));
  Serial.println();
  Serial.print("sizeof(int32_t)="); Serial.println(sizeof(int32_t));
  Serial.println();
  Serial.print("sizeof(int64_t)="); Serial.println(sizeof(int64_t));
  Serial.println();
  Serial.print("sizeof(uint8_t)="); Serial.println(sizeof(uint8_t));
  Serial.println();
  Serial.print("sizeof(uint16_t)="); Serial.println(sizeof(uint16_t));
  Serial.println();
  Serial.print("sizeof(uint32_t)="); Serial.println(sizeof(uint32_t));
  Serial.println();
  Serial.print("sizeof(uint64_t)="); Serial.println(sizeof(uint64_t));
  Serial.println();

Ahora viene la pregunta del millón. ¿Qué tipo debo usar?

Hay que empezar diciendo que salvo en Arduino DUE que tiene un procesador de 32 bits, el resto usa procesadores de 8 bits, y entre ellos los problemas de portabilidad derivados de usar un tipo sin numerito (que se usan bastante) no existen.

Si quisieramos por ejemplo grabar un entero en la EEPROM, habría que tener especial cuidado con el número de bytes que ocupa el dato y por ejemplo en Arduino UNO un int ocupa 2 bytes (16 bits) pero en Arduino DUE el tipo int ocupa 4 bytes (32 bits).

Los tipos con numerito son algo que no se contempló en las primeras versiones del lenguaje C.

Acabo de leer un artículo en inglés que habla sobre la evolución del lenguaje C, titulado "Cómo programar en C en 2016" y que empieza diciendo:

La primera regla de C es no escribir en C si puedes evitarlo. Si te ves obligado a escribir C, deberías seguir las reglas modernas. C ha estado con nosotros desde principios de los 70. La gente ha “aprendido C” en numerosos puntos de su evolución, pero el conocimiento se suele parar después de aprender, por lo que todo el mundo piensa diferente según el año en que aprendieron. Es importante no quedarse paralizado en las “cosas que aprendí en los 80/90”.

El artículo es este pero no va a aportar gran cosa a los que estáis empezando.

Yo he ido evolucionando y modernizándome a lo largo de los años, pero no completamente. Empecé a interesarme por el mundo Arduino hace unos 3 años, y pese a que yo profesionalmente había trabajado bastantes años en C y en C++, lo cierto es que ya llevaba unos diez años o más sin programar nada en C. (tuve un parón importante).

El artículo habla de cosas interesantes pero para los que estáis aprendiendo a programar en C como primer lenguaje, bastante tenéis ya como para preocuparos de algunos detalles que con el tiempo iréis aprendiendo con la práctica (si es que antes no decidís cambiar a otro lenguaje). Para Arduino, pese a que hay algunas alternativas, de momento trabajar en C y C++ es casi obligado.

El no seguir todas la normas que se recomiendan en el artículo puede tener consecuencias de portabilidad del código a otras máquinas, pero usando Arduinos de 8 bits (como la mayoría) no hay problema con ciertos usos del lenguaje C, así que para vosotros no es demasiado importante lo de usar los tipos con numerito.

Por ejemplo, nos da lo mismo que usemos int en lugar del tipo recomendado int16_t porque en los controladores AVR de 8 bits el tipo int viene definido como tipo int16_t. Sabemos que son dos bytes.

Los problemas de portabilidad de las aplicaciones dentro de Arduino tienen que ver principalmente con las numerosas diferencias que se introducen en cada una de las diferentes placas Arduino.
#85
En Meneamé las reacciones de muchos programadores ante las recomendaciones del artículo, no están siendo buenas.

A mí me divierte bastante estas reacciones de rebeldía ante los sabiondos de la programación por parte de gente que no sabe tanto pero lleva décadas programando y se siente coaccionada.

https://www.meneame.net/story/como-programar-c-2016-eng

Creo que cada entorno de aplicación tiene sus propias exigencias y que para un entorno como Arduino, y a nuestro nivel, tanta recomendación resulta excesiva.

Es bueno conocer en que consiste el uso de ciertas posibilidades modernas del lenguaje para así poder tener todo en cuenta, y poder elegir, pero nada más. Si fueramos profesionales trabajando para una empresa tendríamos que programar ajustándonos a las normas de la empresa sean las que sean. No es el caso.

Preguntad lo que no entendáis y sentiros libres de experimentar la programación como más os apetezca.
#86
El problema es que no tengo medio de comprobar el codigo por lo menos hasta mañana, por que estoy en el curro aprobechando mi rato de comida.
pero bueno intentaré correjir algunos detalles a ver si te cuadra un poco:

1.void setup() {
2. Serial.begin(9600); // incializar el puerto serie
3. pinMode(13,OUTPUT);//Avertimos a arduino que el pin 13 es salida
4.pinMode(A1 INPUT);//Avertimos a arduino que el pin A1 es entrada de datos???

5.}
6. void loop() {
7. int potencio=analogRead(A0);//variable de potenciometro
8. digitalWrite(13,HIGH);//encendemos el led
9.delay(500);//
10. Serial.println(potencio);//Envía el dato como valor entero de 0-1023
11. delay(2000);
12. int v_temp = analogRead(A1) * 0.4888;
/* Leemos la entrada A1 y multiplicamos ese valor por la constante 0.4888 para pasarlo a ºC*/

13. Serial.println(v_temp);//envia datos del sensor al monitor serial
14. delay(2000);
15.}

ahora mis interminables preguntasBlush

¿por que tendria que poner una variable si no voy a necesitar una variable durante el programa ? ¿no valdria con decirle que es una entrada y luego simplemente poner el Nº de esta y la operación a realizar?


Perdón por el detalle de imput-input, es un fallo ortografico para mi cerebro jejeje
#87
Creo que cometí un error diciendo que no hacía falta especificar el modo del pin cuan era analógico. Lo cierto es que yo reservo siempre los pines de entrada analógica para usarlos como tales y como me has hecho dudar lo he consultado y resulta que un pin analógico de entrada se puede usar como pin de salida digital. Es decir, se podría hacer.

pinMode(A1, OUTPUT);
digitalWrite(A1, HIGH);

No suelo inicializar el modo de los pines analógicos porque los uso siempre como entradas analógicas, y parece que por defecto el modo en eso pines ya viene inicializado de esa forma.

(pinMode(A1 INPUT); te dará error, falta la coma)

Acabas de detectar un par de lugares donde puedes ahorrarte variables.
El programa quedaría más compacto y quizás también un poco menos legible.
Se puede usar la llamada a la función de lectura de la entrada ( o la llamada a cualquier otra función que devuelva un valor artimético) como parte de una expresión aritmética que puede ser todo lo complicada que quieras.

Como no siempre da lo mismo el orden en que se realizan las operaciones aritméticas conviene encerrar entre paréntesis las partes que hay que evaluar antes de operar con otros datos.

El compilador no avisa si no pones paréntesis, porque él usa unos convenios para determinar el orden en el cual realiza las operaciones dentro de una expresión, pero si no aciertas puedes estar poniendo una expresión que no responda a lo que tu quieras.

No es lo mismo calcular (6+4)/ (5-3) que 6 + (4/5) -3. Si no pones ningún paréntesis, 6+4/5-3 el compilador usará la reglas de C que determina el orden y lo que calculará será lo mismo que si hubieras puesto 6 + (4/5) -3. Los paréntesis evitan confusiones y ayudan a la legibilidad del programa.

En C, los operadores siguen unas reglas de preferencia donde los operadores *, / y % tienen preferencia sobre los operadores + y -. Para evitar estas preferencias, y forzar un orden diferente, es obligado utilizar paréntesis. Las expresiones con operadores de la misma preferencia se suelen evaluar de izquierda a derecha (por ser el sentido natural de lectura). Otro punto a tener en cuenta es que en una expresión que entraña una división, debería evitar toda posibilidad de división por cero porque el compilador en tiempo de ejecución daría un error.

Tu programa suprimiendo la variables quedaría de a siguiente forma.

6. void loop() {
7.
8. digitalWrite(13,HIGH);//encendemos el led
9.delay(500);//
10. Serial.println( analogRead(A0) );//Envía el dato como valor entero de 0-1023
11. delay(2000);
12.
13. Serial.println( (analogRead(A1) * 0.4888) );//envia datos del sensor al monitor serial
14. delay(2000);
15.}

En la segunda expresión estamos multiplicando un valor entero (leído en una entrada analógica) por una constante que es un valor real en coma flotante y el resultado de una operación de este tipo es un valor real en coma flotante.

Un ordenador solo puede hacer operaciones aritméticas con datos del mismo tipo, así que lo que ocurrirá será una conversión previa de tipos de forma automática.

Por eso cuando un operador tiene operandos de tipos diferentes, éstos se convierten a un tipo común de acuerdo con un reducida número de reglas que eviten pérdida de información. En general, las únicas conversiones automáticas son aquellas que convierten un operando "angosto" a uno más "amplio" sin pérdida de información, tal como convertir un entero 'i' a punto flotante 'f' en una expresión como f + i.

Las expresiones que podrían perder información, como asignar un tipo mayor a uno más corto, o un tipo de punto flotante a un entero tal que i=f , pueden producir una advertencia en el compilador, pero no son ilegales.

Si 'f' vale 31.1 'i' tomará el valor 31 y con un poco de suerte eso sería lo que queríamos hacer ,pero si 'f' es del orden de miles millones y pretendemos guardar el dato en un entero, el compilador te dará el mismo aviso que antes y lógicamente el programa en este caso fallará.

El compilador no siempre puede saber los valores que irán tomando las variables durante la ejecución del programa así que no impide continuar y las advertencias se hacen en base a los valores conflictivos que puedan tomar las variables.
#88
Poco mas que apuntar, tal vez que ya que defines
pinMode(A1, INPUT);

deberías también definir
pinMode(A0, INPUT);
ya que lo usas.



Lo que te comenté del serial y lo de acabar en "ln" o no
si antes de
Serial.println( analogRead(A0) );
pones
Serial.print("Potenciometro: ");

dejandolo así:
Serial.print("Potenciometro: ");
Serial.println( analogRead(A0) );

El serial te pintara por ejemplo: Potenciometro: 256



Realmente es una tontería crear una variable para simplemente mostrarla, muestras el calculo de su contenido y terminas antes

Pero realmente una variable no se usa principalmente para mostrarla, la muestras en la traza como seguimiento, o incluso en un LCD, pero realmente la variable la creas para para usarla en diferentes lugares (seguramente en distinta función de donde se obtubo) y no vas a estar repitiendo su calculo u obtención en cada sitio y cada vez

A modo de ejemplo, obtienes la temperatura de un sensor (como tu ejemplo), y aunque la muestres en el LCD o en el serial, lo que quieres hacer es comprobar si la temperatura esta en un rango determinado para activar un actuador (p.e. activar a High el pin de un rele) que por ejemplo te ponga en marcha el calentador (si es menor a un limite) o unos ventiladores (si supera un límite)

Para lo anterior pides la lectura del pin del sensor de temperatura la calculas transformado el valor obtenido y la almacenas en una variable y esta es la que comparas si se queda corta o se pasa. No vas a estar volviendo a pedir y calculando la temperatura para cada verificación de calentador y ventilador. Esto no va en contra que en el bucle principal vuelvas a revisar la temperatura cada x segundos
#89
Secuencias de escape:
En el lenguaje de programación C, determinados caracteres especiales se pueden representar mediante lo que se conoce como una secuencia de escape. En C consiste en usar un caracter barra invertida '\' (no confundir con la barra de división '/') seguida de un caracter que será traducido a un caracter especial.

Si queremos visualizar una barra invertida sin que sea interpretada como el primer caracter de una secuencia de escape tendremos que escaparla a su vez con un barra invertida así que quedaría como \\ y si quermos imprimir comillas dobles sin que el compilador piense que es el final de las primeras dobles comillas que pusimos al principio de la cadena de caracteres, también hay que escaparla con barra invertida.

Secuencias de escape habituales en C son las siguientes:

\n: insertará un salto de línea donde se coloque.
\b: carácter de retroceso.
\t: tabulación horizontal.
\v: tabulación vertical.
\\: mostrará una contrabarra donde se coloque.
\f: salto de página.
\': mostrará un apóstrofe donde se coloque.
\": mostrará comillas dobles donde se coloque.
\0: fin de una cadena de caracteres.

Un ejemplo del uso de caracteres que usan secuencias de escape en C :

Serial.println ("Comillas dobles entre parentesis=(\")");
Serial.println ("Salto de linea entre parentesis=(\n)");
Serial.println ("Caracter de retroceso entre paréntesis=(\b)");
Serial.println ("Caracter de tabulacion entre parentesis (\t)");
Serial.println ("Caracter nulo de fin de cadena=(\0)");
Serial.println ("Barra invertida entre parentesis=(\\)");

Se pueden usar en cadenas de caracteres delimitadas entre dobles comillas como acabamos de ver en el ejemplo anterior o en datos de tipo caracter.

Por ejemplo:

char NullChar='\0';
char NewLine='\n';

Normalmente en una pasada previa a la compilación propiamente dicha se hacen este tipo de cosas y algunas más que todavía no hemos comentado.
#90
Os voy a poner un programita que servirá para probar las salidas digitales.

Usa una sentencia condicional nueva.

Frente a la construcción if (condicion) {accion_para_condicion_true} else {accion_para_condicion_false} usaremos los operadores '?' y ':' que resultan algo menos legibles pero que cuando se entienden tienen bastante utilidad. Se usan de la forma siguiente: A ? B : C

Tenéis que ver el conjunto como una expresión donde el resultado de la misma será B o C.

En primer lugar tenemos 'A' que es una expresión lógica finalizada con el operador ? (La expresión 'A' valdrá true o false)

Después del operador '?' viene la expresión 'B' que puede ser de cualquier tipo. Basta con que devuelva un valor.

Después del operador ':' viene la expresión 'C' que puede ser de cualquier tipo pero debería ser compatible con el tipo de 'B'.

Podeis ejecutar el programa para ver lo que hace y luego con lo que acabo de decir intentar comprender todo su funcionamiento. Lo que no entendáis preguntadlo. Este programa os ayudará a entender el programador fácil que podéis construir más adelante.

Código:
/*****

(C) Antonio Castro Snurmacher
Simple Electric Timer Arduino (CaoSeta)

****/

#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif


// Por defecto se usarán los seis pines siguientes  4, 5, 6, 7, 8, 9, 10, 11
#define PRIMER_PIN              4
#define MAXNUM_PINS             8    

unsigned long ContLoop=0;

// **********************************************************************************************
// **********************************************************************************************
void TogglePin(int pin){
    digitalWrite(pin, (HIGH==digitalRead(pin)) ? LOW : HIGH);
}

// *****************************************************************************************
// *****************************************************************************************
void PrintLedStatus(){
    for (int i=0; i<MAXNUM_PINS; i++){
         Serial.print((HIGH==digitalRead(i+PRIMER_PIN)) ? 'H' : 'L');
    }
    Serial.println();
}



// *****************************************************************************************
// Cambia el estado de las salidas con una cadencia de 250 ms por pin
// *****************************************************************************************
void ToggleAllPins(){
    for (int i=0; i<MAXNUM_PINS; i++){
        TogglePin(i+PRIMER_PIN);
        PrintLedStatus();
        delay(250);
    }
}

// *****************************************************************************************
// Inicializa los pines y muestra informacion de cuales son.
// *****************************************************************************************
void IniPins(){
    Serial.print(F("Pines disponibles: "));
    for (int i=0; i<MAXNUM_PINS; i++){
        Serial.print(i+PRIMER_PIN);
        Serial.print(',');
        pinMode(i+PRIMER_PIN, OUTPUT);
        digitalWrite(i+PRIMER_PIN, LOW);
    }
    Serial.println();
}


// *****************************************************************************************
// **** SETUP ****
// *****************************************************************************************
void setup() {
    Serial.begin(9600);
    while (!Serial) ; // Necesario esperar para Arduino leonardo y Arduino Pro Micro.
    Serial.println(F("PruLeds"));
    IniPins();
}

// *****************************************************************************************
// **** MAIN LOOP ****
// *****************************************************************************************
void loop(){
    Serial.println(ContLoop++);
    ToggleAllPins();
}

Usuarios navegando en este tema: 4 invitado(s)


Salto de foro: