stm32f407 enc28j60
时间: 2023-10-02 20:09:42 浏览: 98
STM32F407是一款基于ARM Cortex-M4内核的高性能微控制器,而ENC28J60是一款低成本、低功耗的以太网控制器芯片。在使用STM32F407和ENC28J60实现以太网通信功能时,需要进行相应的移植和配置。
首先,通过在F407临时项目中导出xml配置文件并导入到移植目标项目中,可以方便地添加所需的头文件。然后,在移植项目的"Core/Src"文件夹下添加ENC28J60的驱动文件enc28j60.c和enc28j60.h,并确保这两个文件的编码方式为UTF-8。
正点原子的ENC28J60模块有8个引脚,其中GND和V3.3用于供电,MISO/MOSI/SCK用于SPI通信,CS是片选信号,INT为中断输出引脚,RST为模块复位信号。请注意,如果使用的模块是10引脚的,需要注意不能直接连接到Mini开发板。
对于STM32F407自带的以太网mac模块,通常只需外挂一个PHY芯片即可实现以太网物理层。结合lwIP协议栈,可以实现基本的以太网通信功能。
相关问题
stm32f103c8t6 enc28j60 实现UDP
实现UDP通信需要以下步骤:
1. 初始化ENC28J60,包括配置寄存器、设置MAC地址、设置接收和发送缓冲区等。
2. 配置STM32F103C8T6的GPIO和SPI接口,使其能够与ENC28J60进行通信。
3. 实现UDP数据包的发送和接收功能。发送UDP数据包需要构造UDP数据包头,并向目标IP地址发送数据包;接收UDP数据包需要在接收缓冲区中查找UDP数据包头,并从中读取数据。
下面是一个简单的实现UDP通信的代码示例:
```c
#include "enc28j60.h"
#include "udp.h"
#include "stm32f10x.h"
// 初始化ENC28J60
void enc28j60_init(void)
{
// 配置寄存器
enc28j60_write_op(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
while(enc28j60_read_op(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY);
enc28j60_write_op(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_AUTOINC);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXSTL, 0x00);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXSTH, 0x00);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXNDL, ENC28J60_RX_END);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXNDH, ENC28J60_RX_END >> 8);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXRDPTL, 0x00);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXRDPTH, 0x00);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXFCON, ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_PMEN);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, EPMM0, 0x3f);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, EPMCSL, 0xf9);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MACON2, 0x00);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR1, ENC28J60_MACADDR1);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR2, ENC28J60_MACADDR2);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR3, ENC28J60_MACADDR3);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR4, ENC28J60_MACADDR4);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR5, ENC28J60_MACADDR5);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAADR6, ENC28J60_MACADDR6);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAMXFLL, ENC28J60_MAX_FRAMELEN);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, MAMXFLH, ENC28J60_MAX_FRAMELEN >> 8);
// 设置接收和发送缓冲区
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXSTL, (ENC28J60_RX_START));
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXSTH, (ENC28J60_RX_START) >> 8);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXRDPTL, (ENC28J60_RX_START));
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, ERXRDPTH, (ENC28J60_RX_START) >> 8);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, RXEN, 1);
enc28j60_write_op(ENC28J60_WRITE_CTRL_REG, TXRTSCTRL, TXRTSCTRL_RTSB0 | TXRTSCTRL_RTSOE | TXRTSCTRL_RTSEN);
}
// 发送UDP数据包
void udp_send_packet(uint8_t *data, uint16_t len, uint16_t src_port, uint16_t dst_port, uint8_t *dst_mac, uint8_t *dst_ip)
{
uint16_t checksum;
uint16_t total_len = len + UDP_HEADER_LEN;
// 计算UDP伪头部校验和
checksum = ip_checksum_add(0, (uint8_t *)&enc28j60_macaddr, 6);
checksum = ip_checksum_add(checksum, dst_mac, 6);
checksum = ip_checksum_add(checksum, (uint8_t *)&total_len, 2);
checksum = ip_checksum_add(checksum, (uint8_t *)&src_port, 2);
checksum = ip_checksum_add(checksum, (uint8_t *)&dst_port, 2);
checksum = ip_checksum_add(checksum, data, len);
// 构造UDP数据包头
udp_header_t udp_header;
udp_header.src_port = htons(src_port);
udp_header.dst_port = htons(dst_port);
udp_header.len = htons(total_len);
udp_header.checksum = htons(checksum);
// 发送UDP数据包
enc28j60_packet_t packet;
memcpy(packet.eth.dst, dst_mac, 6);
memcpy(packet.eth.src, enc28j60_macaddr, 6);
packet.eth.type = htons(ETHERTYPE_IP);
packet.ip.version = 0x45;
packet.ip.tos = 0x00;
packet.ip.id = htons(0x1234);
packet.ip.flags_offset = htons(0x4000);
packet.ip.ttl = 0x80;
packet.ip.protocol = IP_PROTOCOL_UDP;
memcpy(packet.ip.src, enc28j60_ipaddr, 4);
memcpy(packet.ip.dst, dst_ip, 4);
packet.ip.len = htons(total_len + IP_HEADER_LEN);
memcpy(packet.payload, &udp_header, UDP_HEADER_LEN);
memcpy(packet.payload + UDP_HEADER_LEN, data, len);
enc28j60_send_packet(packet, total_len + UDP_HEADER_LEN + IP_HEADER_LEN);
}
// 接收UDP数据包
uint16_t udp_receive_packet(uint8_t *data, uint16_t max_len, uint16_t *src_port, uint16_t *dst_port, uint8_t *src_ip)
{
enc28j60_packet_t packet;
uint16_t len;
while(1)
{
// 从接收缓冲区中读取一个数据包
len = enc28j60_receive_packet(&packet, sizeof(packet));
// 如果数据包不是UDP数据包,则丢弃
if(packet.ip.protocol != IP_PROTOCOL_UDP)
continue;
// 如果目标IP地址不是本机,则丢弃
if(memcmp(packet.ip.dst, enc28j60_ipaddr, 4) != 0)
continue;
// 如果目标端口不是本机监听的端口,则丢弃
if(ntohs(packet.udp.dst_port) != UDP_PORT)
continue;
// 如果数据包长度超过最大长度,则截断
if(len > max_len + UDP_HEADER_LEN)
len = max_len + UDP_HEADER_LEN;
// 从UDP数据包中读取数据
memcpy(data, packet.payload + UDP_HEADER_LEN, len - UDP_HEADER_LEN);
*src_port = ntohs(packet.udp.src_port);
*dst_port = ntohs(packet.udp.dst_port);
memcpy(src_ip, packet.ip.src, 4);
return len - UDP_HEADER_LEN;
}
}
```
在上面的代码中,`enc28j60.h`和`udp.h`分别定义了ENC28J60和UDP相关的常量和数据结构。函数`enc28j60_init`用于初始化ENC28J60,函数`udp_send_packet`用于发送UDP数据包,函数`udp_receive_packet`用于接收UDP数据包。注意,在发送UDP数据包时需要计算UDP伪头部校验和。在接收UDP数据包时需要判断数据包是否为UDP数据包,并且目标IP地址和目标端口是否匹配。
阅读全文