Сериен порт
Интерфейсът RS-232 е с повече от половин век история и в момента когато казваме "сериен порт" най-често става дума за RS-232. В сравнение със съвременните мегабитови интерфейси като USB (също сериен интерфейс), RS-232 връзката изглежда бавна и ненужна, но тя e същественa поради няколко причини:
- За разбиране на процеса на комуникация с операционната система. Текстовият интерфейс е в основата на всяка една UNIX система, а той базиран върху концепцията на серийния терминал. Днес хардуерният текстов терминал е заместен със псевдо терминал.
- Все още се ползва, въпреки че е загубила широката си употреба, все още се ползва в редица приложения - за връзка с индустриални контролери и комуникационна апаратура.
Интерфейсът RS-232 е с повече от половин век история и в момента когато казваме "сериен порт" най-често става дума за RS-232. В сравнение със съвременните мегабитови интерфейси като USB (също сериен интерфейс), RS-232 връзката изглежда бавна и ненужна, но тя e същественa поради няколко причини:
- За разбиране на процеса на комуникация с операционната система. Текстовият интерфейс е в основата на всяка една UNIX система, а той базиран върху концепцията на серийния терминал. Днес хардуерният текстов терминал е заместен със псевдо терминал.
- Все още се ползва, въпреки че е загубила широката си употреба. Серийния интрефейс се среща за връзка с индустриални контролери и комуникационна апаратура.
Contents
- 1 RS-232C
- 2 Цел на упражнението
- 3 Теория
- 4 Serial port terminal
- 5 Променливи
- 6 Проверка по четност
- 7 Комуникация през C, POSIX и сериен порт
- 8 Задача 1
- 9 Четене сериен порт
- 10 Самостоятелна подготовка
- 11 Край
- 12 Литература
- 13 Цел на упражнението
- 14 Теория
- 15 Serial port terminal
- 16 Променливи
- 17 Проверка по четност
- 18 Комуникация през C, POSIX и сериен порт
- 19 Задача 1
- 20 Четене сериен порт
- 21 Самостоятелна подготовка
- 22 Край
- 23 Литература
RS-232C
Повечето серийни интерфейси с ниска скорост са някакъв вариант на RS-232C стандарта. Този стандарт определя електрическите характеристики и значението на сигнала по всеки от проводниците, както и разположението на пиновете в традиционния 25 пинов конектор (DB-25p фиг.4).
Пълният стандарт RS-232C (EIA-232-E) реално не се използва, защото определя множество сигнали, които са ненужни при обикновена комуникация. DB-25 конекторите са неудобни и поради големината си. В резултат на това те са заместени от 9 пинов конектор (DB-9, фиг.5), а като удобна алтернатива се ползва и RJ-45.
В таблицата са дадени наименованията на сигналите и разположението им на пиновете. Обикновено се ползват 7 проводника за осъществяване на връзка (DSR и DCD; FG и SG; ползват общ проводник).
Таблица с значенията на пиновете (мъжки куплунг) за различните конектори.
DB-25 | DB-9 | RJ-45 | Име | Значение |
1 | - | - | FD | Frame Ground |
2 | 3 | 6 | TD | Transmitted Data |
3 | 2 | 5 | RD | Received Data |
4 | 7 | 8 | RTS | Request To Send |
5 | 8 | 7 | CTS | Clear To Send |
6 | 6 | 1 | DSR | Data Set Ready |
7 | 5 | 4 | SG | Signal Ground |
8 | 1 | 2 | DCD | Data Carrier Detect |
20 | 4 | 3 | DTR | Data Terminal Ready |
На фигури 4,5 и 6 са дедени разположенията на мъжките пинове, в женския конектор те са разположени огледално.
При свързване на две устройства с RS-232 сигналът за предаване (TD) от едно устройство трябва да се подава на пин за приемане (RD) на второто устройство. Поради това се налага два типа конфигурации на серийните устройствата:
- DTE (Data Terminal Equipment) - стандартна схема на свързване
- DCE (Data Communications Equipment) - вътрешно
Всяко едно устройство може да е конфигурирано като DTE или DCE, рядко може да поддържа и двата варианта, но не едновременно.
Null Modem
DB9-1 | DB-2 | ||
---|---|---|---|
Receive Data | 2 |
3 |
Transmit Data |
Transmit Data | 3 |
2 |
Receive Data |
Data Terminal Ready | 4 |
6+1 |
Data Set Ready + Carrier Detect |
System Ground | 5 |
5 |
System Ground |
Data Set Ready + Carrier Detect | 6+1 |
4 |
Data Terminal Ready |
Request to Send | 7 |
8 |
Clear to Send |
Clear to Send | 8 |
7 |
Request to Send |
Серийни
Цел на упражнението
Преговор типове данни, оператори. Достъп до сериен порт.
Теория
Serial port terminal
Linux
Задача Инсталирайте терминалната програма за комуникация през сериен порт GTKterm.
Упътване: Използвайте командата по-долу. След инсталацията може да намерите програмата в Applications -> Accessories.
:~$ sudo apt-get install gtkterm
Windows
ЗадачаСтартирайте Hyper terminal в MS Windows
START -> Programs -> Accessories -> Communications -> Hyper Terminal
Задача Осъществете връзка през сериен порт връзка между Windows и Linux на два съседни компютъра.
Свържете двата компютъра със сериен кабел през RS232 порта. Настройте двете програмите HyperTeminal и GTKterm да предават и приемат с еднакви параметри.
Тествайте различни скорости на предаване и приемане.
Променливи
Разгледайте различните типове данни в C.
Основната причина за съществуване на различни типове данни е да знае компилатора, колко памет да отдели за всяко число, буква или текст, когато съхранява стойностите им. Информацията се ползва и в последствие, при извеждане или при обработка на данните и взаимодействия с други данни.
Задача 1. Създайте програма, която да преобразува числото 65 в символ и да го извежда.
Упътване . Използвайте:
int x = 65;
char y;
y = (char) x;
printf( " %c ", y );
Задача 2. Създайте програма, която да извежда всички букви букви от ASCII кода в поредица AbCdEfGh.... yZ
Упътване . Всяка буква отговаря на число, всяка следваща буква е число с едно по-голямо. Главните букви започват от 65, малките от 97, а общо са 26. Може да ползвате:
int i = 0;
for (i = 0; i< 26; i = i + 2)
{ ... }
Задача 3. Създайте програма, която след въвеждане на буква от клавиатурата, извежда дали кодът на буквата е с четен или нечетен номер.
Упътване. Може да използвате примера от задача 2 на Упражнение 2 и кодът по-долу.
if ( ((int) s) % 2) puts(" .... ");
else puts(" ... ");
Задача 4. Преобразуване на буква в двоичен код. Изпълнете програмата, разгледайте кода и пробвайте с различни букви.
#include <stdio.h> /* Standard input/output definitions */
#define TESTD 'a'
int main(void)
{
int z=128, y = 0;
char a = TESTD;
char b[9] = "00000000";
for ( y=0; y < 8; ++y)
{
b[y] = ((a & z) == z) ? '1' : '0';
/* a = 0 0 1 0 1 0 0 0
AND
z = 0 0 0 0 1 0 0 0
===================
r = 0 0 0 0 1 0 0 0 = z */
z = z >> 1; // <=> z >>= 1 - преместване с един бит
}
printf("%s \n", b);
return 0;
}
Проверка по четност
Задача 5 Преработете кодът от предната задача, така че да ви показва, колко единици има в двоичното число и дали броят на единици е четен или нечетен.
Упътване Може да замените
((a & z) == z) ? '0' : '1';
със
int e=0;
...
if((a & z) == z)
{
++e;
b[y] = '1';
}
Комуникация през C, POSIX и сериен порт
Задача Създайте програма, която да изпраща информация по-серийния порт. Свържете два компютъра със сериен кабел, като на единия изпълнявате програмата, а на другия сте включили, някоя от терминалните програми за управление на серийната връзка от предходната задача.
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#define PORTNAME "/dev/ttyS0"
int main(void)
{
int fd; // File descriptor for the port
struct termios options; // Serial port settings
fd = open( PORTNAME, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)//Could not open the port.
perror("open_port: Unable to open port");
else
fcntl(fd, F_SETFL, 0);
tcgetattr(fd, &options);
cfsetispeed(&options, B2400);
cfsetospeed(&options, B2400);
options.c_cflag |= ( CREAD);
options.c_cflag |= ( CLOCAL);
options.c_cflag &= ( ~CSTOPB);
tcsetattr(fd,TCSANOW, &options);
write(fd, "a \n", 3); //write to serial port
return 0;
}
За повече информация Управление на сериен порт с POSIX, [POSIX serial port]
Задача 1
Създайте програма с безкраен цикъл, която да изпраща една буква към серийния порт. Използвайте специално пригодения кабел и разгледайте осцилограмата на сериен сигнал.
Четене сериен порт
Raw
/****************************************************************\
* Edited by Ilianko
* Description: Raw reading of the serial port
\****************************************************************/
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BAUDRATE B2400
#define MODEMDEVICE "/dev/ttyUSB2"
int main()
{
int fd, c, res, stop = 0;
struct termios oldtio,newtio;
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {perror(MODEMDEVICE); exit(-1);}
fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
newtio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tcsetattr(fd,TCSANOW,&newtio);
tcflush(fd, TCIFLUSH);
/* loop while waiting for input. normally we would do something */
while ( stop == 0)
{
usleep(100);
fflush (stdout);
res = read(fd,buf,10);
// strcat(buf,buf2);
for( c=0; c<res; c++)
{
printf("%c", (char) buf[c]);
}
}
tcsetattr(fd,TCSANOW,&oldtio);/* restore old port settings */
return 0;
}
Canonical
/****************************************************************\
* Edited by Ilianko
* Description: Raw reading of the serial port
\****************************************************************/
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BAUDRATE B2400
#define MODEMDEVICE "/dev/ttyUSB2"
int main()
{
int fd, c, res, stop = 0;
struct termios oldtio,newtio;
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {perror(MODEMDEVICE); exit(-1);}
fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcsetattr(fd,TCSANOW,&newtio);
tcflush(fd, TCIFLUSH);
/* loop while waiting for input. normally we would do something */
while ( stop == 0)
{
usleep(100);
fflush (stdout);
res = read(fd,buf,10);
for( c=0; c<res; c++)
{
printf("%c", (char) buf[c]);
}
}
tcsetattr(fd,TCSANOW,&oldtio);/* restore old port settings */
return 0;
}
Самостоятелна подготовка
1. Напишете името си на латиница, преобразувайте буквите с двоичен код и създайте времева диаграма на физическия сигнал. 1. Да се напише програма, която изпраща символите от клавиатурата към серийния порт.
Край
Задача 11 Деинсталирайте GTKterm.
Упътване: Използвайте командата.
:~$ sudo apt-get purge gtkterm
Литература
Цел на упражнението
Преговор типове данни, оператори. Достъп до сериен порт.
Теория
Serial port terminal
Linux
Задача Инсталирайте терминалната програма за комуникация през сериен порт GTKterm.
Упътване: Използвайте командата по-долу. След инсталацията може да намерите програмата в Applications -> Accessories.
:~$ sudo apt-get install gtkterm
Windows
ЗадачаСтартирайте Hyper terminal в MS Windows
START -> Programs -> Accessories -> Communications -> Hyper Terminal
Задача Осъществете връзка през сериен порт връзка между Windows и Linux на два съседни компютъра.
Свържете двата компютъра със сериен кабел през RS232 порта. Настройте двете програмите HyperTeminal и GTKterm да предават и приемат с еднакви параметри.
Тествайте различни скорости на предаване и приемане.
Променливи
Разгледайте различните типове данни в C.
Основната причина за съществуване на различни типове данни е да знае компилатора, колко памет да отдели за всяко число, буква или текст, когато съхранява стойностите им. Информацията се ползва и в последствие, при извеждане или при обработка на данните и взаимодействия с други данни.
Задача 1. Създайте програма, която да преобразува числото 65 в символ и да го извежда.
Упътване . Използвайте:
int x = 65;
char y;
y = (char) x;
printf( " %c ", y );
Задача 2. Създайте програма, която да извежда всички букви букви от ASCII кода в поредица AbCdEfGh.... yZ
Упътване . Всяка буква отговаря на число, всяка следваща буква е число с едно по-голямо. Главните букви започват от 65, малките от 97, а общо са 26. Може да ползвате:
int i = 0;
for (i = 0; i< 26; i = i + 2)
{ ... }
Задача 3. Създайте програма, която след въвеждане на буква от клавиатурата, извежда дали кодът на буквата е с четен или нечетен номер.
Упътване. Може да използвате примера от задача 2 на Упражнение 2 и кодът по-долу.
if ( ((int) s) % 2) puts(" .... ");
else puts(" ... ");
Задача 4. Преобразуване на буква в двоичен код. Изпълнете програмата, разгледайте кода и пробвайте с различни букви.
#include <stdio.h> /* Standard input/output definitions */
#define TESTD 'a'
int main(void)
{
int z=128, y = 0;
char a = TESTD;
char b[9] = "00000000";
for ( y=0; y < 8; ++y)
{
b[y] = ((a & z) == z) ? '1' : '0';
/* a = 0 0 1 0 1 0 0 0
AND
z = 0 0 0 0 1 0 0 0
===================
r = 0 0 0 0 1 0 0 0 = z */
z = z >> 1; // <=> z >>= 1 - преместване с един бит
}
printf("%s \n", b);
return 0;
}
Проверка по четност
Задача 5 Преработете кодът от предната задача, така че да ви показва, колко единици има в двоичното число и дали броят на единици е четен или нечетен.
Упътване Може да замените
((a & z) == z) ? '0' : '1';
със
int e=0;
...
if((a & z) == z)
{
++e;
b[y] = '1';
}
Комуникация през C, POSIX и сериен порт
Задача Създайте програма, която да изпраща информация по-серийния порт. Свържете два компютъра със сериен кабел, като на единия изпълнявате програмата, а на другия сте включили, някоя от терминалните програми за управление на серийната връзка от предходната задача.
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#define PORTNAME "/dev/ttyS0"
int main(void)
{
int fd; // File descriptor for the port
struct termios options; // Serial port settings
fd = open( PORTNAME, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)//Could not open the port.
perror("open_port: Unable to open port");
else
fcntl(fd, F_SETFL, 0);
tcgetattr(fd, &options);
cfsetispeed(&options, B2400);
cfsetospeed(&options, B2400);
options.c_cflag |= ( CREAD);
options.c_cflag |= ( CLOCAL);
options.c_cflag &= ( ~CSTOPB);
tcsetattr(fd,TCSANOW, &options);
write(fd, "a \n", 3); //write to serial port
return 0;
}
За повече информация Управление на сериен порт с POSIX, [POSIX serial port]
Задача 1
Създайте програма с безкраен цикъл, която да изпраща една буква към серийния порт. Използвайте специално пригодения кабел и разгледайте осцилограмата на сериен сигнал.
Четене сериен порт
Raw
/****************************************************************\
* Edited by Ilianko
* Description: Raw reading of the serial port
\****************************************************************/
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BAUDRATE B2400
#define MODEMDEVICE "/dev/ttyUSB2"
int main()
{
int fd, c, res, stop = 0;
struct termios oldtio,newtio;
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {perror(MODEMDEVICE); exit(-1);}
fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
newtio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tcsetattr(fd,TCSANOW,&newtio);
tcflush(fd, TCIFLUSH);
/* loop while waiting for input. normally we would do something */
while ( stop == 0)
{
usleep(100);
fflush (stdout);
res = read(fd,buf,10);
// strcat(buf,buf2);
for( c=0; c<res; c++)
{
printf("%c", (char) buf[c]);
}
}
tcsetattr(fd,TCSANOW,&oldtio);/* restore old port settings */
return 0;
}
Canonical
/****************************************************************\
* Edited by Ilianko
* Description: Raw reading of the serial port
\****************************************************************/
#include <termios.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BAUDRATE B2400
#define MODEMDEVICE "/dev/ttyUSB2"
int main()
{
int fd, c, res, stop = 0;
struct termios oldtio,newtio;
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {perror(MODEMDEVICE); exit(-1);}
fcntl(fd, F_SETFL, 0);
fcntl(fd, F_SETFL, FNDELAY);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcsetattr(fd,TCSANOW,&newtio);
tcflush(fd, TCIFLUSH);
/* loop while waiting for input. normally we would do something */
while ( stop == 0)
{
usleep(100);
fflush (stdout);
res = read(fd,buf,10);
for( c=0; c<res; c++)
{
printf("%c", (char) buf[c]);
}
}
tcsetattr(fd,TCSANOW,&oldtio);/* restore old port settings */
return 0;
}
Самостоятелна подготовка
1. Напишете името си на латиница, преобразувайте буквите с двоичен код и създайте времева диаграма на физическия сигнал. 1. Да се напише програма, която изпраща символите от клавиатурата към серийния порт.
Край
Задача 11 Деинсталирайте GTKterm.
Упътване: Използвайте командата.
:~$ sudo apt-get purge gtkterm