Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: atmega168 uart и прерывания
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Vooze
День добрый!

Делаю преобразователь/переходник с сигналов RC-аппаратуры (7-ми канальный HiTec) в цифру, с выходом на UART.
МК - atmega168, тактирую от встроенных 8мГц.
RC-приемник формирует на выходе стандартные серво-PWM сигналы, последовательно по каналам.
Первый канал повесил на INT0, остальные на порт С. Данные собираю по таймеру0.
Эта часть проги работает.

Проблема возникла, когда данные решил отправить в UART.
Передаются первые 2-3 байта и все. передача вырубается.
Код писал в CVAVR 2.05, пользовался его же визардом.
думал, что как-то все не успевает и подвисает, в итоге сократил прогу до обычного присваивания в массив чисел.
результат не изменился, выводятся в порт только 3 байта и все.
убирая буферы в UART выводится вообще полная ахинея, но передача не прерывается.
С последовательным портом в таком виде работаю впервые, поэтому прошу помощи. Гугл должных результатов не подсказал.

код:
CODE
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 16.07.2013
Author : NeVaDa
Company :
Comments:


Chip type : ATmega168V
Program type : Application
AVR Core Clock frequency: 8,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega168.h>
#include <stdio.h>
#include <delay.h>



#ifndef RXB8
#define RXB8 1
#endif

#ifndef TXB8
#define TXB8 0
#endif

#ifndef UPE
#define UPE 2
#endif

#ifndef DOR
#define DOR 3
#endif

#ifndef FE
#define FE 4
#endif

#ifndef UDRE
#define UDRE 5
#endif

#ifndef RXC
#define RXC 7
#endif

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)


#define MAX_PPM_CHANNELS 7
#define CH1 PIND.2
#define CH2 PINC.5
#define CH3 PINC.4
#define CH4 PINC.3
#define CH5 PINC.2
#define CH6 PINC.1
#define CH7 PINC.0

unsigned int counter;
unsigned int Channel[MAX_PPM_CHANNELS],ChannelTX[MAX_PPM_CHANNELS];
unsigned char uart_r,flag,start_ppm,end_ppm,n_chan,lo_b,hi_b,tmp;




// USART Receiver buffer
#define RX_BUFFER_SIZE0 50
char rx_buffer0[RX_BUFFER_SIZE0];

#if RX_BUFFER_SIZE0 <= 256
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
#else
unsigned int rx_wr_index0,rx_rd_index0,rx_counter0;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow0;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_wr_index0++]=data;
#if RX_BUFFER_SIZE0 == 256
// special case for receiver buffer size=256
if (++rx_counter0 == 0)
{
#else
if (rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
#endif
rx_buffer_overflow0=1;
}
}
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0[rx_rd_index0++];
#if RX_BUFFER_SIZE0 != 256
if (rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#endif
#asm("cli")
--rx_counter0;
#asm("sei")
return data;
}
#pragma used-
#endif

// USART Transmitter buffer
#define TX_BUFFER_SIZE0 50
char tx_buffer0[TX_BUFFER_SIZE0];

#if TX_BUFFER_SIZE0 <= 256
unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
#else
unsigned int tx_wr_index0,tx_rd_index0,tx_counter0;
#endif

// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter0)
{
--tx_counter0;
UDR0=tx_buffer0[tx_rd_index0++];
#if TX_BUFFER_SIZE0 != 256
if (tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
#endif
}
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm("cli")
if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
{
tx_buffer0[tx_wr_index0++]=c;
#if TX_BUFFER_SIZE0 != 256
if (tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
#endif
++tx_counter0;
}
else
UDR0=c;
#asm("sei")
}
#pragma used-
#endif



// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
start_ppm=1;counter=0;n_chan=0;
PORTB.0=!PORTB.0;
}


// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0xFE;

ChannelTX[0]=0x3031;
ChannelTX[1]=0x3233;
ChannelTX[2]=0x3435;
ChannelTX[3]=0x3637;
ChannelTX[4]=0x3839;
ChannelTX[5]=0x3A3B;
ChannelTX[6]=0x3C3D;
PORTB.1=!PORTB.1;

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=P State5=P State4=P State3=P State2=P State1=P State0=P
PORTC=0x7F;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=P State6=P State5=P State4=P State3=P State2=P State1=P State0=P
PORTD=0xFF;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x02;
TCNT0=0xFE;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x03;
EIMSK=0x01;
EIFR=0x01;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;

// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 19200
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x19;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR1=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

// Global enable interrupts
#asm("sei")

while (1)
{
for (tmp=0;tmp<=6;tmp++)
{
lo_b=(unsigned char) ChannelTX[tmp];
hi_b=(unsigned char) (ChannelTX[tmp]>>8);
putchar(hi_b);
putchar(lo_b);
putchar('!');
}
}
}


Если в основном цикле запрещать таймер0, то все выводится правильно.
что может таймер делать с буфером, если даже когда обработчик пустой, то буфер виснет.

Код
    TIMSK0=0x00;
    for (tmp=0;tmp<=6;tmp++)
        {
        lo_b=(unsigned char) ChannelTX[tmp];
        hi_b=(unsigned char) (ChannelTX[tmp]>>8);
        putchar(hi_b);
        putchar(lo_b);
        putchar('!');
        };
    putchar(0x0A);
    putchar(0x0D);
    TIMSK0=0x01;
artkam
Я правильно понимаю, по задумке Timer0 у Вас с частотой 100кГц переполняется?????
Vooze
Совершенно верно, с этой частотой я измеряю ШИМ из приемника.

Такой точности мне вполне хватит.
Подумываю уже о том, чтобы сделать последовательно и без таймера замерять шим на выходах, а потом отправлять данные, и затем ждать начала новой посылки сигналов.
artkam
С частотой таймера Вы как-то уж слишком замахнулись.
RabidRabbit
Да уж, с таким обработчиком частота вызова перываний таймера 500 кГц? За один период - 16 тактов для процессора, даже Ваш обработчик выполниться поди не успеет sm.gif
Vooze
Да, именно в этом и была проблема. На пустом обработчике прерываний только и успевал МК не накосячить с uart'ом. Я решил проблему тем, что, сначала замеряю ШИМ по каналам, и в перерыве между сериями отправляю данные.
777777
А хорошо ли это - пользоваться встроенным RC-генератором для тактирования UART-а?
RabidRabbit
Цитата(777777 @ Jul 31 2013, 15:28) *
А хорошо ли это - пользоваться встроенным RC-генератором для тактирования UART-а?
А это, по-моему, каждый решает в соответствиями с требованиями по точности скорости того самого UART'а sm.gif
Vooze
Чтобы не плодить темы, задам вопрос здесь.

Есть мега644. Нужно организовать два UART'а.
Все было бы нормально, но второй uart не заводится вообще.

Код
// USART0 initialization
// USART0 Baud Rate: 115200
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x0A;

// USART1 initialization
// USART1 Baud Rate: 115200
UCSR1A=0x00;
UCSR1B=0xD8;
UCSR1C=0x06;
UBRR1H=0x00;
UBRR1L=0x0A;


while (1)
      {
    while(!(UCSR0A & (1<<UDRE0))); UDR0 = 0b10100011;
    while(!(UCSR1A & (1<<UDRE1))); UDR1 = 0b10100101;    
      }


из UART0 все отсылается как часы, а UART1 молчит вообще (мониторю осциллографом).
бьюсь над этим уже пару дней, и с портами шаманствовал на вход/выход/подтяжки, и контроллер менял,
результата нет.

Уважаемые Гуру, посоветуйте пожалуйста, в какую сторону копать-то.


artkam
The ATmega644 has one USART, USART0.

Выдрано слово в слово из даташита... Предлагаю копать в сторону другого контроллера ))
Vooze
Как так, вот из моего даташита
Цитата
19.2 USART1 and USART0
The ATmega164A/164PA/324A/324PA/644A/644PA/1284/1284P has two USART’s, USART0
and USART1.


Хм, понял, не уточнил. у меня atmega644P


И, благодаря Вашему замечанию, есть мысли что попались в партии либо брак, либо ошибка маркировки. Хотя на атмел такое не мог подумать.
ILYAUL
Код
UCSR0B=0xD8

У Вас работают сразу 2 прерывания , причем одно из них похоже Вам совсем не нужно т.к. приемник даже не включён
Отключите 0-ой скорее всего будет работать и 1-ый
И научитесь писать без всяких HEX и BIN
Vooze
проблема решилась заменой контроллера. походу брак.
Цитата
И научитесь писать без всяких HEX и BIN

мне так, как-то удобнее. Это еще со времен z80. BIN в HEX "в уме" раскладывается.
ILYAUL
Я имел ввиду вот так, как пример

Код
DDRB = (1<<PB7)|(1<<PB6)|(0<<PB5)|(1<<PB4)|(0<<PB3)|(1<<PB2)|(1<<PB1)|(1<<PB0)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.