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

Такая проблема:
Пишу программу на WINAVR, смысл таков - по прерыванию UART по линии Rx, программа должна возвращать символ, в зависимости от символа введенного в терминале.
НО, все попытки - сравнение строк, условия if и т.д. были тщетными... компилятор выдавал ворнинги...

В общем вопрос:

Как организовать отправку строки символов, в зависимости от строки введенной в теминале ?
Либо как корректно передать в main() содержание UDR из SIGNAL (SIG_UART_RECV)

Вот так я писал функцию обработки прерывания изначально, но ничего не получалось:

SIGNAL (SIG_UART_RECV)

uint8_t usart_data;
uint8_t *pInpunStr = "start";
char *pDispatch;
int flag;

usart_data= UDR;
flag = strcmp(pInpunStr,usart_data);

if(flag = 1)
pDispatch = "GOOD";

else{
pDispatch = "TRY AGAIN";
}

usart_send_c(pDispatch);

}


CODE
#include <avr/io.h>
#include <avr/interrupt.h>

#include <inttypes.h>
#include <util/delay.h>

#define F_OSC 16000000 /* oscillator-frequency in Hz (F_OSC) - caiaieou!!! */
#define UART_BAUD_RATE 9600
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16l)-1)

void delay_ms(unsigned short ms) {
unsigned short outer1, outer2;
outer1 = 200;
while (outer1) {
outer2 = 1000;
while (outer2) {
while ( ms ) ms--;
outer2--;
}
outer1--;
}
}

int strcmp(unsigned char *t1,unsigned char *t2)
{
while(*t1)
if(*t1-*t2)
return 0;
else{
t1++;
t2++;
}
return 1;
}

void usart_send_c(uint8_t c) {
// wait until UDR ready
while(!(UCSRA & (1 << UDRE)));
UDR = c; // send character
}

void uart_send_s(uint8_t *s) {
// loop until *s != NULL
while (*s) {
usart_send_c(*s);
s++;
}
}


/*Eieoeaeecaoey UART*/
void init(void) {
// set baud rate
UBRRH = (uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_OSC)>>8);
UBRRL = (uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_OSC);

// Enable receiver and transmitter; enable RX interrupt
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);

//asynchronous 8N1
UCSRC = (1 << URSEL) | (3 << UCSZ0);
}


SIGNAL (SIG_UART_RECV) { // USART RX interrupt

uint8_t usart_data;

usart_data= UDR;
usart_send_c(usart_data);
}

int main(void) {
init(); // init USART

while(!(UCSRA & (1 << UDRE)));
UDR = 0x0d;

char *p = "READY!";

while (*p){
while(!(UCSRA & (1 << UDRE)));
UDR = (uint16_t)*p;
p++;
}


#define LED1 7
#define LED_PORT PORTD
#define LED_DDR DDRD

LED_DDR = 1<<LED1;


sei(); // enable interrupts




while(1)
{
LED_PORT=0<<LED1;
_delay_ms(1000);
LED_PORT=1<<LED1;
_delay_ms(1000);
}


return 0;
}
azziz
какая у Вас версия WINAVR? если из последних, то вместо SIGNAL (SIG_UART_RECV) используйте ISR(USART_RX_vect). и что за ворнинги пишет?
uzzzer
Цитата(azziz @ Apr 7 2011, 13:19) *
какая у Вас версия WINAVR? если из последних, то вместо SIGNAL (SIG_UART_RECV) используйте ISR(USART_RX_vect). и что за ворнинги пишет?



У меня из последних версия, вот какие ворнинги пишет для обоих случаев:

SIGNAL (SIG_UART_RECV)

../main.c:82: warning: pointer targets in initialization differ in signedness
../main.c:89: warning: passing argument 2 of 'strcmp' makes pointer from integer without a cast
../main.c:91: warning: suggest parentheses around assignment used as truth value
../main.c:110: warning: passing argument 1 of 'usart_send_c' makes integer from pointer without a cast



ISR(USART_RX_vect)
../main.c:79: warning: 'USART_RX_vect' appears to be a misspelled signal handler
../main.c: In function 'USART_RX_vect':
../main.c:82: warning: pointer targets in initialization differ in signedness
../main.c:89: warning: passing argument 2 of 'strcmp' makes pointer from integer without a cast
../main.c:91: warning: suggest parentheses around assignment used as truth value
../main.c:110: warning: passing argument 1 of 'usart_send_c' makes integer from pointer without a cast
azziz
у Вас неверная формула определения скорости UBRR = F_OSC/(16*UART_BAUD_RATE) - 1
какой у Вас контроллер? имя вектора другое. посмотрите как он определен в файле iomXX.h
где пишете *char напишите unsigned char*.
вместо if(*t1-*t2) попробуйте if((*t1-*t2) == 0)
hd44780
Тогда уж не

uint8_t *pInpunStr = "start";

а

char *pInpunStr = "start";

А если хотите именно uint8_t, то

flag = strcmp((char *)pInpunStr,usart_data);

uzzzer
Цитата(hd44780 @ Apr 7 2011, 14:39) *
;


Все равно выдает те же ворнинги(((
Сергей Борщ
Для начала: Попытка из принятого байта сделать указатель на строку лишена смысла: flag = strcmp(pInpunStr,usart_data);
Вам надо сложить принятые байты в какой-то буфер и потом, по какому-то признаку (прнят символ перевода строки, например), сравнить принятый буфер с образцом команды.
uzzzer
Цитата(Сергей Борщ @ Apr 7 2011, 15:04) *
Для начала: Попытка из принятого байта сделать указатель на строку лишена смысла: flag = strcmp(pInpunStr,usart_data);


Это я просто написал функцию сравнения строк, 0 - если не раны, еденица, если равны)))


Цитата
Вам надо сложить принятые байты в какой-то буфер и потом, по какому-то признаку (прнят символ перевода строки, например), сравнить принятый буфер с образцом команды.


Если можно, поясните, как это сделать... т.е. по переходу из процедуры обработки прерывания в main() уничтожаются все локальные переменные, а как организовать такой буфер ?
Как я понимаю компиллер ругается на несоответствие типов данных.
defunct
Цитата(uzzzer @ Apr 7 2011, 15:16) *
Если можно, поясните, как это сделать... т.е. по переходу из процедуры обработки прерывания в main() уничтожаются все локальные переменные, а как организовать такой буфер ?
Как я понимаю компиллер ругается на несоответствие типов данных.

например так

CODE
volatile char write_index = 0;
volatile char enter_pressed = FALSE;
char cmd[64];


uart_rx_isr()
{
char ch = UDR;

if (enter_pressed) // drop the char, previous command hasn't handled yet.
return;

if (ch >= 0x20)
{
// common case
cmd[ write_index++ ] = UDR;
}
else if (ch == 0x0D)
{
// нажали кнопку enter
if (write_index)
enter_pressed = TRUE;
}
else
{
// other control chars, backspace, tab etc. handle here
}

if (write_index >= sizeof(cmd))
write_index = 0;
}



main()
{
memset( cmd, 0x00, sizeof(cmd));

for(;;)
{
if(enter_pressed)
{
if ( memcmp( "cmd1", cmd, sizeof("cmd1")-1 ) )
....
else if ( memcmp( "cmd2", cmd, sizeof("cmd2")-1 ) )
....

// cmd handled
write_index = 0;
enter_pressed = FALSE;
}
}
}
nk@
Прошу прощения за неоригинальность, но AVRLIB от Pascal Stang включает в себя замечательную библиотечку для работы с UART, причем с FIFO, поддержкой прерываний итд sm.gif Имеется также реализация VT100 и даже command-line интерфейса с редактированием, автокомплишеном. Зачем сушить себе мозги и изобретать колесо - берите готовое и радуйтесь.
http://www.mil.ufl.edu/~chrisarnold/compon...ard/AVR/avrlib/
uzzzer
Огромное все спасибо за помощь.
Вообщем я частично решил проблему с помощью примера к статьи: http://www.chipenable.ru/index.php/program...sart-uart-queue

Переделав основную программу таким образом:

Код
int main(void)
{
  
  unsigned char counter=0; // for test
  
  unsigned char StrRx[counter];// for test
  unsigned char StrTx[counter];
  unsigned char index; //for test
  char *pRx=0;
  unsigned char *pTx=0;  
  char pCmd[]="START";
  unsigned char pEcho[]="TEST PASS !!!";
  unsigned char pFail[]="Try again !!!";
  
  unsigned char symbol;
  int flag;

  //unsigned char symbol;
  USART_Init();
  asm("sei");



  

while(1){
    
    
    /*symbol = USART_GetChar();
    if (symbol == 't')
      USART_SendStr(pEcho);
        
    */
unsigned char tmp;
tmp = USART_GetChar();
//pRx=pCmd;

while(tmp){
pRx++;
*pRx = tmp;

tmp=USART_GetChar();
}


flag = strcmp(pRx,pCmd);

  if(flag==0)
   USART_SendStr(pEcho);
  //else {USART_SendStr(pFail);}


}
return 0;    
}


Но возник такой вопрос:

USART_SendStr(pEcho); - выводит строку символов pEcho ("TEST PASS !!!"), примерно так: TEST PASS !!! TES т.е. по 18 символов, причем три раза нажимаю энтер и три раза выводится по 18 символов... стоит уменьшить SIZE_BUF, до 10 - 11 символов, выводится строка с меньшим количеством символов и два раза нажав энтер выводится два раза соответственно... причем больше трех раз при значении SIZE_BUF=16 не выводится и больше двух раз при значении SIZE_BUF = 10...

Это скрин терминалки:

uzzzer
И еще: Если Ввожу не полную строку "START" или хотя бы строку больше двух символов, но содержащею, хотя бы один "S", то выводится, как будто ввел полностью слово, если больше 6 символов, то ввод прекращается уже не после третьего нажатия энтер, а послн первого или второго. Если только один "S", то на теминалке выводится до бесконечности мое сообщение.
такое чувство, что функция сравнения просто сравнивает первый символ...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.