ATtiny441 и UART. Не могу разобраться

Тема в разделе "Микроконтроллеры AVR", создана пользователем Deniska407, 3 июл 2019.

  1. Deniska407

    Deniska407 Нуб

    Коллеги, помогите!

    Появилось у меня хобби - начал с Ардуино UNO и теперь дорос до контроллера ATtiny441 + Atmel Studio 7. Играюсь с домашне-дачной автоматизацией ...

    Задача очень простая: удаленно посылая телеграммы по RS-485 (протокол ModBus RTU) управлять с компьютера периферией и отвечать компьютеру о своем состоянии. Начал писать код:

    Код:
    Код (C++):
    #define F_CPU 1000000UL
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>

    #define BUFFER_SIZE 128
    #define StartTransmit_SET_OUTPUT  DDRA  |=  (1 << 0)
    #define StartTransmit_LOW  PORTA |=  (1 << 0)
    #define StartTransmit_HIGH  PORTA &= ~(1 << 0)

    #define LED_SET_OUTPUT  DDRA  |=  (1 << 4)
    #define LED_LOW  PORTA |=  (1 << 4)
    #define LED_HIGH  PORTA &= ~(1 << 4)

    volatile unsigned char slaveID = 50;
    unsigned char frame[BUFFER_SIZE];
    unsigned char funktion=1;
    bool broadcastFlag=0;

    void USART_Init()
    {
        UBRR0H = 0;
        UBRR0L = 6;
        UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
        UCSR0C = (1<<USBS0)|(3<<UCSZ00);
    }

    unsigned int calculateCRC(uint8_t bufferSize)
    {
        unsigned int temp, temp2, flag;
        temp = 0xFFFF;
        for (unsigned char i = 0; i < bufferSize; i++)
        {
            temp = temp ^ frame[i];
            for (unsigned char j = 1; j <= 8; j++)
            {
                flag = temp & 0x0001;
                temp >>= 1;
                if (flag)
                temp ^= 0xA001;
            }
        }
        temp2 = temp >> 8;
        temp = (temp << 8) | temp2;
        temp &= 0xFFFF;
        return temp;
    }

    void USART_Transmit( unsigned char data )
    {
        StartTransmit_LOW;
            _delay_ms(5);
                while ( !( UCSR0A & (1<<UDRE0)) );
                UDR0 = data;
            _delay_ms(5);
        StartTransmit_HIGH;
        _delay_ms(5);
    }

    void USART_Transmit_String()
    {
        int i=0;
        unsigned char c = frame[0];
                while(c != '\0')
                    {
                        c = frame[i];
                            if(c!='\0') {USART_Transmit(c);}
                        i++;
                    }
    }

    void exceptionResponse(unsigned char exception)
    {
        if (!broadcastFlag)
        {
            frame[0] = slaveID;
            frame[1] = (funktion | 0x80);
            frame[2] = exception;
            unsigned int crc16 = calculateCRC(3);
            frame[3] = crc16 >> 8;
            frame[4] = crc16 & 0xFF;
            USART_Transmit_String();
        }
    }

    ISR (USART0_RX_vect)
    {
            while ( !(UCSR0A & (1<<RXC0)) );
            slaveID = UDR0;
    }

    int main(void)
    {
        USART_Init();
        StartTransmit_SET_OUTPUT;
        LED_SET_OUTPUT;
        LED_LOW;

        sei();
        while(1)
        {
                    exceptionResponse(2);
                    _delay_ms(5000);          
        }
    }
    и столкнулся со следующей хренью: вбиваю в Terminal Window (встроенный терминал в Atmel Studio 7) число 33 - по указанному выше алгоритму если в буфере что то появилось, то переменная slaveID становится этим. Но она этим становится в хаотичном порядке: может так: 33 81 02 60 5e - и это правильно, она 33, а может так: b3 81 02 61 b6 - это когда первый бит у тройки заменен на 1. Причем непонятно с чем это связано. Вроде вбиваю в поле Send терминала 33, все честно, но результат на выходе ИЛИ-ИЛИ. Нет стабильности. Например та же хрень при вводе 54: 5 раз d4 81 02 d0 69, три раза 54 81 02 d1 81 Для приема в терминал использую китайский переходник с UART на RS-485 и переходник - RS-485 - USB. Если есть у кого какие мысли - помогите, пожалуйста, разобраться.

    Спасибо!
     
  2. parovoZZ

    parovoZZ Гуру

    Скорость на UART какая и от чего тактируется МК?
     
  3. Deniska407

    Deniska407 Нуб

    Скорость UART 9600, контроллер тактируется от внутреннего осциллятора, частота 1 МГц.
     
  4. parovoZZ

    parovoZZ Гуру

    ну так вот и ответ
    вешай внешний кварц или снижай скорость ниже 1200.
     
  5. Deniska407

    Deniska407 Нуб

    ... если бы сыпался мусор, то да, я полностью согласен! но! либо 33, либо b3. то есть 1 бит либо 1 (что не правильно) либо (что правильно) 0. Меняется хаотично при приеме только 1 бит .......
     
  6. Daniil

    Daniil Гуру

    Вы не путаете симптомы разных baudrate-ов и расстройки тактирующего генератора?
     
  7. parovoZZ

    parovoZZ Гуру

    Пока не избавишься от высокого джиттера, дальнейшее обсуждение проблемы бесполезно.
     
  8. Deniska407

    Deniska407 Нуб

    Решено!

    правильно инициализировать UART в моем случае вот так:

    Код (C++):

    void USART_Init()
    {
    UBRR0H = 0;
    UBRR0L = 12;

    UCSR0A = (1 << U2X0);

    UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
    }
     
    Ошибок больше не ловил!

    Спасибо!