更新,目前修复的BUG(下面源码已改)
- 加入了订阅的逻辑,发现了一个BUG,参考下面修改
https://bbs.21ic.com/icview-3016440-1-2.html - 若出现
SINT_STAT_DISCONNECT 无法重新联网,改成Transport_Open 即可 - 没有发心跳包,所以导致掉线重连,这里周期性调用
MQTT_Pingreq 即可(我这里主循环里面时间不准,之后可以放定时器) - 将MAC作为 Client ID ,因为这个CID必须是唯一的,否则会被提下线,username 和密码我就随便设置了
- 加入检查入网逻辑,若60秒没连平台成功,重启
- 加入心跳回复检查,若10秒没收到心跳回复,重启
- 加入看门狗逻辑
一、前言
好久没写博客了,最近比较忙,这次分享一个CH579的组合例子 其实也觉得比较奇怪。。。DHCP感觉是必须的,DNS感觉也是,应该和TCP应用组合在一起才对。。分开来给例子,挺那个的。
二、为何选CH579
- 价格太香了,随便放个图片,不是打广告
- 看一下外设情况
- 总结一下,6鸡,白菜价,引脚多,外设强,就拿来搞以太网都比W5500香
三、资料获取
- 软件(官网地址):https://www.wch.cn/products/CH579.html
- 硬件(立创开源了原厂的开发板):https://oshwhub.com/staunchheart/ch579
这里注意一下:用以太网,必须使用外部32M;若不使用DC-DC,电感部分电路可以直接短接;2个网口灯注意使用EVK的引脚; 所以只用以太网的最小系统就出来了:(注意3.3V的10UF电容必须有,否则在获取DHCP时会不停复位,上电也会复位几次,应该是电压被拉低导致的)
四、参考程序
- 先看看example的目录,对于我们来说,平时都是
DHCP 搭配DNS 搭配使用的,这里分开来,所以我整合了一下 - 分别使用了
DHCP_Client ,MQTT ,DNS 这3个例子
五、程序重点
-
对于库的使用,可以参考CH57xNET协议栈库说明.pdf -
main.c 里面跑了协议栈的主任务函数,并且使用了一个10ms的定时器,这里例子就有对应的注释
int main(void)
{
UINT8 ip[4],i = 0;
UINT8 dns_flag = 0;
SystemClock_UART1_init();
GetMacAddr(MACAddr);
i = CH57xNET_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr);
mStopIfError(i);
PRINT("CH57xNETLibInit Success\r\n");
Timer0Init( 10000 );
NVIC_EnableIRQ(ETH_IRQn);
while ( CH57xInf.PHYStat < 2 ) {
DelayMs(50);
}
PRINT("CH579 DNS client create!\r\n");
while(1)
{
CH57xNET_MainTask();
if(CH57xNET_QueryGlobalInt())CH57xNET_HandleGlobalInt();
if( dns_flag == 0 ){
i = DnsQuery(SocketId,url_dn3,ip);
if(i){
dns_flag = 1;
if( i == 1 ){
PRINT("Domain name:%s \n",url_dn3);
PRINT(" HTTPs_IP=%d.%d.%d.%d\n\n",ip[0],ip[1],ip[2],ip[3]);
}
}
}
}
}
-
上电后的逻辑:上电后建立DNS的UDP(只需调用一次)–>开启DHCP–>DNS拿到IP–>将此IP复制到TCP的Socket参数中–>建立TCP–>建立MQTT 这里比较需要注意的是:SOCKET建立后,其实并不需要自己重新关闭什么的,例子已经帮我们做好了重连操作了;DNS也是,对于插入网口后,只需要使用一次DNS即可,所以在程序中,DNS的SOCKET和MQTT的SOCKET,都是建立了一次后,就不需要自己操作断开什么的了。 -
插拔网口逻辑:拔网口–>GINT_STAT_PHY_CHANGE 01–>使用CH57xNET_DHCPStop()关闭DHCP–>插入网口–>GINT_STAT_PHY_CHANGE 02–>使用CH57xNET_DHCPStart(CH57xNET_DHCPCallBack)重新开启DHCP–>TCPtimeout或者disconnect–>DHCP完成–>TCPtimeout或者disconnect–>自动重连 没太理解的,可以看下这个LOG
六、源码
注意点:
- dns.c和dns.h放到mqtt例子中
- 下面的程序替换掉MQTT_Pub.c
- 将dns.c里面的
status 替换成dns_status ,因为dns.c里面的status和dhcp里面的status冲突了
#include <stdio.h>
#include <string.h>
#include "CH57x_common.h"
#include "core_cm0.h"
#include "CH57xNET.H"
#include "MQTTPacket.H"
#include "dns.h"
#define KEEPLIVE_ENABLE 1
__align(16)UINT8 CH57xMACRxDesBuf[(RX_QUEUE_ENTRIES )*16];
__align(4) UINT8 CH57xMACRxBuf[RX_QUEUE_ENTRIES*RX_BUF_SIZE];
__align(4) SOCK_INF SocketInf[CH57xNET_MAX_SOCKET_NUM];
UINT16 MemNum[8] = {CH57xNET_NUM_IPRAW,
CH57xNET_NUM_UDP,
CH57xNET_NUM_TCP,
CH57xNET_NUM_TCP_LISTEN,
CH57xNET_NUM_TCP_SEG,
CH57xNET_NUM_IP_REASSDATA,
CH57xNET_NUM_PBUF,
CH57xNET_NUM_POOL_BUF
};
UINT16 MemSize[8] = {CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_IPRAW_PCB),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_UDP_PCB),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_TCP_PCB),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_TCP_PCB_LISTEN),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_TCP_SEG),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_IP_REASSDATA),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_PBUF) + CH57xNET_MEM_ALIGN_SIZE(0),
CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_PBUF) + CH57xNET_MEM_ALIGN_SIZE(CH57xNET_SIZE_POOL_BUF)
};
__align(4)UINT8 Memp_Memory[CH57xNET_MEMP_SIZE];
__align(4)UINT8 Mem_Heap_Memory[CH57xNET_RAM_HEAP_SIZE];
__align(4)UINT8 Mem_ArpTable[CH57xNET_RAM_ARP_TABLE_SIZE];
#define RECE_BUF_LEN 536
UINT8 MACAddr[6] = {0x84,0xc2,0xe4,0x02,0x03,0x04};
UINT8 MACAddr_Str[20];
UINT8 IPAddr[4] = {192,168,1,200};
UINT8 GWIPAddr[4]= {192,168,1,1};
UINT8 IPMask[4] = {255,255,255,0};
UINT8 DESIP[4] = {58,213,74,190};
UINT16 aport=1000;
UINT16 CH57xNET_LEDCONN=0x0010;
UINT16 CH57xNET_LEDDATA=0x0080;
char *username = "123";
char *password = "123";
char *sub_topic = "tt456";
char *pub_topic = "tt123";
UINT8 SocketId;
UINT8 SocketRecvBuf[RECE_BUF_LEN];
UINT8 MyBuf[RECE_BUF_LEN];
UINT8 con_flag=0;
UINT8 pub_flag=1;
UINT8 sub_flag=0;
UINT8 tout_flag=0;
UINT16 packetid=0;
UINT8 dns_status;
extern UINT8 dns_buf[512];
UINT8 dhcp_ok = 1;
UINT8 dns_flag = 0;
#define MAX_URL_SIZE 128
UINT8 url_dn3[MAX_URL_SIZE] = "test.mosquitto.org";
UINT16 check_heart;
UINT16 check_conn;
void ETH_IRQHandler( void )
{
CH57xNET_ETHIsr();
}
void TMR0_IRQHandler( void )
{
CH57xNET_TimeIsr(CH57xNETTIMEPERIOD);
R8_TMR0_INT_FLAG |= 0xff;
}
void mStopIfError(UINT8 iError)
{
if (iError == CH57xNET_ERR_SUCCESS) return;
PRINT("mStopIfError: %02X\r\n", (UINT16)iError);
}
UINT8 Transport_Open()
{
UINT8 i;
SOCK_INF TmpSocketInf;
memset((void *)&TmpSocketInf,0,sizeof(SOCK_INF));
memcpy((void *)TmpSocketInf.IPAddr,DESIP,4);
TmpSocketInf.DesPort = 1883;
TmpSocketInf.SourPort = aport++;
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
TmpSocketInf.RecvStartPoint = (UINT32)SocketRecvBuf;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN ;
i = CH57xNET_SocketCreat(&SocketId,&TmpSocketInf);
mStopIfError(i);
i = CH57xNET_SocketConnect(SocketId);
mStopIfError(i);
return SocketId;
}
UINT8 Transport_Close()
{
UINT8 i;
i=CH57xNET_SocketClose(SocketId,TCP_CLOSE_NORMAL);
mStopIfError(i);
return i;
}
void UDPSocketParamInit(UINT8 S,UINT8 *addr,UINT16 SourPort,UINT16 DesPort )
{
UINT8 i;
SOCK_INF TmpSocketInf;
memset((void *)&TmpSocketInf,0,sizeof(SOCK_INF));
memcpy((void *)TmpSocketInf.IPAddr,addr,4);
TmpSocketInf.DesPort = DesPort;
TmpSocketInf.SourPort = SourPort;
TmpSocketInf.ProtoType = PROTO_TYPE_UDP;
TmpSocketInf.RecvStartPoint = (UINT32)SocketRecvBuf;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN ;
i = CH57xNET_SocketCreat(&S,&TmpSocketInf);
mStopIfError(i);
}
void Transport_SendPacket(UINT8 *buf,UINT32 len)
{
UINT32 totallen;
UINT8 *p=buf;
totallen=len;
while(1)
{
len = totallen;
CH57xNET_SocketSend(SocketId,p,&len);
totallen -= len;
p += len;
if(totallen)continue;
break;
}
}
void MQTT_Connect(char *username,char *password)
{
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
UINT32 len;
UINT8 buf[200];
data.clientID.cstring = MACAddr_Str;
PRINT("MQTT_Connect clientID:%s\r\n",data.clientID.cstring);
data.keepAliveInterval = 20;
data.cleansession = 1;
data.username.cstring = username;
data.password.cstring = password;
len=MQTTSerialize_connect(buf,sizeof(buf),&data);
Transport_SendPacket(buf,len);
}
void MQTT_Subscribe( char *topic)
{
MQTTString topicString = MQTTString_initializer;
int req_qos=0;
UINT32 len;
UINT32 msgid=1;
UINT8 buf[200];
topicString.cstring=topic;
len=MQTTSerialize_subscribe(buf,sizeof(buf),0,msgid,1,&topicString,&req_qos);
Transport_SendPacket(buf,len);
}
void MQTT_Unsubscribe(char *topic)
{
MQTTString topicString = MQTTString_initializer;
UINT32 len;
UINT32 msgid=1;
UINT8 buf[200];
topicString.cstring=topic;
len=MQTTSerialize_unsubscribe(buf,sizeof(buf),0,msgid,1,&topicString);
Transport_SendPacket(buf,len);
}
void MQTT_Publish(char *topic,char *payload)
{
MQTTString topicString = MQTTString_initializer;
UINT32 payloadlen;
UINT32 len;
UINT8 buf[1024];
topicString.cstring=topic;
payloadlen=strlen(payload);
len= MQTTSerialize_publish(buf,sizeof(buf),0,0,0,packetid++,topicString,payload,payloadlen);
Transport_SendPacket(buf,len);
}
void MQTT_Pingreq()
{
UINT32 len;
UINT8 buf[200];
len=MQTTSerialize_pingreq(buf,sizeof(buf));
Transport_SendPacket(buf,len);
}
void MQTT_Disconnect()
{
UINT32 len;
UINT8 buf[50];
len=MQTTSerialize_disconnect(buf,sizeof(buf));
Transport_SendPacket(buf,len);
}
void CH57xNET_CreatTcpSocket(void)
{
UINT8 i;
SOCK_INF TmpSocketInf;
memset((void *)&TmpSocketInf,0,sizeof(SOCK_INF));
memcpy((void *)TmpSocketInf.IPAddr,DESIP,4);
TmpSocketInf.DesPort = 1000;
TmpSocketInf.SourPort = 2000;
TmpSocketInf.ProtoType = PROTO_TYPE_TCP;
TmpSocketInf.RecvStartPoint = (UINT32)SocketRecvBuf;
TmpSocketInf.RecvBufLen = RECE_BUF_LEN ;
i = CH57xNET_SocketCreat(&SocketId,&TmpSocketInf);
mStopIfError(i);
#ifdef KEEPLIVE_ENABLE
CH57xNET_SocketSetKeepLive( SocketId, 1 );
#endif
i = CH57xNET_SocketConnect(SocketId);
mStopIfError(i);
i = CH57xNET_SetSocketTTL( SocketId,10 );
mStopIfError(i);
}
#ifdef KEEPLIVE_ENABLE
void net_initkeeplive(void)
{
struct _KEEP_CFG klcfg;
klcfg.KLIdle = 20000;
klcfg.KLIntvl = 10000;
klcfg.KLCount = 5;
CH57xNET_ConfigKeepLive(&klcfg);
}
#endif
UINT8 CH57xNET_LibInit( UINT8 *ip, UINT8 *gwip, UINT8 *mask, UINT8 *macaddr)
{
UINT8 i;
struct _CH57x_CFG cfg;
if(CH57xNET_GetVer() != CH57xNET_LIB_VER)return 0xfc;
CH57xNETConfig = LIB_CFG_VALUE;
cfg.RxBufSize = RX_BUF_SIZE;
cfg.TCPMss = CH57xNET_TCP_MSS;
cfg.HeapSize = CH57x_MEM_HEAP_SIZE;
cfg.ARPTableNum = CH57xNET_NUM_ARP_TABLE;
cfg.MiscConfig0 = CH57xNET_MISC_CONFIG0;
CH57xNET_ConfigLIB(&cfg);
i = CH57xNET_Init(ip,gwip,mask,macaddr);
#ifdef KEEPLIVE_ENABLE
net_initkeeplive( );
#endif
return (i);
}
void CH57xNET_HandleSockInt(UINT8 sockeid,UINT8 initstat)
{
UINT32 len;
UINT8 i;
unsigned char* dup;
unsigned short* packetid;
int qos;
unsigned char* retained;
MQTTString topicName;
unsigned char* payload;
int payloadlen;
unsigned char *p=payload;
if(initstat & SINT_STAT_RECV)
{
len = CH57xNET_SocketRecvLen(sockeid,NULL);
PRINT("Receive Len = %02x\r\n",len);
if (len > 0)
{
if((sockeid==0)&&(dns_status ==3))
{
PRINT("enter rece int!dns_status=3\r\n");
CH57xNET_SocketRecv(sockeid,dns_buf,&len);
dns_status = 4;
i = CH57xNET_SocketClose( sockeid,TCP_CLOSE_NORMAL );
mStopIfError(i);
PRINT("dns_status = 4!\r\n");
}
else
{
CH57xNET_SocketRecv(sockeid,MyBuf,&len);
PRINT("data:");
check_heart = 0;
for(i=0;i<len;i++)
{
PRINT("%02x ",MyBuf[i]);
}
PRINT("\r\n");
switch(MyBuf[0]>>4)
{
case FLAG_CONNACK:
PRINT("connack\r\n");
MQTT_Subscribe(sub_topic);
con_flag=1;
break;
case FLAG_PUBLISH:
MQTTDeserialize_publish(dup,&qos,retained,packetid,&topicName,&payload,&payloadlen,MyBuf,len);
PRINT("payloadlen=%d\r\n",(UINT16)payloadlen);
p=payload;
for(i=0;i<payloadlen;i++)
{
PRINT("%c ",(UINT16)*p);
p++;
}
PRINT("\r\n");
break;
case FLAG_SUBACK:
sub_flag=1;
PRINT("suback\r\n");
break;
default:
break;
}
}
}
}
if(initstat & SINT_STAT_CONNECT)
{
PRINT("TCP Connect Success\r\n");
MQTT_Connect(username, password);
}
if(initstat & SINT_STAT_DISCONNECT)
{
PRINT("TCP Disconnect\n");
Transport_Open();
}
if(initstat & SINT_STAT_TIM_OUT)
{
PRINT("TCP Timout\n");
Transport_Open();
}
}
UINT8 CH57xNET_DHCPCallBack(UINT8 status,void *arg)
{
UINT8 *p;
if(!status){
p = arg;
PRINT("DHCP Success\r\n");
memcpy(IPAddr,p,4);
memcpy(GWIPAddr,&p[4],4);
memcpy(IPMask,&p[8],4);
PRINT("IPAddr = %d.%d.%d.%d \r\n",(UINT16)IPAddr[0],(UINT16)IPAddr[1],
(UINT16)IPAddr[2],(UINT16)IPAddr[3]);
PRINT("GWIPAddr = %d.%d.%d.%d \r\n",(UINT16)GWIPAddr[0],(UINT16)GWIPAddr[1],
(UINT16)GWIPAddr[2],(UINT16)GWIPAddr[3]);
PRINT("IPAddr = %d.%d.%d.%d \r\n",(UINT16)IPMask[0],(UINT16)IPMask[1],
(UINT16)IPMask[2],(UINT16)IPMask[3]);
PRINT("DNS1: %d.%d.%d.%d\r\n",p[12],p[13],p[14],p[15]);
PRINT("DNS2: %d.%d.%d.%d\r\n",p[16],p[17],p[18],p[19]);
dns_status = 1;
}
else{
PRINT("DHCP Fail %02x\n",status);
}
return 0;
}
void CH57xNET_HandleGlobalInt(void)
{
UINT8 initstat;
UINT8 i;
UINT8 socketinit;
initstat = CH57xNET_GetGlobalInt();
if(initstat & GINT_STAT_UNREACH)
{
PRINT("UnreachCode :%d\r\n",CH57xInf.UnreachCode);
PRINT("UnreachProto :%d\r\n",CH57xInf.UnreachProto);
PRINT("UnreachPort :%d\r\n",CH57xInf.UnreachPort);
}
if(initstat & GINT_STAT_IP_CONFLI)
{
}
if(initstat & GINT_STAT_PHY_CHANGE)
{
i = CH57xNET_GetPHYStatus();
PRINT("GINT_STAT_PHY_CHANGE %02x\r\n",i);
if(i == 2)
{
CH57xNET_DHCPStart(CH57xNET_DHCPCallBack);
}
else
{
CH57xNET_DHCPStop();
con_flag = 0;
MQTT_Disconnect();
}
}
if(initstat & GINT_STAT_SOCKET)
{
for(i = 0; i < CH57xNET_MAX_SOCKET_NUM; i ++)
{
socketinit = CH57xNET_GetSocketInt(i);
if(socketinit)CH57xNET_HandleSockInt(i,socketinit);
}
}
}
void Timer0Init(UINT32 time)
{
R8_TMR0_CTRL_MOD = RB_TMR_ALL_CLEAR;
R8_TMR0_CTRL_MOD = 0;
R32_TMR0_CNT_END = FREQ_SYS/1000000*time;
R8_TMR0_INT_FLAG = R8_TMR0_INT_FLAG;
R8_TMR0_INTER_EN = RB_TMR_IE_CYC_END;
R8_TMR0_CTRL_MOD |= RB_TMR_COUNT_EN;
NVIC_EnableIRQ(TMR0_IRQn);
}
void SystemClock_UART1_init(void)
{
PWR_UnitModCfg(ENABLE, UNIT_SYS_PLL);
DelayMs(3);
SetSysClock(CLK_SOURCE_HSE_32MHz);
GPIOA_SetBits( GPIO_Pin_9 );
GPIOA_ModeCfg( GPIO_Pin_9, GPIO_ModeOut_PP_5mA );
UART1_DefInit( );
}
void GetMacAddr(UINT8 *pMAC)
{
UINT8 transbuf[6],i;
GetMACAddress(transbuf);
for(i=0;i<6;i++)
{
pMAC[5-i]=transbuf[i];
}
}
int main(void)
{
UINT32 i = 0;
UINT16 TimeDelay=0;
char payload[500];
UINT8 ip[4];
for(i=0;i<500;i++)
payload[i]='a';
SystemClock_UART1_init();
GetMacAddr(MACAddr);
i = CH57xNET_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr);
mStopIfError(i);
PRINT("CH57xNETLibInit Success\r\n");
sprintf(MACAddr_Str,"%02X%02X%02X%02X%02X%02X",MACAddr[0],MACAddr[1],MACAddr[2],MACAddr[3],MACAddr[4],MACAddr[5]);
PRINT("MAC:%s\r\n",MACAddr_Str);
Timer0Init( 10000 );
NVIC_EnableIRQ(ETH_IRQn);
while ( CH57xInf.PHYStat < 2 ) {
DelayMs(50);
}
PRINT("CH579 MQTT socket create!Publishing\r\n");
WWDG_ResetCfg(TRUE);
while(1)
{
WWDG_SetCounter(0);
CH57xNET_MainTask();
if(CH57xNET_QueryGlobalInt())CH57xNET_HandleGlobalInt();
if( dns_flag == 0 ){
i = DnsQuery(SocketId,url_dn3,ip);
if(i){
dns_flag = 1;
if( i == 1 ){
PRINT("Domain name:%s\r\n",url_dn3);
PRINT("HTTPs_IP=%d.%d.%d.%d\r\n",ip[0],ip[1],ip[2],ip[3]);
memcpy(DESIP,ip,4);
Transport_Open();
}
}
}
DelayMs(1);
TimeDelay++;
if (TimeDelay>20000) {
TimeDelay=0;
if(con_flag)
{
check_heart = 10000;
MQTT_Pingreq();
}
}
if(check_heart)
{
check_heart --;
if(!check_heart)NVIC_SystemReset();
}
if(!con_flag)
{
if(check_conn++ == 60000)NVIC_SystemReset();
}
}
}
|