Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблемы с UART
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Chupa
Доброго времени суток.

Битый день промучался с UART, пытаясь заставить его нормально работать. Методом тыка выяснил, что работает при скорости 14400 бод (пробовал также 9600 и 19200). Но имеется несколько проблем, которые так побороть и не удалось:
1) Отправляемые с ПК символы принимаются не все (с потерями).
2) Отправляемые с МК символы приходят на ПК в виде "ааа" (любые).
3) В каком виде приходят на МК символы неизвестно, но похоже тоже не те, что нужно.

В чем может быть причина? Код:

CODE
#define F_CPU 8000000L
#define LED1 0
#define LED2 1
#define LED_PORT PORTB
#define LED_DDR DDRB

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

ISR(USART_RX_vect)
{
switch(UDR)
{
case '1': LED_PORT |= 1<<LED2; break;
case '0': LED_PORT &= ~(1<<LED2); break;
default: break;
}
}

int main(void)
{
#define baudrate 14400L
#define bauddivider (F_CPU/(16*baudrate)-1)
#define HI(x) ((x)>>8)
#define LO(x) ((x) & 0xFF)

UBRRL = HI(bauddivider);
UBRRH = LO(bauddivider);
UCSRA = 0;
UCSRB = 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE;
UCSRC = 0<<UMSEL|1<<UCSZ0|1<<UCSZ1;

LED_DDR = 1<<LED1|1<<LED2;
LED_PORT = 0xFF;

sei();

while(1)
{
LED_PORT ^= 1<<LED1;
_delay_ms(1000);
}

return 0;
}


P.S. В качестве USB-UART использую программатор USBASP с прошивкой AVR-Doper, в качестве терминала - avrdebug.
_Артём_
Цитата(Chupa @ Sep 13 2012, 19:22) *
Код
    #define HI(x) ((x)>>8)
    #define LO(x) ((x) & 0xFF)

    UBRRL = HI(bauddivider);
    UBRRH = LO(bauddivider);


P.S. В качестве USB-UART использую программатор USBASP с прошивкой AVR-Doper, в качестве терминала - avrdebug.

Может так:
Код
    UBRRL = LO(bauddivider);
    UBRRH = HI(bauddivider);

?
Chupa
biggrin.gif В лучших традициях. Главное, видел, что в UBRR какая-то ерунда выставляется, но не догадался, что мог так перепутать. Все проблемы отпадают, работает на 19200 бод. Спасибо!
adel
День добрый, уважаемые форумчане,
Не хотел создавать отдельного топика, поэтому решил, что уместно написать сюда.
Начал изучать С++ (прочел книжку Лафоре и делал упражения в MS VC++ 6) и попытался применить его в AVR, начав с USART. В основном вся идея была взята с http://waterproofman.wordpress.com/2007/03...uart-c-example/ , изменений почти нет: т к аппаратный usart в ATmega8 в единственном экземпляре, переделал реализацию в синглтон, сделал этому классу абстрактоного предка, изменил пару методов. Отлаживал в Proteus, где было выявлено, что передача нескольких байт идет успешно а вот с приемом беда, и не могу понять почему (подозреваю что в реальном железе будет аналогично).

uart.h:
CODE

#if !defined _C_UART_H_
#define _C_UART_H_

#include <ioavr.h>
#include <intrinsics.h>
#include "C_IO.h"
#include "_string.h"

#define XTAL 8000000L
#define baudrate 9600L
#define bauddivider (XTAL/(16*baudrate)-1)

// синглтон класс UART.
class C_UART : public C_IO
{
private:
// Буфер данных для передачи.
char* pTxBuffer;
// Буфер принятых данных.
char* pRxBuffer;
// Счетчик и объем передаваемых данных.
// Когда они равны передатчик готов передавать следующие данные.
volatile unsigned int uiTxCounter;
volatile unsigned int uiTxSize;
// Счетчик и объем принимаемых данных.
// Когда равны приемник получил необходимый объем данных.
volatile unsigned int uiRxCounter;
volatile unsigned int uiRxSize;
// Конструктор и инициализация USART.
C_UART();
// чтобы нельзя было передавать как параметр функции.
C_UART(const C_UART&);
// для запрета присваивания одного объекта другому
C_UART& operator = (const C_UART&);
// Обработчики прерываний.
#pragma vector = USART_TXC_vect
__interrupt static void TxHandler(void);
#pragma vector = USART_RXC_vect
__interrupt static void RxHandler(void);

public:
// функция, с помощью которой осуществляется ВЕСЬ доступ
// к методам и данным класса.
// Пример синтаксиса вызова: C_UART::instance()->some_function();
static C_UART* Instance();
// Передача заданного и незаданного кол. байт.
bool Send(char* pBuffer, unsigned int uiSize);
bool Send(char* pBuffer);
// Прием заданного количества байт.
bool Receive(char* pBuffer, unsigned int uiSize);
};
#endif


uart.cpp:
CODE

#include "uart.h"

/***********************************МЕТОДЫ*************************************/
// Конструктор с инициализацией USART
C_UART::C_UART()
{
UBRRL = bauddivider & 0x00FF;
UBRRH = (bauddivider>>8)&0x00FF;
UCSRC = (1<<UCSZ1) | (1<<UCSZ0);
uiTxCounter = 0;
uiTxSize = 0;
uiRxCounter = 0;
uiRxSize = 0;
}

// благодаря static объект создается единственный
// раз при первом обращении к instance()
C_UART* C_UART::Instance()
{
static C_UART SingleUART;
return &SingleUART;
}

// Копирование в буфер данных с заданным числом байт, разрешение прерываний
// на передачу, копирование 0-го байта в UDR
bool C_UART::Send(char *pBuffer, unsigned int uiSize)
{
if(!uiSize || !pBuffer || uiTxSize) return false;
uiTxSize = uiSize;
pTxBuffer = pBuffer;
uiTxCounter = 1;
UCSRB |= (1<<TXEN) | (1<<TXCIE);
UDR = pTxBuffer[0];
while(uiTxSize); // ожидание готовности передачи всех данных
return true;
}

// Копирование в буфер данных, разрешение прерываний
// на передачу, копирование 0-го байта в UDR
bool C_UART::Send(char *pBuffer)
{
unsigned int uiSize = strlength(pBuffer);
return (Send(pBuffer,uiSize));
}

// Установка кол. принимаемых байт, адреса приемного буфера, разрешение
// прерываний на прием
bool C_UART::Receive(char *pBuffer, unsigned int uiSize)
{
if(!uiSize || !pBuffer || uiRxSize) return false;
uiRxSize = uiSize;
pBuffer = pRxBuffer;
*pRxBuffer = 0;
uiRxCounter = 0;
UCSRB |= (1<<RXEN) | (1<<RXCIE);
while(uiRxSize); // ожидание готовности приема заданного кол. байт
return true;
}

/******************************ОБРАБОТЧИКИ ПРЕРЫВАНИЙ**************************/
// Копирование в приемный буфер через статический указатель экземпляра принятых
// данных, при достижении требуемого кол. байт запрещение прерываний на прием и
// обнуление размера буфера
#pragma vector = USART_RXC_vect
__interrupt void C_UART::RxHandler(void)
{
C_UART::Instance()->pRxBuffer[C_UART::Instance()->uiRxCounter++] = UDR;
if(C_UART::Instance()->uiRxCounter == C_UART::Instance()->uiRxSize)
{
C_UART::Instance()->uiRxSize = 0;
UCSRB &= ~((1<<RXEN) | (1<<RXCIE));
}
}

// Копирование след. байт находящихся в буферепосле отправки 1-го, при
// достижении требуемого кол. передаваемых байт запрещение прерываний на
// передачу и обнуление размера буфера
#pragma vector = USART_TXC_vect
__interrupt void C_UART::TxHandler(void)
{
if(C_UART::Instance()->uiTxCounter == C_UART::Instance()->uiTxSize)
{
C_UART::Instance()->uiTxSize = 0;
UCSRB &= ~((1<<TXEN) | (1<<TXCIE));
}
else UDR = C_UART::Instance()->pTxBuffer[C_UART::Instance()->uiTxCounter++];
}



Буду очень рад, если подскажите в чем здесь может быть проблема, и как можно улучшить реализацию USART под AVR (возможно, уже есть типовая реализация класса, но я к сожалению нигде не нашел таковую, и было бы здорово если бы кто то ею поделился).
Попробую приложить сюда архив с проектом в EWAVR и Proteus.
Нажмите для просмотра прикрепленного файла
badik
Была у меня подобная проблема с PIC - это железо. На PC посылаю всё без проблем. Обратно - С PC на PIC каша. Это контроллер не успевает. В проге на PC после посылки каждого байта вставил задержку и всё пошло. Возможно так.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.