commit d745a38a173049b2c3009bb83bcc211803b970ef
Author: Martin Kloeckner <mjkloeckner@gmail.com>
Date: Sun, 3 Dec 2023 16:09:55 -0300
first commit
Diffstat:
2 files changed, 224 insertions(+), 0 deletions(-)
diff --git a/DAC_6bit_transreceiver_multiport/DAC_6bit_transreceiver_multiport.ino b/DAC_6bit_transreceiver_multiport/DAC_6bit_transreceiver_multiport.ino
@@ -0,0 +1,73 @@
+// Transceptor
+//
+// Diferencia de tiempo entre usar registros para definir el estado de un pin y
+// usar la funcion incorporada pinMode().
+//
+// https://forum.arduino.cc/t/ddr-vs-pinmode-solved/497927/3
+//
+// DDRD |= 0b00010000; tarda 2 ciclos de clock (~0.125us@16Mhz)
+// bitSet(PORTD, 5, 1); tarda lo mismo que con la sentence previa
+// pinMode(5, OUTPUT); tarda 71 ciclos de clock (~4.43us@16Mhz)
+
+#define DAC_MASK_PORTB B00010101
+#define DAC_MASK_PORTD B01010100
+
+void printR2R (uint8_t);
+void USART_Transmit(uint8_t data);
+uint8_t USART_Receive(void);
+
+void setup() {
+ DDRD |= DAC_MASK_PORTD; // Define como salidas a los pines D2, D4 y D6
+ DDRB |= DAC_MASK_PORTB; // Define como salidas a los pines D8, D10 y D12
+
+ Serial.begin(115200);
+
+ DDRC = 0x00; // Define los pines del puerto C como inputs (0 INPUT, 1 OUTPUT)
+
+ // Registro de Control del ADC
+ ADCSRA = 0x86; // 1000 0110
+ // | ||
+ // | ``- Determinan el factor de division. Con ambos bits
+ // | activos setea un factor de division de 128 (max)
+ // |
+ // `- Activa el ADC
+
+ // Registro de selección de multiplexion del ADC
+ ADMUX = 0x60; // 0110 0000
+}
+
+void loop() {
+ // Lee un valor del pin analogico, luego lo transmite por protocolo USART
+ USART_Transmit(analogRead(A0));
+
+ // Los bits recibidos los manda a la salida
+ printR2R(USART_Receive());
+}
+
+void printR2R (uint8_t num) {
+ // PORTB = 0bABCDEFGH
+ // De PORTB se utilizan los pines D8, D10 y D12 siendo los
+ // bits H, F y D de PORTB respectivamente
+ PORTB = (PORTB &~ DAC_MASK_PORTB)| // Elimina el contenido anterior
+ ((num & (1<<7))>>3)| // Obtiene el valor del bit
+ ((num & (1<<6))>>4)| // en la 6ta posicion y lo mueve
+ ((num & (1<<5))>>5); // para que corresponda con el lugar del
+ // pin asignado en el registro de PORTD
+
+ // PORTD = 0bABCDEFGH
+ // De PORTD se utilizan los pines D6, D4 y D2 siendo los bits B, D y F
+ // de PORTD respectivamente
+ PORTD = (PORTD &~ DAC_MASK_PORTD)|
+ ((num & (1<<4))<<2)|
+ ((num & (1<<3))<<1)|
+ (num & (1<<2));
+}
+
+void USART_Transmit(uint8_t data) {
+ //while(!(UCSR0A & (1<<UDRE0)));
+ UDR0 = data;
+}
+
+uint8_t USART_Receive(void) {
+ return UDR0;
+}
diff --git a/DAC_test_multiport/DAC_test_multiport.ino b/DAC_test_multiport/DAC_test_multiport.ino
@@ -0,0 +1,151 @@
+// En este ejemplo se genera una señal senoidal como salida. Se utilizan
+// registros para manipular los puertos para mayor velocidad, obteniendo asi una
+// señal mas suave.
+
+// Se utilizan los pines D2, D4, D6, D8, D10 y D12 de Arduino UNO (o nano) para
+// implementar un DAC de 6 bits. Dichos pines se deben conectar al circuito R2R
+// correspondiente, siendo los pines D8, D10 y D12 los mas significativos
+
+// Diferencia de tiempo entre usar registros para definir el estado de un pin y
+// usar la funcion incorporada pinMode().
+// https://forum.arduino.cc/t/ddr-vs-pinmode-solved/497927/3
+//
+// Las sentencias siguientes tienen el mismo objetivo, activar el pin 5
+// pinMode(5, OUTPUT); tarda 71 ciclos de clock (~4.43us@16Mhz)
+// DDRD |= 0b00010000; tarda 2 ciclos de clock (~0.125us@16Mhz)
+// bitSet(PORTD, 5, 1); tarda 2 ciclos de clock (~0.125us@16Mhz)
+//
+// La diferencia entre usar la funcion bitSet() y asignar directamente el valor
+// al registro DDRD, es que con el ultimo se pueden activar varias pines al
+// mismo tiempo, mientras que con la funcion bitSet() solo uno.
+
+// Máscara correspondiente a los pines utilizados del Puerto B
+// y del puerto D respectivamente
+// https://www.arduino.cc/en/Reference/PortManipulation
+#define DAC_MASK_PORTB B00010101
+// | | |
+// | | `-- D8
+// | `-- D10
+// `-- D12
+
+#define DAC_MASK_PORTD B01010100
+// | | |
+// | | `-- D2
+// | `-- D4
+// `-- D6
+
+// Tabla con un periodo de un seno muestreado (32 muestras, 8 bits)
+const uint8_t tabla[] PROGMEM = {
+ 128,153,178,200,220,236,247,254,255,251,242,228,
+ 211,189,166,140,115,89,66,44,27,13,4,0,1,8,19,35,55,77,102
+};
+
+const uint8_t largo = sizeof(tabla); // Tamaño de la tabla
+uint8_t indice = 0; // Variable para indexación de la tabla
+uint8_t paso = 1; // Incremento del índice
+uint8_t valor; // Variable para almacenar el valor de cada elemento
+
+void printR2R (uint8_t);
+
+void setup() {
+ DDRD |= DAC_MASK_PORTD; // Define como salidas a los pines D2, D4 y D6
+ // (pertenecen al puerto D)
+ DDRB |= DAC_MASK_PORTB; // Define como salidas a los pines D8, D10 y D12
+ // (pertenecen al puerto B)
+}
+
+void loop() {
+ // Se usa una función especial para leer de la memoria de programa
+ valor = pgm_read_byte(&tabla[indice]);
+
+ // Se envía el valor de la tabla convertido a 6 bits al DAC
+ //printR2R(valor>>2);
+ printR2R(valor);
+
+ indice += paso; // Se incrementa el índice a la próxima muestra
+ indice %= largo; // Se limita el índice al tamaño de la tabla
+
+ delayMicroseconds(98); // Limitación en el tiempo del bucle loop
+ // Permite generar senoidales de menor frecuencia
+}
+
+// Esta función desprecia los ultimos 2 bits menos significativos de `numero`
+void printR2R (uint8_t numero) {
+ // numero = numero<<2;
+
+ // 0 < numero < 255 (8 bits)
+ // ej 69 (0100 0101)
+ // |||| ||``- resolucion de 6 bits, se desprecian los
+ // |||| || bits menos significativos
+ // |||`-``---- PORTD (LSB)
+ // |||
+ // ```--- PORTB (MSB)
+
+ // El parametro `numero` solo puede representar hasta 255 ya que es de 8 bits
+ // Como el DAC es de 6 bits se desprecian los ultimos dos bits menoss
+ // significativos de `numero`. Los 6 bits restantes se mandan al R2R a través
+ // de lo pines correspondientes
+
+ // Ej 71 (0100 0110)
+ // |||| ||||
+ // |||| ||``- resolucion de 6 bits, se desprecian los
+ // |||| || bits menos significativos (sin pin asignado)
+ // |||| ||
+ // |||`-``---- PORTD (LSB)
+ // |||
+ // ```--- PORTB (MSB)
+
+ // PORTD es un registro interno del microcontrolador utilizado
+ // por el arudino, internamente se representa con una variable de 8 bits
+ // correspondiendo cada bit a un pin en del arduino, como se muestra
+ // a continuacion
+
+ // PORTD = `0bABCDEFGH` correspondiendo cada bit a los pines siguientes:
+ // ||||||||
+ // |||||||`- D0 (RXD)
+ // ||||||`- D1 (TXD)
+ // |||||`- D2
+ // ||||`- D3
+ // |||`- D4
+ // ||`- D5
+ // |`- D6
+ // `- D7
+
+ // PORTB es otro registro de 8 bits similar a PORTD pero representa otros
+ // pines
+
+ // PORTB = `0bABCDEFGH` siendo:
+ // ||||||||
+ // |||||||`- D8
+ // ||||||`- D9
+ // |||||`- D10
+ // ||||`- D11
+ // |||`- D12
+ // ||`- D13
+ // |`- X (No disponible en Arduino)
+ // `- X (No disponible en Arduino)
+
+ // Teniendo en cuenta que PORTB contiene los bits mas significativos
+ // es conveniente modificar ese puerto primero, ya que hasta la siguiente
+ // instruccion de modificacion del PORTD, el R2R recibira un valor mas
+ // aproximado al valor final
+
+ // Para asignar un nuevo valor a PORTB primero se borra el contenido
+ // anterior de los pines utilizados, dejando los sin utilizar como
+ // estaban. Luego adiciona el nuevo contenido con la operación OR
+
+ // De PORTB se utilizan los pines D8, D10 y D12 siendo los
+ // bits H, F y D de PORTB respectivamente
+ PORTB = (PORTB &~ DAC_MASK_PORTB)|
+ ((numero & (1<<7))>>3)|
+ ((numero & (1<<6))>>4)|
+ ((numero & (1<<5))>>5);
+
+ // De PORTD se utilizan los pines D6, D4 y D2 siendo los bits B, D y F
+ // de PORTD respectivamente
+ PORTD = (PORTD &~ DAC_MASK_PORTD)| // Elimina el contenido anterior
+ ((numero & (1<<4))<<2)| // obtiene el valor del bit
+ ((numero & (1<<3))<<1)| // en la 6ta posicion y lo mueve
+ (numero & (1<<2)); // para que corresponda con el lugar del
+ // pin asignado en el registro de PORTD
+}