|
UART и прерывания, передает назад не все |
|
|
|
Oct 21 2010, 00:00
|
Участник

Группа: Участник
Сообщений: 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); } }
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 21)
|
Oct 21 2010, 16:12
|
Участник

Группа: Участник
Сообщений: 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
|
|
|
|
|
Oct 21 2010, 17:03
|
Участник

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

|
Цитата(DpInRock @ Oct 21 2010, 20:24)  Вы бы посмотрели какие-нибудь примеры для начала. НА сайте Атмела их море. То, что вы пишите даже в мусорное ведро не залезет. Злой вы... нет чтобы ссылочку дать... А что в ведро не лезет и сам понял... И где то мора? В апноутах там все под иар заточено что касается уарта... а где примеров на аврстудию набрать?
Сообщение отредактировал AnKing - Oct 21 2010, 17:25
|
|
|
|
|
Oct 21 2010, 17:33
|

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

|
Цитата(XVR @ Oct 21 2010, 11:51)  Использование malloc/free в AVR явно плохая идея, у него и так памяти не много. А уж использование realloc, да еще побайтно - вообще полный абзац (и не только на AVR). Делайте статический кольцевой буфер и обмен с ним по прерываниям. Разобраться в вашей программе практически невозможно  Согласен полностью, это микроконтроллер а не ПК, хотя и на Си пишите, динамическое распределение памяти в МК с малым ОЗУ является потенциальным источником ошибок. Если с кольцевым буфером имеются затруднения, используйте простые с фиксированным размером.
Сообщение отредактировал Danis - Oct 21 2010, 17:37
--------------------
Magic Friend
|
|
|
|
|
Oct 21 2010, 19:05
|
Участник

Группа: Участник
Сообщений: 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
|
|
|
|
|
Oct 21 2010, 20:17
|
Участник

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

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

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
|
|
|
|
|
Oct 22 2010, 07:24
|
Участник

Группа: Участник
Сообщений: 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 отличный пример про кольцевой массив... буду пробовать заюзать
|
|
|
|
|
Oct 22 2010, 07:56
|

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

|
Цитата(AnKing @ Oct 22 2010, 11:24)  Средний светодиод при таком раскладе не моргает? почему? Чтобы установить в единицу N-ый бит регистра PORTB нужно записать: PORTB|=(1<<N); Чтобы сбросить в ноль N-ый бит: PORTB&=~(1<<N); Символы ">>" и "<<" - операция сдвига вправо/влево (учите язык С).
|
|
|
|
|
Oct 22 2010, 08:36
|

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

|
Цитата(Палыч @ Oct 22 2010, 10:56)  Символы ">>" и "<<" - операция сдвига вправо/влево (учите язык С). AnKing имейте ввиду, что это никак не кольцевой сдвиг, а битовый сдвиг с припиской нулей справа или слева.
--------------------
Magic Friend
|
|
|
|
|
Oct 22 2010, 08:56
|

Профессионал
    
Группа: Свой
Сообщений: 1 940
Регистрация: 16-12-07
Из: Москва
Пользователь №: 33 339

|
Цитата(Палыч @ Oct 22 2010, 11:56)  (учите язык С). Цитата так в чем разница между и и или при обращении к регистрам? Похоже и цифровую логику И и ИЛИ вспомнить не помешает
--------------------
Закон Мерфи:
Чем тщательнее составлен проект, тем больше неразбериха, если что-то пошло не так
|
|
|
|
|
Oct 22 2010, 16:12
|

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

|
Цитата(ILYAUL @ Oct 22 2010, 12:56)  Похоже и цифровую логику И и ИЛИ вспомнить не помешает Конечно посмотрите таблицу истинности для И и ИЛИ. & - лог. умножение, | лог. сумма. вот Вам Палыч писал: PORTB|=(1<<N); То есть эквивалентно: PORTB = ( PORTB | (1<<N) ) ; Предположим PORTB имеет значение 0b0000000 После лог. Или получим при N = 4: 0b00000000 | 0b00010000 = 0b00010000; T.е установили бит 4 в регистре PORTB.
Сообщение отредактировал Danis - Oct 22 2010, 16:21
--------------------
Magic Friend
|
|
|
|
|
Oct 23 2010, 07:27
|
Участник

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

|
Спасибо что разъяснили, хотя над сдвигом еще придется голову поломать Набросал себе такой хидер для удобства, точнее украл с avrfreaks Код #define SETBIT(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) #define CLEARBIT(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT)) #define FLIPBIT(ADDRESS,BIT) (ADDRESS ^= (1<<BIT)) #define GETBIT(ADDRESS,BIT) (ADDRESS & (1<<BIT)) #define BITWRITE(c,p,m) (c ? SETBIT(p,m) : CLEARBIT(p,m)) на первое время я думаю покатит, все же лучше чем сдвиги самому продумывать А вот кольцевой буфер идею которого я нашел где-то в гугле Правда работать не хочет... и несколько отличается от того, что мне писали здесь, вместо указателейц используется побитовая маска, идею которой я, дурак, так и не понял В статье писали что лучше всего использовать такой буфер в размерности 256, при этом битовую маску задавать одним байтом... может кто пояснит, спасибо. Код #define RXBUF_SIZE 16 //размер буфера обязательно равен степени двойки! #define RXBUF_MASK (RXBUF_SIZE-1) #define BLOCK_TIMEOUT 10 #define BYTE_TIMEOUT 10 #define BLOCK_SIZE 8
unsigned char rxbuf[RXBUF_SIZE]; unsigned char inrx, outrx;
unsigned char rxtimeout = 0;
unsigned char idxDiff(unsigned char idxIN, unsigned char idxOUT, unsigned char bufsize) { if (idxIN >= idxOUT){ return (idxIN - idxOUT); FLIPBIT(PORTB,0); } else{ return ((bufsize - idxOUT) + idxIN); FLIPBIT(PORTB,1); } }
//программка отслеживает прием и его таймауты, и в зависимости от приема // сбрасывает буфер либо переключает режим работы. Подпрограмма должна // вызываться в бесконечном цикле main. void usartPool (void) { char value; unsigned char rxcnt = idxDiff (inrx, outrx, RXBUF_SIZE); if (0 == rxcnt) { //в буфере ничего нет if (rxtimeout >= BLOCK_TIMEOUT) { //в буфере ничего нет давно //... } } else if (rxcnt < BLOCK_SIZE) { //в буфере что-то есть, но мало if (rxtimeout >= BYTE_TIMEOUT) { //прошла слишком большая пауза между байтами, // сбрасываем буфер приема outrx = inrx; } } else { //в буфере корректно приняты BLOCK_SIZE байт, // обрабатываем данные //... do{ value = rxbuf[outrx++]; while ( !( UCSR0A & (1<<UDRE0)) ) UDR0 = value; outrx &= RXBUF_MASK; } while(inrx!=outrx); } }
int main (void) { USART_Init(BAUD_PRESCALE); sei(); for(;;) // Loop forever { usartPool(); } } ISR(USART_RX_vect) { char ReceivedByte; ReceivedByte = UDR0; // Fetch the recieved byte value into the variable "ByteReceived" //while ( !( UCSR0A & (1<<UDRE0)) ) UDR0 = ReceivedByte; // Echo back the received byte back to the computer rxbuf[inrx++] = ReceivedByte; inrx &= RXBUF_MASK; rxtimeout = 0; FLIPBIT(PORTB,0); }
|
|
|
|
|
Oct 23 2010, 08:00
|

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

|
Цитата(AnKing @ Oct 23 2010, 11:27)  ... вместо указателей используется побитовая маска, идею которой я, дурак, так и не понял Вместо указателей используются индексы (inrx, outrx). Поскольку, размер буфера равен 2 в степени N, то под индекс достаточно точно N битов. Если в переменной-индексе "отбрасывать"(обнулять) биты выше N, то значение этой переменной при наращивании на единицу будет циклически изменяться (пример для буфера длиною 256: 0,1,2,3,...,254,255,0,1,...,254,255,0,1,...). Если длина буфера 256 (т.е. 2 в степени 8), то для индексации достаточно переменной длиною ровно 8 бит (char, обычно, как раз имеет такой размер), при этом никаких "лишних" бит (корорые нужно отбрасывать/обнулять) нет - что бывает удобным.
|
|
|
|
|
Oct 23 2010, 19:15
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Палыч @ Oct 23 2010, 14:00)  Если длина буфера 256 (т.е. 2 в степени 8), то для индексации достаточно переменной длиною ровно 8 бит (char, обычно, как раз имеет такой размер), при этом никаких "лишних" бит (корорые нужно отбрасывать/обнулять) нет - что бывает удобным. Идея использования разрядности переменных для ограничения диапазона изменения величины это очень плохая идея. Потому, что разрядность переменных архитектурно- и компиляторно-зависимая величина. В стандарте СИ разрядность переменных не определена строго. В очередной раз привожу пример: CCS от TI и МК из серии TMS320, где char 16-и битный. Ну и добавок, отсутствие явной проверки на выход за границы диапазона отведенной памяти это источник глюков, а в ОС, например, это еще и источник появления уязвимостей.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|