Автор Тема: Пар. порт / qt4  (Прочетена 2131 пъти)

ivo1204

  • Напреднали
  • *****
  • Публикации: 987
    • Профил
Пар. порт / qt4
« -: May 05, 2009, 02:02 »
Здравейте,
Нямам време за цяла 'статия', просто лек увод за тия, които 'не знаят'. За другите, нека допълват ...

Паралелният порт е много удобен за леки проекти, в който нямаме време и средства да инвестираме много.

Писането в паралелният порт може да стане  без да пишем драйвер за ядрото, а като го заобиколим – просто искаме от ядрото 'привилегии' ( c примерно ioperm(0x378,2,1))  и използваме входно изходни оператори:

// запис на '1' в порта
#include <sys/io.h>
#include <unistd.h>
...........................
ioperm(0x378,2,1)
.outb(1,0x378);
............................

 ioperm(адрес например 0x378, брой следващи адреси  за които искаме привилегия – 4, статус активен -  1); 
 outb(1,0x378);  // запис на '1' в порта
http://linux.die.net/man/2/ioperm
http://www.doc.ic.ac.uk/~ih/doc/par/

По много начини можем да видим действителните адреси на нашият паралелен порт, например в
 /sys/class/ppdev/parport0/device/resources:
state = active
io 0x378-0x37f
irq 7

0x378 е адреса в който можем да четем/ записваме  данни, (регистър данни), 0x379 е статус регистъра, а  0x37А ще е контролният регистър. Ако не става записването на изходни данни, вероятната причина е че не сте разрешили изхода ( с бит 5, С5  на 0x37A ) .
***ВНИМАНИЕ!!!
Макар че не ми се е случвало да изгоря паралелен порт досега, вижда се, че това е много вероятно при неправилно свързване ( програмиране).
 Може да приемем, че товароспособността на шините е 5 мили ампера.
(макар и на 20ма държи). Също, тя е различна в зависимост от включването  - дали '0' или '1' е на изхода/товара.
Конфликт се получава, когато например имаме на изхода '0' (0 волта), а от товара се получава '1' (5 волта.). Или ако използваме 5 Волта напрежение ( то е максималното!!! ) , то 1 кило ом съпротивление м/у порта и товара би ни предпазило от всяка конфликтна ситуация. ( 5 волта делено на 1000 ома е 0.005 ампера).
Ако за товар ползвате светодиоди например, 100-200 ома е ОК.(макар че ги връзвам директно при мен...).

Порт Дата( 2 – 9 )<-----> резистор<------->товар.
Порт маса (25,24,23,...)<---------------------> маса.

Сега, нека минем на софтуера:
Ще използвам Убунту 9.04,  Kdevelop, QT 4 Designer

Старт, Разработка->KDevelop-> KDevelop Multilanguage IDE.
Project-> New Project -> C++->QMake project -> Empty Qmake Template ( в нова празна директория).
File-> New-> ( *.cpp)-> main
Значи направихме файл main.cpp,

File-> New-> (QT4 Widget  *.ui)-> form
Форма, (която ще си 'нарисуваме' с QT 4 Designer ) .
Щракаме на формата (form.ui в kdevelop), отваря се  Designer-а
Слагаме един pushButton и един lcdNumber ( може от property editor
 да сложим mode -> hex).

Записваме формата и затваряме 'дизайнера'.
Имаме грубият материал, сега го навързваме:

Разликата между QT3 и QT4 е много голяма, специално в случая, затова и я ползвам за пример. Който е ползвал версия 3, знае че всичко може да си направи с дизайнера, друго му не трябва. Тук обаче не.
С дизайнера (верс. 4) направихме клас 'ui_form' ,  но ние ще използваме класа form, а липсващото ще си добавим в два файла – my.cpp и my.h . правим ги. В 'main.cpp' пишем:

// файл main.cpp
#include <QApplication>
 #include "my.h"

 int main(int argc, char *argv[])
 {
     QApplication app(argc, argv);
     Form f;
     f.show();
     return app.exec();
 }
-----------------------------------------------------------
Проектият файл за qmake – то трябва да изглежда така:
SOURCES += main.cpp \
my.cpp
FORMS += form.ui
HEADERS += my.h
--------------------------------------------------------
Заглавният файл (my.h):

 #ifndef FORM_H
 #define FORM_H
 #include "ui_form.h"  //    <= ще си го направи qmake (uic,..)

 class Form : public QWidget, private Ui::Form
 {
     Q_OBJECT
 public:
     Form(QWidget *parent = 0);        
 private slots:
 private:
 };
 #endif
------------------------------------------------------
#include <QtGui>
 #include "my.h"

 Form::Form(QWidget *parent)
     : QWidget(parent)
 {

     setupUi(this);   
 }

void Form::read_pp(){
}
---------------------------------------

Сега трябва да сме готови, Build->Build project -> Execute Main Program
Имаме програмата, ама не работи както искаме. Само показва формата.
Имаме мегдан за творчество, (като и досега) какво и как ще напишем е просто лично решение, но например решаваме една част да сложим във формата, друга няма начин, ще пишем.

Начи щракане на бутона е събитие, което ни е дефинирано предварително. То води до излъчване на сигнали (emit .....), clicked() е този, който ни трябва. И трябва да го прихванем, затова с дизайнера добавяме слот ( Change signals/slots.... -> slots '+' )   read_pp().
После от signal/slot editor добавяме ('+'):
Sender:    pushButton
Signal:     clicked()
Receiver: Form
Slot:        read_pp()

Сега вече, можем да го ползваме, добавяме го в   my.cpp:
void Form::read_pp(){} // най-отдолу

и в my.h:
 private slots:   
void read_pp();  <- това, обявяваме слот , който ще се изпълни при щракане на бутона.

Единственото, което ни остава е да попълним тази функция с код, който да прочете порта и да ги изобрази на lcdNumber widget-a.

my.cpp
#include <QtGui>
 #include "my.h"
// Добавяме :
#include <sys/io.h>
#include <unistd.h>
 // за да използваме ioperm(...), iob(..)
...................
void Form::read_pp(){
ioperm(0x378,4,1); 
 char y=inb(0x378);
lcdNumber->display(y); //  lcdNumber->display(inb(0x378));
}

Начи ние наследихме класа на формата чрез класа form, и промените ги правим в него (my.h, my.cpp), а от формата ( с дизайнера) ползваме слотове,сигнали ( от class ui_form) и т.н.
Реално би било добре записа и четенето в порта да си е отделна команда и да се извиква с параметри, но това тук е пример и би бил полезен за някой, който иска бързо да си свърши работа, без да задълбава много.

Активен

dvasilev

  • Напреднали
  • *****
  • Публикации: 200
  • Distribution: Kubuntu, Debian
  • Window Manager: KDE
    • Профил
    • WWW
Re: Пар. порт / qt4
« Отговор #1 -: May 06, 2009, 09:51 »
На мен този подход не ми допада много. В единия от линковете пише:
Цитат
The use of ioperm() requires root privileges.
Цитат
This call is mostly for the i386 architecture. On many other architectures it does not exist or will always return an error.

Доколкото паралелния порт е character device, не ли е по-добре достъпа до него да се осъществява чрез съответния запис в /dev.
Активен

ivo1204

  • Напреднали
  • *****
  • Публикации: 987
    • Профил
Re: Пар. порт / qt4
« Отговор #2 -: May 07, 2009, 04:44 »
dvasilev,
ioperm() работи  на 32 и 64-битова версия Убунту, има вариант за избягване 'роот' ограничението, просто примера бе много прост, нормално е да се ползва :
if (ioperm()) { ......}
С привилегиите има чалъм, ама струва ли си?

 Писането с inb() ( и другите)е много бързо, може да се наложи изчакване.
Написано е с вграденият асемблер (sys/io.h):
------------------------------------
static __inline unsigned char
inb (unsigned short int port)
{
  unsigned char _v;

  __asm__ __volatile__ ("inb %w1,%0":"=a" (_v):"Nd" (port));
  return _v;
}
---------------------------------
 
Основно, директното писане е за предпочитане при домашни проекти, програматори, ЛСД дисплеи, разни други интерфейси и протоколи, които сам си измислиш. За ден-два си решаваш проблема и с хардуера, и със  софтуера.... Пример:
 http://www.vk2zay.net/article/31
 

Активен