Вот решил выложить свои мучения по данной теме.
Может кому нибудь пригодится. В инете так и толком ничего не нашел.
Алгоритм следующий:
Ногу PD0 и PD2 нужно замкнуть.
1) Устанавливаем внешнее прерывание (INT0) на захват спадающего фронта.
2) Прерывание произошло, устанавливаем внешнее прерывание (INT0) на захват восходящего фронта,
устанавливаем счетчик Timer1 на отсчет времени.
3)Прерывание произошло, останавливаем таймер, запрещаем внешнее прерывание.
4)Подсчитываем битрайт, и задерживаемся(delay_us()) до конца данного байта.
5)Настраиваем скорость усарта и принимаем данные.
Испытания проводил на Mega8, 16Mhz, на скоростях от 9600-210000.
Главные условия, чтобы младший бит первого байта посылки был равен 1.
Прием начинается со 2-го байта. Грубо говоря 1-й байт нужен для синхронизации.
Также реулизована возможность засыпания процессора. Если это не нужно, просто закомментируйте
#define SLEEP.
В принципе пока все устраивает, просто хотел узнать Ваше мнение.
Вопрос:
Теоретически после того как определили битрайт(это в конце старт-бита) нужно
сделать delay_us() равный: 1bit time*8(до начала стоп бита), а уже потом
устанавливать битрайт. Но вреальности принимается ерунда.
Но если написать следущее:
Код
for(n=0; n < (char)baudrate-1; n++) delay_us(1);//Ничего не делаем до начала следующего байта
for(n=0; n < (char)baudrate-1; n++) delay_us(1);
for(n=0; n < (char)baudrate-1; n++) delay_us(1);
То все работает.
Эта задержка примерно равна 2-м битам.
Мне так кажется что пока я дохожу до этого момента, проходит время равное 6-ти битам.
Вот сам код:
Код
#include <ioavr.h>
#include <inavr.h>
#include "USART.h"
//********************************************************************************
**********
#define SLEEP
unsigned static char state;
unsigned int baudrate;
#pragma vector = INT0_vect
__interrupt void OnCapt()
{
if(0==state)//Перехват падения фронта
{
state = 1;
MCUCR |= (1<<ISC01) | (1<<ISC00); //Установка прерывания по восходящему фронту
TCNT1H=0;//Обнуляем таймер
TCNT1L=0;
TCCR1B|=(0<<CS12) |(0<<CS11) | (1<<CS10);//Запускем таймер 1 без делителя
}
else if(state==1)//Перехват подъема фронта
{
state = 2;
baudrate = TCNT1L;
baudrate |= (int)TCNT1H<<8;
TCCR1B&=~((0<<CS12) |(0<<CS11) | (1<<CS10));//Запрещяем таймер
MCUCR &= ~((1<<ISC01) | (1<<ISC00));//Запрещяем захват по фронту
GICR &= ~(1<<INT0);//Запрещаем прерывание по захвату
}
}
unsigned int Usart_autobaud(void)
{
unsigned char n;
state=0;
MCUCR |= (1<<ISC01) | (0<<ISC00); //Установка прерывания по спадающему фронту
GICR |= (1<<INT0); //Разрешение прерывания
#ifdef SLEEP
MCUCR |= (1<<SE); //Разрешаем режим сна до первого внешнего прерывания
asm("sleep");
MCUCR &= ~(1<<SE); //Запрещаем режим сна до первого внешнего прерывания
#endif
while(state != 2); //Ждем окончание старт бита(восходящий фронт)
//Определяем битрайт
baudrate = (baudrate>>3)-1; //baudrate=(baudrate/8)-1
for(n=0; n < (char)baudrate-1; n++) delay_us(1);//Ничего не делаем до начала следующего байта
for(n=0; n < (char)baudrate-1; n++) delay_us(1);
return baudrate;
}
//********************************************************************************
**********
void main( void )
{
DDRD = 0x00;
PORTD = 0x00;
DDRB = 0x00;
PORTB = 0x00;
DDRC = 0x00;
PORTC = 0x00;
#ifdef SLEEP
MCUCR |= (0<<SM2)|(0<<SM1)|(0<<SM0);//Режим сна Idle
#endif
USART0_init();//Инициализируем уарт
__enable_interrupt();
delay_s(1);
while(1)
{
USART0_set_speed(Usart_autobaud()); //Определяем битрайт и устанавливаем скорость
UCSRB |= (1 << RXCIE)| (1 << RXEN); //Разрешаем прием и прерывание усарта
while(!USARTBuffSize); //Ждем конца приема данных
UCSRB &= ~((1 << RXCIE) | (1 << RXEN)); //Запрещаем прием и прерывание усарта
USART_SEND_STR(UsartBuff, USARTBuffSize+1);
USARTBuffSize = 0;
}
}
#include <inavr.h>
#include "USART.h"
//********************************************************************************
**********
#define SLEEP
unsigned static char state;
unsigned int baudrate;
#pragma vector = INT0_vect
__interrupt void OnCapt()
{
if(0==state)//Перехват падения фронта
{
state = 1;
MCUCR |= (1<<ISC01) | (1<<ISC00); //Установка прерывания по восходящему фронту
TCNT1H=0;//Обнуляем таймер
TCNT1L=0;
TCCR1B|=(0<<CS12) |(0<<CS11) | (1<<CS10);//Запускем таймер 1 без делителя
}
else if(state==1)//Перехват подъема фронта
{
state = 2;
baudrate = TCNT1L;
baudrate |= (int)TCNT1H<<8;
TCCR1B&=~((0<<CS12) |(0<<CS11) | (1<<CS10));//Запрещяем таймер
MCUCR &= ~((1<<ISC01) | (1<<ISC00));//Запрещяем захват по фронту
GICR &= ~(1<<INT0);//Запрещаем прерывание по захвату
}
}
unsigned int Usart_autobaud(void)
{
unsigned char n;
state=0;
MCUCR |= (1<<ISC01) | (0<<ISC00); //Установка прерывания по спадающему фронту
GICR |= (1<<INT0); //Разрешение прерывания
#ifdef SLEEP
MCUCR |= (1<<SE); //Разрешаем режим сна до первого внешнего прерывания
asm("sleep");
MCUCR &= ~(1<<SE); //Запрещаем режим сна до первого внешнего прерывания
#endif
while(state != 2); //Ждем окончание старт бита(восходящий фронт)
//Определяем битрайт
baudrate = (baudrate>>3)-1; //baudrate=(baudrate/8)-1
for(n=0; n < (char)baudrate-1; n++) delay_us(1);//Ничего не делаем до начала следующего байта
for(n=0; n < (char)baudrate-1; n++) delay_us(1);
return baudrate;
}
//********************************************************************************
**********
void main( void )
{
DDRD = 0x00;
PORTD = 0x00;
DDRB = 0x00;
PORTB = 0x00;
DDRC = 0x00;
PORTC = 0x00;
#ifdef SLEEP
MCUCR |= (0<<SM2)|(0<<SM1)|(0<<SM0);//Режим сна Idle
#endif
USART0_init();//Инициализируем уарт
__enable_interrupt();
delay_s(1);
while(1)
{
USART0_set_speed(Usart_autobaud()); //Определяем битрайт и устанавливаем скорость
UCSRB |= (1 << RXCIE)| (1 << RXEN); //Разрешаем прием и прерывание усарта
while(!USARTBuffSize); //Ждем конца приема данных
UCSRB &= ~((1 << RXCIE) | (1 << RXEN)); //Запрещаем прием и прерывание усарта
USART_SEND_STR(UsartBuff, USARTBuffSize+1);
USARTBuffSize = 0;
}
}
И еще вопрос.
В даташите написано, что пробуждение от сна по внешнему прерыванию разрешено во всех режимах.
Но у меня прерывание происходит только в режиме сна Idle.
Что я делаю не так ?