4G模块这里选择的是域格的YM310 X09物美价廉,单片机选择国产普冉(PUYA)单片机,通过串口和单片机交互。

软件

         4G模块本身的AT指令并不复杂,下面是模块需要设置的相关AT指令。

uint8_t CGATT[] = "AT+CGATT?\r\n";                                //查看当前 GPRS 附着状态
uint8_t CIPMUX[] = "AT+CIPMUX=0\r\n";          					  //设置为单连接模式
uint8_t CIPQSEND[] = "AT+CIPQSEND=1\r\n";                         //设置为快发模式
uint8_t CSTT[] = "AT+CSTT\r\n";	                                  //启动任务,设置 APN模块注册网络后会从网络自动获取<apn>并激活一个 PDP 上下文
uint8_t	CIICR[] = "AT+CIICR\r\n";	                              //激活移动场景,获取 IP 地址
uint8_t CIFSR[] = "AT+CIFSR\r\n";								  //查询分配的 IP 地址

uint8_t CIPSTART[] = "AT+CIPSTART=\"TCP\",\"XX.XX.XX.XX\",1000\r\n";  //其中:"TCP"为链接的协议类型,"XX.XX.XX.XX"为对端服务器的 IP 地址, 1000为对端服务器的 TCP 端口号

 初始化单片机

        初始化串口,并重定向UART1

int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)(&ch), 1, HAL_MAX_DELAY);
    return ch;
}

 void UART_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 使能 GPIOA 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    // 配置 UART1 的 GPIO 引脚
    // PA9  - UART1 TX
    // PA10 - UART1 RX
    GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART1; // 根据芯片手册选择正确的复用功能
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 配置 UART2 的 GPIO 引脚
    // PA2 - UART2 TX
    // PA3 - UART2 RX
    GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_USART2; // 根据芯片手册选择正确的复用功能
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
 
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;

void UART1_Init(void)
{
    // 使能 UART1 时钟
    __HAL_RCC_USART1_CLK_ENABLE();

    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
	
		huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
	
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        // 初始化错误处理
        APP_ErrorHandler();
    }
}
void UART2_Init(void)
{
    // 使能 UART2 时钟
    __HAL_RCC_USART2_CLK_ENABLE();

    huart2.Instance = USART2;
    huart2.Init.BaudRate = 115200;
    huart2.Init.WordLength = UART_WORDLENGTH_8B;
    huart2.Init.StopBits = UART_STOPBITS_1;
    huart2.Init.Parity = UART_PARITY_NONE;
    huart2.Init.Mode = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;

		huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
	
    if (HAL_UART_Init(&huart2) != HAL_OK)
    {
        // 初始化错误处理
        APP_ErrorHandler();
    }
}
 

void UART_Interrupt_Init(void)
{
    // 使能 UART1 中断
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);

    // 使能 UART2 中断
    HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
    __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
}

 单片机发送接收AT实现连接TCP

        按照下面这样替换上面AT的字符串发送就行。对返回数据进行对比确定是否正常,不正常循环发送。

	HAL_UART_Transmit(&huart2, CIPSTART, sizeof(CIPSTART) - 1, HAL_MAX_DELAY);
    HAL_Delay(100);
    strx=strstr((const char*)g_usart_rx_buf,(const char*)"OK");
		while(strx == NULL)
		{
				memset(g_usart_rx_buf, 0, sizeof(g_usart_rx_buf));
				HAL_UART_Transmit(&huart2, CIPSTART, sizeof(CIPSTART) - 1, HAL_MAX_DELAY);
				HAL_Delay(100);
				strx = strstr((const char*)g_usart_rx_buf,(const char*)"OK");
		}
		memset(g_usart_rx_buf, 0, sizeof(g_usart_rx_buf));

连接TCP后就能进行发送相关信息了,因为发送完字符串需要发送结束符0x1A,这里做个函数进行发送数据。

/**
  * @brief 发送AT命令及数据,以0x1A结尾
  * @param huart: UART句柄指针
  * @param atCmd: AT命令字符串 (如"AT+QISEND=0\r\n")
  * @param data: 要发送的数据缓冲区
  * @param timeout: 超时时间(ms)
  * @retval HAL状态
  */
HAL_StatusTypeDef UART_SendCommandWithData(UART_HandleTypeDef *huart, const char *atCmd, const char *data, uint32_t timeout)
{
    HAL_StatusTypeDef status;
		uint8_t endMarker = 0x1A; // 结束符
    // 1. 发送AT命令
    if((status = HAL_UART_Transmit(huart, (uint8_t*)atCmd, strlen(atCmd), timeout)) != HAL_OK)
    {
        return status;
    }
    // 2. 发送数据
    if(data != NULL && *data != '\0')
    {
        if((status = HAL_UART_Transmit(huart, (uint8_t*)data, strlen(data), timeout)) != HAL_OK)
        {
            return status;
        }
    }
    // 3. 发送结束符0x1A
		return HAL_UART_Transmit(huart,&endMarker, 1, timeout);
		HAL_Delay(100);
		strx=strstr((char*)g_usart_rx_buf,(char*)"SEND OK");//是否正确发送
		while(strx==NULL)
			{
        strx=strstr((char*)g_usart_rx_buf,(char*)"SEND OK");//是否正确发送
        HAL_Delay(100);
			}
    HAL_Delay(100);

 下面是主函数实现:

int main(void)
{
    HAL_Init();     				// systick初始化
		// 初始化 UART GPIO
    UART_GPIO_Init();
    // 初始化 UART1 和 UART2
    UART1_Init();  	//串口1初始化,打印调试信息
    UART2_Init();		//串口2初始化,连接X09模块
    // 初始化 UART 中断
    UART_Interrupt_Init();
	BSP_LED_Init(LED_GREEN);  //LED初始化
    printf("+++\r\n");
    HAL_Delay(500);
	printf("start\r\n");
	HAL_UART_Receive_IT(&huart2, &g_usart_rx_buf[0], 1);  // 启动接收
    X09_init();    //X09模块注册网络
	TCP_init();   //发送指令让模块连接MQTT服务器
    while (1)
    {
        // 或者直接调用发送TCP数据
		UART_SendCommandWithData(&huart2, "AT+QISEND=0\r\n", "Test data payload", 1000);
	}
 }

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐