这是一套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);
}
}