这是一套AT指令收发程序,不仅可以控制集成AT指令的传感器模块,也可以把单片机当作AT模块处理其他设备发送的AT命令。该程序不仅适用于51单片机,也适用于其他单片机。

串口初始化以及收发程序

#include "usart.h"

xdata u8 USART_RX_BUF[60];     	// 接收缓冲,最大60个字节
xdata char USART_TX_BUF[60];	// 发送缓冲区

xdata u8 USART_RX_STA = 0;      // 接收状态标记(这个可以参考正点原子的程序) 
								// bit7,	接收完成标志
								// bit6,	接收到0x0d,回车由两个字节组成0x0D和0x0A
								// bit5~0,	接收到的有效字节数量
											
											

//-----------------------------------------------------------------------------
//  串口初始化函数,根据不同的硬件编写               
//-----------------------------------------------------------------------------
void UART_Init(void)
{

}

//-----------------------------------------------------------------------------
//  串口接收中断
//-----------------------------------------------------------------------------
void UART_ISR(void) interrupt ISRUart  // Vector @  0x23
{
	u8 Res;
	if (RI0) {
		RI0 = 0;        // 清除标志位
		RB80 = 0;
		Res = S0BUF;		// 读取接收到的数据
		// 上面几行代码,根据不同的硬件编写
		
		// 串口接收逻辑,重点
		if((USART_RX_STA&0x80) == 0) 	// 接收未完成
		{			
			if(USART_RX_STA&0x40)	// 接收到了0x0d
			{
				if(Res != 0x0A)USART_RX_STA=0;	// 接收错误,重新开始
				else USART_RX_STA|=0x80;		// 接收完成了 
			} 
			else		//还没收到0X0D
			{
				if(Res==0x0d)USART_RX_STA|=0x40;	// 如果当前收到0X0D
				else {
					USART_RX_BUF[USART_RX_STA&0X3F] = Res;		// 把数据放到接收缓冲区
					USART_RX_STA++;
					if(USART_RX_STA>(USART_MAX_RECV_LEN-1))USART_RX_STA=0;		// 接收数据超出范围,重新开始接收	  
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
//  发送一个字节的数据                    
//-----------------------------------------------------------------------------
void UART_Write_One_Byte(u8 txData)
{
    S0BUF = txData;
    while(!TI0);
	TI0 = 0;
}

//-----------------------------------------------------------------------------
//  发送字符串
//-----------------------------------------------------------------------------
void SendString(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
        UART_Write_One_Byte(*s++);         //发送当前字符
    }
}

AT指令处理

#include "at.h"

#include <stdio.h>
#include <string.h>		// sprintf函数


//-----------------------------------------------------------------------------
//  Function:   u8* at_check_cmd(u8 *str)
//	给模块发送命令后,检测接收到的应答
//	str:期待的应答结果
//	返回值:0,没有得到期待的应答结果
//	其他,期待应答结果的位置(str的位置)
//-----------------------------------------------------------------------------
u8* at_check_cmd(u8 *str)
{
	char *strx = 0;
	if(USART_RX_STA&0X80)		// 接收到一次数据了
	{ 
		USART_RX_BUF[USART_RX_STA&0X7F] = 0;// 添加结束符
		strx = strstr((const char*)USART_RX_BUF, (const char*)str);
	} 
	return (u8*)strx;
}

//-----------------------------------------------------------------------------
//  Function:   u8 at_send_cmd(char *cmd, u8 *ack, u16 waittime)
//	向模块发送命令
//	cmd:发送的命令字符串
//	ack:期待的应答结果,如果为空,则表示不需要等待应答
//	waittime:等待时间(单位:10ms)
//	返回值:0,发送成功(得到了期待的应答结果)
//        1,发送失败
//-----------------------------------------------------------------------------
u8 at_send_cmd(char *cmd, u8 *ack, u16 waittime)
{
	u8 res=0; 
	USART_RX_STA=0;
	// 如果串口可以使用printf函数最好,否则就用下面两行代码
	sprintf(USART_TX_BUF, "%s\r\n", cmd);	// 格式化命令,
	SendString(USART_TX_BUF);				// 发送命令
	
	if(ack&&waittime)		// 需要等待应答
	{
		while(--waittime)	// 等待倒计时
		{
			Delay1ms(10);
			if(USART_RX_STA&0X80)// 接收到期待的应答结果
			{
				if(at_check_cmd(ack))
				{
					break;// 得到有效数据 
				}
				USART_RX_STA=0;
			} 
		}
		if(waittime==0)res=1; 
	}
	return res;
} 

/*----------------------------------------------------------*/
/*函数名:AT指令 解包
/*参  数:redata:接收的数据  
/*----------------------------------------------------------*/
void Deal_Rx_Data(u8 *redata)
{
	if(strstr((char *)redata, "AT+MODE?"))	// *********如果搜索到AT+MODE?*********
	{
		sprintf(USART_TX_BUF, "MODE:%d", (int)mode);		// 格式化命令
		at_send_cmd(USART_TX_BUF, "", 0);					// 回复,不检查应答
	}
}

主函数,逻辑处理

//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "usart.h"
#include "at.h"

//-----------------------------------------------------------------------------
// Main loop 主函数
//-----------------------------------------------------------------------------
void main(void) 
{
	// 初始化。。。
	
	// 检查AT模块是否正常工作,发送AT,等待应答OK,超时时间20*10ms
	if(!at_send_cmd("AT", "OK", 20)){		// 返回0,则说明接收到了OK
		LED1 = 1;		// 点亮一个灯,或其他操作
	}

	while (1) {
		// 其他操作。。。
		
		// AT解包逻辑  
		if(USART_RX_STA&0X80)	// 接收到数据
		{
			// 给接收到的报文最后一个字符添加一个停止符,
			// 这样就可以避免:如果第二条报文长度比第一条短,那么第一条还有内容没有被覆盖,
			// 当这里添加一个停止符之后,后面与第二条报文无关的内容则不会参与解包。				
			USART_RX_BUF[USART_RX_STA&0X3F] = '\0';		
			Deal_Rx_Data(USART_RX_BUF);	// 解包
			USART_RX_STA = 0;		// 清零串口接收标志位
		}
		
		// 发送AT指令, 举例
		// 修改模式,发送AT+MODE=2,不需要应答
		at_send_cmd("AT+MODE=2", "", 0);
	}
}