Calculadora con funciones

Se asigna una tecla para calcular el valor de una función, en éste caso se sustituye la tecla ‘*’ por una función factorial como ejemplo:

Al presionar la tecla «!» se obtiene el valor del factorial del número.

5 !
120.000

Instrucciones Arduino

El archivo de intrucciones modificado a partir de calculadora básica y la función de la tecla escrita al final se muestra a continuación:

// Calculadora tecla factorial 2018.06.24
// blog.espol.edu.ec/edelros
// edelros@espol.edu.ec 

#include <LiquidCrystal_I2C.h> // LCD por I2C 
#include <Wire.h> //comunicación I2C 
#include <Keypad.h> //Teclado

// Pantalla LCD. npxmp FilasxColumnas
const byte mp = 20;
const byte np = 4;
LiquidCrystal_I2C lcd(0x27,mp,np); 

// Teclado ntxmt FilasxColumnas
const byte nt = 4; 
const byte mt = 4;
char tabla[nt][mt]={
        {'1', '2', '3', '+'},
        {'4', '5', '6', '-'},
        {'7', '8', '9', '!'},
        {'C', '0', '.', '='}};  
byte PinF[nt] = {7,6,5,4}; 
byte PinC[mt] = {3,2,1,0}; 
Keypad teclado = Keypad(makeKeymap(tabla),
                        PinF,PinC,nt,mt); 

// variables de calculadora
float numA = 0;
float numB = 0;
float resultado = 0; 
String num1, num2;
char operador  = ' ';
int tamano = 0;
byte cualnum = 0;
boolean haypunto = 0;

void setup(){
  // inicializa pantalla
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Calculadora-Basica");
  lcd.setCursor(0,1);
  lcd.print("FCNM-ESPOL");
  delay (2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("blog.espol.edu.ec");
  lcd.setCursor(0,1);
  lcd.print("/matg1052");
  delay (2000);
  lcd.clear();
}

void loop(){
  char tecla = teclado.getKey(); 

  // tecla presionada numero
  if (tecla != NO_KEY){
    if (tecla=='1' || tecla=='2' || tecla=='3' ||
        tecla=='4' || tecla=='5' || tecla=='6' || 
        tecla=='7' || tecla=='8' || tecla=='9' || 
        tecla=='0'){
      if (cualnum <= 1){
        num1 = num1 + tecla;
        cualnum = 1;
        }
      if (cualnum == 2){
        num2 = num2 + tecla;
        }
    }
    
    // tecla punto decimal
    if (tecla=='.' and haypunto==0){
      if (cualnum == 1 or cualnum == 0){
        tamano = num1.length();
        if (tamano == 0)
          {num1= "0.";}
        else
          {num1 = num1 + tecla;}
        }
      if (cualnum == 2){
        tamano = num2.length();
        if (tamano == 0)
          {num2= "0.";}
        else
          {num2 = num2 + tecla;}
        }
      haypunto = 1;
      }
  
    //tecla de Operacion
    if (cualnum >= 1 && (tecla == '+' || 
        tecla == '-' || tecla == '!' || 
        tecla == '/')){
      operador = tecla;
      cualnum = 2;
      haypunto = 0;
      }
  
    // obtener resultado
    if (tecla == '=' && cualnum == 2){
      obtenerresultado();
      }
    // tecla factorial
    if (tecla == '!'){
        resultado = factorial(numA);
        num1 = String(resultado);
        num2 = "";
        cualnum = 2;
        haypunto = 0;
        }
  
    //tecla Borrar C Clear
    if (tecla == 'C'){
      cualnum = 0;
      num1 = "";   num2 = "";
      operador = ' ';
      resultado = 0;
      haypunto = 0;
      }
    numA = num1.toFloat();
    numB = num2.toFloat();
  
    // SALIDA A PANTALLA LCD
    mostrarpantalla();
    }
  }

void obtenerresultado(){
  if (operador == '+') 
    {resultado = numA + numB;}
  if (operador == '-')
    {resultado = numA - numB;}
  if (operador == '*')
    {resultado = numA * numB;}
  if (operador == '/')
    {resultado = numA / numB;}
  num1 = String(resultado);
  num2 = "";
  cualnum = 2;
  haypunto = 0;
  }

void mostrarpantalla(){
    lcd.clear();
    lcd.setCursor(0,0);
    // muestra decimales = 3
    lcd.print(numA,3);
    if (numB!=0){
      lcd.setCursor(0,1);
      lcd.print(numB,3);    
      }
    lcd.setCursor(mp-2,0);
    lcd.print(operador);
  }


// ------ Funcion Factorial ----
float factorial(float n){
    float resultado = 1;
    int i = 2;
    for (i = 2; i<=n; i++){
        resultado = resultado*i;
    }
    return resultado;
}

Calculadora Básica-LCD y Teclado4x4

Como proyecto base se usa una calculadora básica para números reales (float).

Los componentes usados son los que tenía disponible, pueden usarse otros modelos de arduino, otros tamaños de pantalla.

La lista de componentes es:

Componentes
Descripción Unidades Observacion
Teclado 4×4 1 de membrana
Pantalla LCD 20×4 ó 16×2 1 o la que esté disponible
Módulo I2C para la pantalla 1 compatible con la pantalla LCD si no lo tiene integrado
Arduino Uno o equivalente y cable USB 1 o el modelo que esté disponible
cable Conector hembra – macho 4 para conectar el I2C al arduino
Espadines o conector macho-macho 8 pines para conectar el teclado al arduino

El módulo I2C facilita la conexión con menos cables: usando las señales SDA (Serial Data) y SCL (Serial Clock), y las de alimentación Vcc (5V) y GND.

El prototipo puede ser adaptado a otros modelos de pantallas, teclados y arduinos, debe cambiar las variables que controlan el display, el teclado o las entradas en los arduinos.


Librerías Arduino

Las librerías usadas para el manejo de los módulos del prototipo, en caso de no encontrarse disponibles en el Programa Arduino

Librería para pantalla LCD con I2C

Librería para teclado


Instrucciones en Arduino

Instrucciones básicas para operaciones de suma, resta y multiplicación, ver distribución del teclado.

// Calculadora Básica 2018.06.24
// blog.espol.edu.ec/edelros
// edelros@espol.edu.ec 

#include <LiquidCrystal_I2C.h> // LCD por I2C 
#include <Wire.h> //comunicación I2C 
#include <Keypad.h> //Teclado

// Pantalla LCD. npxmp FilasxColumnas
const byte mp = 20;
const byte np = 4;
LiquidCrystal_I2C lcd(0x27,mp,np); 

// Teclado ntxmt FilasxColumnas
const byte nt = 4; 
const byte mt = 4;
char tabla[nt][mt]={
        {'1', '2', '3', '+'},
        {'4', '5', '6', '-'},
        {'7', '8', '9', '*'},
        {'C', '0', '.', '='}};  
byte PinF[nt] = {7,6,5,4}; 
byte PinC[mt] = {3,2,1,0}; 
Keypad teclado = Keypad(makeKeymap(tabla),
                        PinF,PinC,nt,mt); 

// variables de calculadora
float numA = 0;
float numB = 0;
float resultado = 0; 
String num1, num2;
char operador  = ' ';
int tamano = 0;
byte cualnum = 0;
boolean haypunto = 0;


void setup(){
  // inicializa pantalla
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("Calculadora-Basica");
  lcd.setCursor(0,1);
  lcd.print("FCNM-ESPOL");
  delay (2000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("blog.espol.edu.ec");
  lcd.setCursor(0,1);
  lcd.print("/matg1052");
  delay (2000);
  lcd.clear();
}

void loop(){
  char tecla = teclado.getKey(); 

  // tecla presionada numero
  if (tecla != NO_KEY){
    if (tecla=='1' || tecla=='2' || tecla=='3' ||
        tecla=='4' || tecla=='5' || tecla=='6' || 
        tecla=='7' || tecla=='8' || tecla=='9' || 
        tecla=='0'){
      if (cualnum <= 1){
        num1 = num1 + tecla;
        cualnum = 1;
        }
      if (cualnum == 2){
        num2 = num2 + tecla;
        }
    }
    
    // tecla punto decimal
    if (tecla=='.' and haypunto==0){
      if (cualnum == 1 or cualnum == 0){
        tamano = num1.length();
        if (tamano == 0)
          {num1= "0.";}
        else
          {num1 = num1 + tecla;}
        }
      if (cualnum == 2){
        tamano = num2.length();
        if (tamano == 0)
          {num2= "0.";}
        else
          {num2 = num2 + tecla;}
        }
      haypunto = 1;
      }
  
    //tecla de Operacion
    if (cualnum >= 1 && (tecla == '+' || 
        tecla == '-' || tecla == '*' || 
        tecla == '/')){
      operador = tecla;
      cualnum = 2;
      haypunto = 0;
      }
  
    // obtener resultado
    if (tecla == '=' && cualnum == 2){
      obtenerresultado();
      }
  
    //tecla Borrar C Clear
    if (tecla == 'C'){
      cualnum = 0;
      num1 = "";   num2 = "";
      operador = ' ';
      resultado = 0;
      haypunto = 0;
      }
    numA = num1.toFloat();
    numB = num2.toFloat();
  
    // SALIDA A PANTALLA LCD
    mostrarpantalla();
    }
  }

void obtenerresultado(){
  if (operador == '+') 
    {resultado = numA + numB;}
  if (operador == '-')
    {resultado = numA - numB;}
  if (operador == '*')
    {resultado = numA * numB;}
  if (operador == '/')
    {resultado = numA / numB;}
  num1 = String(resultado);
  num2 = "";
  cualnum = 2;
  haypunto = 0;
  }


void mostrarpantalla(){
    lcd.clear();
    lcd.setCursor(0,0);
    // muestra decimales = 3
    lcd.print(numA,3);
    if (numB!=0){
      lcd.setCursor(0,1);
      lcd.print(numB,3);    
      }
    lcd.setCursor(mp-2,0);
    lcd.print(operador);
  }

Funciones personalizadas en Arduino, Entrada/salida serie

Componentes: Arduino, cable USB.

Una forma de usar funciones personalizadas para cálculo en arduino, consiste en serparar las instrucciones de cálculo como una función separada del bloque/lazo principal.

Por ejemplo, se puede usar la forma polinómica de la serie de Taylor para una función no disponible de cálculos con la precisión deseada.

La operatividad se muestra usando como ejemplo la función factorial(),   enviando y recibiendo los valores por medio de la conexión por USB y el «monitor serie». Ejemplo:

Observe que se encuentra habilitado el uso de «nueva línea» y «cambio de línea» (NL & CR) , para que al presionar «ENTER» se considera ingresado todos los dígitos del número.

Funciones para cálculos

Para el ejemplo, se realiza el cálculo del factorial:

n! = 1 x 2 x 3 x … x n

float factorial(float n){
    float resultado = 1;
    int i = 2;
    for (i = 2; i<=n; i++){
        resultado = resultado*i;
    }
    return resultado;
}

En el resultado, la cantidad de dígitos  se extiende usando el tipo real (float). Como práctica,  cambie la variable resultado a tipo entero (int), actualice el programa en el arduino, y calcule para números mayores  a 7; observe y explique el resultado.

Envío y recepción de datos con «monitor Serie»

La prueba de la función se simplifica enviando y recibiendo datos por la conexión USB. La variable mensaje almacena un caracter enviado al arduino, validando que sea un dígito entre 0 y 9. Al presionar «ENTER» se cierra el mensaje, se cambia el valor a número a entero y se procede a usar la función factorial para mostrar el resultado.

// funciones personalizadas para cálculo
// ingreso y salida por 'monitor serial'
// el mensaje se procesa por dígitos hasta presional ENTER
//    y se convierte a número

String mensaje = "";
void setup() {
    Serial.begin(9600);
    // espera por conexion serial-USB
    while (!Serial) {}
    Serial.println("\n calcular funcion(): \n");
}
void loop() {
    int uncaracter = 0;
    float numero = 0;
    float resultado = 0.0;
    while (Serial.available() > 0) {
        uncaracter = Serial.read();
        if (isDigit(uncaracter)) {
            mensaje = mensaje + (char)uncaracter;
        }
        if (uncaracter == '.') {
            mensaje = mensaje + (char)uncaracter;
        }
        if (uncaracter == '\n') {
            numero = mensaje.toInt();
            Serial.print("mensaje: ");
            Serial.println(mensaje);
            Serial.print("numero es: ");
            Serial.println(numero);

            // bloque de función matematica
            resultado = factorial(numero);
            Serial.print("factorial(numero): ");
            Serial.println(resultado);
            mensaje = "";
        }
    }
}

float factorial(float n){
    float resultado = 1;
    int i = 2;
    for (i = 2; i<=n; i++){
        resultado = resultado*i;
    }
    return resultado;
}

Para probar otras funciones, modifique los mensajes siguiendo el contexto del problema a resolver.


Funciones con números reales

Siguiendo el ejemplo de Polinomio de Taylor para el coseno(), en este caso el número de ingreso y salida son es reales (float). El esquema de la función es muy semejante.

1.4 Taylor-polinomio Ejemplo01

// funciones personalizadas para cálculo
// ingreso y salida por 'monitor serial'
// el mensaje se procesa por dígitos número hasta presional ENTER
//    y se convierte a número, para usar la función

String mensaje = "";
void setup() {
    Serial.begin(9600);
    // espera por conexion serial-USB
    while (!Serial) {}
    Serial.println("\n calcular funcion(): \n");
}
void loop() {
    int uncaracter = 0;
    float numero = 0.0;
    double resultado = 0.0;
    while (Serial.available() > 0) {
        uncaracter = Serial.read();
        if (isDigit(uncaracter)) {
            mensaje = mensaje + (char)uncaracter;
        }
        if (uncaracter == '.') {
            mensaje = mensaje + (char)uncaracter;
        }
        if (uncaracter == '\n') {
            numero = mensaje.toFloat();
            Serial.print("mensaje: ");
            Serial.println(mensaje);
            Serial.print("numero es: ");
            Serial.println(numero);

            // bloque de función matematica
            resultado = poliTaylor(numero);
            Serial.print("poliTaylor(numero): ");
            Serial.println(resultado,4);
            Serial.println(cos(numero),4);
            mensaje = "";
        }
    }
}

float poliTaylor(float x){
    float resultado;
    float x0=0.0;
    resultado = 1 - 0.5*(x-x0)*(x-x0); 
    return resultado;
}

Referencias:

Arduino Serial read , Arduino lista de funciones básicas .

Morse Deco – RX mensaje/Python

Se añade la traducción a texto, letra a letra del alfabeto.

Como referencia se usa la función morsedeco(codigo) descrita en Morse Decodificador, desarrollada en otro curso.

Se añade al ejercicio realizado en Morse Deco – RX mensaje morse/Python

0 31
 --- ...  ... --- .
SOS SO
1015 15
 --- ...  ... --- ..
SOS SO
1 31
 --- ...  ... --- ..
SOS SO
1017 15
 --- ...  ... --- ...
SOS SO
0 128
 --- ...  ... --- ...  
SOS SOS 

Tarea: usar en el transmisor un mensaje diferente, escrito por teclado, revisar para arduino el uso del puerto Serial – Envia y Recibe texto.

Con el uso del teclado para el mensaje, observar cuando se inicia la tx y recepción para codificar en Tx y decodificar en Rx.

# Deco señal a morse, luego a texto
# generados desde arduino
# Continuación de: TxRx Inalambrico 433Mhz ASK/OOK
# http://blog.espol.edu.ec/edelros/2018/04/11/txrx-inalambrico-433mhz-askook/

import numpy as np
import matplotlib.pyplot as plt
import serial, time
def morsedeco(codigo): 
    equivale={ 
        '.-':'A', '-...':'B', '-.-.':'C', 
        '----':'CH', '-..':'D', '.':'E', 
        '..-.':'F', '--.':'G', '....':'H', 
        '..':'I', '.---':'J', '-.-':'K',
        '.-..':'L', '--':'M', '-.':'N', 
        '--.--':'Ñ', '---':'O', '.--.':'P', 
        '--.-':'Q', '.-.':'R', '...':'S', 
        '-':'T', '..-':'U', '...-':'V',
        '.--':'W', '-..-':'X', '-.--':'Y', 
        '--..':'Z',
        '-----':'0', '.----':'1', '..---':'2', 
        '...--':'3', '....-':'4', '.....':'5', 
        '-....':'6', '--...':'7', '---..':'8', 
        '----.':'9', 
        '.-.-.-':'.', '-.-.--':',', '..--..':'?', 
        '.-..-.':'"', '--..--':'!', '   ':' ', 
        ' ':' '}
    caracter=equivale[codigo]
    return(caracter)

# INGRESO
puerto = 'com5'
baudios = 9600
tolera = 100    # rango PIN analógico
ancho = 15      # del mensaje

# PROCEDIMIENTO
arduino = serial.Serial(puerto, baudios)
arduino.setDTR(False)
time.sleep(0.3)

# limpia buffer de datos anteriores
arduino.flushInput()  
arduino.setDTR()  
time.sleep(0.3)
print('\nEstado del puerto: ',arduino.isOpen())
print('Nombre del dispositivo conectado: ', arduino.name)
print('Dump de la configuración:\n ',arduino)
print('\n###############################################\n')


# Lectura de datos
antes = 0
cuenta = 0
simbolo = ''
morse_msg = ''
morse_letra = ''
mensaje = ''

while True:
    # espera hasta recibir un dato
    while (arduino.inWaiting()==0):
        pass
    
    # lee binario del puerto serial
    lectura = arduino.readline()
    # binario a texto, elimina /r/n
    texto = lectura.decode().strip()
    valor = int(texto)
    
    # Busca duración de símbolo
    # valor repetido
    diferencia = np.abs(valor-antes)
    if (diferencia < tolera):
        cuenta = cuenta + 1
    
    else:
        print(antes,cuenta)
        # Revisa espacios
        if (antes<(0+tolera)):
            # Cambio de simbolo
            if (cuenta<(2*ancho+4)):
                simbolo = ''
            else:
                # letra completa
                letra = morsedeco(morse_letra)
                mensaje = mensaje + letra
                morse_letra = ''
                if (cuenta<(4*ancho+5)):
                    simbolo = ' '
                else:
                    # cambio de palabra
                    simbolo = '  '
                    mensaje = mensaje + ' '
        
        # Revisa punto o raya        
        else:
            if (cuenta40:
            morse_msg = ''
            mensaje = ''
            
    antes = valor
    
# Cerrar el puerto serial.
serial.Serial.close

Morse Deco – RX mensaje morse/Python

Decodifica en python desde el puerto serial los valores del pin del receptor descrito en: Morse Codec – TxRx Inalámbrico 433Mhz ASK/OOK

Se recibe en el puerto serial la señal OOK equivalente al mensaje morse de «SOS».

La lectura del puerto serial continua de lo presentado en Serial – Lectura datos se obtienen los valores entre [0,1023]

El resultado se convierte a símbolos morse ' .-' contando las veces que cada valor se repite «Alto»(1) o «Bajo»(0). Se toma como referencia el ancho de 15 para un simbolo, pues el transmisor usa una DURACION =100. Si se modifican éstos valores, se deben ajustar.

1016 15
 --- ...  ...
0 63
 --- ...  ... 
1016 47
 --- ...  ... -
0 32
 --- ...  ... -
1020 47
 --- ...  ... --
0 31
 --- ...  ... --
1019 47
 --- ...  ... ---
0 63
 --- ...  ... --- 
1018 15
 --- ...  ... --- .
0 31
 --- ...  ... --- .
1016 15
 --- ...  ... --- ..
0 31
 --- ...  ... --- ..
1016 15
 --- ...  ... --- ...

las instrucciones en python

# Deco señal a morseñ
# generados desde arduino
# Continuación de: TxRx Inalambrico 433Mhz ASK/OOK
# http://blog.espol.edu.ec/edelros/2018/04/11/txrx-inalambrico-433mhz-askook/

import numpy as np
import matplotlib.pyplot as plt
import serial, time

# INGRESO
puerto = 'com5'
baudios = 9600
tolera = 100    # rango PIN analógico
ancho = 15      # del mensaje

# PROCEDIMIENTO
arduino = serial.Serial(puerto, baudios)
arduino.setDTR(False)
time.sleep(0.3)

# limpia buffer de datos anteriores
arduino.flushInput()  
arduino.setDTR()  
time.sleep(0.3)
print('\nEstado del puerto: ',arduino.isOpen())
print('Nombre del dispositivo conectado: ', arduino.name)
print('Dump de la configuración:\n ',arduino)
print('\n###############################################\n')


# Lectura de datos
antes = 0
cuenta = 0
simbolo = ''
morse_msg = ''

while True:
    # espera hasta recibir un dato
    while (arduino.inWaiting()==0):
        pass
    
    # lee binario del puerto serial
    lectura = arduino.readline()
    # binario a texto, elimina /r/n
    texto = lectura.decode().strip()
    valor = int(texto)
    
    # Busca duración de símbolo
    # valor repetido
    diferencia = np.abs(valor-antes)
    if (diferencia < tolera):
        cuenta = cuenta + 1
    
    else:
        print(antes,cuenta)
        # Revisa espacios
        if (antes<(0+tolera)):
            if (cuenta<(2*ancho+4)):
                simbolo = ''
            else:
                if (cuenta<(4*ancho+5)):
                    simbolo = ' '
                else:
                    simbolo = '  '
        
        # Revisa punto o raya        
        else:
            if (cuenta<(ancho+3)):
                simbolo = '.'
            else:
                simbolo = '-'
        cuenta = 0
        morse_msg = morse_msg + simbolo
        print(morse_msg)
        
        if len(morse_msg)>40:
            morse_msg = ''
            
    antes = valor
    
# Cerrar el puerto serial.
serial.Serial.close

Serial – Lectura datos

Un Arduino puede enviar valores numéricos de un sensor por medio del conector USB en forma Serial (secuencial).

Los datos recibidos por una computadora mediante el puerto USB pueden procesarse usando Python. Para ésto debe conocer el puerto «com» y la velocidad de transmisión en los baudios usada por el arduino.

Ejemplo:

Se muestra una lectura de valores numéricos enteros, a partir del cual se puede modificar otros requerimientos.

El ejemplo usa los resultados de la sección Morse para el receptor: TxRx Inalambrico 433Mhz ASK/OOK

0
0
0
1017
1017
1018
1021
1017
1019
1018
1018
1016
1018
1016
1017
1019
1018
1016
1020
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1017
1017
1016
1017
1016

Instrucciones en Python

# Datos desde puerto Serial
# generados desde arduino

import numpy as np
import matplotlib.pyplot as plt
import serial, time

# INGRESO
puerto = 'com5'
baudios = 9600
ventana = 200 # tamaño ventana datos
datos=[] # vector para graficar

# PROCEDIMIENTO
arduino = serial.Serial(puerto, baudios)
arduino.setDTR(False)
time.sleep(0.3)

# limpia buffer de datos anteriores
arduino.flushInput()  
arduino.setDTR()  
time.sleep(0.3)
print('\nEstado del puerto: ',arduino.isOpen())
print('Nombre del dispositivo conectado: ', arduino.name)
print('Dump de la configuración:\n ',arduino)
print('\n###############################################\n')

# Lectura de datos
while True:
    #esperar hasta recibir un dato
    while (arduino.inWaiting()==0):
        pass 

    # lee linea desde puerto serial
    lectura = arduino.readline()
    # binario a texto, elimina /r/n
    texto = lectura.decode().strip()
    valor = int(texto)
    datos.append(valor)
    
    # mantiene el tamaño "ventana" de datos 
    if (len(datos)>=ventana):
        datos.pop(0)
    print(valor)
    
# Cerrar el puerto serial.
serial.Serial.close

Morse Codec – TxRx Inalámbrico 433Mhz ASK/OOK

El punto de partida es la combinación de Morse Codec – LEDTxRx Inalambrico 433Mhz ASK/OOK . Al primero se añade el pin 4 con el dato/símbolo bit «Alto»(1) o «Bajo» (0), que al repetirlos genera el espacio o tono morse.

Como receptor se usa la misma configuración de TxRx Inalambrico 433Mhz ASK/OOK , que permite visualizar lo recibido en un segundo arduino.

El mensaje de prueba del transmisor es » SOS   » que permite observar los valores o la gráfica en el monitor o plotter serial del programa de arduino.

Al separar el receptor del transmisor, o bloquear la señal, se obtendrán lecturas diferentes a las ideales, lo que permite disponer de nuevo material de trabajo para decodificar la señal correctamente.

Temas como corrección de errores, distancias de cobertutas, etc aparecen a partir de éste punto.

El siguiente paso consiste en decodificar la secuencia de 0’s y 1’s como puntos y rayas, previo a convertirlos nuevamente a letras.

Calidad de Señal entre Tx y Rx

El los dispositivos RF433 transmisor y receptor se encuentran muy cercanos, a unos 10 cm, pues aún no se les ha añadido una antena. Al separar un poco los RF433 se visualiza ruido en la señal, que afecta al mensaje enviado.

Si se presentan muchos problemas, simplifique conectando un cable entre el TxRfPin 4 y el RxRfPin A0

/*  CODificador morse
 *   recibe un mensaje y transmite usando RF 433 Mhz
 *   equivale: estructura de datos char y string
 *   funciones: codificar y decodificar
 */

// PIN para el LED, led integrado = 13
#define PIN_LED 13
//Duración de un símbolo en  ms
#define DURACION 100
#define TxRfPin 4 

void setup(){
  pinMode(PIN_LED, OUTPUT );
  digitalWrite( PIN_LED, LOW );
  pinMode(TxRfPin, OUTPUT);
  digitalWrite( TxRfPin, LOW );
  
}

void loop(){
  String mensaje = " SOS  ";
  String mensajemorse;
  char simbolo;
  int n;
  mensajemorse = codifica(mensaje);
  // Transmite el mensaje
  n = mensajemorse.length();
  for(int i=0; i<=n; i++){
    simbolo = mensajemorse[i];
    morseTxRF(simbolo);
  }
}

void morseTxRF(char simbolo){
    if (simbolo == '.'){
        digitalWrite(PIN_LED, HIGH );
        digitalWrite(TxRfPin, HIGH);
        delay( DURACION ); 
        digitalWrite(PIN_LED, LOW );
        digitalWrite(TxRfPin, LOW);
        delay( DURACION );
    }
    if (simbolo == '-'){
        digitalWrite(PIN_LED, HIGH );
        digitalWrite(TxRfPin, HIGH);
        delay( DURACION*3 );
        digitalWrite(PIN_LED, LOW );
        digitalWrite(TxRfPin, LOW);
        delay( DURACION );
    }
    if (simbolo == ' ') {
        digitalWrite(PIN_LED, LOW );
        digitalWrite(TxRfPin, LOW);
        delay( DURACION );
    }
}

// Equivalente letra a código Morse. Estructura de datos
static const struct {const char letra, *codigo;} equivale[] =
{
  { 'A', ".-" }, { 'B', "-..." }, { 'C', "-.-." }, 
  { 'D', "-.." }, { 'E', "." }, { 'F', "..-." }, 
  { 'G', "--." }, { 'H', "...." }, { 'I', ".." },
  { 'J', ".---" }, { 'K', "-.-" }, { 'L', ".-.." },
  { 'M', "--" }, { 'N', "-." }, { 'O', "---" }, 
  { 'P', ".--." }, { 'Q', "--.-" }, { 'R', ".-." },
  { 'S', "..." }, { 'T', "-" }, { 'U', "..-" }, 
  { 'V', "...-" }, { 'W', ".--" }, { 'X', "-..-" },
  { 'Y', "-.--" }, { 'Z', "--.." }, 
  { ' ', " " },   //espacio entre palabras 
  { '1', ".----" }, { '2', "..---" }, { '3', "...--" },
  { '4', "....-" }, { '5', "....." }, { '6', "-...." }, 
  { '7', "--..." }, { '8', "---.." }, { '9', "----." }, 
  { '0', "-----" },
  { '.', ".–.–.–" }, { ',', "--..--" }, { '?', "..--.." },
  { '!', "-.-.--" }, { ':', "---..." }, { ';', "-.-.-." }, 
  { '(', "-.--." }, { ')', "-.--.-" }, { '"', ".-..-." },
  { '@', ".--.-." }, { '&', ".-..." },
};

String codifica(String mensaje){
  String mensajemorse = "";
  int i, j, n, m;
  bool encontre;
  n = mensaje.length();
  m = (sizeof equivale / sizeof *equivale);
  for( i = 0; i<n; i++ ){
    encontre = 0;
    j=0;
    while(j<m and encontre==0){
      if(toupper(mensaje[i]) == equivale[j].letra){
        mensajemorse += equivale[j].codigo;
        encontre=1;
       }
      j++;
    }
    mensajemorse += " "; //separador de caracteres
  }
  return mensajemorse;  
}

Por realizar:

Fácilmente se determina la necesidad de un decodificador que use los datos y convierta a morse, o a texto, en el arduino o en un computador a partir de los datos seriales. Mostrar los datos en pantalla del PC o en una pantalla LCD en el arduino.

Morse Codec – LED y Buzzer

Se puede escuchar el tono del código morse enviado a un Buzzer en el pin 9.

Se añade al ejemplo anterior para un led la instrucción tone(PIN_BUZZER, NOTA, DURACION),

que requiere PIN_BUZZER, la frecuencia de la NOTA para el sonido y la duración.

El pin de señal S del Buzzer se conecta el Pin 9 del arduino, y se alimenta el VCC (+) y GND(-) completando todo lo necesario para que empiece a sonar el mensaje en el buzzer.

/*  CODificador morse
 *   recibe un mensaje y controla un buzzer en pin 9
 *   equivale: estructura de datos char y string
 *   funciones: codificar y decodificar
 */

// PIN para el LED, led integrado = 13
#define PIN_LED 13
#define PIN_BUZZER 9
#define NOTA 440
//Duración de un símbolo en  ms
#define DURACION 100

void setup(){
  pinMode( PIN_LED, OUTPUT );
  pinMode( PIN_BUZZER, OUTPUT );
  digitalWrite( PIN_LED, LOW );
}

void loop(){
  String mensaje = "SOS   ";
  String mensajemorse;
  char simbolo;
  int n;
  mensajemorse = codifica(mensaje);
  // Transmite el mensaje
  n = mensajemorse.length();
  for(int i=0; i<=n; i++){
    simbolo = mensajemorse[i];
    morseLedTx(simbolo);
  }
}

void morseLedTx(char simbolo){
    if (simbolo == '.'){
      digitalWrite( PIN_LED, HIGH );
      tone(PIN_BUZZER, NOTA, DURACION);
      delay( DURACION );
      digitalWrite( PIN_LED, LOW );
      delay( DURACION );
    }
    if (simbolo == '-'){
      digitalWrite( PIN_LED, HIGH );
      tone(PIN_BUZZER, NOTA, DURACION*3);
      delay( DURACION*3 );
      digitalWrite( PIN_LED, LOW );
      delay( DURACION );
    }
    if (simbolo == ' ') {
      delay( DURACION );
    }
}

// Equivalente letra a código Morse. Estructura de datos
static const struct {const char letra, *codigo;} equivale[] =
{
  { 'A', ".-" }, { 'B', "-..." }, { 'C', "-.-." }, 
  { 'D', "-.." }, { 'E', "." }, { 'F', "..-." }, 
  { 'G', "--." }, { 'H', "...." }, { 'I', ".." },
  { 'J', ".---" }, { 'K', "-.-" }, { 'L', ".-.." },
  { 'M', "--" }, { 'N', "-." }, { 'O', "---" }, 
  { 'P', ".--." }, { 'Q', "--.-" }, { 'R', ".-." },
  { 'S', "..." }, { 'T', "-" }, { 'U', "..-" }, 
  { 'V', "...-" }, { 'W', ".--" }, { 'X', "-..-" },
  { 'Y', "-.--" }, { 'Z', "--.." }, 
  { ' ', " " },   //espacio entre palabras 
  { '1', ".----" }, { '2', "..---" }, { '3', "...--" },
  { '4', "....-" }, { '5', "....." }, { '6', "-...." }, 
  { '7', "--..." }, { '8', "---.." }, { '9', "----." }, 
  { '0', "-----" },
  { '.', ".–.–.–" }, { ',', "--..--" }, { '?', "..--.." },
  { '!', "-.-.--" }, { ':', "---..." }, { ';', "-.-.-." }, 
  { '(', "-.--." }, { ')', "-.--.-" }, { '"', ".-..-." },
  { '@', ".--.-." }, { '&', ".-..." },
};

String codifica(String mensaje){
  String mensajemorse = "";
  int i, j, n, m;
  bool encontre;
  n = mensaje.length();
  m = (sizeof equivale / sizeof *equivale);
  for( i = 0; i<n; i++ ){
    encontre = 0;
    j=0;
    while(j<m and encontre==0){
      if(toupper(mensaje[i]) == equivale[j].letra){
        mensajemorse += equivale[j].codigo;
        encontre=1;
       }
      j++;
    }
    mensajemorse += " "; //separador de caracteres
  }
  return mensajemorse;  
}

Referencia: https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/

Serial – Envia y Recibe texto

Recibe mensajes de teclado usando el puerto serial, para prueba se usa «Monitor Serial» del programa de Arduino.

El programa solo hace ECO de lo recibido por el arduino, puede ser usado para enviar mensajes e intrucciones al arduino.

/*
 * Recibe y envia texto por puerto serial
 */
String datoserial = "";
void setup(){
  Serial.begin(9600);
}
void loop(){
    // Revisa datos escritos en monitor serial:
    if (Serial.available() > 0) {
        datoserial = Serial.readStringUntil('\n');
        //presenta en pantalla
        Serial.print("ECO Recibido: "); 
        Serial.println(datoserial);
        }
}

Referencia:

https://playground.arduino.cc/ArduinoNotebookTraduccion/Serial

https://www.arduino.cc/en/Serial/ReadStringUntil