开发板介绍

这里选择STM32f103开发板和域格YM310 X09开发板。

STM32F103系列价格低廉,开发板成本低,丰富的外设扩展。

YM310 X09开发板是域格推出的基于移芯平台设计的,包含电源,SIM 卡,USB,天线,音频等必要功能的最小硬件系统。模块这边直接用普通AT版本就行了。

一、软件

这里我单片机用得标准库,直接重定向UART2支持printf函数。

#pragma import(__use_no_semihosting)

// FILE结构体定义
struct __FILE { int handle; };
FILE __stdout;

// 退出函数
void _sys_exit(int x) { while(1); }

// 串口输出
int fputc(int ch, FILE *f) {
    while(!(USART2->SR & 0x40));  // 等待发送完成
    USART2->DR = ch;              // 发送字符
    return ch;
}

初始化UART2串口与模块进行通信

//初始化IO 串2
//bound:波特率
void uart2_init(u32 bound)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能,GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2
 	USART_DeInit(USART2);  //复位串口2
	 //USART2_TX   PA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
   
    //USART2_RX	  PA.3,
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3

   //Usart1 NVIC 配置

    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//115200
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART2, &USART_InitStructure); //初始化串口
		
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART2, ENABLE);                    //使能串口 

}

这里串口初始化完成,后面通过串口查询模块注网是否正常。

void X09_Init(void)
{
		printf("AT\r\n"); 
		delay_ms(500);
		printf("AT\r\n"); 
		delay_ms(500);
		strx=strstr((const char*)RxBuffer,(const char*)"OK");//返回OK
	while(strx==NULL)
		{
				Clear_Buffer();	  //清空接收buff缓存
				printf("AT\r\n"); 
				delay_ms(500);
				strx=strstr((const char*)RxBuffer,(const char*)"OK");//返回OK
		}
	
		printf("ATE0\r\n"); //关闭回显
		delay_ms(500);
		Clear_Buffer();	
		printf("AT+CSQ\r\n"); //检查CSQ
		delay_ms(500);
		/////////////////////////////////
		printf("AT+CPIN?\r\n");//检查SIM卡是否在位
		delay_ms(500);
		strx=strstr((const char*)RxBuffer,(const char*)"+CPIN: READY");//查看是否返回ready
	while(strx==NULL)
		{
				Clear_Buffer();
				printf("AT+CPIN?\r\n");
				delay_ms(500);
				strx=strstr((const char*)RxBuffer,(const char*)"+CPIN: READY");//检查SIM卡是否在位,等待卡在位。
		}
		Clear_Buffer();	

		printf("AT+CEREG?\r\n");//查看是否注册GSM网络
		delay_ms(500);
		strx=strstr((const char*)RxBuffer,(const char*)"+CEREG: 0,1");//返回正常
		extstrx=strstr((const char*)RxBuffer,(const char*)"+CEREG: 0,5");//返回正常,漫游
	while(strx==NULL&&extstrx==NULL)
		{
				Clear_Buffer();
				printf("AT+CEREG?\r\n");//查看是否注册GSM网络
				delay_ms(500);
				strx=strstr((const char*)RxBuffer,(const char*)"+CEREG: 0,1");//返回正常
				extstrx=strstr((const char*)RxBuffer,(const char*)"+CEREG: 0,5");//返回正常,漫游
		}
		Clear_Buffer();
}		

确定模块注网成功后,这里确定http post AT流程。4G模块本身AT指令不复杂,下面是模块需要设置的相关AT指令

AT+SAPBR=3,1,"CONTYPE","GPRS"    //设置 HTTP 功能的承载类型

OK


AT+SAPBR=3,1,"APN",""    //模块注册网络后会从网络自动获取<apn>并激活一个PDP 上下文

OK


AT+SAPBR=1,1    //激活该承载的 GPRS PDP 上下文

OK


AT+SAPBR=2,1   //查询下承载的状态

+SAPBR: 1,1,"10.63.47.89"

OK


AT+HTTPINIT   //HTTP 协议栈初始化

OK


AT+HTTPPARA="CID",1     //设置 HTTP 会话参数:CID

OK


AT+HTTPPARA="URL","http://xx.xx.xx.xx:xxxx/parse"   //设置 HTTP 会话参数:URL

OK


AT+HTTPPARA="USER_DEFINED","Content-Type: application/json"  //设置HTTP参数值

OK

这里post数据案例:
AT+HTTPDATA=253,100000  //输入 253个字节,等待时间是 10S,输入时间要设定的足够大以保证数据输入

DOWNLOAD

 。。。这里输入具体post数据   

OK


AT+HTTPACTION=1   //POST开始

OK

+HTTPACTION: 1,200,1038


AT+HTTPREAD       //读取post获取得内容

+HTTPREAD: 1038

{"message":具体返回消息}

OK

上面是AT指令,下面是单片机具体post 主要代码获取

char datalu[] = 
        "{\"xxxx\":\"2025-01-14 10:54:33\","
        "\"xxx\":\"http://xx.xx.xx.xx:8081/mall\","
        "\"xx\":\"MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=\","
        "\"xx\":\"S00000012501144dd3dc4\","
        "\"xx\":\"a07551ecef7daa76c3d299353038a705\","
        "\"xx\":\"S0000001\","
        "\"xx\":\"20250114105433\"}";

void HTTP_Init(void)
{

	 ...........
		
		printf("AT+HTTPDATA=%d,100000\r\n",sizeof(datalu));              // 输入N字节,等待时间是10S,输入时间要设定的足够大以保证数据输入
    delay_ms(500);
    strx=strstr((const char*)RxBuffer,(const char*)"DOWNLOAD");
		if(strx!=NULL)
		{
		Clear_Buffer();
		printf("%s\r\n",datalu);                  //post的字符串
		}
		delay_ms(500);
		extstrx=strstr((const char*)RxBuffer,(const char*)"OK");
		while(extstrx==NULL)
		{
				Clear_Buffer();
				printf("AT+HTTPDATA=%d,100000\r\n",sizeof(datalu));
				delay_ms(500);
			  strx=strstr((const char*)RxBuffer,(const char*)"DOWNLOAD");
				if(strx!=NULL)
				{
				//printf("%s",RxBuffer);
				printf("%s\r\n",datalu);                 //post的字符串
				Clear_Buffer();
				}
				delay_ms(500);
				strx=strstr((const char*)RxBuffer,(const char*)"OK");
		}
		Clear_Buffer();
		
		
		printf("AT+HTTPACTION=1\r\n");    //psot开始
    delay_ms(500);
    strx=strstr((const char*)RxBuffer,(const char*)"OK");  
		extstrx=strstr((const char*)RxBuffer,(const char*)"+HTTPACTION: 1,200");//psot成功   例:+HTTPACTION: 1,200,1038
		while(strx==NULL&&extstrx==NULL)
		{
				Clear_Buffer();
				printf("AT+HTTPACTION=1\r\n");  
				delay_ms(500);
				strx=strstr((const char*)RxBuffer,(const char*)"OK"); 
				extstrx=strstr((const char*)RxBuffer,(const char*)"+HTTPACTION: 1,200"); //psot成功
		}
		Clear_Buffer();
		
		
		printf("AT+HTTPREAD\r\n");   //将post打印到串口
		
		while(1)
		{
		printf("post 执行完成");
		}
        //这里接收buff已经有post数据了。
}

   这里写个函数处理一下post接收得数据,只要中间得数据部分。


void json_from_rx_buffer(char *rx_buffer) {
    // 1. 检查是否包含有效数据
    if (rx_buffer == NULL || strlen(rx_buffer) == 0) {
        Uart1_Send("No data in RxBuffer!\n");
        return;
    }

    // 2. 查找第一个 '{' 和最后一个 '}'
    char *json_start = strchr(rx_buffer, '{');
    char *json_end = strrchr(rx_buffer, '}');

    // 3. 检查是否找到有效JSON
    if (json_start && json_end && json_end > json_start) {
        // 计算JSON长度
        int json_length = json_end - json_start + 1;

        // 4. 提取JSON数据(可存入全局变量或直接处理)
        char json_data[json_length + 1];  // +1 存放 '\0'
        strncpy(json_data, json_start, json_length);
        json_data[json_length] = '\0';   // 确保字符串结束

        Uart1_Send(json_data);  // 输出: {数据}
    } else {
        Uart1_Send("No valid JSON found!\n");
    }
}

这里http  post数据就已经在json_data里面了。

主函数:

 int main(void)
 {	

		delay();	    	 //延时函数初始化	  
		NVIC(); 	 //设置NVIC
		LED_Init();		  		//初始化与LED连接的硬件接口
		uart1_init(115200);//串口1初始化,打印调试信息
		uart2_init(115200);//串口2初始化,连接X09模块
		printf("+++");
		delay_ms(500);
		printf("+++");
		delay_ms(500);
		X09_Init(); //X09初始化查询注网
		HTTP_Init();  //HTTP服务
		while(1)
		{
			
		  Uart1_Send(json_data);  // 输出: {数据}  
          delay_ms(500);  
          LED1=!LED1;
        
		}
}

这里就完成把模块post数据发送到单片机UART1串口了。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐