Algunos caracteres no se transmiten correctamente de mega32 a ESP8266

2

Hace poco compré un ESP-01 para un proyecto simple de wi-fi que lee la temática de un sitio web.

Primero conecté el ESP-01 directamente en el convertidor TTL (cp2102) para leer la temperatura y todo funcionó bien a 9600 bps con los comandos AT, etc.

Luego creé un programa con winAVR para que el mega32 hiciera lo mismo usando uart a 9600 bps (UBRRL = 0x68; (o 104) para Fosc = 16MHz) pero no funcionó.

Así que utilicé un analizador lógico para comprobar qué funcionó mal con los caracteres que envié.

El resultado fue muy extraño ya que algunos de los caracteres (de los comandos AT enviados) que van desde mega32 (Tx) a ESP-01 (Rx) no se transmiten correctamente.

Intenté reducir la velocidad de transmisión del ESP-01 a 4800, pero la velocidad más baja es de 9600. No sé si alguna versión de firmware tiene la opción de una velocidad de transmisión inferior.

Por alguna razón, mega32 no puede transmitir con precisión todos los caracteres y no puedo entender por qué sucede esto. Tal vez tenga algo que ver con el cristal, pero cuando lo cambié, sucedió lo mismo. Puse un poco de retraso antes de los caracteres defectuosos que solucionaron algunos, pero no todos (1 o 2 de cada 10+) (mal método, lo sé).

También mi i ha conectado mi pin Tx (mega 32) a un divisor de voltaje para convertirlo a 3.3v para el pin Rx del ESP-01.

Después de muchas dificultades decidí pedir ayuda.

Adjunté mi código y una instantánea del analizador lógico para el comando AT AT + CIPSTART = 0, "TCP", "api.thingspeak.com", 80 (el dañado). Los otros dos comandos AT que utilizo en el código antes de que CIPSTART se transmitan casi ... bien (el '\ r' o '\ n' no se transmiten correctamente, pero de alguna manera el ESP-01 acepta los comandos).

El código completo se puede ver a continuación

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "LCD4BIT.h"
#include <stdlib.h>
#include <stdio.h>

unsigned char interface_var = 0;
unsigned char counter[34];
unsigned char var = 0;

void usart_init(void)
{
    UCSRB |= (1<<TXEN) | (1<<RXEN) | (1<<RXCIE) ; //  enable receive transmit of usart
    UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (1<<URSEL);
    UBRRL = 0x68; //  baudrate = 9600 , Fosc=16MHz, UBRR value = 104 (0x68)
}
void usart_send( unsigned char ascii)
{
    while(!(UCSRA & (1<<UDRE)));
    UDR = ascii;

}
unsigned char usart_receive(void)
{
    while (!(UCSRA & (1<<RXC)));
    return UDR;
}
void send_AT( unsigned char message[])
{
    unsigned char i=0;
    while(message[i] != '
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "LCD4BIT.h"
#include <stdlib.h>
#include <stdio.h>

unsigned char interface_var = 0;
unsigned char counter[34];
unsigned char var = 0;

void usart_init(void)
{
    UCSRB |= (1<<TXEN) | (1<<RXEN) | (1<<RXCIE) ; //  enable receive transmit of usart
    UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (1<<URSEL);
    UBRRL = 0x68; //  baudrate = 9600 , Fosc=16MHz, UBRR value = 104 (0x68)
}
void usart_send( unsigned char ascii)
{
    while(!(UCSRA & (1<<UDRE)));
    UDR = ascii;

}
unsigned char usart_receive(void)
{
    while (!(UCSRA & (1<<RXC)));
    return UDR;
}
void send_AT( unsigned char message[])
{
    unsigned char i=0;
    while(message[i] != '%pre%')
{
    usart_send(message[i]);   // This sends data to esp-01
    i++;

}

int main(void)
{
    //OSCCAL = 0xA9;

    unsigned char AT[] = "AT\r\n";
    unsigned char CIPMUX[] = "AT+CIPMUX=1\r\n";
    unsigned char CIPSTART[] =  "AT+CIPSTART=0,\"TCP\",\"api.thingspeak.com\",80\r\n";
    unsigned char CIPSEND[] = "AT+CIPSEND=0,110\r\n";
    unsigned char GET_DATA[] = "GET https://api.thingspeak.com/apps/thinghttp/send_request?api_key=xxxxxxxxxxxxxxxx\r\n";
    unsigned char SEND_DATA[] = "GET https://api.thingspeak.com/update?api_key=xxxxxxxxxxxxxxxxxxxxxxx=50\r\n";

    //_delay_ms(200);
    LCD_init(); // intitialize LCD
    usart_init(); // initialize usart
    _delay_ms(500);
    sei();

    _delay_ms(200);
    send_AT(AT);

    _delay_ms(2000);
    send_AT(CIPMUX);   

    _delay_ms(2000);
    send_AT(CIPSTART);

    while(1)
    {   

    }//while(1) close

}// main close

ISR(USART_RXC_vect)    // Every time an AT command is sent correctly type OK on the LCD (Logic analyzer works better though :-p)
{

     unsigned char a = 0;
    //LCD_data(a);

    a = UDR;

    if(a == 'O')
    {LCD_data('O');}
    if(a == 'K')
    {LCD_data('K');}
    if(a == 'd')
    {LCD_data('d');}
    if(a == 'L')
    {LCD_data('L');}

}
') { usart_send(message[i]); // This sends data to esp-01 i++; } int main(void) { //OSCCAL = 0xA9; unsigned char AT[] = "AT\r\n"; unsigned char CIPMUX[] = "AT+CIPMUX=1\r\n"; unsigned char CIPSTART[] = "AT+CIPSTART=0,\"TCP\",\"api.thingspeak.com\",80\r\n"; unsigned char CIPSEND[] = "AT+CIPSEND=0,110\r\n"; unsigned char GET_DATA[] = "GET https://api.thingspeak.com/apps/thinghttp/send_request?api_key=xxxxxxxxxxxxxxxx\r\n"; unsigned char SEND_DATA[] = "GET https://api.thingspeak.com/update?api_key=xxxxxxxxxxxxxxxxxxxxxxx=50\r\n"; //_delay_ms(200); LCD_init(); // intitialize LCD usart_init(); // initialize usart _delay_ms(500); sei(); _delay_ms(200); send_AT(AT); _delay_ms(2000); send_AT(CIPMUX); _delay_ms(2000); send_AT(CIPSTART); while(1) { }//while(1) close }// main close ISR(USART_RXC_vect) // Every time an AT command is sent correctly type OK on the LCD (Logic analyzer works better though :-p) { unsigned char a = 0; //LCD_data(a); a = UDR; if(a == 'O') {LCD_data('O');} if(a == 'K') {LCD_data('K');} if(a == 'd') {LCD_data('d');} if(a == 'L') {LCD_data('L');} }

    
pregunta Lefteris

3 respuestas

5

Resumen: sus síntomas se ajustan a los errores de sincronización de bits UART marginales. Use UBRRL = 0x67; en lugar de UBRRL = 0x68; para 9600 baudios (realmente bits por segundo) UART de un reloj de CPU de 16 MHz, según lo recomendado por Atmel.

Detalles: El hecho de que tanto su módulo ESP8266 como la propia decodificación UART de su analizador lógico, no logre decodificar correctamente parte de su salida UART ATmega32 de "9600 baudios", es una clara indicación de que El ATmega32 es la fuente probable del problema.

Luego, el hecho de que a veces hay una diferencia en la interpretación entre esos dos receptores (por ejemplo, el analizador lógico no descodifica '/ r' o '/ n' pero el ESP8266 acepta el comando y, por lo tanto, debe haber descodificado uno o ambos caracteres), muestra que el problema es marginal.

  

Por alguna razón, mega32 no puede transmitir con precisión todos los caracteres y no puedo entender por qué sucede esto.

Usted es correcto y está bien hecho para usar un analizador lógico. Si hubiera utilizado el analizador para obtener tiempos más precisos de cada bit, habría encontrado el problema. Es su velocidad de bits (velocidad en baudios) lo que es un poco incorrecto, porque ha utilizado:

UBRRL = 0x68;

En realidad, para un ATmega32 con reloj de 16 MHz, el valor correcto es:

UBRRL = 0x67;

La velocidad de datos incorrecta ligeramente es lo que afecta a los diferentes receptores UART de manera diferente (como se encontró a sí mismo).

Como dije, solo necesitaba avanzar un poco más al verificar los intervalos de bits (normalmente se usa un osciloscopio para esto, pero espero que su analizador lógico también muestre los intervalos de bits necesarios) y tenga la confianza de que estaba "en el camino correcto" con su análisis de los resultados observados, y estoy seguro de que usted mismo habría encontrado la respuesta :-)

Editado para agregar:

Vea el cálculo aquí: Stack Overflow : ¿Cuál es la función de los registros UBRRH y UBRRL en atmega32?

Consulte la Nota de la aplicación de Atmel AVR306: usando el AVR USART en dispositivos tinyAVR y megaAVR - La Tabla 3-5 en la página 7 muestra que el valor UBRR correcto para 9600 baudios con un reloj de 16MHz es 103 decimal = 0x67 . / p>     

respondido por el SamGibson
3

¡Problema resuelto! Había dos cosas que estaba haciendo mal.

Primero que todo utilicé UBRRL = 0x68 que estaba mal. Debe ser UBRRL = 0x67; Verifique la respuesta de Sam Gibson arriba (los enlaces también) .

Y segundo, ya que tuve que usar un convertidor de nivel de voltaje de 5v a 3.3v, usé un divisor de voltaje desde el pin Tx del mega32 al pin Rx del esp-01 (ya que es tolerante a 3.3v). Pero los valores de resistencia del divisor de voltaje que utilicé eran demasiado grandes (10k y 20k). Así que de acuerdo con la sugerencia de gbulmer anterior, cambié las resistencias a 2k y 4k. Y funcionó. Dado que el divisor de voltaje proporciona el mismo nivel de voltaje con ambos conjuntos de resistencias, lo único que cambia es la corriente que pasa al pin Rx del ESP-01. Debe tener algo que ver con la capacitancia de entrada del Rx del ESP8266.

Pero lo importante para mí aquí, que me gustaría compartir con ustedes, es el procedimiento de depuración y no el resultado, ya que esto le ayudará a encontrar el problema más rápido y con menos La frustración no solo por este proyecto, sino por cualquier proyecto que involucre Comunicación Serial.

Así que el procedimiento que utilicé es el siguiente

  1. Conecte el ESP-01 directamente al módulo USB a TTL (yo uso CP2102)
  2. Conéctelo a su PC y abra una aplicación de terminal (uso "Terminal")
  3. Vuelva a verificar la configuración de UART de la Terminal para que coincida con la configuración de ESP (velocidad en baudios, barras de parada, etc.)
  4. Marque tanto CR = CR + LF como + CR (en la parte inferior)
  5. Envíe los comandos AT que desee al ESP y espere una respuesta de ESP

Si todo se ha configurado correctamente, el ESP debe responder en consecuencia. ¡Lo que es bueno! No vayas más lejos hasta que esto funcione.

  1. Cree un programa de C simple como el de arriba con los mismos comandos AT que usó en la Terminal.
  2. Tenga mucho cuidado con los caracteres de escape como '\ r' '\ n' '\ "(verifique wiki-pedia) dentro de sus cadenas, de lo contrario el ESP responderá con un error.
  3. Conecte su osciloscopio o analizador lógico al Pin Tx del microcontrolador. (Prefiero el analizador lógico, ya que muestra los caracteres reales transmitidos).
  4. Si el analizador lógico muestra transmisión de caracteres dañados ...

9a. Verifique el valor UBRRL de uC e intente nuevamente. (Para 9600 baudrate UBRRL = 0x67 pero a veces UBRRL = 0x68 también funciona sin errores ...) 9b. Coloque pequeñas resistencias divisoras de voltaje para el pin Tx de la uC (1k y 2k estarían bien) e intente nuevamente. (Los valores grandes como 10k y 20k corromperán su transmisión con seguridad) 9c. Verifique la fuente de alimentación de ESP y el microcontrolador e intente nuevamente. (Las fluctuaciones de los voltajes de suministro (5v para uC y 3.3v para ESP) pueden dañar la transmisión)

  1. Si la transmisión aún está dañada, desconecte el ESP Rx y Tx del microcontrolador Tx y Rx.
  2. Conecte los pines Tx y Rx del microcontrolador al módulo USB a TTL y conéctese a la computadora
  3. Al mismo tiempo, conecte el analizador lógico a la Tx y Rx del microcontrolador.
  4. Inicie una transmisión con el microcontrolador y en la pestaña de recepción de la Terminal verá los datos entrantes del microcontrolador.
  5. Verifique si los datos / comandos recibidos son los mismos con los que escribió en su código C.
  6. Si los comandos recibidos están dañados, verifique su código, la configuración de UART del microcontrolador y del terminal e intente nuevamente.
  7. También verifique los caracteres recibidos con su analizador Logic. Ayuda mucho

Creo que el procedimiento anterior lo ayudará a comprender qué salió mal con sus transmisiones ESP-01 (si las hubiera).

Espero que esta publicación sea de utilidad.

    
respondido por el Lefteris
1

Hay un montón de posibles causas.

¿Está seguro de que el formato y la velocidad de los datos son compatibles?

¿Mega y ESP8266 utilizan el tamaño, paridad y bits de parada de mismo ? p.ej. 8 bits de datos, sin paridad, 1 bit de parada (o lo que sea). Ser diferente causaría un problema que podría verse afectado al imprimir caracteres adicionales.

¿Ha intentado escribir un programa simple para enviar datos desde uno, y el otro lo ha enviado de vuelta, lo que prueba todos los códigos de caracteres posibles? Comience con caracteres imprimibles, por ejemplo.

int buff[256];
int i = 0;
for (char c=' '; c<127; c++) {
  Serial.print(c);
  if (Serial.available()) {
     char inc = Serial.read();
     buff[inc] = i;
     i++;
   }
}
while (Serial.available()) {
   char inc = Serial.read();
   buff[inc] = i;
   i++;
}

ADVERTENCIA: no he compilado ni probado este código

Todos los códigos de caracteres deben pasar. Si eso está bien, entonces haga lo mismo con print(0x80|c); para probar caracteres imprimibles con un alto conjunto de bits, luego todos los códigos que incluirán códigos de control como \ r y \ n. La idea es detectar códigos que se corrompen o se "traguen" y descubrir un patrón.

Editar:
Puede excluir algunas posibilidades enviando los datos directamente a la mega o ejecutando un programa similar en el ESP8266. Este casi debe funcionar, pero si no lo hace, cambia los lugares para buscar.

    
respondido por el gbulmer

Lea otras preguntas en las etiquetas