Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблемы с рисование графика CBuilder 
:(
    Опции темы
ГЫнок
Дата 11.4.2009, 15:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 20.3.2009

Репутация: нет
Всего: нет



Здравствуйте!
История такая: Взял МК и зашил в него програму, которая по виртуальному ком порту передает резальтаты сканирования АЦП при этом используется 4 байта из всего буфера, в данном случае получается скорость 4 кбайт/сек. На ПК эти данные получаю и рисую 2 графика, при этом использую 1 поток...
Возникле 3 проблемы:
1. Когда кривая доходит до конца графика, я естественно отправляю ее вначало и обновляю фон чтоб линии не накладывались    if (ci>=500) {ci=10; Fon();}, но вот беда программа выресовывает только до первого обновления графика а далее из ком порта читаются только нули... программу закрывает открываешь и все повторяется.

2. Попробовал закоментировать обновление графикая    if (ci>=500) {ci=10; /*Fon();*/}, данные считываются нормально но линии накладываются друг на друга и получается каша...

3. Через некоторое время происходт странности один из Image'в прост пропадает и не появляется а бывает оба пропадают

Пробовал сохранять данные из ком в буфер и ресовать график не в потоке а по таймеру 10 раз в сек, но получется некрасива и график себя странно ведет.... Но нет глюков как в потоке... Ничего не понимаю  smile ... smile ...

Код

void ReadPrinting(void);

//---------------------------------------------------------------------------
void Fon () {              // Создается фон для графика ось Х и ось У                                                                                   
    Word i, j;
    PatBlt(Form1->Image1->Canvas->Handle, 0, 0,
    Form1->Image1->ClientWidth, Form1->Image1->ClientHeight, WHITENESS);
    Form1->Image1->Canvas->Lock();
    Form1->Image1->Canvas->MoveTo(10, 10);
    Form1->Image1->Canvas->LineTo(10, 138);
    Form1->Image1->Canvas->LineTo(500, 138);
    for (i=8; i<=128; i+=8)
    {
    Form1->Image1->Canvas->MoveTo(8, 138-i);
    Form1->Image1->Canvas->LineTo(13, 138-i);
    };
    for (j=10; j<500; j+=10)
    {
    Form1->Image1->Canvas->MoveTo(10+j, 136);
    Form1->Image1->Canvas->LineTo(10+j, 141);
    Form1->Image1->Canvas->MoveTo(10, 138);
    }
    i=0; j=0;
    PatBlt(Form1->Image2->Canvas->Handle, 0, 0,
    Form1->Image2->ClientWidth, Form1->Image2->ClientHeight, WHITENESS);
    Form1->Image1->Canvas->Lock();
    Form1->Image2->Canvas->MoveTo(10, 10);
    Form1->Image2->Canvas->LineTo(10, 138);
    Form1->Image2->Canvas->LineTo(500, 138);
    for (i=8; i<=128; i+=8)
    {
    Form1->Image2->Canvas->MoveTo(8, 138-i);
    Form1->Image2->Canvas->LineTo(13, 138-i);
    };
    for (j=10; j<500; j+=10)
    {
    Form1->Image2->Canvas->MoveTo(10+j, 136);
    Form1->Image2->Canvas->LineTo(10+j, 141);
    Form1->Image2->Canvas->MoveTo(10, 138);
    }
}
//главная функция потока, реализует приём байтов из COM-порта
DWORD WINAPI ReadThread(LPVOID)
{
 COMSTAT comstat;        //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
 DWORD btr, temp, mask, signal;    //переменная temp используется в качестве заглушки

 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);    //создать сигнальный объект-событие для асинхронных операций
 SetCommMask(COMport, EV_RXCHAR);                            //установить маску на срабатывание по событию приёма байта в порт
 while(1)                        //пока поток не будет прерван, выполняем цикл
  {
   WaitCommEvent(COMport, &mask, &overlapped);                //ожидать события приёма байта (это и есть перекрываемая операция)
   signal = WaitForSingleObject(overlapped.hEvent, INFINITE);    //приостановить поток до прихода байта
   if(signal == WAIT_OBJECT_0)                        //если событие прихода байта произошло
    {
     if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
      if((mask & EV_RXCHAR)!=0)                    //если произошло именно событие прихода байта
       {
        ClearCommError(COMport, &temp, &comstat);        //нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                           //и получить из неё количество принятых байтов
        if(btr)                                  //если действительно есть байты для чтения
        {
         ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         ReadPrinting();                           //вызываем функцию для вывода данных на экран и в файл
        }
       }
    }
  }    
}

//---------------------------------------------------------------------------

//выводим принятые байты на экран и в файл (если включено)
void ReadPrinting()
{
 WORD res1, res2;

 res1=bufrd[0]+bufrd[1]*256;
 res2=bufrd[2]+bufrd[3]*256;

    if (ci==10) {Form1->Image1->Canvas->MoveTo(10, 128); Form1->Image2->Canvas->MoveTo(10, 128);}
    Form1->Image1->Canvas->LineTo(ci, 138-res1/8);
    Form1->Image2->Canvas->LineTo(ci, 138-res2/8);
    ci++;
    if (ci>=500) {ci=10; Fon();}

 Form1->StatusBar1->Panels->Items[2]->Text = "Всего принято " + IntToStr(counter) + " байт";    //выводим счётчик в строке состояния

 if(Form1->CheckBox3->Checked == true)  //если включен режим вывода в файл
  {
   write(handle, bufrd, strlen(bufrd)); //записать в файл данные из приёмного буфера
  }
 memset(bufrd, 0, BUFSIZE);            //очистить буфер (чтобы данные не накладывались друг на друга)
}



З.Ы. Заранее спосибо!
PM MAIL   Вверх
Anikmar
Дата 11.4.2009, 15:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 5
Всего: 59



Вообще-то VCL не многопоточная. Надо синхронизировать при обращении к ее функциям из другого потока.
PM MAIL ICQ   Вверх
ГЫнок
Дата 11.4.2009, 20:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 20.3.2009

Репутация: нет
Всего: нет



Звучит зловещи...
Кто-то мне посоветовал все данные отправлять в файл а потом считать оттуда, это конечно вариант но необходимо все видеть в реальном времени...

Я сделал вывод что предется развивать тему с рисованием графика по таймеру учитывая что это заработало хоть и криво по началу...

Можетели еще варианты предложить чтоб было из чего выбирать?
PM MAIL   Вверх
Anikmar
Дата 11.4.2009, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 5
Всего: 59



Вариантов тут немного.
Основной поток - считывает данные из порта, дополнительный их рисует.
Или наоборот - дополнительный считывает, основной рисует.

Цитата(ГЫнок @  11.4.2009,  20:48 Найти цитируемый пост)
Звучит зловещи...

Особо зловещего ничего нет. Просто в вашем варианте мне трудно оценить количество срабатываний - т.е. успеет ли график отрисоваться при использовании синхронизации.

Исходя из описания проблемы мне видится следующая причина: Закраска фона достаточно длительная процедура. Когда ваш график полностью завершился происходит перерисовка фона. Пока она еще не закончилась вызывается метод рисования. Получаем повторный вход в нереентерабельную VCL и, соответственно глюк.

Попробуйте все обращения к VCL из потока оформить через Synchronize. 
PM MAIL ICQ   Вверх
ГЫнок
Дата 11.4.2009, 21:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 20.3.2009

Репутация: нет
Всего: нет



Ясна...
Если известно что в секунду передается 1000 пакетов, т.е. цикл в потоке чтения повторяется 1000 раз в сек. Эта информация может помоч в этом не легком деле? 

Вопрос по поводу Synchronize, так вроде ее нужно применять при использование потока TThread, а с функциями WinApi в ней нет необходимости...
PM MAIL   Вверх
Anikmar
Дата 11.4.2009, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 5
Всего: 59



Цитата(ГЫнок @  11.4.2009,  21:49 Найти цитируемый пост)
Вопрос по поводу Synchronize, так вроде ее нужно применять при использование потока TThread, а с функциями WinApi в ней нет необходимости... 

Упс, невнимательно посмотрел. Вообще-то я всегда считал, что смешивать потоки WinAPI и VCL не стоит.
1000 раз в секунду это много. График реально обновляться должен намного реже - 25 раз в секунду - это уже обычное видео. Для графика достаточно и одного раза в секунду.
Раз уж визуализацию делаете средствами VCL - то попробуйте использовать TThread. Хотя разницы большой я не вижу - VCL не многопоточна, значит нереентерабельна. И каким образом в нее поступают вызовы мне кажется безразлично. Я ни разу не использовал потоки, созданные через WinAPI с VCL - либо то либо другое. Но TThread скорее всего обертка, поэтому синхронизация нужна по-любому. ИМХО.
PM MAIL ICQ   Вверх
xvr
Дата 13.4.2009, 14:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



  •  Рисовать что-либо через VCL из другого потока НЕЛЬЗЯ (как бы этот поток не создавался). Используйте TThread & Synchronize
  •  Рисовать лучше в TPaintBox (кажется так оно называется), и обновлять его в OnPaint событии. Рисование в TImage тянет за собой накладные расходы по изменению собственно картинки в памяти

PM MAIL   Вверх
Anikmar
Дата 13.4.2009, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 5
Всего: 59



В любом случае частота 1000 Герц для обновления не нужна. 
Вижу два подхода:
1. Менять прошивку контроллера. Если программа контроллера будет сама обрабатывать статистику и пересылать ее пару раз в секунду на комп этого за глаза хватит, чтобы насладится графиком.
2. Основной поток чтения из порта должен быть занят только одним: считать данные и сохранить их для последующего анализа. Вызывать из него методы отображения не нужно - он должен только обновлять некий глобальный объект статистики (через методы синхронизации).
А вот основной поток должен раз-два в секунду брать обновленную статистику и отображать ее в графике. Таким образом чтение из порта отделим от медленной процедуры отрисовки. Не успел отрисоваться - не беда, зато данные приняты все - их потом можно внимательно изучить.

На мой взгляд 2-й подход правильней. Лично я использовал его.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0549 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.