RT-Thread—STM32—enc28j60
概述
本教程主要是講解如何使用ENC28J60模塊介入以太網
本例程的模板使用通用模板環境搭建裏面的模板RT-Thread—STM32—環境搭建
文末也有我移植好的例程,不過建議大家從頭開始移植,加深印象^_^
配置
- 打開工程目錄,在ENV下輸入menuconfig進入圖形化配置界面
- 配置SPI2
- 使用ENC28J60軟件包
- 使用lwIP 2.0.2
- 使能socket
- 使能network相關組件
- 保存配置並且退出ENV
代碼修改
- 添加
drv_enc28j60.c
,drv_enc28j60.h
,m_udp.h
,m_udp.c
文件 - 在
drv_enc28j60.c
文件中添加ENC28J60和SPI相關的初始化
#include <rtthread.h>
#include <enc28j60.h>
#include <drivers/pin.h>
#include "spi_flash.h"
#include <rtdevice.h>
#include "drv_spi.h"
#include "enc28j60.h"
#include <board.h>
#define ENC28J60_BUS "spi2"
#define ENC28J60_DEVICE "qspi20"
#define ENC28J60_CS GET_PIN(B,8)//14 // PA0 for STM32F103RC defined in drv_gpio.c
#define ENC28J60_INT GET_PIN(B,9)//15 // PA1 for STM32F103RC defined in drv_gpio.c
#define ENC28J60_RESET GET_PIN(B,10)//20 // PA4 for STM32F103RC defined in drv_gpio.c
/* 接線相關
* GND--------接地
* VCC--------接電源
* CS---------PB8(可自定義)
* INT--------PB9(可自定義)
* RST--------PB10(可自定義)
* SCK--------PB13(SPI2的SCK)
* MOSI(SI)---PB15(SPI2的MOSI)
* MISO(SO)---PB14(SPI2的MISO)
*
*/
void enc28j60_int_handler(void *args)
{
/* enter interrupt */
rt_interrupt_enter();
enc28j60_isr();
/* leave interrupt */
rt_interrupt_leave();
}
/* 設備初始化 */
static int rt_hw_enc28j60_init(void)
{
/* Configure SPI */
rt_hw_spi_device_attach("spi2", "qspi20", GPIOB, GPIO_PIN_8);
/* Configure Reset */
rt_pin_mode(ENC28J60_RESET, PIN_MODE_INPUT_PULLUP);
rt_pin_write(ENC28J60_RESET,0);
rt_thread_delay(1);
rt_pin_write(ENC28J60_RESET,1);
enc28j60_attach(ENC28J60_DEVICE);
/* Configure Interrupt */
rt_pin_mode(ENC28J60_INT, PIN_MODE_INPUT_PULLUP);
rt_pin_attach_irq(ENC28J60_INT, PIN_IRQ_MODE_FALLING, enc28j60_int_handler, (void*)"callbackargs");
rt_pin_irq_enable(ENC28J60_INT, PIN_IRQ_ENABLE);
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_enc28j60_init);
- 在
m_udp.c
文件裏面添加了通過代碼實現UDP server的簡單功能
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "m_udp.h"
#include <sys/socket.h> //使用BSD socket,需要包含sockets.h頭文件
#include <netdb.h>
#include <string.h>
#include <finsh.h>
#define BUFSZ 1024
const char send_data1[] = "I'm a client.\n"; /* 發送用到的數據 */
void thread_udp_entry(void *param)
{
int sock;
int bytes_read;
char *recv_data;
socklen_t addr_len;
struct sockaddr_in server_addr, client_addr;
/* 分配接收用的數據緩衝 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
/* 分配內存失敗,返回 */
rt_kprintf("No memory\n");
return;
}
/* 創建一個socket,類型是SOCK_DGRAM,UDP類型 */
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
rt_kprintf("Socket error\n");
/* 釋放接收用的數據緩衝 */
rt_free(recv_data);
return;
}
/* 初始化服務端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000); //設置自己的端口號
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 綁定socket到服務端地址 */
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
/* 綁定地址失敗 */
rt_kprintf("Bind error\n");
/* 釋放接收用的數據緩衝 */
rt_free(recv_data);
return;
}
addr_len = sizeof(struct sockaddr);
rt_kprintf("UDPServer Waiting for client on port 5000...\n");
while(1)
{
bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,(struct sockaddr *)&client_addr, &addr_len);
recv_data[bytes_read] = '\0';
/* 輸出接收的數據 */
rt_kprintf("\n(%s , %d) said : ", inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
rt_kprintf("%s", recv_data);
/* 發送數據 */
sendto(sock, send_data1, strlen(send_data1), 0,(struct sockaddr *)&client_addr, sizeof(struct sockaddr));
rt_thread_mdelay(500);
}
}
/* 初始化任務 */
static int m_udp_sample(void)
{
rt_thread_t tid_udp = rt_thread_create("m_udp",
thread_udp_entry,
RT_NULL,
1024,
20, 5);
if (tid_udp != RT_NULL)
{
rt_thread_startup(tid_udp);
}
}
INIT_APP_EXPORT(m_udp_sample);
測試
- 燒錄代碼,連接上網線,通過Xshell調試
- 查看自己IP
- 使用 DNS Ping 百度的服務器
- 在同一個路由下面,模擬UDP client發數據 如圖:
- 如果結果和我一樣就說明你已經成功了
- 其他的我就不做詳細解釋了。以下是我已經做好好項目的文件工程
- 鏈接:https://pan.baidu.com/s/1SGPS2tbt-vIwHDbm1UeQfg 提取碼:3e9l
小結
很多智能設備都需要接入互聯網,本節就通過ENC28J60模塊讓單片機通過有線網接入了互聯網,大家可能會問,如何通過無線WIFI接入互聯網,這裏推薦一個樂鑫的ESP8266WIF模塊.樂鑫官網
備註:提供一下個人微信號 Hleafleafleaf,歡迎加好友,共同學習!共同進步!