#include "cat.h" uint32_t current_tick = 0; //当前运行时间 用于LED闪烁 硬件看门狗等 _Bool NetworkingFlag = 0; //联网标志位 1联网 0离线 char databuff[256]; //构建数据用的临时缓冲区 uint8_t online_counter = 1; //查询子设备上线的计数变量 uint8_t data_counter = 1; //查询子设备数据的计数变量 void catGpioInit(void) { GPIO_InitTypeDef GPIO_Initure = {0}; // GPIOA_RCC_ENABLE; GPIOC_RCC_ENABLE; GPIO_Initure.Pin= CAT_POW_Pin; //设置电源脚 GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //开漏输出 GPIO_Initure.Pull = GPIO_NOPULL; //不上下拉 GPIO_Initure.Speed = GPIO_SPEED_FREQ_LOW; //低速 (必需设置!) HAL_GPIO_Init(CAT_POW_GPIO_Port,&GPIO_Initure); //设置 // GPIO_Initure.Pin= CAT_RST_Pin; //设置复位脚(预留) // GPIO_Initure.Pull = GPIO_NOPULL; //不上下拉 // GPIO_Initure.Mode = GPIO_MODE_OUTPUT_OD; //开漏输出 // GPIO_Initure.Speed = GPIO_SPEED_FREQ_LOW; //低速 // HAL_GPIO_Init(CAT_RST_GPIO_Port,&GPIO_Initure); //设置 GPIO_Initure.Pin = CAT_RUN_Pin ; //设置运行读取脚 GPIO_Initure.Mode = GPIO_MODE_INPUT; //输入模式 GPIO_Initure.Pull = GPIO_PULLUP; //使能上拉 GPIO_Initure.Speed = GPIO_SPEED_FREQ_LOW; //低速 HAL_GPIO_Init(CAT_RUN_GPIO_Port,&GPIO_Initure); //设置 // GPIO_Initure.Pin = CAT_NET_Pin ; //设置网络读取脚 // GPIO_Initure.Mode = GPIO_MODE_INPUT; //输入模式 // GPIO_Initure.Pull = GPIO_PULLUP; //使能上拉 // GPIO_Initure.Speed = GPIO_SPEED_FREQ_LOW; //低速 // HAL_GPIO_Init(CAT_NET_GPIO_Port,&GPIO_Initure); //设置 } //模块开机后会收到 +NITZ: 24/04/13,12:11:59+32,0 实际时间 2024/4/13 20:11:59秒 void catReset(void) { uint8_t Multiple = 200; //短暂延时 默认100ms uint8_t netstep = 0; char serverbuff[100] = {0}; //例子:AT+MCONFIG="8c91c2a533b3c573","965669176415378622","ad592e4c3e7117c6",0,0,0,0 char portbuff[50] = {0}; //例子:AT+MIPSTART="58.17.14.95",1880 char topicbuff[50]= {0}; //订阅主题 才能收到云平台下发的控制指令 sprintf(serverbuff,"AT+MCONFIG=\"%s\",\"%s\",\"%s\",0,0,0,0",MqttInfo_Struct.ClientID,MqttInfo_Struct.Username,MqttInfo_Struct.Passward); sprintf(portbuff, "AT+MIPSTART=\"%s\",%d",MqttInfo_Struct.ServerIP,MqttInfo_Struct.ServerPort); sprintf(topicbuff, "AT+MSUB=\"%s%s\",0",MqttInfo_Struct.Topic,MqttInfo_Struct.ClientID); #if 0 if(POWER_STA==1) { //如果PB1是高电平,表示目前处于关机状态 log_info("目前4G模块处于关机状态,准备开机"); //串口输出信息 POWER_KEY(1); //先拉高 HAL_Delay(1500); //延时 POWER_KEY(0); //再拉低,开机 } else { //反之PA0是低电平,表示目前处于开机状态 log_info("目前4G模块处于开机状态,准备重启"); //串口输出信息 POWER_KEY(1); //先拉高 HAL_Delay(1500); //延时 POWER_KEY(0); //再拉低,关机 HAL_Delay(3000); //间隔 POWER_KEY(1); //先拉高 HAL_Delay(1500); //延时 POWER_KEY(0); //再拉低,开机,完成重启 } #endif log_info("准备复位"); POWER_KEY(1); //先拉高 复位 HAL_Delay(1000); //延时 POWER_KEY(0); //再拉低 HAL_Delay(3000); //间隔 HAL_Delay(3000); HAL_Delay(Multiple); if(catSendCmd("AT","OK", 8,30)) { log_info("开机失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("开机成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("关闭回显"); // 串口提示数据 if(catSendCmd("ATE0","OK", 5, 30)) { log_info("关闭回显失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("关闭回显成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备查询卡状态"); // 串口提示数据 if(catSendCmd("AT+CPIN?","READY", 5, 30)) { log_info("查询卡状态失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("查询卡状态成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备设置单连接\r\n"); // 串口提示数据 if(catSendCmd("AT+CIPMUX=0","OK", 5, 30)) { log_info("设置单连接失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("设置单连接成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备配置网络"); // 串口提示数据 if(catSendCmd("AT+CSTT","OK", 5, 30)) { log_info("配置网络失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("配置网络成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备激活网络"); // 串口提示数据 if(catSendCmd("AT+CIICR","OK", 5, 30)) { log_info("激活网络失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("激活网络成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备连接服务器"); // 串口提示数据 if(catSendCmd(serverbuff,"OK", 5, 30)) { log_info("连接服务器失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("连接服务器成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备连接TCP端口"); if(catSendCmd(portbuff,"OK", 5, 30)) { log_info("连接TCP端口失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("连接TCP端口成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备配置保活时间"); if(catSendCmd("AT+MCONNECT=1,60","OK", 5, 30)) { log_info("配置保活时间失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("配置保活时间成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("准备订阅主题"); if(catSendCmd(topicbuff,"SUBACK", 5, 30)) { log_info("订阅主题失败,准备重启"); //串口输出信息 NVIC_SystemReset(); //重启! } else { netstep += 1; //步进增加 log_info("订阅主题成功"); //串口输出信息 } HAL_Delay(Multiple); log_info("当前来到步:%d",netstep); if(netstep >= 10) { NetworkingFlag = 1; log_info("联网过程一切OK!"); } else { NetworkingFlag = 0; log_info("联网失败,重启"); HAL_Delay(Multiple); NVIC_SystemReset(); //重启! } //CAT1_printf("AT+MPUB=\"/iot/sub/live/post/8c91c2a533b3c573\",0,0,\"{\\22header\\22:\\22iot.sub.live.post\\22,\\22version\\22:\\221.0\\22,\\22body\\22:{\\22online\\22:[{\\22uid\\22:\\2239dde8bcbf424b1b\\22,\\22secret\\22:\\22129460d7f87bd872\\22}]}}\"\r\n"); } //子设备上线 标准指令 Lora子设备测试-02 // CAT1_printf("AT+MPUB=\"/iot/sub/live/post/8c91c2a533b3c573\",0,0,\"{\\22header\\22:\\22iot.sub.live.post\\22,\\22version\\22:\\221.0\\22,\\22body\\22:{\\22online\\22:[{\\22uid\\22:\\2239dde8bcbf424b1b\\22,\\22secret\\22:\\22129460d7f87bd872\\22}]}}\"\r\n"); //子设备上线 经过测试也可以 Lora子设备测试-02 // CAT1_printf("AT+MPUB=\"/iot/data/up/8c91c2a533b3c573\",0,0,\"{\\22header\\22:\\22iot.sub.live.post\\22,\\22version\\22:\\221.0\\22,\\22body\\22:{\\22online\\22:[{\\22uid\\22:\\2239dde8bcbf424b1b\\22,\\22secret\\22:\\22129460d7f87bd872\\22}]}}\"\r\n"); //实际串口捕获的数据: //AT+MPUB="/iot/sub/live/post/8c91c2a533b3c573",0,0,"{\22header\22:\22iot.sub.live.post\22,\22version\22:\221.0\22,\22body\22:{\22online\22:[{\22uid\22:\2239dde8bcbf424b1b\22,\22secret\22:\22129460d7f87bd872\22}]}}" //转义后: // "/iot/sub/live/post/8c91c2a533b3c573",0,0, //"{ //"header":"iot.sub.live.post", //"version":"1.0", //"body":{ // "online":[ // { // "uid":"39dde8bcbf424b1b", // "secret":"129460d7f87bd872" // } // ] // } //}" //发送上线消息后 云平台回复: //设备回复数据:+MSUB: "/iot/data/down/8c91c2a533b3c573",47 byte,{"code":200,"message":"success","success":true} //云平台子设备上线后 发送开关指令后 单片机收到数据如下: //+MSUB: "/iot/data/down/8c91c2a533b3c573",158 byte,{"extend":{"uid":"39dde8bcbf424b1b"},"id":"976660012242325829","header":"iot.sub.prop.set","version":"1.0","body":{"sw1":{"time":1713020358015,"value":true}}} //其中uid是子设备的设备id /*-------------------------------------------------*/ /*函数名:卡模块发送指令 */ /*参 数:cmd:指令 */ /*参 数:ret:对比数据 */ /*参 数:cnt:发送次数 */ /*参 数:timeout:超时时间(50ms的倍数) */ /*返回值:0:正确 其他:错误 */ /*-------------------------------------------------*/ uint8_t catSendCmd(char *cmd, char *ret, uint8_t cnt, uint8_t timeout) { uint8_t result = 1; // 默认结果设为错误(非0值) while(cnt > 0 && result != 0) { CAT1_printf("%s\r\n", cmd); // 发送指令 结尾加上换行回车 uint8_t current_timeout = timeout; while(--current_timeout) { HAL_Delay(50); u2flushReceiveBuffer(); //刷新接收缓冲区的数据指针 if (strstr((char *)U2_CopyBuff, ret)) {//查找匹配字符串 result = 0; // 找到期望的回复,结果设为正确(0值) break; } } if (current_timeout == 0) // 如果timeout<=0,说明超时,但此时未收到期望回复 log_info("第%d次超时",cnt); cnt--; // 发送次数减1 } return result; } /*-------------------------------------------------*/ /*函数名:串口3被动事件 */ /*参 数:data :数据 */ /*参 数:datalen :数据长度 CLOSED */ /*返回值:无 */ /*-------------------------------------------------*/ void u2PassiveEvent(uint8_t *data, uint16_t datalen) { //主机被平台踢下线 准备重启 if(strstr((char *)data,"CLOSED")) { log_info("主机被迫下线,准备重启!"); NVIC_SystemReset();//重启 } //收到主机控制指令:+MSUB: "/iot/data/down/cfd6dba662690a5e",118 byte,{"id":"977013940154814794","header":"iot.prop.set","version":"1.0","body":{"sw1":{"time":1713104741005,"value":true}}} if(strstr((char *)data,"iot.prop.set")) { log_info("收到控制指令"); Relay_Action(data); // 继电器响应网络数据 } } // 继电器响应网络数据 //收到子设备控制指令:+MSUB: "/iot/data/down/a284c67982b089f9",119 byte,{"id":"111750363407137710","header":"iot.prop.set","version":"1.0","body":{"sw1":{"time":1746600094207,"value":false}}} void Relay_Action(uint8_t *data) { uint8_t i = 0; char *TempPointer; // 临时指针 char CmdId[18] = {0}; // 存贮id的数据,以响应服务器下发的数据 if(strstr((char *)data,MqttInfo_Struct.Topic)) { //查找 /iot/data/down/ 出现的位置 TempPointer = strstr((char *)data, ",\"id\":\""); if (TempPointer) { TempPointer += 7; // 跳过 ,"id":" for (i = 0; i < 18; i++) { if ((TempPointer[i] >= '0' && TempPointer[i] <= '9') || ((TempPointer[i] >= 'a') && (TempPointer[i] <= 'z')) || ((TempPointer[i] >= 'A') && (TempPointer[i] <= 'Z'))) { CmdId[i] = TempPointer[i]; } else { log_info("非法字符: %c (ASCII %d)", TempPointer[i], TempPointer[i]); break; } } if(i == 18 && TempPointer[18] == '"') { // 验证18位数字后紧跟引号 log_info("ID校验通过: %s", CmdId); } } if(strstr((char *)data,"\"sw")) { //先判断收到的数据是不是开关量 TempPointer = strstr((char *)data,"\"sw"); // 记录sw位置 switch(TempPointer[3]) { // 判断操作哪个开关 case '1': if (strstr((char *)data, "true")) { log_info("开关1打开"); ;;// } if (strstr((char *)data, "false")) { log_info("开关1关闭"); ;;// } break; case '2': if (strstr((char *)data, "true")) { log_info("开关2打开"); ;;// } if (strstr((char *)data, "false")) { log_info("开关2关闭"); ;;// } break; case '3': if (strstr((char *)data, "true")) { log_info("开关3打开"); ;;// } if (strstr((char *)data, "false")) { log_info("开关3关闭"); ;;// } break; case '4': if (strstr((char *)data, "true")) { log_info("开关4打开"); ;;// } if (strstr((char *)data, "false")) { log_info("开关4关闭"); ;;// } break; } } //推送回复消息 OK CAT1_printf("AT+MPUB=\"/iot/data/up/%s\",0,0,\"{\\22id\\22:\\22%s\\22,\\22code\\22:0,\\22message\\22:\\22OK\\22}\"\r\n",MqttInfo_Struct.ClientID, CmdId); } } //主动事件 LED闪烁 void activeEvents(void) { //LED闪烁:联网 熄灭:离线 if (HAL_GetTick() - current_tick >= 200) { if(NetworkingFlag)//连接成功 LED1_TOGGLE; else LED1_OFF;//熄灭网络指示灯 current_tick = HAL_GetTick(); //更新时间 } }