STM32网口数据收发
时间: 2024-12-28 07:25:27 浏览: 7
### STM32以太网接口数据收发教程
#### 使用内置MAC模块进行数据收发
对于采用STM32内部集成的以太网MAC模块的情况,通常会搭配外部PHY芯片来构成完整的物理层电路。初始化过程中需要设置DMA控制器用于高效地搬运网络帧,并启动LwIP或其他轻量级TCP/IP协议栈以便于高层应用开发。
```c
// 初始化以太网硬件资源并注册回调函数
void ETH_Init(void){
/* 配置GPIO, 使能时钟 */
// 设置Ethernet MAC和PHY之间的MII/RMII接口模式
// 启动LWIP协议栈
}
```
一旦完成了基础环境搭建,在接收到新消息时将会触发中断事件通知CPU有新的数据待处理[^1]:
```c
// 处理接收的数据包
void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth){
struct pbuf* pb;
uint8_t* buffer;
while (HAL_OK == HAL_ETH_GetReceivedFrame_IT(heth)){
// 获取接收到的数据指针
buffer = (uint8_t*) heth->RxDesc[0].Buffer1Addr;
// 创建pbuf并将原始字节数组复制进去
pb = pbuf_alloc(PBUF_RAW, heth->RxFrameInfos.length, PBUF_POOL);
memcpy(pb->payload, buffer, heth->RxFrameInfos.length);
// 调用LwIP输入函数解析并分派该数据包
ethernetif_input(&gnetif);
// 准备下一个接收描述符供下次使用
HAL_ETH_DiscardFrame(heth);
}
}
```
针对发送操作,则需先构建好欲传送的信息体再调用相应API发出请求:
```c
err_t low_level_output(struct netif *netif, struct pbuf *p){
err_t ret_err;
uint32_t framelength;
if(p != NULL){
// 计算总长度
framelength = p->tot_len;
// 将缓冲区中的内容拷贝到发送缓存里去
memcpy((uint8_t *)heth.Instance->TxDesc[tx_cur_idx].Buffer1Addr,
p->payload, framelength);
// 更新描述表项里的有效载荷大小字段
heth.Instance->TxDesc[tx_cur_idx].Status &= ~(ETH_DMATXDESC_TTSE | ETH_DMATXDESC_IC |
ETH_DMATXDESC_LS | ETH_DMATXDESC_FS |
ETH_DMATXDESC_DC | ETH_DMATXDESC_DP |
ETH_DMATXDESC_GT | ETH_DMATXDESC_LD |
ETH_DMATXDESC_JF | ETH_DMATXDESC_OS);
heth.Instance->TxDesc[tx_cur_idx].Length = framelength;
// 提交当前条目给DMA引擎执行实际传输动作
__DSB();
heth.Instance->DMATPDR = tx_cur_idx;
tx_cur_idx++;
if(tx_cur_idx >= TX_DESC_CNT) tx_cur_idx=0;
ret_err = ERR_OK;
}else{
ret_err = ERR_BUF;
}
return ret_err;
}
```
#### 利用W5500扩展以太网功能
如果选用的是基于SPI通讯方式工作的独立型SoC如W5500作为辅助器件的话,则可以按照下面的方式来进行编程设计。这里给出一段简单的例子展示怎样利用库函数完成基本的套接字创建以及读写流程[^2]:
```c
#include "wizchip_conf.h"
#include "socket.h"
#define SOCKET_NUM 0 // 套接字编号
#define SERVER_IP_ADDR {192,168,1,1} // 远程服务器IPv4地址
#define PORT 7 // UDP端口号
int main(){
char send_data[]="Hello Server!";
int recv_size;
unsigned char rx_buffer[128];
wizchip_init(); // 初始化WIZCHIP设备
setSHAR(MAC_ADDRESS); // 设定本地MAC地址
setSIPR(STA_IP_ADDR); // 设定静态IP地址
setGWR(GATEWAY_ADDR); // 默认网关
setSUBR(SUBNET_MASK); // 子网掩码
socket(SOCKET_NUM, Sn_MR_UDP, PORT, 0x00); // 打开指定类型的Socket
connect(SOCKET_NUM, SERVER_IP_ADDR, PORT); // 发起连接尝试(仅适用于TCP)
sendto(SOCKET_NUM,send_data,strlen(send_data),SERVER_IP_ADDR,PORT); // 发送UDP报文
do {
recv_size = recvfrom(SOCKET_NUM,rx_buffer,sizeof(rx_buffer)-1,(unsigned char*)&SERVER_IP_ADDR,&port);\
if(recv_size>0){ // 如果成功收到了回应...
rx_buffer[recv_size]='\0'; // 添加字符串结束标志
printf("Receive:%s\n",rx_buffer);// 输出显示所接受的内容
}
}while(recv_size<=0); // 循环直到确实获取到了返回值为止
close(SOCKET_NUM); // 关闭使用的Socket句柄
deinit_wizchip(); // 清除所有配置释放相关资源
}
```
阅读全文