|
USART запрос/ответ, как принять массив через функцию getchar() ? |
|
|
|
Dec 17 2011, 19:08
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Да, заведите второй буфер, для пакета. Заведите счётчик принятых байтов. При отправке запроса обнуляйте его. И потом начинайте увеличивать по приёму каждого байта. Пока счётчик меньше пяти - проверяем заголовок. Досчитали до пяти - значит пошли данные, складываем их в буфер. Досчитали до скольки-то там - данные закончились, проверяем хвостик пакета, и, если всё правильно, то обрабатываем принятые данные. После этого можно снова отправлять запрос. Добавьте ещё тайм-аут на приём символа, для надёжности.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 17 2011, 21:24
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Цитата(ILYAUL @ Dec 17 2011, 23:33)  80 F1 10 26 , а вот 0x26 это счётчик передаваемых байт - похоже CE - контрольная сумма (2 младших разряда) Цитата(AHTOXA @ Dec 17 2011, 22:08)  Да, заведите второй буфер, для пакета Да я вот думаю может нафиг вообще этот кольцевой буффер  Чего то он меня с толку сбивает. Создать буффер в который будут приниматься байты. Когда нужно - читать его. А при каждом следующем запросе начинать прием байтов в начало буффера, перезаписывая его.
Сообщение отредактировал mr_smit - Dec 17 2011, 21:27
|
|
|
|
|
Dec 18 2011, 06:24
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Просто я не понимаю каким образом мне вызывать getchar() Код if (rx_counter>42) { // всего 43 байта в ответе char i; char buf[50]; for (i=0;i<42;i++) { buf[i] = getchar(); }; } Так как то криво
Сообщение отредактировал mr_smit - Dec 18 2011, 07:05
|
|
|
|
|
Dec 18 2011, 09:07
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
В общем убрал кольцевой буффер и сделал вот так: Код #define BUFFER_SIZE 200 unsigned char buffer[BUFFER_SIZE]; // приемный буффер unsigned char startCommunication[] = {0x81,0x10,0xf1,0x81,0x03}; volatile unsigned char counter;
// USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { char status,data; status=UCSRA; data=UDR; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { buffer[counter]=data; counter++; if (counter >= BUFFER_SIZE) { counter = 0; } } } Если вдруг буффер переполнится то пишем данные в его начало. Просто не сойдется контрольная сумма. Получим данные при следующем запросе. Теперь отправка команды. Код void SendCommand (unsigned char *command) { counter = 0; while (*command) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } } Использование: Код SendCommand(startCommunication); Работает (смотрю COM порт сниффером). Но если написать: Код flash unsigned char startCommunication[] = {0x81,0x10,0xf1,0x81,0x03}; То на строчке: Код SendCommand(startCommunication); Выдает ошибку: Error: function argument #1 of type 'flash unsigned char [5]' is incompatible with required parameter of type 'unsigned char *'Я так понимаю нельзя со строкой из флеша напрямую работать. Так то конечно всё равно, но строчки статичные, пусть лучше во флеше лежат. Как то можно к ним обратиться в моём случае?
Сообщение отредактировал mr_smit - Dec 18 2011, 09:14
|
|
|
|
|
Dec 18 2011, 12:14
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
И еще: Код unsigned char startCommunication[] = {0x81,0x10,0xf1,0x81,0x03}; ... void SendCommand (unsigned char *command) { counter = 0; while (*command) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } } ... SendCommand(startCommunication); Почему то выдает один лишний байт  Откуда 04 ???
|
|
|
|
|
Dec 18 2011, 14:06
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(mr_smit @ Dec 18 2011, 15:07)  Выдает ошибку: Error: function argument #1 of type 'flash unsigned char [5]' is incompatible with required parameter of type 'unsigned char *' Я так понимаю нельзя со строкой из флеша напрямую работать. Так то конечно всё равно, но строчки статичные, пусть лучше во флеше лежат. Как то можно к ним обратиться в моём случае? Я не знаю, как это сделано в CVAVR, но видимо надо объявить SendCommand как Код void SendCommand (flash unsigned char *command) Ну или что-то типа этого. Цитата(mr_smit @ Dec 18 2011, 18:14)  Почему то выдает один лишний байт  Откуда 04 ??? Это вам ещё повезло, что всего один лишний байт  У вас в SendCommand идёт проверка на ноль (признак конца команды). А нуля-то и нет! Добавьте: unsigned char startCommunication[] = {0x81,0x10,0xf1,0x81,0x03, 0};
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 18 2011, 18:20
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
AHTOXA, спасибо!!!!! Код void SendCommand (flash unsigned char *command) Работает!!! Код flash unsigned char startCommunication[] = {0x81,0x10,0xf1,0x81,0x03,0}; Работает!!!! А может можно как то переделать функцию SendCommand так чтобы не дописывать 0 в комманды? Просто я с этими указателями чего то путаюсь  А вот этот кусок вообще не понимаю: Код while (*command) {} каким макаром тут проверка на ноль идет  Это же указатель на первый элемент массива. Причем тут ноль? P.S. Да, не сам писАл. Нашел пример.
|
|
|
|
|
Dec 18 2011, 20:39
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Цитата там наверно дальше где-то есть Код command++; аа вот оно Код UDR = *command++; т.е. UDR присваивается значение первого элемента массива, а сам указатель после операции указывает уже на второй, потом на следующей итерации снова while проверяет его и если не ноль, то снова идёт присвоение UDR а command указывает на следующий элемент.... и так пока не встретится ноль в общем )
--------------------
The truth is out there...
|
|
|
|
|
Dec 18 2011, 21:06
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(mr_smit @ Dec 19 2011, 00:20)  А вот этот кусок вообще не понимаю: конструкция Код while (выражение) {команды} выполняет команды пока выражение не ноль. command - указатель, да. А *command - то, на что указывает указатель. Про продвижение указателя sigmaN уже объяснил. ЗЫ. Читать букварь по Си, срочно! Без понимания основ трудно написать что-то приличное.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 18 2011, 21:26
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(mr_smit @ Dec 18 2011, 20:20)  А может можно как то переделать функцию SendCommand так чтобы не дописывать 0 в комманды? Просто я с этими указателями чего то путаюсь  Переделать можно, например так: Код void SendCommand (unsigned char *command, unsigned char length) { while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } } B вызывать соотв.: Код SendCommand(startCommunication, 5); Цитата(mr_smit @ Dec 18 2011, 20:20)  А вот этот кусок вообще не понимаю: Код while (*command) {} каким макаром тут проверка на ноль идет P.S. Да, не сам писАл. Нашел пример. *command = чтение байта по указателю command и если там 0, то получается while (0) - цикл заканчивается. Цитата(mr_smit @ Dec 18 2011, 20:20)  Это же указатель на первый элемент массива. Причем тут ноль? На первый байт он указывал на входе в функцию. Код: Код UDR = *command++; означает, что в UDR пишется байт по указателю, затем указатель инкрементируется (++ - постинкремент).
|
|
|
|
|
Dec 19 2011, 08:16
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Цитата Завести переменную битовую как флаг разрешения, инвертировать её по прерыванию и опрашивать в основном цикле? Вполне себе нормальный подход. Вопрос только в красоте его исполнения и универсальности. Вот тут покрутите учебный курс http://easyelectronics.ru/category/avr-uchebnyj-kurs как раз описывается служба таймеров и типа планировщик задач. Всё на Си.
--------------------
The truth is out there...
|
|
|
|
|
Dec 19 2011, 08:48
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Цитата(sigmaN @ Dec 19 2011, 11:16)  Курс этот я видел/читал. Просто подумал может кто сталкивался с такой задачей. Может как то проще можно. Хотя куда уж  Остановлюсь на этом пока. Вот так сделал: Код volatile bit OldState, StartSend; ... // Timer1 output compare A interrupt service routine interrupt [TIM1_COMPA] void timer1_compa_isr(void) // каждые 250 мс { OldState = StartSend; // запоминаем состояние StartSend^=1; // инвертируем бит } ... if (StartSend != OldState) {}
Сообщение отредактировал mr_smit - Dec 19 2011, 12:03
|
|
|
|
|
Dec 20 2011, 11:07
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
У меня тут вопрос появился. Нигде не смог найти толкового описания как переводить из одной системы исчисления в другую. В общем что мне надо: В "моём" ответе 11-й байт это температура. Формула для пересчета в реальную температуру: N=E-40 [°C]. E - передаваемое значение, N - физическая величина. В примере это значение равно 47. Берем windows калькулятор. Переводим 47 hex в dec. Получаем 71. Дальше 71-40=31°C. Собственно говоря как это сделать? И как быть если температура будет отрицательной? Код unsigned char temp; char convert[16]; ... temp = buffer[10]; temp = (преобразовать в dec) - 40; // ???? sprintf(convert,"%u",temp); // вывод на дисплей char Т.е. 0х47 hex -> 71 dec ??? И как быть с отрицательной температурой? И есть ли что то быстрее sprintf ?
|
|
|
|
|
Dec 20 2011, 17:35
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Ладно, мне надо вычесть 40. Т.е. 40 dec в hex будет 28. Тогда: Код unsigned char temp; char convert[16]; ... temp = buffer[10]; temp = temp - 28; if ((temp >> 8) == 1) { // если отрицательное sprintf(convert,"-%02u",temp); } else { sprintf(convert,"%02u",temp); } // вывод на дисплей char Правильно? Или нет?
|
|
|
|
|
Dec 20 2011, 17:56
|

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

|
Цитата(mr_smit @ Dec 20 2011, 21:35)  Ладно, мне надо вычесть 40. Т.е. 40 dec в hex будет 28. ... Правильно? Или нет? Коль нужно вычесть сорок, то и вычитайте Код temp = temp - 40; Если нужно использовать шестнадцатиричную константу: Код temp = temp - 0x28;
|
|
|
|
|
Dec 20 2011, 18:48
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(mr_smit @ Dec 20 2011, 21:35)  Код if ((temp >> 8) == 1) { // если отрицательное Правильно? Или нет? а не проще вот так? Код if (temp & 0x80) { // если отрицательное да и %02u - вроде как тут нужно %03 d, одно место останется под знак, да и число будет выводиться как обычное десятичное знаковое, а не беззнаковое
|
|
|
|
|
Dec 20 2011, 19:27
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Цитата(toweroff @ Dec 20 2011, 21:48)  а не проще вот так? Код if (temp & 0x80) { // если отрицательное да и %02u - вроде как тут нужно %03 d, одно место останется под знак, да и число будет выводиться как обычное десятичное знаковое, а не беззнаковое Решил потестировать немного: Код unsigned char temp = 0x19; char convert[16]; ... temp = temp - 0x28; if (temp & 0x80) { sprintf(convert,"-%03d",temp); put_string(115,4,convert,0xF800,1); } else { sprintf(convert,"%02d",temp); put_string(115,4,convert,0xF800,1); } Если написать unsigned char temp = 0x47, то выводится число 31, всё правильно (47hex - 28hex = 1F hex ->31dec) Но если написать unsigned char temp = 0x19, то выводится число -241, а не -15 (19hex - 25hex = FFFFFFFFFFFFFFF1 hex -> -15dec) Всё равно не понимаю как минус вывести. P.S. F1 hex = 241 dec
Сообщение отредактировал mr_smit - Dec 20 2011, 19:45
|
|
|
|
|
Dec 20 2011, 19:44
|

Гуру
     
Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514

|
Цитата(mr_smit @ Dec 20 2011, 23:27)  Решил потестировать немного: Код unsigned char temp = 0x19; char convert[16]; ... temp = temp - 0x28; if (temp & 0x80) { sprintf(convert,"-%03d",temp); put_string(115,4,convert,0xF800,1); } else { sprintf(convert,"%02d",temp); put_string(115,4,convert,0xF800,1); } Если написать unsigned char temp = 0x47, то выводится число 31, всё правильно (47hex -> 71dec -> 71-40) Но если написать unsigned char temp = 0x19, то выводится число -241, а не -15 (19hex -> 25dec -> 25-40) ну тогда вот так: Код unsigned char temp = 0x19; char convert[4]; // куда больше-то? ... temp = temp - 40; sprintf(convert, "%s%02d", ((temp & 0x80)? "-": ""), ((temp & 0x80)? (unsigned char)(0-temp): temp) ); put_string(115,4,convert,0xF800,1); ну это на скорую руку. Скорее всего, что-то не так с отображением sprintf, должно быть нормально. Сама она должна разруливать отрицательные числа
|
|
|
|
|
Dec 20 2011, 19:51
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Цитата(toweroff @ Dec 20 2011, 15:17)  ...и содержимое 7 младших битов есть дополнение до 0 Дошло. В случае отрицательной температуры надо добавить: temp = 256 - temp;Код unsigned char temp = 0x19; char convert[16]; ... temp = temp - 0x28; if (temp & 0x80) { temp = 256 - temp; sprintf(convert,"-%d",temp); put_string(115,4,convert,color_chislo,1); } else { sprintf(convert,"%d",temp); put_string(115,4,convert,color_chislo,1); } Выводит -15. Ура! Спасибо!
Сообщение отредактировал mr_smit - Dec 20 2011, 20:02
|
|
|
|
|
Dec 21 2011, 18:10
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Цитата(XVR @ Dec 21 2011, 14:18)  Жуть, столько телодвижений вместо того, что бы просто написать signed char temp (как у вас по сути и должно быть) Код signed char temp = 0x19; char convert[16]; ... temp = temp - 0x28; sprintf(convert,"%d",temp); Спасибо за код. Скажите ещё почему sizeof не работает. Выводит только первые 2 байта: Код void SendCommand (unsigned char *command) { unsigned int length = 0; length = sizeof(command); while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } }
Сообщение отредактировал mr_smit - Dec 21 2011, 18:22
|
|
|
|
|
Dec 21 2011, 21:09
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(mr_smit @ Dec 21 2011, 20:10)  Спасибо за код. Скажите ещё почему sizeof не работает. Выводит только первые 2 байта: Код void SendCommand (unsigned char *command) { unsigned int length = 0; length = sizeof(command); while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } } Вы не правы: это именно sizeof() и работает, и работает он так как надо, то есть так как Вы указали: length = sizeof(command); = размер command, который есть тип unsigned char * - на многих 8-битных МК (например АВР), для указателя на байт хватает 2 байта. Вот у Вас два байта и шлются в порт, на 32 битных МК слалось бы, наверное 4 байта. Совет: Укажите длину посылки как параметр функции. Код [code]void SendCommand (unsigned char *command, unsigned int length ) { // (unsigned char *command, unsigned int length = 0), если нужно умолчание, хотя к чему оно здесь? while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = *command++; } } [/code]
|
|
|
|
|
Dec 21 2011, 22:03
|

Участник

Группа: Участник
Сообщений: 62
Регистрация: 22-07-09
Пользователь №: 51 457

|
Просто вроде как sizeof должна возвращать длину массива. Но тут да, точно, указатель, а не массив (я начинаю понимать  ) Может тогда убрать указатель из аргумента функции? Просто хочу писАть: SendCommand(startCommunication); без указания длинны Код void SendCommand (unsigned char command) { unsigned int length,length1 = 0; length = length1 = sizeof(command); while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = command[length1 - length]; } } Но чет ругается компилятор
|
|
|
|
|
Dec 21 2011, 23:11
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(mr_smit @ Dec 22 2011, 00:03)  Просто вроде как sizeof должна возвращать длину массива. Но тут да, точно, указатель, а не массив (я начинаю понимать  ) Может тогда убрать указатель из аргумента функции? Просто хочу писАть: SendCommand(startCommunication); без указания длинны Код void SendCommand (unsigned char command) { unsigned int length,length1 = 0; length = length1 = sizeof(command); while (length--) { while(!(UCSRA & (1<<UDRE))); // ждем окончания передачи байта UDR = command[length1 - length]; } } Но чет ругается компилятор Что ж ему не ругаться: command - это байт , а вы к нему обращаетесь как элементу массива (хамите). Понятно Вам что нужно: функция аналогичная например такому(C#. правда а не Си) Код void F1(byte []byte_array) { for (int i=0; i<byte_array.Length; i++) { byte_array[i]=i;// нужные действия } } Но в C# каждый массив всегда содержит свою длину, а в Си - нет. Может и есть что-то такое в Си, а может и нет(утверждать не буду, не помню).
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|