Во-первых для передачи на сервер некоторого числового значения (значений) никакие адаптеры не нужны.
Atmega8 может сама передавать на сервер числовые значения.
Всё это делали в прошлой теме.
https://www.radiokot.ru/forum/viewtopic ... start=1529Вообще это отдельная большая интересная тема. Когда доделаем надо будет написать по этой теме статью))
Разобраться с W5500 не сложно.
W5500_client+Atmega8 - такое уже делали.
Потом все переделали на W5500_server))
https://www.radiokot.ru/forum/viewtopic ... &start=452Просто W5500_client оказался никому не нужен))
Собственно вся работа с W5500 сводится к записи чтению регистров (согласно даташиту).
План такой:
Берём Atmega8.
Припаиваем к Atmega8 модуль W5500 по SPI.
Открываем даташит. Читаем описание регистров.
Пишем программу например на Си в Atmel Studio или в CodeVisionAVR (кому как удобно).
Прошиваем Atmega8 любым программатором.
Смотрим в анализаторе трафика (например Wireshark) как бегают пакеты.
Всё))
понимании работы (хотя бы на самом минимальном уровне) сетевого модуля W5500
Разберём подробно))
как реализовать инициализацию, проверку подключения к серверу, открытие_закрытие соединения ( и вообще как это все и многое другое и необходимое делается и в каком порядке ) я не знаю.
Очень просто))
Подключаем W5500 к Atmega8 согласно схеме.
- SPI.jpg
- (38.01 KiB) Скачиваний: 380
Далее инициализация W5500.
Для инициализации W5500 нам надо прописать регистры.
По SPI передаём пакеты байтов.
Формат пакета - адрес, контрольный байт (режим чтения/записи, формат), байты данных.
W5500 поддерживает несколько форматов чтения/записи. Формат определяет контрольный байт.
Выбираем формат переменной длины.
Далее W5500 состоит из двух частей - физический уровень (PHY) и логический уровень (процессор, память, регистры и т.д.).
Настраиваем физический уровень W5500.
Пример кода программы:
//Сначала делаем общий сброс (RESET) W5500.
PORTB.7=0; //
delay_ms(100); //
PORTB.7=1; //
delay_ms(100); //
//Потом настраиваем PHY.
/////////////////////////////////////////////// сброс PHY:
// перед настройкой PHY сделать программный Cброс PHY:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x2E; SPI(); tx=0x04; SPI(); // Address + Control Registers
tx=0x00; SPI(); // Data -0x00
tx=0x00; SPI(); // Data -0x00
PORTB.6=1; // SS W5500
/////////////////////////////////////////////// пишем режим PHY:
// 1... .... RST - 1.
// .1.. .... программная настройка режима - 1
// ..0. .... 10BT Full-duplex, Auto-negotiation disabled / Power Down mode
// ...0 .... 10BT Full-duplex, Auto-negotiation disabled / Power Down mode
// .... 1... 10BT Full-duplex, Auto-negotiation disabled / Power Down mode
// .... .1.. Duplex Status
// .... ..0. Speed Status
// .... ...1 Link Status
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x2E; SPI(); tx=0x04; SPI(); // Address + Control Registers
tx=0xC8; SPI(); // Data -0xC8 (10 Мбит/с, Full-duplex)
tx=0x00; SPI(); // Data -0x00
PORTB.6=1; // SS W5500
/////////////////////////////////////////////// читаем статус PHY: (это по желанию)
//PORTB.6=0; // SS W5500
//tx2=0x00; SPI2(); tx2=0x2E; SPI2(); tx2=0x00; SPI2(); // Address + Control Registers
//tx2=0x00; SPI2(); x1 = rx2; // Data
//tx2=0x00; SPI2(); x2 = rx2; // Data
//PORTB.6=1; // SS W5500
// При чтении регистра PHY (адрес 0x2E) ответ будет -0xCD00
// Значит W5500 подключился к роутеру или компу по сетевому проводу.
// загорелся жёлтый светодиод.
// зелёный светодиод мигает только в момент приёма и отправки пакетов.
- 1.jpg
- (32.86 KiB) Скачиваний: 342
// Линк поднялся.
Далее настраиваем логический уровень W5500.
Память W5500 состоит из блоков. Главный регистр управления W5500 и 8 штук сокетов.
Размер блоков можно менять но нам это не нужно))
Находим главный регистр управления W5500 (блок номер 0)
Вот он подробно расписан
записываем в него шлюз, маску, IP, MAC:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x04; SPI(); // Address + Control Registers
// -шлюз
tx=192; SPI(); // Gateway Address (GAR0) (0x0001 - Address)
tx=168; SPI(); // Gateway Address (GAR1) (0x0002 - Address)
tx=0; SPI(); // Gateway Address (GAR2) (0x0003 - Address)
tx=1; SPI(); // Gateway Address (GAR3) (0x0004 - Address)
// -маска
tx=255; SPI(); // Subnet Mask Address (SUBR0) (0x0005 - Address)
tx=255; SPI(); // Subnet Mask Address (SUBR1) (0x0006 - Address)
tx=255; SPI(); // Subnet Mask Address (SUBR2) (0x0007 - Address)
tx=0; SPI(); // Subnet Mask Address (SUBR3) (0x0008 - Address)
// -MAC (Wiznet_01:02:03)
tx=0x00; SPI(); // Source Hardware Address (SHAR0) (0x0009 - Address)
tx=0x08; SPI(); // Source Hardware Address (SHAR1) (0x000A - Address)
tx=0xDC; SPI(); // Source Hardware Address (SHAR2) (0x000B - Address)
tx=0x01; SPI(); // Source Hardware Address (SHAR3) (0x000C - Address)
tx=0x02; SPI(); // Source Hardware Address (SHAR4) (0x000D - Address)
tx=0x03; SPI(); // Source Hardware Address (SHAR5) (0x000E - Address)
// -IP
tx=192; SPI(); // Source IP Address (SIPR0) (0x000F - Address)
tx=168; SPI(); // Source IP Address (SIPR1) (0x0010 - Address)
tx=0; SPI(); // Source IP Address (SIPR2) (0x0011 - Address)
tx=3; SPI(); // Source IP Address (SIPR3) (0x0012 - Address)
PORTB.6=1; // SS W5500
// W5500 на пинг отвечает.
Добавлено after 8 minutes 31 second:Далее открываем сокет.
Например откроем сокет номер 2.
Для этого надо прописать регистр сокета номер 2.
Регистр сокета номер 2 находится в блоке 0x09.
Вот он подробно расписан
записываем в него протокол TCP и порт (например стандартный порт для браузера 80):
// Протокол: пишем протокол TCP Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x00; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x01; SPI(); // Data -0x01 (protocol TCP).
PORTB.6=1; // SS W5500
// Порт: пишем Socket_2 Source Port:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x04; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x00; SPI(); // Data -0x00 (порт 00)
tx=0x50; SPI(); // Data -0x50 (порт 80)
PORTB.6=1; // SS W5500
//Далее надо открыть сокет номер 2.
//Работать с сокетами надо с помощью команд.
//Для этого пишем команду OPEN сокет номер 2.
// пишем команду OPEN Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x01; SPI(); // Data -0x01 (OPEN)
PORTB.6=1; // SS W5500
//Далее, если у нас W5500_strver, то надо переключить сокет номер 2 в режим прослушивания.
//Для этого пишем команду LISTEN сокет номер 2.
// пишем команду LISTEN Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x02; SPI(); // Data -0x02 (LISTEN)
PORTB.6=1; // SS W5500
//Все команды есть в даташите.
//Далее сидим и ждём пока к нашему W5500_strver кто-то подключится..... например браузер ))
Socket_2_LISTEN:
/////////////////////////////////////////////////////////////////////////////////////////////
// читаем статус Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x03; SPI(); tx=0x48; SPI(); // Address + Control Registers
tx=0x00; SPI(); x1 = rx; // Data -0x14 (SOCK_LISTEN)
PORTB.6=1; // SS W5500
///////////////////////////////////////////////////////// Socket_2_LISTEN: (Ждём SYN):
//Статус сокета:))
//0x14-LISTEN, 0x16-SYN, 0x17-ESTABLISHED, 0x11-DISCON,
//0x1C-CLOSE_WAIT, 0x18-FIN_WAIT, 0x00-FIN/ACK.
if (x1 != 0x14) goto Socket_2_ESTABLISHED; // > Socket_2_ESTABLISHED
goto Socket_2_LISTEN; // > Socket_2_LISTEN
/////////////////////////////////////////////////////////////////////////////////////////////
// Когда сокет изменит свой статус на 0x17-ESTABLISHED, значит к нашему W5500_strver кто-то подключился)).
// Тут осторожней... Тут бывают ещё разные ошибки подключения и т .д.
// Если подключение прошло успешно (Т.е. W5500 получил пакет SYN от браузера, отправил пакет SYN ACK браузеру и получил ACK от браузера) статус сокета номер 2 изменится на 0x17-ESTABLISHED.
// Если всё нормально, то далее переходим в режим приёма/отправки пакетов - ESTABLISHED:
Socket_2_ESTABLISHED:
delay_ms(1);
/////////////////////////////////////////////////////////////////////////////////////////////
// Читаем размер принятых данных Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x26; SPI(); tx=0x48; SPI(); // Address + Control Registers
tx=0x00; SPI(); x1 = rx; // Data -Sn_RX_RSR0 -размер принятых данных
tx=0x00; SPI(); x2 = rx; // Data -Sn_RX_RSR1 -размер принятых данных
PORTB.6=1; // SS W5500
//////////////////////////////////////////////////////////// таймаут FIFO_RX Socket_2:
tm_SOCKET++;
if (tm_SOCKET > 1000) { // цикл - 1c ждём Data
goto Socket_2_DISCON; // FIFO_RX пуст > Socket_2_DISCON
//goto TX_Socket_2; // > TX, FIN
};
/////////////////////////////////////////////////////////////////////////////////////////////
// проверка FIFO_RX:
len = x1; len = (len<<8)|x2; // размер принятых данных // 0x0000
if (len == 0x00) goto Socket_2_ESTABLISHED; // FIFO_RX пуст > ждём Data
//RX_Socket_2:
///////////////////////////////////////////////////////////////////////////////////////////// приём пакета:
// Читаем начальный адрес принятых данных Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x28; SPI(); tx=0x48; SPI(); // Address + Control Registers
tx=0x00; SPI(); x1 = rx; // Data -Sn_RX_RD0 -начальный адрес принятых данных
tx=0x00; SPI(); x2 = rx; // Data -Sn_RX_RD1 -начальный адрес принятых данных
PORTB.6=1; // SS W5500
// начальный адрес принятых данных Socket_2:
add = x1; add = (add<<8)|x2; // 0x0000
/////////////////////////////////////////////////////////////////////////////////////////////
// Читаем данные с начального адреса Socket_2:
x1 = (add>>8);
x2 = add;
PORTB.6=0; // SS W5500
tx=x1; SPI(); tx=x2; SPI(); tx=0x58; SPI(); // Address + Control Registers
////////////////////////////////////////// Data RX W5500:
for (x=0; x<8; x++) {
tx=0; SPI(); bufer_RX_W5500[x] = rx;
};
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
// Пишем указатель RX Socket_2 до увеличенного значения:
add = add + len; //add - начальный адрес принятых данных // 0x0000
//len - размер принятых данных // 0x0000
x1 = (add>>8);
x2 = add;
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x28; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=x1; SPI(); // Data -Sn_RX_RD0 -конечный адрес принятых данных
tx=x2; SPI(); // Data -Sn_RX_RD1 -конечный адрес принятых данных
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
// Пишем команду завершение приема Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x40; SPI(); // Data -0x40 (RECV)
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
//Приём закончен.
//Пакет в буфере bufer_RX_W5500[x] Atmega8 ))
//Дальше надо что-то ответить тому кто к нам подключился... а то не удобно... Кто-то (браузер) ждёт от нас ответа))
//Передача пакета браузеру:
//TX_Socket_2:
/////////////////////////////////////////////////////////////////////////////////////////////
// Читаем начальный адрес для записи данных Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x24; SPI(); tx=0x48; SPI(); // Address + Control Registers
tx=0x00; SPI(); x1 = rx; // Data -Sn_TX_WR0 -начальный адрес для записи данных
tx=0x00; SPI(); x2 = rx; // Data -Sn_TX_WR1 -начальный адрес для записи данных
PORTB.6=1; // SS W5500
// начальный адрес для записи данных:
add = x1; add = (add<<8)|x2; // 0x0000
/////////////////////////////////////////////////////////////////////////////////////////////
// начальный адрес для записи данных:
x1 = (add>>8);
x2 = add;
// Пишем данные Socket_2 с начального адреса:
PORTB.6=0; // SS W5500
tx=x1; SPI(); tx=x2; SPI(); tx=0x54; SPI(); // Address + Control Registers
// сброс len
len = 0; // 0x0000
////////////////////////////////////////// Data TX W5500 HTTP (например отправим текстовую страницу для браузера):
//GET / HTTP/1.1
//unsigned char bufer_TX_W5500_HTTP[]={
//"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n>|"
//};
//bufer_TX_W5500_HTTP
for (x=0; bufer_TX_W5500_HTTP[x] != '|' ; x++) {
tx=bufer_TX_W5500_HTTP[x]; SPI(); len++;
};
////////////////////////////////////////// GET /1 HTTP/1.1
if (bufer_RX_W5500[5] == '1') {
////////////////////////////////////////// Data TX W5500:
for (x=0; x<30 ; x++) {
//////////////////////////////////////// перенос строка \r\n
tx='<'; SPI(); len++;
tx='b'; SPI(); len++;
tx='r'; SPI(); len++;
tx='>'; SPI(); len++;
//////////////////////////////////////// счёт x > HEX > DEC > 000
bi = x;
z=0; while (bi>99) {z++; bi=bi-100;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
z=0; while (bi>9) {z++; bi=bi-10;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
z=0; while (bi) {z++; bi=bi-1;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
//////////////////////////////////////// пробел
tx=' '; SPI(); len++;
//////////////////////////////////////// RX_int[x] > HEX > DEC > 000
bi = RX_int[x];
z=0; while (bi>99) {z++; bi=bi-100;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
z=0; while (bi>9) {z++; bi=bi-10;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
z=0; while (bi) {z++; bi=bi-1;}; // LED(z+48);
tx=z+48; SPI(); len++; // HEX
/////////////////////////////////////////
};
};
/////////////////////////////////////////// Data END
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
// Пишем указатель TX Socket_2 до увеличенного значения:
add = add + len; // add - конечный адрес переданных данных // 0x0000
// len - размер переданных данных // 0x0000
x1 = (add>>8);
x2 = add;
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x24; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=x1; SPI(); // Data -Sn_TX_WR0 -конечный адрес передачи данных
tx=x2; SPI(); // Data -Sn_TX_WR1 -конечный адрес передачи данных
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
// Пишем команду передачи Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x20; SPI(); // Data -0x20 (SEND)
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
//if (Sn_CR == 0x00); // По окончанию передачи регистр -Sn_CR будет = 0x00.
//Передача закончена.
//Далее, если передавать ничего не будем, то закрываем соединение с браузером.
//Передаем пакет FIN браузеру:
Socket_2_DISCON:
/////////////////////////////////////////////////////////////////////////////////////////////
// передаем FIN:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x08; SPI(); // Data -0x08 (DISCON)
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
tm_SOCKET = 0; // сброс таймаут Socket_2 (FIN)
//Ждём подтверждения (пакет FIN/ACK) от браузера:
Socket_2_FIN:
/////////////////////////////////////////////////////////////////////////////////////////////
// читаем статус Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x03; SPI(); tx=0x48; SPI(); // Address + Control Registers
tx=0x00; SPI(); x1 = rx; // Data -0x00 (FIN/ACK получен)
PORTB.6=1; // SS W5500
///////////////////////////////////////////////////////////////////////////////// DISCON:
// Статус сокета -0x18 SOCK_FIN_WAIT -сокет закрывается > -0x00 FIN/ACK получен
if (x1 == 0x00) goto Socket_2_CLOSE;// FIN/ACK получен > Socket_2_CLOSE
////////////////////////////////////////////// таймаут SOCKET_1_DISCON:
tm_SOCKET++; // таймаут Socket_2 (FIN)
if (tm_SOCKET > 1000) { // цикл - 1c ждём FIN/ACK
goto Socket_2_CLOSE; // нет FIN/ACK > Socket_2_CLOSE
};
/////////////////////////////////////////////////////////////////////////////////////////////
delay_ms(1);
goto Socket_2_FIN; // > Socket_2_FIN (Ждём FIN/ACK)
// Далее... по желанию. Можно закрыть сокет номер 2.
// А можно не закрывать.
// Допустим Закрываем сокет:
Socket_2_CLOSE:
tm_SOCKET = 0; // сброс таймаут SOCKET (FIN)
/////////////////////////////////////////////////////////////////////////////////////////////
// закрываем Socket_2:
PORTB.6=0; // SS W5500
tx=0x00; SPI(); tx=0x01; SPI(); tx=0x4C; SPI(); // Address + Control Registers
tx=0x10; SPI(); // Data -0x10 (CLOSE)
PORTB.6=1; // SS W5500
/////////////////////////////////////////////////////////////////////////////////////////////
// Далее... по желанию. Можно опять открыть сокет номер 2.
goto Socket_2_OPEN; // > Socket_2_OPEN
А если у нас W5500_client, то надо переключить сокет номер 2 в режим подключения к серверу - команда CONNECT .
Просто в начале добавить в программу команду CONNECT.
В этом случае W5500_client сам отправит пакет SYN серверу и будет ждать пакет SYN/ACK и после отправит ACK - т.е. сам установит с сервером соединение.
Затем сокет номер 2 перейдёт в режим ESTABLISHED.
Остальное всё тоже самое ))
Кратко вот.