环境:


开发环境:MDK5.23


rt-thread版本:2.1.0


lwip版本:1.4.1


单片机型号:stm32f407


phy芯片型号:


说明:

本程序是udp客户端模块。绑定固定端口进行收发。udp接收是一个线程,接收到数据利用邮箱机制推送到其他处理模块。udp发送提供了多种发送接口。


源码:

udp_socket.h

/**

* Copyright (c), 2015-2025

* @file udp_socket.h

* @brief udp端口头文件

* @author jdh

* @verbatim 

* Change Logs:

* Date           Author       Notes

* 2017-12-22     jdh          新建

* @endverbatim 

*/

 

#ifndef _UDP_SOCKET_H_

#define _UDP_SOCKET_H_

 

#include "drivers.h"

 

/**

* @brief 最大注册邮箱数

*/

 

#define MAX_NUM_UDP_SOCKET_MAILBOX  10

 

/**

* @brief 接收数据结构.邮箱会推送此结构指针

*/

 

struct UdpSocketRx

{

    T_Buffer_Large buffer;

    struct sockaddr_in sockaddr;

};

 

/**

* @brief 模块载入

*/

 

void udp_socket_load(void);

 

/**

* @brief 更新服务器信息

*/

 

void udp_socket_update_server_info(void);

 

/**

* @brief socket是否工作

* @return true: 工作.false: 不工作

*/

 

bool udp_socket_is_work(void);

 

/**

* @brief 发送数据

* @param data:发送数据存放地址

* @param size:发送数据字节数

* @param dst_ip: 目的ip

* @param dst_port: 目的端口

*/

 

void udp_socket_tx(uint8_t *data, uint16_t size, char *dst_ip, uint16_t dst_port);

 

/**

* @brief 发送数据

* @param data:发送数据存放地址

* @param size:发送数据字节数

* @param sockaddr: 目的地址

*/

 

void udp_socket_tx_sockaddr(uint8_t *data, uint16_t size, struct sockaddr_in sockaddr);

 

/**

* @brief 发送数据给服务器

* @param data:发送数据存放地址

* @param size:发送数据字节数

*/

 

void udp_socket_tx_server(uint8_t *data, uint16_t size);

 

/**

* @brief 发送数据给配置服务器

* @note 配置服务器无效则发送给服务器

* @param data:发送数据存放地址

* @param size:发送数据字节数

*/

 

void udp_socket_tx_config_server(uint8_t *data, uint16_t size);

 

/**

* @brief 注册邮箱

* @note 接收数据后会推送到此邮箱

* @param mailbox: 邮箱地址

*/

 

void udp_socket_register_mailbox(rt_mailbox_t mailbox);

 

/**

* @brief 增加传输层头后发送数据

* @param dst_device: 目标设备类型

* @param data: 发送数据存放地址

* @param size: 发送数据字节数

* @param sockaddr: 目的地址

*/

 

void udp_socket_tx_sockaddr_add_trans_head(uint8_t dst_device, uint8_t *data, uint16_t size, struct sockaddr_in sockaddr);

 

/**

* @brief 发送确认帧

* @param dst_device: 目标设备类型

* @param cmd: 确认帧命令字

* @param ack_cmd: 需要确认的命令

* @param sockaddr: 目的地址

*/

 

void udp_socket_tx_sockaddr_ack_frame(uint8_t dst_device, uint8_t cmd, uint8_t ack_cmd, struct sockaddr_in sockaddr);

 

/**

* @brief 增加传输层头后发送数据

* @param dst_device: 目标设备类型

* @param data: 发送数据存放地址

* @param size: 发送数据字节数

* @param sockaddr: 目的地址

*/

 

void udp_socket_tx_server_add_trans_head(uint8_t dst_device, uint8_t *data, uint16_t size);

 

/**

* @brief 发送确认帧

* @param dst_device: 目标设备类型

* @param cmd: 确认帧命令字

* @param ack_cmd: 需要确认的命令

* @param sockaddr: 目的地址

*/

 

void udp_socket_tx_server_ack_frame(uint8_t dst_device, uint8_t cmd, uint8_t ack_cmd);

 

#endif 

udp_socket.c

/**

* Copyright (c), 2015-2025

* @file udp_socket.c

* @brief udp端口主文件

* @author jdh

* @verbatim 

* Change Logs:

* Date           Author       Notes

* 2017-12-22     jdh          新建

* 2017-12-26     jdh          增加网络和lwip功能

* @endverbatim 

*/

 

#include "framework.h"

#include "stm32f4xx_eth.h"

#include

 

#define TAG                     "LOG_UDP"

 

/**

* @brief 配置帧超时时间.单位:ms.超过这个时间,射频模块的回复就不会再发向配置服务器

*/

 

#define CONFIG_TIMEOUT          500

 

/**

* @brief 启动稳定期.单位:ms

*/

 

#define STARTUP_WAIT_TIME       1000

 

/**

* @brief 日志项编号

*/

 

static uint8_t _log_item = 0;

 

static int _socket;

static bool _is_net_work = false;

static struct sockaddr_in _server_addr;

static struct UdpSocketRx _udp_socket_rx;

 

/**

* @brief 配置服务器的地址

*/

 

static struct sockaddr_in _config_server_addr;

static T_Time _last_config_frame_time;

 

/**

* @brief 邮箱数组

*/

 

static struct rt_mailbox *_mailbox_array[MAX_NUM_UDP_SOCKET_MAILBOX];

static uint8_t _len_mailbox_array = 0;

 

/**

* @brief 发送数据

*/

 

static T_Buffer_Large Buffer_Tx;

 

static void thread_init(void* parameter);

static void init_lwip(void);

static void set_ip(void);

static void bind_socket(void);

static void socket_rx(void);

static bool is_frame_valid(void);

static inline void send_mailbox(void);

 

/**

* @brief 模块载入

*/

 

void udp_socket_load(void)

{

    _log_item = log_register(TAG);

    

#ifdef RT_USING_LWIP

    rt_thread_t tid_init = rt_thread_create("init_net",

thread_init, (void*)0,

THREAD_STACK_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_SLICE_NORMAL);

rt_thread_startup(tid_init);

#endif

}

 

static void thread_init(void* parameter)

{   

    init_lwip();

    udp_socket_update_server_info();

    bind_socket();

    socket_rx();

}

 

static void init_lwip(void)

{

    /* LwIP Initialization */

    {

        extern void lwip_sys_init(void);

 

        /* register ethernetif device */

        eth_system_device_init();

 

//        rt_hw_stm32_eth_init();

        rt_hw_stm32_eth_init_my();

 

        /* init lwip system */

        lwip_sys_init();

        rt_kprintf("TCP/IP initialized!n");

    }

    

    set_ip();

}

 

static void set_ip(void)

{

    set_if("e0", para_manage_read_ip(), para_manage_read_gateway(), para_manage_read_mask());

    set_dns(para_manage_read_dns());

}

 

/**

* @brief 更新服务器信息

*/

 

void udp_socket_update_server_info(void)

{

    _server_addr.sin_family = AF_INET;

_server_addr.sin_port = htons(para_manage_read_server_port());

struct hostent *host;

host = (struct hostent *)gethostbyname(para_manage_read_server_ip());

_server_addr.sin_addr = *((struct in_addr *)host->h_addr);

rt_memset(&(_server_addr.sin_zero), 0, sizeof(_server_addr.sin_zero));

}

 

static void bind_socket(void)

{

    struct sockaddr_in local_addr;

    

    // 创建socket

    if ((_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)

    {

        log_w(_log_item, "socket errorn");

        // todo

        return;

    }

    

    // 初始化本地地址

    local_addr.sin_family = AF_INET;

    local_addr.sin_port = htons(para_manage_read_port());

    local_addr.sin_addr.s_addr = INADDR_ANY;

    rt_memset(&(local_addr.sin_zero), 0, sizeof(local_addr.sin_zero));

    

    // 绑定端口

    if (bind(_socket, (struct sockaddr *)&local_addr, sizeof(struct sockaddr)) == -1)

    {

        log_w(_log_item, "Bind errorn");

        // todo 

        return;

    }

    

    thread_delay(STARTUP_WAIT_TIME);

    _is_net_work = true;

}

 

static void socket_rx(void)

{

    rt_uint32_t addr_len;

    

    addr_len = sizeof(struct sockaddr);

    

    while (1)

{

        _udp_socket_rx.buffer.len = recvfrom(_socket, 

                                             _udp_socket_rx.buffer.buf, 

                                             LEN_BUFFER_LARGE - 1, 

                                             0, (struct sockaddr *)&_udp_socket_rx.sockaddr, &addr_len);

        

        if (is_frame_valid())

        {   

            log_i(_log_item, "udp rx ip:%s port:%02dn", inet_ntoa(_udp_socket_rx.sockaddr.sin_addr.s_addr), 

                                                     ntohs(_udp_socket_rx.sockaddr.sin_port));

            

            if (_udp_socket_rx.buffer.buf[PTH_DST_DEVICE_POS] == DEVICE_STATION)

            {

                // 发送给本机

                send_mailbox();

            }

            else

            {

                // 转发

                uart_tx(_udp_socket_rx.buffer.buf[PTH_ADDITIONAL_POS], _udp_socket_rx.buffer.buf, _udp_socket_rx.buffer.len);

                

                // 保存配置服务器信息

                if (_udp_socket_rx.buffer.buf[PTH_DST_DEVICE_POS] == DEVICE_TIME_MODULE || 

                    _udp_socket_rx.buffer.buf[PTH_DST_DEVICE_POS] == DEVICE_RADIO_MODULE)

                {

                    _config_server_addr = _udp_socket_rx.sockaddr;

                    _last_config_frame_time = get_local_time();

                }

            }

            

[1] [2] [3]
关键字:rt-thread  udp客户端  stm32f407 引用地址:基于rt-thread的udp客户端

上一篇:配置rt-thread中的lwip模块
下一篇:设计单片机日志系统

推荐阅读

两年前,波士顿动力的人形机器人Atlas还需要一条大的安全绳来拖着它沿着平坦的路线前进。五年前,它需要一个大的栓接支撑结构来保持直立。现在,它可以漫不经心地跃起、越过障碍,要知道这个动作可以让许多人气喘吁吁。该公司在12日早上发布的视频中展示了Atlas的新技能:Atlas显示越过了一根木头,然后一路向前,跳上了一组40厘米的台阶。虽然让一个巨大...
近年来,随着电商、快递行业的迅猛增长及智慧物流的深入推进,带动了移动机器人行业的蓬勃发展。新的移动机器人公司如雨后春笋般快速增长,并得到了资本的青睐。据不完全统计,2012年国内生产移动机器人本体的企业在20家以内,2015年12月达到了60家左右,2018年超过了120家企业,增长速度惊人。 生产移动机器人企业爆发式增长的背后,得益于移动机器人...
通过串口助手控制led,还有加了蜂鸣器,也有响声,不过不是太大,一点学习,希望大家多指教。#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器typedef unsigned int u16; //对数据类型进行声明定义typedef unsigned char u8;sbit beep=P1^5;void delay(u16 i){ while(i--);}/*************...
广告摘要声明广告10月8日下午,新时达苏州办事处开业典礼在苏州南师大科技园隆重举行。此次苏州办事处的成立,预示着新时达在补强及拉通销售网络、增强本地客户服务能力方面,将开启新的进程。新时达董事、总经理武玉会,副总经理兼运控事业部总经理王刚志,众为兴总经理徐建生等公司领导出席本次开业庆典,与现场嘉宾、办事处工作人员共同见证了这一里程...

史海拾趣

问答坊 | AI 解惑

TT50短信透明收发模块

TT50短信透明收发模块特点    ●无需用户掌握GSM和SMS方面的知识,无需复杂编程,无需编码转换,通过串口透明收发中英文手机短信。      短时间内开发出稳定、可靠的基于GSM手机短信通讯的设备。 ...…

查看全部问答∨

第四届(1999年)全国大学生电子设计竞赛题目

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 …

查看全部问答∨

线材在设备中使用简介

针对动力线(三相)、讯号线、IO线、特殊电源线简介 共通点: 线材本身就是阻抗体,为何电线会发烫发热?为何会有压降?为何会耗电? 都是电阻造成的。此阻抗来自何处? 1、 自身材料(金、银、铜、铝、锡) 传输系数(导电率)—金最佳、最贵 ...…

查看全部问答∨

有些关于LM358的中文资料

本帖最后由 paulhyde 于 2014-9-15 04:17 编辑 关于LM358的资料 Lm358内部包括两个独立的、高增益、内部频率补偿的双运算放大器,适合于电源电压范围很宽的单电源使用,也适用于双电源工作模式,再推荐工作条件下,电源电流与电源电压无关,它的 ...…

查看全部问答∨

GPS导航电子地图如何更新升级

导航电子地图众所周知为GPS导航的核心和根本,导航地图更新和升级乃是导航地图生命线,甚至是GPS导航产品存活的标准。我国GPS导航市场经过几年的发展,现在关于导航地图的升级问题越来越来严重,成为导航电子地图商的一大难题。    &nbs ...…

查看全部问答∨

HIVE-BASE+FAT?

如何实现FAT配置注册表实现自动化分区功能,因为我的EBOOT没有分区功能,但又想实现HIVE-BASE+FAT? 环境:S3C2410+NAND(64)+RAM(64)…

查看全部问答∨

vc2005开发的智能设备ocx如何能在pc下vc2005智能设备下测试?

vc2005开发的智能设备ocx如何能在pc下vc2005智能设备下测试? …

查看全部问答∨

关于LQFP144的STM32,可以画成2层板吗?

关于LQFP144的STM32,可以画成2层板吗? 1。我参考一些开发板,大都是4层的,当然它板子尺寸比较小,而且采用0603封装。 我问做产品的,也是4层,抗干扰。 2。但是我的板子由于接插件较多,所以板子尺寸为200*250mm, 电路也不是很复杂,所 ...…

查看全部问答∨

告诉大家一个良好习惯

5分钟点击一次保存,每次工作项目文件夹做两次备份!不管是软件设计还是硬件设计,还是神马的,反正打开软件了就得养成良好习惯5分钟点一次保存,最好一闲下来手痒就点保存,保存,另存,存~~~~~~~~~~~~~~~~~~…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved