Урок 71
Часть 2
LAN. ENC28J60. ARP
В предыдущей части урока мы настроили проект, поправили ошибки прошлого занятия, вынесли функции реализации протокола ARP в отдельный модуль и создали обработчик прерываний USART на приём.
Теперь начнём обрабатывать результат, своевременно меняя все статусы, и в конце вызовем приём из USART
b = str[0];
//если вдруг случайно превысим длину буфера
if (usartprop.usart_cnt>20)
{
usartprop.usart_cnt=0;
}
else if (b == 'a')
{
usartprop.is_ip=1;//статус отрпавки ARP-запроса
}
else
{
usartprop.usart_buf[usartprop.usart_cnt] = b;
usartprop.usart_cnt++;
}
HAL_UART_Receive_IT(&huart1,(uint8_t*)str,1);
}
Я думаю, тут и объяснять нечего, так всё ясно. То что строк много, это ничего, я просто везде использовал фигурные скобки независимо от количества строк кода, так как пока мы работаем только с ARP, а в последствии, я думаю подтянутся другие протоколы, соответственно появятся статусы и нам не придется ничего добавлять, то есть для простоты написания будущего кода. А символ «a» мы отслеживаем для того, что введенную строку мы будем им заканчивать, чтобы как-то отследить окончание данной строки. То есть мы будем в терминале вводить IP-адрес устройства, MAC-адрес которого мы хотим узнать.
Теперь отловим изменение статуса в функции net_poll, создав в ней для начала локальный четырехэлементный массив
uint16_t len;
uint8_t ip[4]={0};
Далее после приёма очередного пакета мы в этой функции начнём следить за статусом
eth_read(frame,len);
}
if (usartprop.is_ip==1) //статус отправки ARP-запроса
{
HAL_UART_Transmit(&huart1,usartprop.usart_buf,usartprop.usart_cnt,0x1000);
HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,0x1000);
usartprop.is_ip = 0;
usartprop.usart_cnt=0;
}
}
Заодно мы здесь выведем в терминал строку, принятую из него же и опять обнулим все наши статусы для того, чтобы нормально ждать следующую строку из USART.
Давайте соберём код, прошьём контроллер и попробуем что-то ввести в терминальную программу
Как видим, у нас всё получилось. Мы вводим на данный момент ip-адрес нашего ПК или какой-то другой и получаем его в нашей программе в виде строки.
Но запрос ARP посылать мы пока не сможем, так как нам теперь нужно из строки преобразовать данный адрес в четырехэлементный беззнаковый целочисленный массив.
Для этого добавим в этом же модуле соответствующую функцию где-то над функцией eth_read, добавив в неё сразу несколько локальных переменных. Результат функции будет записываться по адресу ipextr
//-----------------------------------------------
//функция преобразования строкового значения IP в 32-битное числовое
void ip_extract(char* ip_str,uint8_t len, uint8_t* ipextr)
{
uint8_t offset = 0;
uint8_t i;
char ss2[5] = {0};
char *ss1;
int ch = '.';
}
//--------------------------------------------------
Теперь пробежим по функции на предмет появления точек
int ch = '.';
for(i=0;i<3;i++)
{
ss1 = strchr(ip_str,ch);
}
Опять мы используем новую интересную функцию, которая следит за вхождением символа в строке, добавленной в качестве первого аргумента, а затем возвращает адрес в памяти вхождения данного символа. Только нам удобнее работать не с адресом а со смещением относительно начала строки с IP-адресом, поэтому вычислим это смещение
ss1 = strchr(ip_str,ch);
offset = ss1-ip_str+1;
Затем мы скопируем ещё в одну строку часть нашей строки до точки, а затем закончим её нулём, как того просит функция, которую мы будем использовать далее
offset = ss1-ip_str+1;
strncpy(ss2,ip_str,offset);
ss2[offset]=0;
А далее мы, преобразовав вышесозданную строку в число, запишем его в соответствующий элемент массива для адреса
ss2[offset]=0;
ipextr[i] = atoi(ss2);
Далее мы соответствующим образом сдвинем указатели нашей строки с IP-адресом и длины этой строки, а затем выйдем из цикла for
ipextr[i] = atoi(ss2);
ip_str+=offset;
len-=offset;
}
Теперь, выйдя из цикла мы уже работаем с последним байтом IP-адреса, после которого уже точки нет и также записываем его в соответствующий элемент возвращаемого массива адреса IP
len-=offset;
}
strncpy(ss2,ip_str,len);
ss2[len]=0;
ipextr[3] = atoi(ss2);
}
Продолжим писать тело функции net_pool, используя вышенаписанную функцию, вставив код в соответствующее место в этой функции, также здесь мы выведем результат нашей функции в порт USART в целях проверки правильности написания кода вышенаписанной функции
HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,0x1000);
ip_extract((char*)usartprop.usart_buf,usartprop.usart_cnt,ip);
sprintf(str1,"%d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
Давайте это проверим, собрав код и прошив контроллер и затем введя такую же строку, какую и вводили, в терминальной программе
Функция прекрасно работает.
Теперь перейдём в файл arp.с и начнём писать там функцию отправки ARP-запроса, так как для этого у нас теперь всё готово
//-----------------------------------------------
uint8_t arp_request(uint8_t *ip_addr)
{
uint8_t i;
return 1;
}
//--------------------------------------------------
Добавим прототип этой функции и вызовем её в net.c в функции net_pool. Вызов функции напишем вместо отправки ip-адреса в USART, он нам там уже не нужен, так как это была просто проверка работы функции преобразования строкового значения IP-адреса в целочисленный массив
sprintf(str1,"%d.%d.%d.%d\r\n", ip[0],ip[1],ip[2],ip[3]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
arp_request(ip);
Также зайдём в файл net.h и добавим там макросы для нулевого и широковещательного MAC-адресов
#define IP_ADDR {192,168,1,197}
#define MAC_BROADCAST {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}
#define MAC_NULL {0x00,0x00,0x00,0x00,0x00,0x00}
//--------------------------------------------------
В следующей части урока мы отправим запрос ARP, а также начнём писать функцию заполнения таблицы ARP.
Предыдущий урок Программирование МК STM32 Следующая часть
Техническая документация:
Документация на микросхему ENC28J60
Перечень ошибок ENC28J60 (Errata)
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN Сетевой Модуль.
Переходник USB to TTL можно приобрести здесь ftdi ft232rl
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Добавить комментарий