使用keil5中的RL_TCPNet中间件--建立篇
来源:互联网 发布:2017淘宝实拍保护入口 编辑:程序博客网 时间:2024/06/03 16:24
前言
RL_TCPnet也算是一个比较有名的小型协议栈,相比于LwIP,它支持非常多的应用协议。并且这是ARM自家出的中间件,专门针对自家内核做过优化,性能强劲。所以学一下它非常有必要。这次搞以太网算是第二次了,去年开始尝试玩了一下,自己画了一套F107以太网开发板,但是最后是没调出来。后来发现是硬件电路画的有问题,就没接下去弄了。这次又拿起来搞,总结上次电路失败的经验,我又重新设计了一块电路板。嗯,这次是一次成功啊^_^!所以在学习网络应用之前,得首先确保你的硬件是可以用的啊,不然车底盘不稳,开的再快迟早是要翻车的呀!先上一份我做好的成品。最终学习目地是做一个串口服务器:)
硬件电路设计
嵌入式以太网接口一般有以下几种模式:
- 1.MCU内部自带MAC+PHY,比如TI的LM3S6911,此款芯片是自带MAC和PHY,外部接上RJ45接口电路就可以使用了。
- 2.MCU内部自带MAC,需要外接PHY。比如我使用的STM32F107,外接一个DP83848物理芯片和添加RJ45接口电路就可以使用了。当然PHY有很多LA8720、DM9162等都可以使用。
- 3.MCU内部既不带MAC也不带MAC和PHY,这就是一般低端的单片机了,这种情况下可以使用SPI接口网络芯片,典型的就是enc28j60。像F103不带MAC的就可以使用SPI驱动该芯片,以实现网络应用。
MAC即媒体访问控制,处于链路层的下方。MAC的作用是使设备在多节点应用中,不会引起访问冲突。
PHY即端口物理层,是OSI参考模型中的最底层。常用的PHY基本寄存器都一样,不一样的是各个厂家提供的扩展寄存器和专门设置的寄存器。所以驱动成功立一种PHY,驱动另一种PHY也就很简单。
底层驱动接口
(1)独立于介质的接口:MII
该接口有16根线,使用25MHz外部晶振驱动时钟系统。支持10Mbps和100Mbps的运行速率。
(2)精简的独立于介质的接口:RMII
RMII将标准减少到7根线,支持10Mbps和100Mbps运行速率;时钟信号需提高到50MHz;MAC和PHY需要使用同样的时钟源;使用2位宽的数据收发。
(3)DP83848的RMII应用电路
我所使用的接口就是RMII,使用该接口就没有MII那么多线看着头晕的麻烦。具体电路如下,DP83848其它的引脚功能需要自行查阅数据手册了
创建工程
在确保硬件可以使用的情况下,接下来就要开始创建工程来驱动这个PHY。自keil5发布以来,创建和使用中间件就非常方便,特别是在使用中间件的时候,省去了很多移植的花费的时间。你可能会看到我就是不停的勾选,勾选勾选,一个工程例子代码就创建好了。。。(我使用的版本是5.23,组件都是最新版本)
(1)新建UDP例子工程
1.CMSIS驱动选择
新建一个工程,创建工程名,选择芯片F107RC(具体芯片具体选择),接下来就跳到“Manage Run-Time Environment”窗口。这是重点,选好依赖整个创建过程就很快。驱动选择如下:
这里说明一下,在勾选时,选项卡变黄是因为缺少相应的依赖,依赖齐全后,就变成绿色。因为RL_TCPnet这个版本需要使用RTX,所以RTOS必选。因为我使用的是MAC+PHY,所以MAC驱动必选,PHY按所选用的芯片来选择。像其它的PHY芯片,因为基本寄存器都一样,所以可以在keil5提供的一种PHY驱动文件中来更改驱动文件,以适应自己的PHY。选择UASRT驱动是用来Debug输出时使用的。
2.STM32驱动选择
图中的DMA和GPIO是keil提供的驱动文件,目的是与CMSIS Driver相互依赖。使用STM32的标准库的GPIO是用来初始化PHY的复位引脚的。
3.STDIO调试选择
使能STDOUT后,在程序中就可以使用printf函数。keil为F1提供相应的串口驱动,所以我们不必编写相应的串口驱动程序。
4.NetWork选择
具体的选择如图所示,内核选择Debug STDIO调试版本,正式发布后可选择发行版本。接口使用的ETH,序号1表示有一个MAC物理IP.其它2个是供串行接口使用。现在这个例子不使用服务,我们使用UDP做测试。
(2)文件配置
以上工程依赖配置好后,就要添加相应的文件,配置文件了。
1.添加模板代码
鼠标右键“Source Group1”向该组增加文件。
增加UDP模板代码文件
增添stoutio模板文件
去掉main函数注释
编译一下工程,会错误提示,然后按着错误来解决相应的问题。
上图中提示出了2个错误,分别是ETH和USART找不到。那需要配置“RTE_Device.h”文件,进入此文件的配置视图模式。具体配置如下:
ETH接口有使用重映射的方式,要具体选择。系统的时钟一定不要配置错误。选择好后,再编译一次,还有一个错误 ,如下图:
这个提示是stdout_usart使用的串口号没有选择,配置如下:
因为我使用的是串口1,所以编号要选择对应的,波特率选择115200,打印速度多少会快点。
2.配置RTX
再编译一次就没啥错误了。你以为这就完了?其实还有很多。接下来配置RTX:
配置启动文件的中断调用堆栈
RTX系统配置要注意以下几点:1.RTOS kernel Timer要和系统时钟频率相同。2.RL_TCPnet在初始化时会创建2个线程,每个线程给它分配1k的栈空间,”Number of threads whith usr-provied stack size “设置为2;”Total stack size for threads whith user-provied stack size “设置2048,总共2K。待会儿调试窗口看到线程的运行状况。3.定时器线程运行栈设置为512。
中断服务程序使用堆栈介绍
RL_TCPnet在RTXv4中使用的堆栈需求
3.配置NetWork
RTX配置好后,接下来就是配置网络。
NetConfig.c配置基本上不用改。“Local Host Name”可以改成自定义。作用可以不使用IP地址就行访问。如:ping my_host 指令
Net_Config_ETH_0.h的配置:改IP地址和网关,不开启DHCP,将该线程栈设置1024。IPV6可以关掉,其它默认。
Net_Config_UDP.h配置使用默认配置5个socket
Net_Debug.c配置开启相应的服务报警,该报警有3个级别,我选择全部显示,当然也可以只选择errors 级别
4.更改必要的代码
现在大体上基本上配置完了,接下来配置一下复位脚,向udp_socket.c添加代码。注意stdio需要初始化,外部声明stdout_init(),然后在main函数进行初始化。
#include "rl_net.h"#include "GPIO_STM32F10x.h"//需要手动添加#include <stdio.h> //需要手动添加int32_t udp_sock; // UDP socket handleextern int stdout_init (void);//需要手动添加void send_udp_data (void);static void delay_ms (int ms) { ms *= (SystemCoreClock/10000); while (ms--) { __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); }} void GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure);}void PHY_Reset(void){ GPIO_ResetBits(GPIOA,GPIO_Pin_6); delay_ms(100); GPIO_SetBits(GPIOA,GPIO_Pin_6);}
更改一下例子代码,这个例子代码的作用是本地UDP接收到0x01 0xAA指令就向目标UDP回显数据。目标IP和端口是192.168.1.220:77,当然这可以自己随意改动
// Notify the user application about UDP socket events.uint32_t udp_cb_func (int32_t socket, const NET_ADDR *addr, const uint8_t *buf, uint32_t len) { // Data received if ((buf[0] == 0x01) && (len == 2)) { // Switch LEDs on and off // LED_out (buf[1]); send_udp_data(); } return (0);}// Send UDP data to destination client.void send_udp_data (void) { if (udp_sock > 0) { // IPv4 address: 192.168.0.1 NET_ADDR addr = { NET_ADDR_IP4, 77, 192, 168, 1, 220 };//可以根据自己的IP地址来 // IPv6 address: [fe80::1c30:6cff:fea2:455e]// NET_ADDR addr = { NET_ADDR_IP6, 2000,// 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// 0x1c, 0x30, 0x6c, 0xff, 0xfe, 0xa2, 0x45, 0x5e }; uint8_t *sendbuf; sendbuf = netUDP_GetBuffer (2); sendbuf[0] = 0x01; sendbuf[1] = 0xAA; netUDP_Send (udp_sock, &addr, sendbuf, 2); }}
主函数添加复位引脚初始化代码
int main (void) { stdout_init(); GPIO_Configuration(); PHY_Reset(); printf("PHY_RESET!\r\n"); netInitialize (); // Initialize UDP socket and open port 2000 udp_sock = netUDP_GetSocket (udp_cb_func); if (udp_sock > 0) { netUDP_Open (udp_sock, 2000); }}
调试
编译一下没有错误,配置一下工程,生成Hex文件就可以测试啦!
进入Debug调试模式,打开线程窗口可以看到系统创建的2个线程。如果使能其它服务,将会创建其它线程,对应的RTX的Number of Threads的相关配置要更改设置。
连接好串口,查看串口调试助手打印的信息,可以很层次的看见系统运行的情况。可以很清晰的看到,数据通信是按模型层次来一步步传递的。
打开网络调试助手,设置本地IP和远程目标IP。发送数据,就可以看到数据回显,表示通信成功
- 使用keil5中的RL_TCPNet中间件--建立篇
- Laravel 中间件建立使用
- KEIL5,STM32工程建立注意事项
- Keil5 安装使用
- Keil5无法使用Jlink
- STM32 Keil5建立工程模板步骤
- keil5
- [ActiveMQ]消息中间件在Java中的使用
- 使用中间件
- 使用keil5 搭建2440开发环境
- 使用keil5.22遇到的一个问题
- Keil5 使用C51及silicon方法
- Apache apusic---ActiveMQ中间件在JMS1.1、J2EE中的使用
- 中间件课程中的参考书
- java中的中间件
- 中间件中的基本概念
- nodejs中的中间件--Multer
- express中的static中间件
- spring Boot项目遇到的一个小问题学习到repeatable annotations
- 人工智能进小学
- Google Exoplayer之全面认识
- CNN数玉米穗--TasselNet: Counting maize tassels in the wild via local counts regression network
- 【loli的胡策】联校11.2(dp+乱搞+期望dp)
- 使用keil5中的RL_TCPNet中间件--建立篇
- 面试算法题(一)
- IOS使用pods初次加载出现Pods-resources.sh: Permission denied错误的解决方案
- SpringBoot启动时的Banner设置
- CENTOS 安装redis
- 【python】统计文件中的字符串数目
- wordpress搭建个人博客
- 查看mysql数据库连接数、并发数相关信息
- 如何将别人训练好的model用到自己的数据上----微调模型