Pregunta:
Control remoto de RF usando VirtualWire en ATtiny85 funcionando a 8MHz en oscilador interno
Ricardo
2014-03-18 05:42:09 UTC
view on stackexchange narkive permalink

Estoy tratando de hacer un control remoto de RF usando ATtiny85 funcionando a 8MHz en un oscilador interno, este módulo transmisor RF 434MHz barato (como el que se muestra a continuación) y VirtualWire lib, pero no ha tenido éxito hasta ahora .

RF transmitter

Entonces, antes de continuar, ¿es posible usar VirtualWire con ATtiny85 funcionando a 3.6V y 8MHz con su oscilador interno? Si es así, ¿cómo?

Encontré algunas fuentes dispersas de información en la Red sobre esto, pero no pude encontrarle mucho sentido.

He construido versiones ATMega328 del receptor y transmisor usando VirtualWire sin mayores problemas. Ambos módulos se comunican entre sí y se pierden muy pocos datos. Ahora, cuando intenté reemplazar el transmisor ATMega328 con una versión más pequeña usando el ATtiny85, tengo problemas.

Estos son los síntomas:

  1. El principal parece ser que cuando agrego la inclusión de VirtualWire, mi boceto parece ralentizarse mucho . Así que me imagino que es una cuestión de tiempo. Pero no estoy seguro de cuál es el problema.

  2. Puse un visor en ATtiny85 pin 6 (PB1) pero No veo que se esté transmitiendo nada fuerte>. Creo que me equivoqué con los nombres de los pines.

  3. Puedo hacer que el LED parpadee y también puedo leer los botones sin problemas.

Aquí están los esquemas y la diseño de placa para el control remoto:

RC schematic

La placa actualmente se alimenta con 2 pilas AA NiMH que actualmente están a 2.6V. Puedo hacer que el ATtiny85 parpadee con ese voltaje. Planeo alimentar el RC con una batería de litio CR2 de 3.6V.

Aquí hay más detalles de mi entorno de desarrollo:

  • Arduino IDE 1.05
  • Estoy usando núcleos ATtiny desde aquí
  • Estoy programando el ATtiny85 usando un Arduino UNO R3 como ISP, sin problemas (está funcionando porque puedo hacer que el ATtiny85 parpadee un LED ).

Y aquí está mi código:

  #include <VirtualWire.h> # define VCC_PIN A1
#define BTN_PIN A2 # define LED_PIN A3 # define TXD_PIN PB1 # define BLINK_UP_TIME 25 # define BUTTON_NONE 0 # define BUTTON_1 1 # define BUTTON_2 2 # define BUTTON_3 3 # define BUTTON_4 4 # define BUTTON_5 5 # define BUTTON_6 6 configuración de pinvoid () { BTN_PIN, INPUT); pinMode (TXD_PIN, SALIDA); pinMode (VCC_PIN, SALIDA); pinMode (LED_PIN, SALIDA); // deje el transmisor de RF apagado por ahora digitalWrite (VCC_PIN, LOW); // Inicializar el IO y el ISR vw_set_tx_pin (TXD_PIN); vw_setup (2000); // Bits por segundo // avisa al usuario que estamos vivos: heartbeat blink (3, 50); delay (1000);} uint8_t buf [VW_MAX_MESSAGE_LEN]; uint8_t buflen = VW_MAX_MESSAGE_LEN; void loop () {botón byte = ReadButtons (); if (button! = BUTTON_NONE) {// botón de transmisión presionado digitalWrite (LED_PIN, HIGH); // Destella una luz para mostrar la transmisión digitalWrite (VCC_PIN, HIGH); // enciende el transmisor en delay (10); buf [0] = botón; vw_send (buf, 1); vw_wait_tx (); // Espere hasta que todo el mensaje se haya ido digitalWrite (LED_PIN, LOW); // apaga el LED digitalWrite (VCC_PIN, LOW); // apaga el transmisor} delay (100);} byte ReadButtons () {unsigned int buttonVoltage = analogRead (BTN_PIN); botón de byte = BUTTON_NONE; // no devuelve ningún botón pulsado si las siguientes comprobaciones no escriben en btn if (buttonVoltage < 10) {button = BUTTON_1; } else if (buttonVoltage < 200) {button = BUTTON_2; } else if (buttonVoltage < 400) {button = BUTTON_3; } else if (buttonVoltage < 550) {button = BUTTON_4; } else if (buttonVoltage < 720) {button = BUTTON_5; } else if (buttonVoltage < 900) {button = BUTTON_6; } else if (buttonVoltage > 1000) {button = BUTTON_NONE; } return (button);}  

Entonces, ¿Qué ocurre con mi configuración?

Sabes que generalmente necesitas agregar una antena en el módulo transmisor, ¿verdad? Además, quizás también intente reducir los bits / segundo en la configuración de virtualwire.
@FakeName bueno, para ser honesto, ni siquiera he soldado el módulo de RF a la placa todavía, ya que ni siquiera puedo conseguir que la MCU envíe los bits al pin TX todavía. Así que estoy colocando la sonda del osciloscopio en el pin TX y si veo un intento de transmisión, soldaré el módulo.
Ah, vaya, me perdí eso. Definitivamente necesitas buscar un mapeo de pines adecuado. La biblioteca virtualwire reclama compatibilidad general con AVR8, además de tener una nota específica sobre ATtiny84. Aunque tengo curiosidad. Algunos de sus pines son `A {n}`, mientras que el pin del transmisor es `PB {n}`. ¿Es ese el mnemónico de pin correcto?
No veo `PB1` definido en ninguno de los encabezados ATtiny que vincula. Suponiendo que su transmisor está en el PUERTO B, pin 1, * creo * que debería tener `#define TXD_PIN 1`, ya que se accede al puerto B usando el mnemónico IO digital tradicional.
@FakeName Después de mucha depuración, la combinación de pines `Axe` final fue la que funcionó para mí (excepto por el pin TXD, obviamente). Supongo que puede referirse a `PBx` o` Ax`, ya que son macros que terminan siendo reemplazadas por números enteros (adivinando aquí).
El problema es que parece que las variables estáticas a las que se refiere `PBx` * no * están definidas por las bibliotecas ATtiny, por lo que pueden funcionar * incidentalmente *. ¿Ha verificado que puede controlar el PUERTO B 1 normalmente (por ejemplo, con comandos simples `digitalWrite ()`? Alternativamente, simplemente cambie los pines LED y TX, y use el pin LED (que sabe que funciona) para la salida de datos.
De hecho, "PBn" está definido por AVR-Libc. Da la casualidad de que arduino-tiny asigna PBn a Dn, y cada `PBn` se define para tener el valor de` n` para su uso con `_BV ()`.
Mencionas que usas Arduino IDE, ¿has definido una nueva placa para tu ATtiny? Esto se puede agregar a `ARDUINO_INSTALL_DIR / harware / arduino / boards`. De lo contrario, tendría que `#define VW_PLATFORM VW_PLATFORM_GENERIC_AVR` y usar las llamadas adicionales necesarias para las plataformas AVR genéricas.
@jfpoilpret El paquete attiny-master instala un montón de nuevas placas ATtiny en el IDE. Da soporte para varias combinaciones de ATtiny45 / 84/85 con 1/8 / 16MHz con osciladores internos y externos. Puedo programar el 85 con los 3 relojes cuando comento VW.
¿Tiene alguna forma de comprobar que la frecuencia de la MCU es la misma que la frecuencia `F_CPU` utilizada para compilar su código? Normalmente, cuando un programa parece ser más lento de lo que debería, a menudo se debe a una falta de coincidencia entre `F_CPU` y la frecuencia real (que se configura mediante fusibles en su caso, supongo).
¿Ocurre la desaceleración cuando se usa 3.6V en comparación con el uso de 5V?
La ralentización se produce cuando incluyo VirtualWire incluye y llamadas a funciones. Si los comento, el tiempo vuelve a la normalidad.
¿Intentaste incluir VirtualWire pero sin llamar a la función? Eso eliminaría la posibilidad de que las inclusiones redefinan algunas macros.
@jfpoilpret: comento la inclusión Y las llamadas de entrada y salida por completo, de ida y vuelta, al depurar. Pero las llamadas por sí solas no se compilarán sin el include.
Mi idea era en realidad mantener la inclusión pero eliminar las llamadas (que deberían compilarse), luego verificar si experimenta una desaceleración o no. Si es así, eso significaría que hay algo en la inclusión que sobrescribe una macro como `F_CPU`, o una variable estática (instancia de clase) que, cuando se construye, cambia algo importante.
@jfpoilpret Lo tengo. Lo intentaré antes de que abandone el tablero. Probablemente daré un paso atrás y haré una versión ATmega328.
Yo mismo he tenido algunos problemas con el reloj del ATtiny85. Una vez intenté conectar una pantalla LCD a uno y nunca funcionó, solo unas pocas veces pude distinguir el texto destrozado.
Cuatro respuestas:
#1
+3
imjosh
2014-03-21 02:55:14 UTC
view on stackexchange narkive permalink

Probé esos Tiny cores que estás usando y tuve muchos problemas. Cambié a http://code.google.com/p/arduino-tiny/ y parece mucho mejor. Cree una segunda carpeta de instalación de Arduino y agregue los núcleos diminutos de arduino. Las constantes de nombre de pin son como PIN_A0, PIN_A1, ..., PIN_B1, etc. Entonces, pruébelo.

Miré brevemente el código VirtualWire y hay ifdefs específicamente para Attiny85, por lo que debería trabajo. Aquí hay un proyecto derivado con ejemplos de ATTINY85 en funcionamiento: http://cosa-arduino.blogspot.de/2013/03/news-virtual-wire-interface.html

+1 ¡Excelente, gracias! Lo intentaré y te lo haré saber.
#2
+3
Mr.K
2018-08-23 00:43:34 UTC
view on stackexchange narkive permalink

Updated 26-08-2018: added tx(false); at the end of send. Without it, the TX pin could remain high, flooding the 433MHz band and making any other communication on it almost impossible!!!

Although these are all pretty old posts, I've still been struggling to get VirtualWire or its successor RadioHead working on an Attiny85. Typically the problem is that VirtualWire uses timer 0 and thereby breaks other stuff.

Now, for RX you typically don't want to spend all your processing cycles waiting for bits to come in, so you want it to be interrupt-driven, but for TX you can often do without that ... So, I did a bit of reverse-engineering of the VirtualWire TX code and implemented it as a simple send routine which can be used without needing a dedicated timer-interrupt. Using the code below on Attiny85 and an Arduino Uno as receiver with the normal VirtualWire library and the same baudrate, works just great for me, so if someone else can benefit from it, then here it is (including some code to read out an ultrasonic distance sensor and driving some leds - up to the reader to strip out what he doesn't need):

#include <util/crc16.h>#define LED_PIN           3#define LED2_PIN          4#define TX_PIN            2#define TX_BAUDRATE       2000#define TX_MICROINTERVAL  (1000000UL/TX_BAUDRATE)#define TX_MAXLEN         12#define TRIGGER_PIN       0#define ECHO_PIN          1inline void led(const bool onOff) { digitalWrite(LED_PIN, onOff ? HIGH : LOW); }inline void led2(const bool onOff) { digitalWrite(LED2_PIN, onOff ? HIGH : LOW); }inline void tx(const bool onOff) { digitalWrite(TX_PIN, onOff ? HIGH : LOW); }inline void trigger(const bool onOff) { digitalWrite(TRIGGER_PIN, onOff ? HIGH : LOW); }const uint8_t header[8] = { 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x38, 0x2C };const uint8_t conv4to6[16] = { 0x0D, 0x0E, 0x13, 0x15, 0x16, 0x19, 0x1A, 0x1C,                               0x23, 0x25, 0x26, 0x29, 0x2A, 0x2C, 0x32, 0x34 };
void rawSend(const uint8_t * p, uint8_t len) {  while (len--) {    const uint8_t val = *p++;    for (uint8_t mask = 1; mask != 0x40; mask <<= 1) {      tx(val & mask);      delayMicroseconds(TX_MICROINTERVAL);    }  }}void send(const uint8_t * buf, const uint8_t len) {  //  First create the payload ...  static uint8_t payload[(TX_MAXLEN+3)*2];  uint8_t * p = payload;  uint16_t crc = 0xFFFF;  uint8_t v = len + 3;  crc = _crc_ccitt_update(crc, v);  *p++ = conv4to6[v >> 4];  *p++ = conv4to6[v & 0x0F];  for (uint8_t l = len; l--;) {    v = *buf++;    crc = _crc_ccitt_update(crc, v);    *p++ = conv4to6[v >> 4];    *p++ = conv4to6[v & 0x0F];  }  crc = ~crc;  v = (uint8_t)crc;  *p++ = conv4to6[v >> 4];  *p++ = conv4to6[v & 0x0F];  v = (uint8_t)(crc >> 8);  *p++ = conv4to6[v >> 4];  *p++ = conv4to6[v & 0x0F];  //  Now transmit the header and the payload ...  rawSend(header, sizeof(header));  rawSend(payload, (len + 3)*2);  tx(false);}void setup() {  pinMode(LED_PIN, OUTPUT);  pinMode(LED2_PIN, OUTPUT);  led(false);  led2(false);  pinMode(TX_PIN, OUTPUT);  tx(false);  pinMode(TRIGGER_PIN, OUTPUT);  pinMode(ECHO_PIN, INPUT);  trigger(false);}int measure() {  trigger(false); delay(10); trigger(true); delay(10); trigger(false);  //  We support up to 6m, i.e. 6000mm, so that would take  //  6000mm * 2 / 0.34mm/ms = 35294ms to get to the end  //  and back, hence let's use a timeout along those  //  lines ...  unsigned long duration = pulseIn(ECHO_PIN, HIGH, 36000);  if (!duration || (duration > 35500)) return 0;  return (int)(duration * 34 / 200);}int bufferedMeasure() {  static int lastVal = 0;  static bool toggle = true;  int newVal = measure();  if (newVal) {    led2(toggle);    toggle = !toggle;    lastVal += (newVal-lastVal)/10;  }  return lastVal;}
// the loop routine runs over and over again forever:void loop() {    //  Measure the distance ...    int val = bufferedMeasure();    if (val) {      static unsigned long data;      led(true);      data = 0xD1570000UL|val;      send((const uint8_t *)&data, sizeof(data));      led(false);    } else {      led(true); delay(100); led(false); delay(100);      led(true); delay(100); led(false); delay(100);      led(true); delay(100); led(false);    }    delay(1000);}
#3
+1
Joel
2014-05-21 06:40:54 UTC
view on stackexchange narkive permalink

Prueba la biblioteca de Manchester en su lugar. Esta publicación incluye toda la información necesaria excepto los diagramas de cableado: La biblioteca de Manchester no se compilará para Attiny85

#4
+1
user2973
2014-07-21 01:28:53 UTC
view on stackexchange narkive permalink

Pasé algún tiempo haciendo que VirtualWire funcionara en attiny84. Veo dos problemas con su código:

  1. Dado que el tiny85 solo tiene un temporizador, VirtualWire y millis / micros código>. Por lo tanto, sus retrasos no funcionarán como se esperaba.
  2. VirtualWire usa valores predeterminados para vw_ptt_pin (10) y vw_rx_pin (11). Esos pines no existen en attiny85. Cuando vwsetup llama a pinMode con estos valores, provoca escrituras en direcciones de memoria arbitrarias. Es probable que esto haga que su boceto se comporte de manera impredecible. Para arreglar set vw_set_ptt_pin () y vw_set_rx_pin () a pines que existen en el tiny85 o modificar la fuente de VirtualWire.
Gracias por tu respuesta. Noté síntomas del elemento 1 anterior: el tiempo se equivocó cuando intenté hacer que VirtualWire funcionara. El ítem 2 parece ser una buena razón para que todo no funcione. Mi solución para este problema fue seguir con ATmega328 para cosas de RF. Echaré un vistazo y veré si puedo volver a usar VW con mis ATTinies.


Esta pregunta y respuesta fue traducida automáticamente del idioma inglés.El contenido original está disponible en stackexchange, a quien agradecemos la licencia cc by-sa 3.0 bajo la que se distribuye.
Loading...