关于无线传输的基础知识,参考:
和wifi一样,GPRS现在也基本上是使用模组。不过GPRS不用和WiFi一样要输入SSID和密码,开机就会自动联网,所以使用起来更方便一些。但是GPRS要有手机卡,流量是要钱的。
GRPS的天线通常是外置的。
关于天线可参考:物联网天线|IoT天线|GPS天线|WiFi天线- 德宝通信
SIM8000C
SIM800C是一款四频GSM/GPRS模块,支持高达85.6kbps的GPRS数据传输。它具有强大的扩展能力和丰富的接口,包括UART、USB2.0、GPIO等。该模块为客户的应用提供了极大的灵活性和易于集成的能力。
更多参考:SIM800C
AT指令示例:
更多详细内容查看厂家给的模组使用手册,此处不再赘述。
关键代码
/* Includes ------------------------------------------------------------------*/ #include "MyApplication.h" /* Private define-------------------------------------------------------------*/ #define TCP_Server (uint8_t*)"AT+CIPSTART=\"TCP\",\"115.29.109.104\",6511\r\n" //Doit.am远程信息转发服务 /* Private variables----------------------------------------------------------*/ static uint8_t SIM800C_Connect_Error_Flag = FALSE; //SIM800C联网错误标志位 /* Private function prototypes------------------------------------------------*/ static void StartUp(void); //启动SIM800C static void TCP_Connect_Server(void); //通过TCP连接服务器 static void Transfer_SHT30(void); //传送SHT30的温湿度 static void Receive_Information(void); //接收信息 static void DMA_Receive_Set(void); //DMA重新设置 static void Error(void); //错误信息 //内部函数 static void SendAT(uint8_t *,uint8_t *); //发送AT指令 static void Moudle_Sync_Baud(void); //同步波特率 static void Moudle_Check_SIM_Status(void); //检查SIM卡状态 static void Moudle_Check_Network_Register(void); //检查网络注册 static void Moudle_Check_Attach_GPRS_Service(void); //检查粘附GPRS网络 static void Moudle_BringUp_Wireless_Connect(void); //建立无线链接 static void Moudle_StartUp_TCP_Connect(void); //开始TCP连接 /* Public variables-----------------------------------------------------------*/ SIM800C_t SIM800C = { FALSE, TIMER6_10S, StartUp, TCP_Connect_Server, Transfer_SHT30, Receive_Information, DMA_Receive_Set, Error }; /* * @name StartUp * @brief 启动SIM800C * @param None * @retval None */ static void StartUp() { //如果模块处于开机状态,先关机 if(READ_GPRS_STATUS == GPIO_PIN_SET) { printf("The module of SIM800C shutdown!\r\n"); //模块关机 SET_GPRS_PWRKEY; HAL_Delay(1000); HAL_Delay(1000); HAL_Delay(1000); CLR_GPRS_PWRKEY; //等待模块关机完成 Timer6.usDelay_Timer = 0; while(READ_GPRS_STATUS == GPIO_PIN_SET) { if(Timer6.usMCU_Run_Timer >= TIMER6_10S) { SIM800C.Error(); break; } } //按手册提示,关机后迅速重启模块,至少延时800ms HAL_Delay(1000); } //如果模块处于关机状态,进行开机 if(READ_GPRS_STATUS == GPIO_PIN_RESET) { printf("The module of SIM800C startup!\r\n"); //模块开机 SET_GPRS_PWRKEY; HAL_Delay(1000); HAL_Delay(1000); CLR_GPRS_PWRKEY; //等待模块开机完成 Timer6.usDelay_Timer = 0; while(READ_GPRS_STATUS == GPIO_PIN_RESET) { if(Timer6.usMCU_Run_Timer >= TIMER6_10S) { SIM800C.Error(); break; } } } } /* * @name SendAT * @brief 发送AT指令 * @param AT_Command -> 待发送的AT指令 Respond_Str -> 回应数据中包含的字符串 * @retval None */ static void SendAT(uint8_t * AT_Command,uint8_t * Respond_Str) { uint8_t* const Ptr_AT_Command = AT_Command; uint8_t* const Ptr_Respond_Str = Respond_Str; //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(Ptr_AT_Command); //打印信息 printf("%s",Ptr_AT_Command); //等待模块回应数据,超时错误处理 Timer6.usDelay_Timer = 0; while(strstr((const char*)UART2.pucRec_Buffer,"\r\n") == NULL) { if(Timer6.usDelay_Timer > TIMER6_100mS) { SIM800C.Error(); break; } } //延时10ms,接收完全部字节 HAL_Delay(10); //模块回应数据处理处理 if(strstr((const char*)UART2.pucRec_Buffer,(const char*)Ptr_Respond_Str) == NULL) { SIM800C.Error(); } //打印信息 printf("%s",UART2.pucRec_Buffer); } /* * @name TCP_Connect_Server * @brief 通过TCP连接服务器 * @param None * @retval None */ static void TCP_Connect_Server() { __HAL_UART_DISABLE_IT(&huart2,UART_IT_IDLE); //禁止串口2的空闲中断 SIM800C.StartUp(); //启动GPRS模块 Moudle_Sync_Baud(); //同步波特率 SendAT(AT_CMD_ECHO_OFF,(uint8_t*)"OK"); //关闭回显 Moudle_Check_SIM_Status(); //检查SIM卡状态 SendAT(AT_CMD_CCID,(uint8_t*)"OK"); //显示ICCID Moudle_Check_Network_Register(); //检查网络注册 Moudle_Check_Attach_GPRS_Service(); //检查粘附GPRS网络 SendAT(AT_CMD_CIPMODE,(uint8_t*)"OK"); //设置为透传模式 SendAT(AT_CMD_CSTT,(uint8_t*)"OK"); //开始任务,设置APN Moudle_BringUp_Wireless_Connect(); //建立无线链接 SendAT(AT_CMD_CIFSR,(uint8_t*)"."); //获取本地IP地址 Moudle_StartUp_TCP_Connect(); //开始TCP连接 SIM800C.DMA_Receive_Set(); //DMA重新接收设置,开始接收TCP服务器的指令 if(SIM800C.TCP_Connect_Status == TRUE) __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); //使能串口2的空闲中断 } /* * @name Moudle_Sync_Baud * @brief 同步波特率 * @param None * @retval None */ static void Moudle_Sync_Baud() { SIM800C_Connect_Error_Flag = FALSE; LED.LED_OFF(LED2); LED.LED_OFF(LED3); HAL_GPIO_WritePin(OUT_NPN_GPIO_Port,OUT_NPN_Pin,GPIO_PIN_RESET); Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(AT_CMD_AT); //打印信息 printf("%s",AT_CMD_AT); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //超时处理 if(Timer6.usDelay_Timer >= TIMER6_10S) { SIM800C.Error(); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"OK") == NULL); } /* * @name Moudle_Check_SIM_Status * @brief 检查SIM卡状态 * @param None * @retval None */ static void Moudle_Check_SIM_Status() { if(SIM800C_Connect_Error_Flag == FALSE) { Timer6.usDelay_Timer = 0; do { //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(AT_CMD_CPIN); //打印信息 printf("%s",AT_CMD_CPIN); //延时1000ms,等待接收完成 HAL_Delay(1000); //打印信息 printf("%s",UART2.pucRec_Buffer); //超时处理 if(Timer6.usDelay_Timer >= TIMER6_10S) { SIM800C.Error(); break; } } while(strstr((const char*)UART2.pucRec_Buffer,"OK") == NULL); } } /* * @name Moudle_Check_Network_Register * @brief 检查网络注册 * @param None * @retval None */ static void Moudle_Check_Network_Register() { if(SIM800C_Connect_Error_Flag == FALSE) { Timer6.usDelay_Timer = 0; while(1) { //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(AT_CMD_CREG); //打印信息 printf("%s",AT_CMD_CREG); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //判断注册 if((strstr((const char*)UART2.pucRec_Buffer,",1") != NULL) || (strstr((const char*)UART2.pucRec_Buffer,",5") != NULL)) { break; } else { HAL_Delay(1000); HAL_Delay(1000); } //超时处理 if(Timer6.usDelay_Timer >= TIMER6_2min) { SIM800C.Error(); break; } } } } /* * @name Moudle_Check_Attach_GPRS_Service * @brief 建立无线链接 * @param None * @retval None */ static void Moudle_Check_Attach_GPRS_Service() { if(SIM800C_Connect_Error_Flag == FALSE) { Timer6.usDelay_Timer = 0; while(1) { //输出信号强度 SendAT(AT_CMD_CSQ,(uint8_t*)"OK"); //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(AT_CMD_CGATT); //打印信息 printf("%s",AT_CMD_CGATT); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //判断注册 if(strstr((const char*)UART2.pucRec_Buffer,"+CGATT: 1") != NULL) { break; } else { HAL_Delay(1000); HAL_Delay(1000); } //超时处理 if(Timer6.usDelay_Timer >= TIMER6_2min) { SIM800C.Error(); break; } } } } /* * @name Moudle_BringUp_Wireless_Connect * @brief 建立无线链接 * @param None * @retval None */ static void Moudle_BringUp_Wireless_Connect() { if(SIM800C_Connect_Error_Flag == FALSE) { Timer6.usDelay_Timer = 0; while(1) { //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(AT_CMD_CIICR); //打印信息 printf("%s",AT_CMD_CIICR); //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //建立无线链接成功 if(strstr((const char*)UART2.pucRec_Buffer,"OK") != NULL) { LED.LED_ON(LED2); break; } //建立无线链接失败 if(strstr((const char*)UART2.pucRec_Buffer,"ERROR") != NULL) { SIM800C.Error(); break; } //超时处理 if(Timer6.usDelay_Timer >= TIMER6_85S) { SIM800C.Error(); break; } } } } /* * @name Moudle_StartUp_TCP_Connect * @brief 开始TCP连接 * @param None * @retval None */ static void Moudle_StartUp_TCP_Connect() { if(SIM800C_Connect_Error_Flag == FALSE) { printf("Connect TCP Server!\r\n"); Timer6.usDelay_Timer = 0; while(1) { //DMA重新接收设置 SIM800C.DMA_Receive_Set(); //发送AT指令 UART2.SendString(TCP_Server); //打印信息 printf("%s",TCP_Server); //等待模块返回数据 while(Timer6.usDelay_Timer < TIMER6_160S) { if((strstr((const char*)UART2.pucRec_Buffer,"CONNECT") != NULL) | (strstr((const char*)UART2.pucRec_Buffer,"FAIL") != NULL)) { break; } } //延时100ms,等待接收完成 HAL_Delay(100); //打印信息 printf("%s",UART2.pucRec_Buffer); //TCP服务器链接失败 if(strstr((const char*)UART2.pucRec_Buffer,"FAIL") != NULL) { printf("Connect TCP Server Failure!\r\n"); SIM800C.TCP_Reconnect_Timer = 0; SIM800C.Error(); break; } //TCP服务器链接成功 if(strstr((const char*)UART2.pucRec_Buffer,"CONNECT") != NULL) { printf("Connect TCP Server Success!\r\n"); SIM800C.TCP_Connect_Status = TRUE; SIM800C.TCP_Reconnect_Timer = 0; LED.LED_ON(LED3); break; } //超时处理 if(Timer6.usDelay_Timer >= TIMER6_160S) { SIM800C.TCP_Reconnect_Timer = 0; SIM800C.Error(); break; } } } } /* * @name Transfer_SHT30 * @brief 传送SHT30的温湿度 * @param NONE * @retval None */ static void Transfer_SHT30() { float Temp_float = 0; uint16_t Temp_uint16 = 0; //温度值 -40至125℃,精度0.1℃ if(SHT30.fTemperature < 0) { Temp_float = 0 - SHT30.fTemperature; *(UART2.pucSend_Buffer + 0) = '-'; } else { Temp_float = SHT30.fTemperature; *(UART2.pucSend_Buffer + 0) = ' '; } Temp_uint16 = (uint16_t)(Temp_float*10); if(Temp_uint16 < 10) //0.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = ' '; *(UART2.pucSend_Buffer + 3) = '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16 + '0'; } else if(Temp_uint16 < 100)//x.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = ' '; *(UART2.pucSend_Buffer + 3) = Temp_uint16/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } else if(Temp_uint16 < 1000)//xx.x { *(UART2.pucSend_Buffer + 1) = ' '; *(UART2.pucSend_Buffer + 2) = Temp_uint16/100 + '0'; *(UART2.pucSend_Buffer + 3) = Temp_uint16%100/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } else//xxx.x { *(UART2.pucSend_Buffer + 1) = Temp_uint16/1000 + '0'; *(UART2.pucSend_Buffer + 2) = Temp_uint16%1000/100 + '0'; *(UART2.pucSend_Buffer + 3) = Temp_uint16%100/10 + '0'; *(UART2.pucSend_Buffer + 4) = '.'; *(UART2.pucSend_Buffer + 5) = Temp_uint16%10 + '0'; } //数据传送 UART2.SendString((uint8_t *)"The Temperature of SHT30 is "); HAL_Delay(3); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 28 = 2.68ms UART2.SendArray(UART2.pucSend_Buffer,6); HAL_Delay(1); //延时,等待数组发送完 时间 = (11*1000ms)/115200 * 6 = 0.58ms UART2.SendString((uint8_t *)"℃\r\n"); HAL_Delay(1); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 4 = 0.39ms //湿度值 0 - 100%RH,精度1%RH if(SHT30.ucHumidity < 10) { *(UART2.pucSend_Buffer + 0) = ' '; *(UART2.pucSend_Buffer + 1) = SHT30.ucHumidity + '0'; } else { *(UART2.pucSend_Buffer + 0) = SHT30.ucHumidity/10 + '0'; *(UART2.pucSend_Buffer + 1) = SHT30.ucHumidity%10 + '0'; } *(UART2.pucSend_Buffer + 2) = '%'; *(UART2.pucSend_Buffer + 3) = 'R'; *(UART2.pucSend_Buffer + 4) = 'H'; //数据传送 UART2.SendString((uint8_t *)"The Humidity of SHT30 is "); HAL_Delay(3); //延时,等待字符串发送完 时间 = (11*1000ms)/115200 * 25 = 2.39ms UART2.SendArray(UART2.pucSend_Buffer,5); } /* * @name Receive_Information * @brief 接收信息 * @param None * @retval None */ static void Receive_Information() { if(SIM800C.TCP_Connect_Status == TRUE) { printf("Received information from the TCP server\r\n"); printf("%s",UART2.pucRec_Buffer); printf("\r\n"); //切换继电器状态 if(strstr((const char*)UART2.pucRec_Buffer,"Flip Relay") != NULL) { Relay.Relay_Flip(); } if(strstr((const char*)UART2.pucRec_Buffer,"Flip Buzzer") != NULL) { if(Buzzer.Status == Buzzer_Status_OFF) { Buzzer.ON(); } else { Buzzer.OFF(); } } //DMA重新接收设置,接收TCP服务器的新指令 SIM800C.DMA_Receive_Set(); } } /* * @name DMA_Receive_Set * @brief DMA接收设置 * @param None * @retval None */ static void DMA_Receive_Set(void) { //串口2禁止DMA接收 HAL_UART_DMAStop(&huart2); //清缓存 Public.Memory_Clr(UART2.pucRec_Buffer,strlen((const char*)UART2.pucRec_Buffer)); //串口2开启DMA接收 HAL_UART_Receive_DMA(&huart2,UART2.pucRec_Buffer,UART2_Rec_LENGTH); } /* * @name Error * @brief 错误信息 * @param None * @retval None */ static void Error() { SIM800C_Connect_Error_Flag = TRUE; SIM800C.TCP_Reconnect_Timer = 0; HAL_GPIO_WritePin(OUT_NPN_GPIO_Port,OUT_NPN_Pin,GPIO_PIN_SET); } /************************************* End Of File *************************************/