День добрый, уважаемые форумчане,
Не хотел создавать отдельного топика, поэтому решил, что уместно написать сюда.
Начал изучать С++ (прочел книжку Лафоре и делал упражения в 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.
Нажмите для просмотра прикрепленного файла