|
全能小网关|CH32V208--6、板载ETH功能初体验
[复制链接]
WCHNET协议库
随着物联网的普及,越来越多的单片机系统需要用到网络通讯。 WCHNET 芯片自带以太网 MAC,部分芯片有内置 10M PHY,支持 10M 以太网(部分芯片还支持 100M/1000M 速率),全双工,半双工,自动协商,线路自动转换等功能,可以直接和网络终端如 PC,嵌入式设备进行数据交互。WCHNET 协议栈库提供了 TCP/IP 子程序库,集成了 TCP、UDP、ARP、RARP、ICMP、IGMP等以太网协议栈,可以同时支持 TCP、UDP 和 IPRAW 三种模式。
库函数
WCHNET的库其实并没有多复杂,也只是提供一些简单的功能,实现一些TCP/IP的简单应用是不错的。例如socket,http服务,mqtt应用等等。 但是如果想实现更多的功能,例如sntp校时,websocket服务,grpc服务等等应用,还是需要考虑类似lwip这些使用更广泛的库。
运行DHCP例程
这段代码演示了如何使用WCH提供的以太网库进行DHCP操作,获取IP地址,并创建TCP连接。
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2022/05/20
* Description : Main program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
*@Note
DHCP example, demonstrating that DHCP automatically obtains an IP address.
For details on the selection of engineering chips,
please refer to the "CH32V20x Evaluation Board Manual" under the CH32V20xEVT\EVT\PUB folder.
*/
#include "string.h"
#include "eth_driver.h"
u8 MACAddr[6];
u8 IPAddr[4] = {0, 0, 0, 0};
u8 GWIPAddr[4] = {0, 0, 0, 0};
u8 IPMask[4] = {0, 0, 0, 0};
u8 DESIP[4] = {192, 168, 1, 100};
u16 desport = 1000;
u16 srcport = 1000;
u8 SocketId;
u8 SocketRecvBuf[WCHNET_MAX_SOCKET_NUM][RECE_BUF_LEN];
u8 MyBuf[RECE_BUF_LEN];
* @fn mStopIfError
*
* <a href="https://bbs.eeworld.com.cn/home.php?mod=space&uid=159083" target="_blank">@brief</a> check if error.
*
* @param iError - error constants.
*
* <a href="https://bbs.eeworld.com.cn/home.php?mod=space&uid=784970" target="_blank">@return</a> none
*/
void mStopIfError(u8 iError)
{
if (iError == WCHNET_ERR_SUCCESS)
return;
printf("Error: %02X\r\n", (u16) iError);
}
* @fn TIM2_Init
*
* @brief Initializes TIM2.
*
* @return none
*/
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
NVIC_SetPriority(TIM2_IRQn, 0x80);
NVIC_EnableIRQ(TIM2_IRQn);
}
* @fn WCHNET_CreateTcpSocket
*
* @brief Create TCP Socket
*
* @return none
*/
void WCHNET_CreateTcpSocket(void)
{
u8 i;
SOCK_INF TmpSocketInf;
memset((void *) &TmpSocketInf, 0, sizeof(SOCK_INF));
memcpy((void *) TmpSocketInf.IPAddr, DESIP, 4);
TmpSocketInf.DesPort = desport;
TmpSocketInf.SourPort = srcport++;
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN;
i = WCHNET_SocketCreat(&SocketId, &TmpSocketInf);
printf("WCHNET_SocketCreat %d\r\n", SocketId);
mStopIfError(i);
i = WCHNET_SocketConnect(SocketId);
mStopIfError(i);
}
* @fn WCHNET_DataLoopback
*
* @brief Data loopback function.
*
* @param id - socket id.
*
* @return none
*/
void WCHNET_DataLoopback(u8 id)
{
#if 1
u8 i;
u32 len;
u32 endAddr = SocketInf[id].RecvStartPoint + SocketInf[id].RecvBufLen;
if ((SocketInf[id].RecvReadPoint + SocketInf[id].RecvRemLen) > endAddr) {
len = endAddr - SocketInf[id].RecvReadPoint;
}
else {
len = SocketInf[id].RecvRemLen;
}
i = WCHNET_SocketSend(id, (u8 *) SocketInf[id].RecvReadPoint, &len);
if (i == WCHNET_ERR_SUCCESS) {
WCHNET_SocketRecv(id, NULL, &len);
}
#else
u32 len, totallen;
u8 *p = MyBuf, TransCnt = 255;
len = WCHNET_SocketRecvLen(id, NULL);
printf("Receive Len = %d\r\n", len);
totallen = len;
WCHNET_SocketRecv(id, MyBuf, &len);
while(1){
len = totallen;
WCHNET_SocketSend(id, p, &len);
totallen -= len;
p += len;
if( !--TransCnt ) break;
if(totallen) continue;
break;
}
#endif
}
* @fn WCHNET_HandleSockInt
*
* @brief Socket Interrupt Handle
*
* @param socketid - socket id.
* intstat - interrupt status
*
* @return none
*/
void WCHNET_HandleSockInt(u8 socketid, u8 intstat)
{
if (intstat & SINT_STAT_RECV)
{
WCHNET_DataLoopback(socketid);
}
if (intstat & SINT_STAT_CONNECT)
{
WCHNET_ModifyRecvBuf(socketid, (u32) SocketRecvBuf[socketid], RECE_BUF_LEN);
printf("TCP Connect Success\r\n");
}
if (intstat & SINT_STAT_DISCONNECT)
{
printf("TCP Disconnect\r\n");
}
if (intstat & SINT_STAT_TIM_OUT)
{
printf("TCP Timeout\r\n");
WCHNET_CreateTcpSocket();
}
}
* @fn WCHNET_HandleGlobalInt
*
* @brief Global Interrupt Handle
*
* @return none
*/
void WCHNET_HandleGlobalInt(void)
{
u8 intstat;
u16 i;
u8 socketint;
intstat = WCHNET_GetGlobalInt();
if (intstat & GINT_STAT_UNREACH)
{
printf("GINT_STAT_UNREACH\r\n");
}
if (intstat & GINT_STAT_IP_CONFLI)
{
printf("GINT_STAT_IP_CONFLI\r\n");
}
if (intstat & GINT_STAT_PHY_CHANGE)
{
i = WCHNET_GetPHYStatus();
if (i & PHY_Linked_Status)
printf("PHY Link Success\r\n");
}
if (intstat & GINT_STAT_SOCKET) {
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
socketint = WCHNET_GetSocketInt(i);
if (socketint)
WCHNET_HandleSockInt(i, socketint);
}
}
}
* @fn WCHNET_DHCPCallBack
*
* @brief DHCPCallBack
*
* @param status - status returned by DHCP
* 0x00 - Success
* 0x01 - Failure
* arg - Data returned by DHCP
*
* @return DHCP status
*/
u8 WCHNET_DHCPCallBack(u8 status, void *arg)
{
u8 *p;
u8 tmp[4] = {0, 0, 0, 0};
if(!status)
{
p = arg;
printf("DHCP Success\r\n");
if(!memcmp(IPAddr, p ,sizeof(IPAddr)))
return READY;
if(memcmp(IPAddr, tmp ,sizeof(IPAddr))){
* then disconnect the last connection.*/
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
memcpy(IPAddr, p, 4);
memcpy(GWIPAddr, &p[4], 4);
memcpy(IPMask, &p[8], 4);
printf("IPAddr = %d.%d.%d.%d \r\n", (u16)IPAddr[0], (u16)IPAddr[1],
(u16)IPAddr[2], (u16)IPAddr[3]);
printf("GWIPAddr = %d.%d.%d.%d \r\n", (u16)GWIPAddr[0], (u16)GWIPAddr[1],
(u16)GWIPAddr[2], (u16)GWIPAddr[3]);
printf("IPMask = %d.%d.%d.%d \r\n", (u16)IPMask[0], (u16)IPMask[1],
(u16)IPMask[2], (u16)IPMask[3]);
printf("DNS1: %d.%d.%d.%d \r\n", p[12], p[13], p[14], p[15]);
printf("DNS2: %d.%d.%d.%d \r\n", p[16], p[17], p[18], p[19]);
WCHNET_CreateTcpSocket();
return READY;
}
else
{
printf("DHCP Fail %02x \r\n", status);
if(memcmp(IPAddr, tmp ,sizeof(IPAddr))){
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
return NoREADY;
}
}
* @fn main
*
* @brief Main program
*
* @return none
*/
int main(void)
{
u8 i;
Delay_Init();
USART_Printf_Init(115200);
printf("DHCP Test\r\n");
if((SystemCoreClock == 60000000) || (SystemCoreClock == 120000000))
printf("SystemClk:%d\r\n", SystemCoreClock);
else
printf("Error: Please choose 60MHz and 120MHz clock when using Ethernet!\r\n");
printf("net version:%x\n", WCHNET_GetVer());
if( WCHNET_LIB_VER != WCHNET_GetVer()){
printf("version error.\n");
}
WCHNET_GetMacAddr(MACAddr);
printf("mac addr:");
for(i = 0; i < 6; i++)
printf("%x ", MACAddr<i>);
printf("\n");
TIM2_Init();
WCHNET_DHCPSetHostname("WCHNET");
i = ETH_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr);
mStopIfError(i);
if(i == WCHNET_ERR_SUCCESS)
printf("WCHNET_LibInit Success\r\n");
WCHNET_DHCPStart(WCHNET_DHCPCallBack);
while(1)
{
* which needs to be called cyclically*/
WCHNET_MainTask();
* if there is an interrupt, call the global interrupt handler*/
if(WCHNET_QueryGlobalInt())
{
WCHNET_HandleGlobalInt();
}
}
}
运行程序
运行程序后,插入网线,并重启设备,等待10秒左右,可以看到设备已获取到IP地址,如下图
在电脑上使用ps shell来ping板子,可以看到可以顺利连上板子
WCH官方库调用起来是挺简单的,官方给的demo也很好,可以快速帮开发者熟悉网络库的使用,整体体验下来还是挺舒服的。
|
|