реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> UART и прерывания, передает назад не все
AnKing
сообщение Oct 21 2010, 00:00
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



не могу понять тут то ли строка записывается не до конца, то ли не до конца выводится

В гипертерминале ввожу (123-enter) подряд много раз
а в выводе получаю последовательно 1 потом после еще одного (123-enter) - 2, еще раз - 3 и пустая строка и так по кругу

Код
#include <avr\io.h>
#include <util\delay.h>
#include <stdlib.h>
#include <avr\interrupt.h>
//#include <stdio.h>  

char *StrToPrint; //указатель на строку которую будем выводить uart
char HelloWorld[]="Hello World";

//процедура отправки строки по UART////////
void u_send (char *str) {
    if (str==NULL) return;                    //проверяем не попался ли нам нулевой указатель, если попался то сразу выходим
    static char j=0;                         //счетчик
    if (*(str+j)!='\0'){                        //проверяем не достигнут ли конец строки
//    USART_Transmit('t');
//        UDR0=str[j];                            //отправляеме байт (так компилятор ругается почему то)
        UDR0=*(str+j);                        //то же самое тока компиляиор не ругается
        j++;                                //инкрементируем счетчик
    }
    else {
    UCSR0B&=~(_BV(UDRIE0));                    //запрещаем прерывание по опустошению регистра UDR
    j=0;                                    //сбрасываем счетчик;
    }
}
//////////////////////////////////////////

//////////////////////////////////////////

//процедура приема строки по UART с использованием прерываний////////
/*при первом вызове функции создаем указатель на char выделяем память под 1 символ,
ждем пока он не придет, когда пришел записываем его в выделенную память, если
есть еще символы то выделяем еще байт и так до тех пор пока все символы не кончатся.
При последуюющих вызовах функции сначала нужно очистить память которую выделяли в прошлый раз
для этого указатель str объявляли как static.

выход из функции происходит только когда придет символ '\r' или '\0'
*/
char * u_receive_int (void) {
static char * str=NULL;        //объявляем указатель на строку статическим что бы при повторных вызовах можно было очистить память
static int i=0;            //создаем счетчик
char temp;                    //временная переменная
if (i==0) {                //если i==0 то либо функция еще не вызывалась либо в прошлый раз строка закончилась и надо освободить память
    free(str);            //то освобождаем память
    str=NULL;            //сбрасываем указаель    
}
temp=UDR0;                     //Считываем принятый байт в temp
if ((temp!='\0')&&(temp!='\r')) {    //Если приянтый байт не равен '\r' или '\0' то:
    str=(char*) realloc(str, i+1);        //выделяем память под символы
    *(str+i)=temp;                    //записываем принятый байт в конец массива
    i++;                    //инкрементируем счетчик
    //PORTB=1<<1;
    return NULL;            //так так это еще не конец строки то возвращаем нулевой указатель
}
else {
    //PORTB=1<<2;
    *(str+i)='\0';                    //записываем '\0' в конец массива
    i=0;                             //обнуляем счетчик
    return str;                        // возвращаем указатель на область памяти, по которому можно обратиться к принятым данным
};

}

//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////


//Обработчик прерывания от UART, по завершению приема//////////
SIGNAL(SIG_USART_RECV){
    StrToPrint=u_receive_int();     //
}
//////////////////////////////////////////////////////////////


//Обработчик прерывания от UART, по опустошению UDR//////////
SIGNAL(SIG_USART_DATA){
PORTB=1<<2;
    u_send (StrToPrint);
}
//////////////////////////////////////////////////////////////*/



void USART_Init( unsigned int baud )
    {
    // Set baud rate
    //UCSRB|=_BV(RXCIE); //Разрешение прерывания по завершению приема
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    // Enable receiver and transmitter & interrupts
    UCSR0B = (1<<RXCIE0)|(1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0);
    // Set frame format: 8data, 1stop bit
    UCSR0C = (0<<USBS0)|(3<<UCSZ00);
    }


int main (void)
{
//char k='s';

DDRB=0x00;

USART_Init(47);

while(1){
    sei();

    //u_send(HelloWorld);
    if (StrToPrint){            //печатаем то на что указывает StrToPrint, если указатель нулевой, то ничего не напечатается
    u_send(StrToPrint);
    StrToPrint=NULL;                    //Если напечаталось, то сбрасываем указатель, что бы больш не печаталось
      }
    //printf("Hello, World");  //не работает
    _delay_ms(100);
}
}
Go to the top of the page
 
+Quote Post
XVR
сообщение Oct 21 2010, 08:51
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Использование malloc/free в AVR явно плохая идея, у него и так памяти не много. А уж использование realloc, да еще побайтно - вообще полный абзац (и не только на AVR).
Делайте статический кольцевой буфер и обмен с ним по прерываниям.

Разобраться в вашей программе практически невозможно cranky.gif
Go to the top of the page
 
+Quote Post
smalcom
сообщение Oct 21 2010, 08:55
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 292
Регистрация: 26-06-07
Пользователь №: 28 718



Цитата
static char j=0; //счетчик
if (*(str+j)!='\0'){

а цикл где?

реалок... вобщеим программа - бред полнейший, вытирай и пиши заново. только не так же
Go to the top of the page
 
+Quote Post
AnKing
сообщение Oct 21 2010, 16:12
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



Переписал по другому, теперь легче разобраться заюзал функции из libc
хотелось бы чтобы программа переходила к обработке stdin как только в нем возникнет переход на новую строку.
Но у меня почемуто ничего не происходит
вот код
Код
#include <avr\io.h>
#include <util\delay.h>
#include <stdlib.h>
//#include <avr\interrupt.h>
#include <stdio.h>
#include <string.h>

static int comm_flag=0;
static int uart_putchar(char c, FILE *stream);
static int uart_getchar(FILE *stream);

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
static FILE mystdin = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);

static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}

static int uart_getchar(FILE *stream)
{
  char c=' ';
  loop_until_bit_is_set(UCSR0A, RXC0);
  c=UDR0;
  if(c=='\r' || c=='\0' || c=='\n') comm_flag=1;
  return c;
}


void USART_Init( unsigned int baud )
    {
    // Set baud rate
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    // Enable receiver and transmitter & interrupts
    UCSR0B = (1<<RXCIE0)|(1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0);
    // Set frame format: 8data, 1stop bit
    UCSR0C = (0<<USBS0)|(3<<UCSZ00);
    }


int main (void)
{
char kk[20];
char * pch;
char func_f[]="comm";

DDRB=0x00;

USART_Init(47);
stdout = &mystdout;
stdin = &mystdin;
printf("\n>>command>>");

while(1){
    //kk=NULL;
    PORTB=0<<0;
    PORTB=0<<1;
    PORTB=0<<2;

    //printf("\nSystem Initialised\n");
    if(comm_flag==1){
        scanf("%s",kk);
        printf("\ncommand is - %s\n",kk);

        pch = strtok (kk,"_");
        while (pch != NULL)
        {
          printf ("%s\n",pch);
          if(strcmp(pch,func_f)==0){ printf("\nhello_COMM\n"); }
          pch = strtok (NULL, "_");
        }
    }
    _delay_ms(100);
    PORTB=1<<0;
    PORTB=1<<1;
    PORTB=1<<2;
    _delay_ms(100);
}
}

Кстати компилятор пишет что прога занимает 90% места в контроллере... фигасе... почему?
И моргает почемуто только третий диод.


Сообщение отредактировал AnKing - Oct 21 2010, 16:14
Go to the top of the page
 
+Quote Post
DpInRock
сообщение Oct 21 2010, 16:24
Сообщение #5


Гуру
******

Группа: Участник
Сообщений: 2 254
Регистрация: 4-05-07
Из: Moscow
Пользователь №: 27 515



Вы бы посмотрели какие-нибудь примеры для начала. НА сайте Атмела их море.
То, что вы пишите даже в мусорное ведро не залезет.


--------------------
On the road again (Canned Heat)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 21 2010, 16:25
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(AnKing @ Oct 21 2010, 19:12) *
прога занимает 90% места в контроллере... фигасе... почему?
scanf, printf. Вероятно из-за них. Тип контроллера вы не указали...


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AnKing
сообщение Oct 21 2010, 17:03
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



Цитата(DpInRock @ Oct 21 2010, 20:24) *
Вы бы посмотрели какие-нибудь примеры для начала. НА сайте Атмела их море.
То, что вы пишите даже в мусорное ведро не залезет.

Злой вы... нет чтобы ссылочку дать...
А что в ведро не лезет и сам понял...
И где то мора? В апноутах там все под иар заточено что касается уарта... а где примеров на аврстудию набрать?

Сообщение отредактировал AnKing - Oct 21 2010, 17:25
Go to the top of the page
 
+Quote Post
Danis
сообщение Oct 21 2010, 17:33
Сообщение #8


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(XVR @ Oct 21 2010, 11:51) *
Использование malloc/free в AVR явно плохая идея, у него и так памяти не много. А уж использование realloc, да еще побайтно - вообще полный абзац (и не только на AVR).
Делайте статический кольцевой буфер и обмен с ним по прерываниям.
Разобраться в вашей программе практически невозможно cranky.gif


Согласен полностью, это микроконтроллер а не ПК, хотя и на Си пишите, динамическое распределение памяти в МК с малым ОЗУ является потенциальным источником ошибок. Если с кольцевым буфером имеются затруднения, используйте простые с фиксированным размером.

Сообщение отредактировал Danis - Oct 21 2010, 17:37


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
XVR
сообщение Oct 21 2010, 18:48
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата
Но у меня почемуто ничего не происходит
Что бы что то происходило из stdin надо что то прочесть, а у вас ничего не читается
Может scanf и попробует что то прочесть, но для этого на него должно попасть управление, а для этого comm_flag должен стать 1, а для этого надо попасть в uart_getchar, а для этого надо что нибудь прочесть, а для этого надо выполнить scanf, а для ... Ну и т.д.
Go to the top of the page
 
+Quote Post
AnKing
сообщение Oct 21 2010, 19:05
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



Цитата(Danis @ Oct 21 2010, 21:33) *
Согласен полностью, это микроконтроллер а не ПК, хотя и на Си пишите, динамическое распределение памяти в МК с малым ОЗУ является потенциальным источником ошибок. Если с кольцевым буфером имеются затруднения, используйте простые с фиксированным размером.

А можно примерчик кольцевого буфера для usart на avr студии?
попробовал для простоты переписать прогу так, начал с совсем простого, но прерывание не работает

Код
#include <avr/io.h>
#include <avr/interrupt.h>

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

void USART_Init( unsigned int baud )
    {
    // Set baud rate
    UBRR0H = (unsigned char)(baud>>8);
    UBRR0L = (unsigned char)baud;
    // Enable receiver and transmitter & interrupts
    UCSR0B = (1<<RXCIE0)|(1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0);
    // Set frame format: 8data, 1stop bit
    UCSR0C = (0<<USBS0)|(3<<UCSZ00);
    }

int main (void)
{
    
USART_Init(BAUD_PRESCALE);
sei();

   for(;;) // Loop forever
   {
    /*  while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR
      ReceivedByte = UDR0; // Fetch the recieved byte value into the variable "ByteReceived"

      while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
      UDR0 = ReceivedByte; // Echo back the received byte back to the computer*/
   }  
}
ISR(USART_RX_vect)
{
   char ReceivedByte;
   ReceivedByte = UDR0; // Fetch the recieved byte value into the variable "ByteReceived"
   UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}

Забыл написть - Мега48 на плате STK48
добавил в бесконечный цикл мигание диодом
если закомментироваль глобальное разрешение прерываний - мигает, если нет то нет

Сообщение отредактировал AnKing - Oct 21 2010, 19:58
Go to the top of the page
 
+Quote Post
AnKing
сообщение Oct 21 2010, 20:17
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



Разобрался почему не работало... Было включено прерывание (1<<UDRIE0) о пустом буфере.
Следовательно вопрос прерывание работает всегда даже если у меня нет для него функции?
И как можно отменить отдельное прерывание далее по программе? (UCSR0B&=~(_BV(UDRIE0)); - вот это что-то не работает)
как можно обратиться к отдельному биту в регистре не похерив все остальные?
И так что там по поводу кольцевого буфера, может подкинет кто примерчик пожалста

Сообщение отредактировал AnKing - Oct 21 2010, 20:38
Go to the top of the page
 
+Quote Post
Danis
сообщение Oct 22 2010, 04:04
Сообщение #12


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(AnKing @ Oct 21 2010, 23:17) *
как можно обратиться к отдельному биту в регистре не похерив все остальные?


На Си - это поразрядные опрерации &(Поразрядное И) , | (паразрядное ИЛИ) ,
а вообще если это регистр можно и установить отдельно бит, ели по pdf на это бит регистра разрешена запись.

cbi $12. 7 ; Очистить бит 7 в Порте D это на ассемблере для AVR, вот еще поизучайте системму команд обязательно:
http://www.gaw.ru/html.cgi/txt/doc/micros/avr/asm/start.htm


Цитата(AnKing @ Oct 21 2010, 23:17) *
И так что там по поводу кольцевого буфера, может подкинет кто примерчик пожалста



Даю 100% рабочий кусок кода, но Вам его нужно будет подкорректировать, т.к он
написан для PIC24 с использованием компилятора C30, но это будет вам полезно, самому тоже поразбираться, что и как, не помешает.

Наилучшие пожелания!



// ---- Колцевая очередь ------------------------------
struct Line{
WORD size_line;
WORD Rx_Ptr;
WORD Tx_Ptr;
WORD num_element;
BYTE *ptr_buff ;
};


// --------- Структуры для данных UART1_Rx ----------
struct Line Rx1_Line;
struct Line* Ptr_Rx_line1;
BYTE RX_UART1_buff[64];


// ------ Инициализация очереди ----------------------
void Rx1_Line_init(void)
{
// Очищение очереди
memset( &Rx1_Line, 0, sizeof(Rx1_Line) ) ;
// Размер очереди
Rx1_Line.size_line = sizeof(RX_UART1_buff);
// Очищение буфера
memset( &RX_UART1_buff[0],0,sizeof(RX_UART1_buff) );
// настройка Указателя очереди на буфер
Rx1_Line.ptr_buff = &RX_UART1_buff[0];
// настройка Указателя на очередь
Ptr_Rx_line1 = &Rx1_Line ;
}
//****************************************************


// ---------- Обработчик прерывания UART_RX1 (С30) -----------------------------------------------------
void __attribute__((__interrupt__, no_auto_psv)) _AltU1RXInterrupt(void) - Тут замените на свой код
{
BYTE TEMP;
IEC0bits.U1RXIE = 0; // UART1 Receiver Interrupt Enable bit (1 = Interrupt request enabled)
while(U1STAbits.URXDA != 0) // Пока есть, что вычитать а аппаратного буфера UART Rx
{
TEMP = U1RXREG;
set_Line_element(Ptr_Rx_line1, TEMP);
}
IFS0bits.U1RXIF = 0; // сбросил флаг прерывания
IEC0bits.U1RXIE = 1; // UART1 Receiver Interrupt Enable bit (1 = Interrupt request enabled)
}
//********************************************************************************
****



// -------Функция получает указатель на очередь и байт ------------------------------------
// --- который записывается в эту очередь -----------------------------------------------------
void set_Line_element(struct Line *Ptr, BYTE data)
{
IEC1bits.U2RXIE = 0; // UART2 Receiver Interrupt Enable bit (1 = Interrupt request enabled) - Тут замените на свой код (Запрет прерываний по UART Rx)

Ptr -> ptr_buff[Ptr -> Rx_Ptr] = data;

Ptr -> Rx_Ptr++;
Ptr -> num_element++;

if ( Ptr -> num_element >= Ptr -> size_line)
Ptr -> num_element = Ptr -> size_line;

Ptr -> Rx_Ptr = (Ptr -> Rx_Ptr % Ptr -> size_line);

IEC1bits.U2RXIE = 1; // UART2 Receiver Interrupt Enable bit (1 = Interrupt request enabled) - Тут замените на свой код (Разрешение прерываний по UART Rx)
}
//********************************************************************************
************

Сообщение отредактировал Danis - Oct 22 2010, 04:41


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
AnKing
сообщение Oct 22 2010, 07:24
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 56
Регистрация: 2-02-08
Пользователь №: 34 686



Вам это может показаться элементарным но все же
_delay_ms(100);
PORTB|=(1<<0);
PORTB|=(0<<1);
PORTB|=(1<<2);
_delay_ms(100);
PORTB&=(0<<0);
PORTB&=(1<<1);
PORTB&=(0<<2);

Средний светодиод при таком раскладе не моргает? почему?
в первом случае использую или но если использую или и во втором то не моргают все?
так в чем разница между и и или при обращении к регистрам?
что за символ такой "<<"и чем он отличается от ">>" и где их применять?

прочитал про побитовые операции но там нигде нет очевидных примеров про регистра и все на асме

PS отличный пример про кольцевой массив... буду пробовать заюзать
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 22 2010, 07:56
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(AnKing @ Oct 22 2010, 11:24) *
Средний светодиод при таком раскладе не моргает? почему?

Чтобы установить в единицу N-ый бит регистра PORTB нужно записать:
PORTB|=(1<<N);
Чтобы сбросить в ноль N-ый бит:
PORTB&=~(1<<N);
Символы ">>" и "<<" - операция сдвига вправо/влево (учите язык С).
Go to the top of the page
 
+Quote Post
Danis
сообщение Oct 22 2010, 08:36
Сообщение #15


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(Палыч @ Oct 22 2010, 10:56) *
Символы ">>" и "<<" - операция сдвига вправо/влево (учите язык С).


AnKing имейте ввиду, что это никак не кольцевой сдвиг,
а битовый сдвиг с припиской нулей справа или слева.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 18:14
Рейтинг@Mail.ru


Страница сгенерированна за 0.01509 секунд с 7
ELECTRONIX ©2004-2016