sim900a模块 为什么只对一个号码作用

27554人阅读
CortexM3(STM32)(15)
实现了收发短信,并且支持字符短信和PDU格式短信,支持电话拨打与接听
长期工作稳定
//SIM900.C
/*************************************************************************************************************
STM32 SIM900底层驱动函数
* 创建时间:
* 最后修改时间:
GSM_CDMA发送短信等
:添加字节超时与总超时
*************************************************************************************************************/
#include &system.h&
#include &usart.h&
#include &SIM900.h&
#include &delay.h&
#include &string.h&
#include &ucos_ii.h&
#include &unicode_gbk.h&
#include &main.h&
//SIM900通信缓冲区
u8 SIM900_Buff[SIM900_BUFF_SIZE]; //缓冲区
//调试开关
#define SIM900_DBUG 0
#if SIM900_DBUG
#include &system.h&
#define SIM900_debug(format,...) uart_printf(format,##__VA_ARGS__)
#define SIM900_debug(format,...) /\
#endif //SIM900_DBUG
//所有短信接收缓冲区
//#define PDU_BUFF_SIZE 1024*20
//20KB 可以一次读取50条未读短信
u8 SmsPduBuff[PDU_BUFF_SIZE];
//PDU数据缓冲区
static u8 PhoneNumtoPDUChar(u8 *pNum, char *pChar,u8 NumLen);
//将电话号码字符转换为PDU要求的字符
static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen);
//将字符转换为电话号码
static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen); //将字符串转换为unicode,并存储为16进制样式的字符串
static u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen); //将字符unicode转换为字符串
static u32 GSM_StringToHex(char *pStr, u8 NumDigits);
//将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
static void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits); //将整型数字转换为16进制样式字符串(字母为大写,不带结束符)
static int gsmDecode7bit(const u8* pSrc, char* pDst, int nSrcLength);//7bit编码解码
static int gsmEncode7bit(const char* pSrc,u8* pDst);
static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum);
static PHONE_NUMBER SMSServeN
//全局短信中心号码
/*************************************************************************************************************************
: void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen)
: 设置全局短信中心号码
: pSMSServeNumber:短信中心号码,NumLen:短信中心号码长度
* 最后修改时间
用于发送短信的时候进行调用
*************************************************************************************************************************/
void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen)
if(NumLen & PHONE_NUMBER_MAX_LEN) NumLen = PHONE_NUMBER_MAX_LEN; //限制电话号码长度
for(i = 0;i & NumLi ++)
SMSServeNumber.PhoneNumBuff[i] = pSMSServeNumber[i];
SMSServeNumber.PhoneNumLen = NumL
SMSServeNumber.PhoneNumBuff[SMSServeNumber.PhoneNumLen] = '\0';
//添加结束符
SIM900_debug(&设置短信中心号码为:%s\r\n&,SMSServeNumber.PhoneNumBuff);
/*************************************************************************************************************************
: bool GSM_CheckNotASCII(char *pBuff,u16 Len)
: 检查字符串中是否含有非ASCII编码
: pBuff:字符串缓冲区;Len:长度
: FALSE:字符串全部为ASCII编码;TRUE:字符串含有非ASCII编码,一般为汉字编码
* 最后修改时间
用于选择发送短信的模式,选择U2S或者7BIT编码
*************************************************************************************************************************/
bool GSM_CheckNotASCII(char *pBuff,u16 Len)
for(i = 0;i & Li ++)
if(pBuff[i] &= 0x80)
return TRUE;
return FALSE;
/*************************************************************************************************************************
: static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum)
: 计算指定字符的偏移位置
: pBuff:字符串缓冲区;
CharNum:字符偏移
: 字符串大小
* 最后修改时间
计算指定数量的字符(不分中英文)的大小,比如PDU,U2S模式下,短信只能有70个字符,但是不分中英文
此时英文只占用一个字节,但是中文占用2个字节
*************************************************************************************************************************/
static u16 GSM_GetU2SCharOffset(char *pBuff,u16 CharNum)
u16 cnt = 0;
for(i = 0;i & CharN)
if(pBuff[i] &= 0x80) //中文
else if(pBuff[i] == 0) //字符串结束
/*************************************************************************************************************************
: bool SIM900_WaitSleep(void)
: 等待GSM模块空闲,并重新唤醒
: TimeOut:等待超时,时间单位ms
: TRUE:成功;FALSE:超时
* 最后修改时间
用于等待操作完成,防止快速操作造成模块不响应
*************************************************************************************************************************/
bool SIM900_WaitSleep(u32 TimeOut)
TimeOut /= 100;
TimeOut +=1;
SIM900_SetDTR(1);
//等待模块空闲后进入SLEEP模式
for(i = 0;i & TimeOi ++)
GSM_Delay100MS();
//延时100ms
SIM900_SendATcom(&AT&);
//发送&AT&,同步波特率,并且等待应答
if(AT_RETURN_TIME_OUT == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 15)) //等待响应,超时150ms
SIM900_SetDTR(0);
if(i == TimeOut)
SIM900_debug(&模块进入空闲模式失败!\r\n&);
return FALSE;
GSM_Delay100MS();
//延时100ms
SIM900_debug(&模块进入空闲模式成功!\r\n&);
SIM900_TestAT(10);
return TRUE;
/*************************************************************************************************************************
: bool GSM_SendSMS(char *pSMS, char *pPhoneNumber)
: 发送一条短信
: pSMS:短信内容缓冲区指针,内容为文本文档,并且字符串需要结束符
pPhoneNumber:目标电话号码
: TRUE:短信发送成功;FALSE:短信发送失败
*最后修改时间 :
: 需要先调用SIM900_SetSMSServeNumber()设置短信中心号码
需要使用全局的PDU数据缓冲区
一定要添加结束符
当短信长度超过单条短信长度限制后会发送多条短信
*************************************************************************************************************************/
#define SMS_MAX_LEN
//短信最大长度
bool GSM_SendSMS(char *pSMS, char *pPhoneNumber)
char SMSBuff[160+1]; //短信最大160B,加上一个结束符
u8 PDUBuff[512];
//短信PDU数据缓冲区
//短信长度
//短信发送偏移位置,用于发送多条短信
SMSLen = strlen(pSMS); //获取要发送的短信长度
if(SMSLen & SMS_MAX_LEN) SMSLen = SMS_MAX_LEN; //限制短信最大长度,防止无限发送
if(strlen(SMSServeNumber.PhoneNumBuff) == 0)
SIM900_debug(&由于短信中心号码设置失败,导致短信无法发送!\r\n&);
return FALSE;
SMSOffset = 0;
//起始偏移为0
if((SMSLen-SMSOffset) & 160)
j = SMSLen-SMSO
for(i = 0;i &i ++)
SMSBuff[i] = pSMS[SMSOffset + i]; //复制短信到发送缓冲区
SMSBuff[j] = 0; //添加结束符
if(GSM_CheckNotASCII(SMSBuff,j) == TRUE) //分割的短信中含有非ASCII编码,那么只能使用U2S编码,只能发送70个字符(包括中英文)
SMSOffset += GSM_GetU2SCharOffset(SMSBuff,70); //第一条短信限制70个字符,返回下一条分割的起始位置
SMSBuff[SMSOffset] = 0;
SMSOffset += //下一条分割的起始位置
SMSBuff[SMSOffset] = 0;
//SIM900_WaitSleep(1000); //等待上一个操作完成
if(GSM_SendOneSMS(SMSBuff, PDUBuff, SMSServeNumber.PhoneNumBuff, pPhoneNumber) == TRUE)
SIM900_debug(&发送短信成功!\r\n&);
SIM900_debug(&发送短信失败!\r\n&);
return FALSE;
if(SMSOffset &= SMSLen) //短信发送完成,退出
return TRUE;
/*************************************************************************************************************************
: void SIM900_HardwareInit(void)
: 初始化SIM900相关的硬件
* 最后修改时间
主要初始化与SIM900相关的STM32 IO 以及 UART
*************************************************************************************************************************/
void SIM900_HardwareInit(void)
SIM900_UartInit();
//初始化串口
SIM900_SetRxBuff(SIM900_Buff, SIM900_BUFF_SIZE); //设置通信缓冲区
//初始化RI,用于指示新短信或者电话
DeviceClockEnable(DEV_GPIOB,ENABLE);
//使能GPIOB时钟
GPIOx_Init(GPIOB,BIT14, IN_IPU, IN_IN);
//上拉输入
GPIOx_Init(GPIOB,BIT12|BIT13|BIT15, OUT_PP, SPEED_10M); //推挽输出
SIM900_SetDTR(0);
//取消SLEEP
SIM900_SetRESET(1);
//复位无效
SIM900_SetPWR(1);
//上电无效
/*************************************************************************************************************************
: void SIM900_HardwarePowerUP(void)
: SIM900硬件开机
* 最后修改时间
用于SIM900模块开机,拉低PWR
*************************************************************************************************************************/
void SIM900_HardwarePowerUP(void)
SIM900_SetPWR(1); //恢复高电平
GSM_DelayMS(200);
SIM900_SetPWR(0); //拉低750ms开机
GSM_DelayMS(750);
GSM_Delay100MS();
SIM900_SetPWR(1); //恢复高电平
GSM_DelaySer(3); //延时3S等待开机完毕
/*************************************************************************************************************************
: void SIM900_HardwarePowerDOWN(void)
: SIM900硬件关机
* 最后修改时间
用于SIM900模块关机机,拉低PWR大于1S小于5S
*************************************************************************************************************************/
void SIM900_HardwarePowerDOWN(void)
SIM900_SetPWR(1); //恢复高电平
GSM_DelayMS(200);
SIM900_SetPWR(0); //拉低1500ms关机
GSM_DelaySer(1);
GSM_DelayMS(500);
SIM900_SetPWR(1); //恢复高电平
GSM_DelaySer(2); //延时2S等待注销网络
/*************************************************************************************************************************
: void SIM900_HardwareReset(void)
: SIM900硬件复位
* 最后修改时间
用于SIM900模块硬件复位
*************************************************************************************************************************/
void SIM900_HardwareReset(void)
SIM900_SetRESET(1); //恢复高电平
GSM_Delay100MS();
SIM900_SetRESET(0); //拉低100mS复位
GSM_Delay100MS();
SIM900_SetRESET(1); //恢复高电平
GSM_DelaySer(2); //延时2S
/*************************************************************************************************************************
: bool SIM900_ModuleInit(void)
: 初始化SIM900模块
: FALSE:初始化失败;TRUE:初始化成功
* 最后修改时间
主要初始化与SIM900配置,以及初始化网络
*************************************************************************************************************************/
bool SIM900_ModuleInit(void)
u8 retry = 5;
//重试次数
//检测模块存在
retry = 5;
//重试次数
SIM900_SendATcom(&AT&); //发送&AT&,同步波特率,并且等待应答
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 10)) //等待响应,超时100ms
}while(retry);
if(retry == 0) return FALSE;
//设置关闭回显
retry = SIM900_RETRY;
//重试次数
SIM900_SendATcom(&ATE 0&); //发送&ATE&,关闭回显模式
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 10)) //等待响应,超时100ms
SIM900_debug(&\r\n关闭AT回显模式成功!\r\n&);
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0)
SIM900_debug(&\r\n关闭AT回显模式失败!\r\n&);
return FALSE;
//设置短消息格式为PDU格式
retry = SIM900_RETRY;
//重试次数
SIM900_SendATcom(&AT+CMGF=0&); //发送&AT+CMGF&,设置短消息格式为PDU格式
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 10)) //等待响应,超时100ms
SIM900_debug(&\r\n设置短消息格式为PDU格式成功!\r\n&);
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0)
SIM900_debug(&\r\n设置短消息格式为PDU格式失败!\r\n&);
return FALSE;
//使能RI引脚提示
retry = SIM900_RETRY;
//重试次数
SIM900_SendATcom(&AT+CFGRI=1&); //发送&AT+CFGRI&,启动RI引脚提示
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 10)) //等待响应,超时100ms
SIM900_debug(&\r\n启动RI引脚提示成功!\r\n&);
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0)
SIM900_debug(&\r\n启动RI引脚提示失败!\r\n&);
return FALSE;
//设置模块sleep模式使能
retry = SIM900_RETRY;
//重试次数
SIM900_SendATcom(&AT+CSCLK=1&); //发送&AT+CSCLK&,启动SLEEP模式
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 10)) //等待响应,超时100ms
SIM900_debug(&\r\n设置SLEEP成功!\r\n&);
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0)
SIM900_debug(&\r\n设置SLEEP失败!\r\n&);
return FALSE;
SIM900_SetDTR(1); //使能SLEEP模式
return TRUE;
/*************************************************************************************************************************
: bool SIM900_TestAT(u32 retry)
: SIM900 AT 命令通信测试
: retry:重试次数
: FALSE:通信失败;TRUE:通信成功
* 最后修改时间
每隔20ms向SIM900发送一个&AT&,等待响应返回
*************************************************************************************************************************/
bool SIM900_TestAT(u32 retry)
//检测模块存在
SIM900_SendATcom(&AT&);
//发送&AT&,同步波特率,并且等待应答
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 15)) //等待响应,超时150ms
return TRUE;
}while(retry);
return FALSE;
/*************************************************************************************************************************
: SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut)
: 获取SIM900的AT指令响应
: pRxBuff:接收缓冲区指针(输入);pLen:接收到的数据大小(输出),
pKeyword:关键字,为字符串,比如&OK&,如果在接收到的字符串中有OK字符,就返回成功,否则失败(输入)
ByteTime:字节超时时间,单位ms最大999ms
TimeOut:等待超时时间,单位字节超时时间
: SIM900_ERROR
* 最后修改时间
本函数会在接收缓冲区字符串结束添加'\0'
:添加字节超时与总超时
*************************************************************************************************************************/
SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut)
u32 cnt1, cnt2=0; //接收数据计数器
u32 timeCnt = TimeO
if(ByteTime & 999)ByteTime = 999;
cnt1 = cnt2;
GSM_DelayMS(ByteTime);
//延时字节超时
cnt2 = SIM900_GetRxCnt();
//获取接收数据计数器
if(cnt1 == cnt2)
//完成接收数据了,退出等待
timeCnt --;
if((cnt1 & 0)&&(timeCnt!=0)) timeCnt=1;
//数据接收完毕,退出
timeCnt = TimeO
}while(timeCnt);
//等待超时
if(cnt2 == 0)
SIM900_debug(&\r\nAT指令返回超时\r\n&);
return AT_RETURN_TIME_OUT;
//返回超时错误
//数据接收完毕
*pLen = cnt2;
//返回接收数据长度
pRxBuff[cnt2] = '\0';
//将数据结尾添加结束字符串
SIM900_debug(&%s\r\n&,pRxBuff);
//打印返回信息
if(strstr((const char*)pRxBuff, pKeyword) != NULL)
//搜索关键字
SIM900_debug(&%s 返回成功!\r\n&,pKeyword);
return AT_RETURN_OK;
else if(strstr((const char*)pRxBuff, &ERROR&) != NULL)
SIM900_debug(&%s 返回错误!\r\n&,pKeyword);
return AT_RETURN_ERROR;
SIM900_debug(&%s 返回未知!\r\n&,pKeyword);
return AT_RETURN_UNKNOWN;
/*************************************************************************************************************************
: int SIM900_GetSmsNum(void)
: 获取SIM卡存储的短信数量
: &0:错误,其它:短信数量
* 最后修改时间
*************************************************************************************************************************/
int SIM900_GetSmsNum(void)
u8 retry = SIM900_RETRY;
//重试次数
SIM900_SendATcom(&AT+CPMS?&); //发送&AT+CPMS&,获取短信数量
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0) return -1;
p = strstr((const char*)SIM900_Buff, &\&SM\&&);
//搜索字符&&SM&&
if(p != NULL)
if(p[6] != ',') n = 2;
//短信数量有可能是1位数,也有可能是2位数,通过判断后面是否为','
else n = 1;
return GSM_StringToDec(p + 5, n);
//跳过前面的5字节,&&SM&,&,并获取存储的短信数量
return -1;
/*************************************************************************************************************************
: bool SIM900_DelMultiSMS(SIM900_DEL DelStatus)
: SIM900批量删除短信
: SIM900_DEL
: TRUE:成功;FALSE:失败;
* 最后修改时间
批量删除的时候可能会很慢
*************************************************************************************************************************/
bool SIM900_DelMultiSMS(SIM900_DEL DelStatus)
u8 retry = SIM900_RETRY;
//重试次数
switch(DelStatus)
case DEL_READ_SMS:
//删除所有已读短信
SIM900_SendATcom(&AT+CMGDA=1&);
case DEL_UNREAD_SMS:
//删除所有未读短信
SIM900_SendATcom(&AT+CMGDA=2&);
case DEL_SENT_SMS:
//删除所有已经发送的短信
SIM900_SendATcom(&AT+CMGDA=3&);
case DEL_UNSENT_SMS:
//删除所有未发送短信
SIM900_SendATcom(&AT+CMGDA=4&);
case DEL_INBOX_SMS:
//删除所有接收短信
SIM900_SendATcom(&AT+CMGDA=5&);
case DEL_ALL_SMS:
//删除所有短信
SIM900_SendATcom(&AT+CMGDA=6&);
default: return FALSE;
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 200))//等待响应,超时2S
return TRUE;
SIM900_Ready(); //等待就绪
}while(retry --);
return FALSE;
/*************************************************************************************************************************
: SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt)
: 读取SIM900所有的未读短信
: pUnreadSMSBuff:未读短信PDU数据缓冲区指针,BuffSize:缓冲区大小,pPDUCnt:PDU数据大小
: SIM900_ERROR
* 最后修改时间
短信最大存储数量为50条
缓冲区必须足够大,做好最坏打算,有50条未读短信,如果缓冲区不够大,会发送溢出
溢出后虽然不会造成系统错误,但是会覆盖前面的未读短信数据.
*************************************************************************************************************************/
SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt)
SIM900_ERROR
u8 retry = SIM900_RETRY;
//重试次数
SIM900_SetRxBuff(pUnreadSMSBuff, BuffSize);
//重新设置接收缓冲区
SIM900_SendATcom(&AT+CMGL=0&);
//发送&AT+CMGL&,读取所有的未读短息
error = SIM900_GetATResp(pUnreadSMSBuff, pPDUCnt, &OK&, 250, 4); //等待响应,超时1000ms
if(error == AT_RETURN_OK)
SIM900_Ready(); //等待就绪
}while(retry);
SIM900_SetRxBuff(SIM900_Buff, SIM900_BUFF_SIZE);
//恢复默认缓冲区
/*************************************************************************************************************************
: bool GSM_ParsePDUSMS(char *pPDU,char *pSMS,u32 len,SMS_INFO *pInfo)
: 解析一条PDU格式短信
: pPDU:短信PDU数据缓冲区指针
pSMS:解析后的短信缓冲区指针
pInfo:短信信息指针
: TRUE:成功;FALSE:失败
: void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt);
*最后修改时间 :
*************************************************************************************************************************/
bool GSM_ParsePDUSMS(char *pPDU, char *pSMS, u32 PDUSize, SMS_INFO *pInfo)
u16 cnt = 0;
p = strstr((const char*)pPDU, &+CMGR:&);
if(p == NULL)
SIM900_debug(&短信中没有搜索到\&+CMGR:\&\r\n&);
p = strstr((const char*)pPDU, &+CMGL:&);
if(p == NULL)
SIM900_debug(&短信中没有搜索到\&+CMGL:\&\r\n&);
return FALSE;
//提取短信的编号 //+CMGR: 1,&&,34
if(p[8] != ',') pInfo-&IndexNum = GSM_StringToDec(p + 7, 2); //短信索引可能是1位数,也有可能是2位数,通过判断后面是否为','
else pInfo-&IndexNum = GSM_StringToDec(p + 7, 1);;
p = strstr((const char*)p, &\r\n&); //寻找短信PDU开始位置
cnt = ((u32)p - (u32)pPDU) + 2;
//找到短信PDU开始的位置了
if(p == NULL || cnt &= PDUSize)
pInfo-&SMS_Size = 0;
SIM900_debug(&短信解析错误!\r\n&);
return FALSE;
//获取短信中心号码长度
temp = GSM_StringToHex(&pPDU[cnt], 2); //将16进制样式字符串转换为整型数
//跳过前面的短信中心号码长度字节
cnt += temp*2;
//跳过前面的短信中心信息
//解析PDU数据
//UDHI为1,代表用户数据有头部信息,用于标识短信拆分信息
pInfo-&PDU = GSM_StringToHex(&pPDU[cnt], 2); //将16进制样式字符串转换为整型数//PDU数据
//跳过PDU头数据字节
//计算发送短信的号码的长度
temp = GSM_StringToHex(&pPDU[cnt], 2); //将16进制样式字符串转换为整型数
//跳过电话号码长度字节
//跳过地址类型,常为&91&,一字节
pInfo-&NumLen = ChartoPhoneNum((char *)&pPDU[cnt], (char *)&(pInfo-&NumBuff[0]), (temp & SMS_NUM_LEN_MAX - 2) ? (SMS_NUM_LEN_MAX - 2) : temp); //转换发送号码
pInfo-&NumBuff[pInfo-&NumLen] = 0; //结束符
//lcd_printf(&pInfo-&NumLen=%d\r\n&,pInfo-&NumLen);
//uart_printf(&%s\r\n&,pInfo-&NumBuff);
cnt += (temp%2) ? (temp+1) : //跳过发送号码长度的字节数
cnt+=2; //跳过PID,2B
pInfo-&DSC = GSM_StringToHex(&pPDU[cnt], 2); //获取DSC信息
cnt+=2; //跳过DSC,2B
//cnt+=2; //跳过VP,2B //没有这个标志
//cnt+=2; //跳过UDL,2B//没有这个标志
pInfo-&Timer.Year = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');
cnt += 2; //年
pInfo-&Timer.Month = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0'); cnt += 2; //年
pInfo-&Timer.Day = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');
cnt += 2; //年
pInfo-&Timer.Hour = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0');
cnt += 2; //年
pInfo-&Timer.Minute = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0'); cnt += 2; //年
pInfo-&Timer.Second = (pPDU[cnt + 1] - '0') * 10 + (pPDU[cnt] - '0'); cnt += 2; //年
cnt += 2; //跳过时差2字节
SMS_Size = GSM_StringToHex(&pPDU[cnt], 2);
//计算短信字符数量,不管英文,中文都算一个字符
SIM900_debug(&SMS_Size = GSM_StringToHex(&pPDU[cnt], 2) = %d\r\n&,SMS_Size);
//跳过短信长度字节,2B
if(pInfo-&PDU & 0x40) //用户数据有头部信息,标识短信已经被分割为几条
//跳过前面8个数据,只要后面的4个,标识
SMS_Size -= 12;
//短信长度减去偏移
pInfo-&AllNum = GSM_StringToHex(&pPDU[cnt], 2);//计算总分割数
//跳过2B的总数
pInfo-&PreNum = GSM_StringToHex(&pPDU[cnt], 2);//计算当前位置
//跳过2B的当前位置
SIM900_debug(&短信分割:%d/%d\r\n&,pInfo-&AllNum, pInfo-&PreNum);
pInfo-&AllNum = pInfo-&PreNum = 0; //短信没有被分割
//DCS 00:7BIT编码;08:UCS2编码;04:8bit编码
switch((pInfo-&DSC) & 0x0f)
case 0x00: //7bit编码
SIM900_debug(&短信为7bit编码(TEXT格式)\r\n&);
pInfo-&SMS_Size = (SMS_Size & 160) ? 160 : SMS_S
//短信大小
pInfo-&TEXT_MODE = 1;
SMS_Size = (SMS_Size * 7 / 8) + (((SMS_Size * 7) % 8) ? 1 : 0);//计算短信占用空间大小
for(temp = 0;temp & SMS_Stemp ++)
//将PDU数据转换为16进制数据
pPDU[temp] = GSM_StringToHex(&pPDU[temp && 1], 2); //1B数据转换为PDU格式后占用2B
gsmDecode7bit((u8 *)pPDU, (char *)pSMS, SMS_Size); //7bit-&8bit,数据长度会发生变化
//SIM900_debug(&SMS:%s\r\n&,pSMS);
case 0x04: //8bit编码
SIM900_debug(&短信为8bit编码(不支持)\r\n&);
return FALSE;
case 0x08: //UCS2编码
SIM900_debug(&短信为UCS2编码(PDU格式)\r\n&);
pInfo-&TEXT_MODE = 0;
SMS_Size = (SMS_Size & 140) ? 140 : SMS_S
//短信字符限制为140B
//UNICODE PDU转换为字符串 --& GBK,返回短信大小,每个短信字符占用2字节,每个字节转换为PDU后占用2B
pInfo-&SMS_Size = UnicodeStrToString((u8 *)pPDU+cnt,(char *)pSMS,SMS_Size&&1);
default:SIM900_debug(&未知短信编码格式!\r\n&);return FALSE;
pSMS[pInfo-&SMS_Size] = '\0';
//添加结束符
return TRUE;
/*************************************************************************************************************************
: SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum)
: 读取一条TEXT格式短信
: pSMS:解析后的短信存放位置指针,注意存放的最大大小由_MAX_SMS_SIZE决定
pInfo:短信信息指针
IndexNum:短信索引号
: GSM_ERROR:状态
: 短信读取与解析
*最后修改时间 :
*************************************************************************************************************************/
SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum)
SIM900_ERROR
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
//配置短信为TEXT格式
SIM900_SendATcom(&AT+CMGF=1&);
if(SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20) == AT_RETURN_OK)
sprintf((char *)SIM900_Buff, &AT+CMGR=%d&, IndexNum);
//写入索引号
SIM900_SendATcom((char *)SIM900_Buff);
//发送读取短信命令
error = SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20);
//等待返回
if(error == AT_RETURN_OK)
GSM_ParseTextSMS((char *)SIM900_Buff, pSMS, cnt, pInfo);
//解析TEXT格式短信
SIM900_SendATcom(&AT+CMGF=0&); //配置短信为PDU格式
error = SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20);
/*************************************************************************************************************************
: u32 GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo)
: 解析一条TEXT格式短信
: pText:短信TEXT数据缓冲区指针
pSMS:解析后的短信缓冲区指针
TextSize:数据大小
pInfo:短信信息指针
: TRUE:成功;FALSE:失败
*最后修改时间 :
: 需要先切换到TEXT格式,用于解析TEXT格式短信,之后会切换回PDU格式
需要先解析为PDU后才知道是否为TEXT格式短信
*************************************************************************************************************************/
bool GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo)
u16 cnt = 0;
// u16 SMS_S
pText[TextSize] = '\0';
//添加结束符
p = strstr((const char*)pText, &+CMGR:&);
p = strstr((const char*)p, &\r\n&); //寻找短信TEXT开始位置
cnt = ((u32)p - (u32)pText) + 2;
//找到短信TEXT开始的位置了
if(p == NULL || cnt &= TextSize)
SIM900_debug(&TEXT短信解析错误!\r\n&);
return FALSE;
p +=2; //跳到短信开始位置
for(cnt = 0;cnt & pInfo-&SMS_Scnt ++) //复制短信
pSMS[cnt] = p[cnt];
pSMS[pInfo-&SMS_Size] = 0;
//添加结束符
return TRUE;
/*************************************************************************************************************************
: static u8 PhoneNumtoPDUChar(u8 *pNum, char *pCHAR,u8 NumLen)
: 将电话号码字符转换为PDU要求的字符
: pNum:电话号码指针
pChar:字符缓冲区指针
NumLen:电话号码长度
: 字符长度
: 底层宏定义
*最后修改时间 :
: 主要用于电话号码,短信中心号码转换
如果长度为奇数,则将补成偶数,并在最后一个字符的高位保留位0
本函数不添加结束符
*************************************************************************************************************************/
static u8 PhoneNumtoPDUChar(u8 *pNum, char *pChar,u8 NumLen)
for(i = 0;i & NumLi ++)
temp = (pNum[i]+'0') & 0x0f;
if(i % 2) //位数为奇数
pChar[i-1] = (temp & 9) ? ('a' + temp - 10) :( temp + '0');
//位数为偶数
pChar[i+1] = (temp & 9) ? ('a' + temp - 10) : (temp + '0');
pChar[NumLen-1] = 'F';
return (NumLen + 1);
return NumL
/*************************************************************************************************************************
: static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen)
: 将字符转换为电话号码
: pCHAR:字符缓冲区指针
pNum:电话号码指针
charLen:字符号码长度
: 电话长度
: 底层宏定义
*最后修改时间 :
: 主要用于电话号码,短信中心号码转换
如果电话长度为奇数,则将补成偶数,并在最后一个字符的高位保留位0
转换后为字符
*************************************************************************************************************************/
static u8 ChartoPhoneNum(char *pChar, char *pNum, u8 CharLen)
for(i = 0;i & CharLi ++)
temp = pChar[i];
if(temp == 'F') //还有一位就结束了
pChar[i+1];
return i + 1;
else if(temp & '9') //非数字
return 0; //电话号码格式错误
else if(i % 2) //位数为奇数
pNum[i-1] =
else //位数为偶数
pNum[i+1] =
/*************************************************************************************************************************
: static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen)
: 将字符串转换为unicode,并存储为16进制样式的字符串
: pStr:字符缓冲区指针
pucode:转换结果缓冲区
SrtLen:字符串字节长度
: 转换成为字符后的长度
: u16 OneGBKtoUNICODE(u16 GBKCode)
*最后修改时间 :
: 用于将短信内容转换为PUD格式,本函数不添加字符串结束符
如&a,b,c&---&&0,0,6,1,0,0,6,2,0,0,6,3&
输出缓冲区至少为输入的4倍
*************************************************************************************************************************/
static u32 StringToUnicodeStr(char *pStr, char *pucode,u32 SrtLen)
u8 chTmp= 0;
u32 cnt = 0;
for(i = 0;i & SrtLi ++)
if(pStr[i] & 0x80) //ASCII
temp = pStr[i];
temp = pStr[i ++]&& 8;
temp |= pStr[i];
temp = OneGBKtoUNICODE(temp);
for(m = 0; m &= 12; m+=4)
chTmp = (temp && (12-m)) & 0x0F;
//先取高位
if(chTmp & 0x09)
//! 0x0A-0x0F
pucode[cnt ++] = chTmp-0x0A+'A';
//! 'A'-'F'
//! 0x00-0x09
pucode[cnt ++] = chTmp-0x00+'0';
//! '0'-'9'
/*************************************************************************************************************************
: u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen)
: 将字符unicode转换为字符串
: pucode:转换结果缓冲区
pStr:字符缓冲区指针
SrtLen:字符串字节长度
: 转换成为字符后的长度
: u16 OneUNICODEtoGBK(u16 unicode);
*最后修改时间 :
: 用于将PUD格式短信解析,本函数不添加字符串结束符
:解决短信中句号无法解析
*************************************************************************************************************************/
static u32 UnicodeStrToString(u8 *pucode,char *pStr,u32 SrtLen)
u32 cnt = 0;
for(i = 0;i & SrtLi+=4)
if(pucode[i] == '0') //0
H = pucode[i+2];
L = pucode[i+3];
H = (H & '9') ? H - 'A' + 10 : H - '0';
L = (L & '9') ? L - 'A' + 10 : L - '0';
pStr[cnt++] = (H && 4) + L;
H = pucode[i];
L = pucode[i+1];
H = (H & '9') ? H - 'A' + 10 : H - '0';
L = (L & '9') ? L - 'A' + 10 : L - '0';
temp = (H && 4) + L;
temp &&= 8;
H = pucode[i+2];
L = pucode[i+3];
H = (H & '9') ? H - 'A' + 10 : H - '0';
L = (L & '9') ? L - 'A' + 10 : L - '0';
temp |= (H && 4) + L;
//lcd_printf(&temp1 = 0x%04X\r\n&,temp);
switch(temp)
case 0x3002: //句号无法显示,转换为GBK编码句号
temp = 0xA1A3;//'。';
temp = OneUNICODEtoGBK(temp); //编码转换
//lcd_printf(&temp2 = 0x%04X\r\n&,temp);
pStr[cnt++] = temp && 8 ;
pStr[cnt++] = temp & 0
/*************************************************************************************************************************
: u32 GSM_StringToHex(char *pStr, u8 NumDigits)
: 将16进制样式字符串转换为16进制整型数(必须保证字符串字母都是大写)
: pStr:字符串起始指针
NumDigits:数字位数,16进制数字位数
: 转换后的数字
*最后修改时间 :
: 比如字符串&A865&转换后为0xA865,位数为4位
必须保证字符串字母都是大写
*************************************************************************************************************************/
static u32 GSM_StringToHex(char *pStr, u8 NumDigits)
u32 HEX = 0;
NumDigits = (NumDigits & 8) ? 8 : NumD //最大支持8位16进制数
for(i = 0;i & NumDi ++)
HEX &&= 4;
temp = pStr[i];
temp = (temp & '9') ? temp - 'A' + 10 : temp - '0';
return HEX;
/*************************************************************************************************************************
: void GSM_HexToString(u32 HexNum,c har *pStr, u8 NumDigits)
: 将整型数字转换为16进制样式字符串(字母为大写,不带结束符)
: HexNum:16进制数字
pStr:字符缓冲区指针
NumDigits:数字位数,16进制数字位数
*最后修改时间 :
: 比如字符串0xA865转换后为&A865&,位数为4位
*************************************************************************************************************************/
static void GSM_HexToString(u32 HexNum,char *pStr, u8 NumDigits)
NumDigits = (NumDigits & 8) ? 8 : NumD //最大支持8位16进制数
for(i = 0;i & NumDi ++)
temp = 0x0f & (HexNum && (4 * (NumDigits - 1 - i)));
temp = (temp & 0x09) ? (temp - 0x0A + 'A') : (temp + '0');
/*************************************************************************************************************************
: u32 GSM_StringToDec(char *pStr, u8 NumDigits)
: 将10进制样式字符串转换为整型数(必须保证完全为数字字符)
: pStr:字符串起始指针
NumDigits:数字位数,10进制数字位数
: 转换后的数字
*最后修改时间 :
: 比如字符串&1865&转换后为1865,位数为4位
必须保证完全为数字字符
*************************************************************************************************************************/
u32 GSM_StringToDec(char *pStr, u8 NumDigits)
u32 DEC = 0;
NumDigits = (NumDigits & 10) ? 10 : NumD //最大支持10位10进制数
for(i = 0;i & NumDi ++)
temp = pStr[i] - '0';
if(temp & 9)
//只能是数字范围
for(j = 1;j & (NumDigits - i);j ++)
temp *= 10;
return DEC;
/*************************************************************************************************************************
: SIM900_CALLS SIM900_TestCallStatus(void)
: SIM900 通话状态检测
: retry:重试次数
: FALSE:通信失败;TRUE:通信成功
* 最后修改时间
每隔20ms向SIM900发送一个&AT&,等待响应返回
*************************************************************************************************************************/
SIM900_CALLS SIM900_TestCallStatus(void)
u8 retry = SIM900_RETRY;
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
SIM900_SendATcom(&AT+CPAS&);
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20))
//等待响应,超时200ms
p = strstr((const char*)SIM900_Buff, &+CPAS:&);
//搜索字符&+CPAS&
if(p != NULL)
cnt = GSM_StringToDec(p + 7, 1);
//获取状态编码
if(cnt & SIM900_CALL_CENTER)
return SIM900_CALL_ERROR;
else return (SIM900_CALLS)
SIM900_Ready(); //等待就绪
}while(retry);
return SIM900_CALL_ERROR;
/*************************************************************************************************************************
: bool SIM900_HangUp(void)
: SIM900 挂掉电话
: FALSE:通信失败;TRUE:通信成功
* 最后修改时间
*************************************************************************************************************************/
bool SIM900_HangUp(void)
u8 retry = SIM900_RETRY;
//检测模块存在
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
SIM900_SendATcom(&ATH&);
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200ms
return TRUE;
SIM900_Ready(); //等待就绪
}while(retry);
return FALSE;
/*************************************************************************************************************************
: bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber)
: 获取短信服务中心号码
: pServeNumber:电话号码存储缓冲区指针
: FALSE:通信失败;TRUE:通信成功
* 最后修改时间
获取SIM卡内部的短信服务中心号码,一般在办理SIM卡的时候已经进行了设置.
如果没有预置短信中心号码需要使用手机进行设置
*************************************************************************************************************************/
bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber)
char *p,*p1;
u8 retry = SIM900_RETRY;
//重试次数
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
//+CSCA: &+0&,145
SIM900_SendATcom(&AT+CSCA?&);
//发送&AT+CSCA&,获取短信服务中心号码
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
p = strstr((const char*)SIM900_Buff, &+CSCA:&);
//搜索字符&+CSCA:&
if(p != NULL)
//搜索成功
p = strstr(p+1, &+&); //搜索&+&
if(p != NULL)
p1 = strstr(p+1, &\&&); //搜索&\&&
if(p1 != NULL)
n = p1 - (p+1); //计算电话号码长度
pServeNumber-&PhoneNumLen = (n & PHONE_NUMBER_MAX_LEN) ? PHONE_NUMBER_MAX_LEN : //存储短信服务中心号码长度
//跳过前面的&+&
for(n = 0;n & pServeNumber-&PhoneNumLn ++)
pServeNumber-&PhoneNumBuff[n] = p[n]; //复制电话号码
pServeNumber-&PhoneNumBuff[n] = '\0';
//添加结束符
SIM900_debug(&短信中心号码:%s(长度:%d)\r\n&,pServeNumber-&PhoneNumBuff,pServeNumber-&PhoneNumLen);
return TRUE;
SIM900_Ready(); //等待就绪
}while(retry);
return FALSE;
/*************************************************************************************************************************
: bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber)
: 获取本机号码
: CenterPhone:电话号码存储缓冲区指针
: FALSE:通信失败;TRUE:通信成功
* 最后修改时间
通常会预存本机号码到SIM卡,也可能没有
*************************************************************************************************************************/
bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber)
char *p,*p1;
u8 retry = SIM900_RETRY;
//重试次数
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
//+CNUM: &&,&&,129,7,4
SIM900_SendATcom(&AT+CNUM&);
//发送&AT++CNUM&,获取号码
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
p = strstr((const char*)SIM900_Buff, &+CNUM:&);
//搜索字符&+CNUM:&
if(p != NULL)
//搜索成功
p = strstr(p+1, &\&,\&&); //搜索&&,&&
if(p != NULL)
p1 = strstr(p+3, &\&,&); //搜索&&,&
if(p1 != NULL)
n = p1 - (p+3);
//计算电话号码长度
pPhoneNumber-&PhoneNumLen = (n & PHONE_NUMBER_MAX_LEN) ? PHONE_NUMBER_MAX_LEN : //存储号码长度
//跳过前面的&\&,\&&
for(n = 0;n & pPhoneNumber-&PhoneNumLn ++)
pPhoneNumber-&PhoneNumBuff[n] = p[n]; //复制电话号码
pPhoneNumber-&PhoneNumBuff[n] = '\0';
//添加结束符
SIM900_debug(&本机号码:%s(长度:%d)\r\n&,pPhoneNumber-&PhoneNumBuff,pPhoneNumber-&PhoneNumLen);
return TRUE;
SIM900_Ready(); //等待就绪
}while(retry);
return FALSE;
/*************************************************************************************************************************
: int SIM900_GetSignal(void)
: 获取信号强度
: &0:获取失败;0-31:信号强度;
* 最后修改时间
*************************************************************************************************************************/
int SIM900_GetSignal(void)
u8 retry = SIM900_RETRY;
//重试次数
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
//+CSQ: 27,0
//+CSQ: 5,0
SIM900_SendATcom(&AT+CSQ&);
//发送&AT++CSQ&,获取号码
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
p = strstr((const char*)SIM900_Buff, &+CSQ:&);
//搜索字符&+CSQ:&
if(p != NULL)
//搜索成功
if(p[7] == ',') //信号强度为1位数
temp = GSM_StringToDec(&p[6], 1);
temp = GSM_StringToDec(&p[6], 2);
SIM900_Ready(); //等待就绪
}while(retry);
return -1;
/*************************************************************************************************************************
: SIM900_NETSTATUS SIM900_GetNetworkStatus(void)
: 获取网络注册状态
: SIM900_NETSTATUS
* 最后修改时间
*************************************************************************************************************************/
SIM900_NETSTATUS SIM900_GetNetworkStatus(void)
u8 retry = SIM900_RETRY;
//重试次数
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
//+CREG: 0,1
SIM900_SendATcom(&AT+CREG?&);
//发送&AT+CREG?&,获取网络注册状态
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
p = strstr((const char*)SIM900_Buff, &+CREG:&);
//搜索字符&+CSQ:&
if(p != NULL)
//搜索成功
return (SIM900_NETSTATUS)GSM_StringToDec(&p[9], 1);
SIM900_Ready(); //等待就绪
}while(retry);
return SIM900_NET_ERROR;
//PDU模式短信限制长度,最大70个字符,不分中英文
//返回:限制之后的字符个数
u32 GSM_PDUStrRes(char *pStr)
u32 n = 0;
while(*pStr != 0)
if(n == 71)
SIM900_debug(&PDU模式短信长度超出70B,强制为70B!\r\n&);
*pStr = 0;
//强制添加结束符
if((u8)*pStr & 0x80) //ASCII
else if((u8)*pStr & 0x80) //中文
pStr += 2;
//发送一条短信
//短信电话号码长度按照字节算但是短信中心号码按照半字节算
//0 0D 10F3E3F9E9D16280
/*************************************************************************************************************************
: bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber)
: 发送一条普通短信,正常长度
: pSMS:短信内容缓冲区指针,内容为文本文档,并且字符串需要结束符
pPDU:PDU数据缓冲区指针
pServeNumber:短信中心号码
pPhoneNumber:目标手机号码结构指针
: TRUE:短信发送成功;FALSE:短信发送失败
*最后修改时间 :
: 短信文本需要添加结束符
电话号码必须以86等国际区号开头
PDU可以发送中文,但是text只能发送英文
*************************************************************************************************************************/
bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber)
SIM900_ERROR
u16 OffsetCnt = 0;
//缓冲区偏移计数器
char ComBuff[16];
nSMSCenterLen= 0, nSMSPduLen = 0;
u16 SMSLen = 0;
//短信字符长度
FunctionalState EnableU2S = DISABLE; //使能U2S编码模式,默认为7BIT编码模式
u8 *p = (u8 *)pSMS;
while(*p != 0)
if(*p &= 0x80)
EnableU2S = ENABLE; //使能U2S编码模式
SIM900_debug(&需要发送的短信为PDU格式\r\n&);
if(EnableU2S == ENABLE)
//使能了U2S编码模式
SMSLen = GSM_PDUStrRes(pSMS); //限制PDU短信长度,计算短信长度
//TEXT模式短信
SMSLen = strlen(pSMS);
//计算短信长度
if(SMSLen & 160)
//短信长度大于160个字符
pSMS[160] = 0;
//添加结束符,限制长度
SMSLen = 160;
//计算短信中心号码长度,+91,+86,短信中心号码必须由86开头,并且要加上91,长度为每个数字半字节,不足补F
temp = (strlen(pServeNumber) + 2 + 1) / 2;
GSM_HexToString(temp, (char *)(pPDU+OffsetCnt), 2); //短信中心号码长度转换为16进制样式字符串
OffsetCnt += 2;
//跳过短信中心号码长度字节
pPDU[OffsetCnt++] = '9'; //服务中心类型
pPDU[OffsetCnt++] = '1';
OffsetCnt += PhoneNumtoPDUChar((u8 *)pServeNumber,(char *)(pPDU+OffsetCnt),strlen(pServeNumber)); //短信中心号码
nSMSCenterLen = OffsetCnt / 2;
pPDU[OffsetCnt++] = '1';
pPDU[OffsetCnt++] = '1';
//! For MR
pPDU[OffsetCnt++] = '0';
pPDU[OffsetCnt++] = '0';
//! For DA
//计算电话号码长度,+86,发送短信的电话号码由86开头,电话号码长度为字符个数
GSM_HexToString(strlen(pPhoneNumber), (char *)(pPDU+OffsetCnt), 2); //手机号码长度转换为16进制样式字符串
OffsetCnt += 2; //跳过手机号码长度字节
pPDU[OffsetCnt++] = '9'; //服务中心类型
pPDU[OffsetCnt++] = '1';
OffsetCnt += PhoneNumtoPDUChar((u8 *)pPhoneNumber,(char *)(pPDU+OffsetCnt),strlen(pPhoneNumber)); //短信发送号码
//! For PID
pPDU[OffsetCnt++] = '0';
pPDU[OffsetCnt++] = '0';
//! For DCS
if(EnableU2S == ENABLE)
pPDU[OffsetCnt++] = '0';
pPDU[OffsetCnt++] = '8';
pPDU[OffsetCnt++] = '0';
pPDU[OffsetCnt++] = '0';
//! For VP
pPDU[OffsetCnt++] = 'A';
pPDU[OffsetCnt++] = 'A';
//! For UDL AND UD
//! 注意,此处先将用户数据长度设置为00,并
//! 记录此时的缓冲区位置,然后等编码完成,
//! 确定了用户数据长度后再修改为实际长度
cnt = OffsetC
pPDU[OffsetCnt++] = '0';
pPDU[OffsetCnt++] = '0';
//短信内容
if(EnableU2S == ENABLE)
temp = StringToUnicodeStr(pSMS,(char *)&pPDU[OffsetCnt], strlen(pSMS));//将短信数据转换为字符数据
OffsetCnt +=
GSM_HexToString(temp/2, (char *)&pPDU[cnt], 2);
//! PDU串的长度,后面AT+CMGS要用到此长度
nSMSPduLen = OffsetCnt / 2 -nSMSCenterL
u8 buff[140];
//TEXT短信缓冲区
temp = gsmEncode7bit(pSMS, buff);
//将ASCII转换为7bit编码
GSM_HexToString(SMSLen, (char *)&pPDU[cnt], 2);
for(cnt = 0;cnt &cnt ++)
GSM_HexToString(buff[cnt], (char *)&pPDU[OffsetCnt+cnt*2], 2); //7bit编码转换为16进制格式字符串
OffsetCnt += (temp && 1);
//! PDU串的长度,后面AT+CMGS要用到此长度
nSMSPduLen = OffsetCnt / 2 -nSMSCenterL
//短信内容长度转换为16进制样式字符串,存储短信长度
pPDU[OffsetCnt++] = 0x1A;
pPDU[OffsetCnt++] = 0x00;
SIM900_debug(&\r\n%s\r\n&,pPDU);
//! 下面是发送过程
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
SIM900_SendATcom(&ATE0&);
if(AT_RETURN_OK != SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
return FALSE;
//! AT+CMGF
SIM900_SendATcom(&AT+CMGF=0&);
if(AT_RETURN_OK != SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
return FALSE;
//! AT+CMGS//////////////////////////////////////////
sprintf(ComBuff, &AT+CMGS=%d&, nSMSPduLen);
SIM900_debug(&AT+CMGS=%d\r\n&, nSMSPduLen);
SIM900_SendATcom(ComBuff);
if(AT_RETURN_ERROR == SIM900_GetATResp(SIM900_Buff, &cnt, &&&, 10, 20)) //等待响应,超时200MS
return FALSE;
//PDU Content
SIM900_ClearRxCnt();
//清除接收缓冲区
SIM900_SendString((char *)pPDU); //发送字符串
error = SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 50);
if(error == AT_RETURN_ERROR)
//返回错误
return FALSE;
temp = 30;
//等待短信接收成功,最大等待30S
SIM900_ClearRxCnt();
//清除接收缓冲区
GSM_DelaySer(1);
error = SIM900_GetATResp(SIM900_Buff, &cnt, &+CMGS&, 10, 20); //查询发送成功提示
SIM900_ClearRxCnt();
//清除接收缓冲区
if(error == AT_RETURN_OK)
SIM900_debug(&短信已发送成功,对方已经接收!\r\n&);
else if(error == AT_RETURN_ERROR)
SIM900_debug(&短信发送失败!很有可能是欠费了!\r\n&);
return FALSE;
if(temp == 0)
SIM900_debug(&短信发送超时!\r\n&);
return FALSE;
}while(temp --);
//测试短信
//D98F4B8BD577ED4FE1
return TRUE;
/*************************************************************************************************************************
: SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut)
: 拨打指定电话号码
: pPhoneNumber:电话号码字符串指针
TimeOut:接听超时,1-255S
: SIM900_CALLS:拨打电话状态
*最后修改时间 :
: 拨打电话
*************************************************************************************************************************/
SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut)
u8 retry = SIM900_RETRY;
//重试次数
char buff[32];
SIM900_ERROR
if(strlen(pPhoneNumber) & 26) return SIM900_CALL_ERROR; //电话号码太长了
sprintf(buff, &ATD%s;&, pPhoneNumber);
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
SIM900_SendATcom(&AT+MORING=1&);
//发送&AT+MORING=1&,设置拨号提示
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0) return SIM900_CALL_ERROR;
//拨打电话
AT+MORING=1
MO CONNECTED
+CDRIND: 0
NO CARRIER
SIM900_SendATcom(buff);
error = SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20);
//等待响应,超时200MS
if(error == AT_RETURN_ERROR)
//返回错误
return SIM900_CALL_ERROR;
GSM_DelaySer(1);
error = SIM900_GetATResp(SIM900_Buff, &cnt, &MO RING&, 10, 1); //查询拨打成功提示
if(error == AT_RETURN_OK)
SIM900_debug(&呼叫成功,对方振铃中...\r\n&);
return SIM900_CALL_RING;
error = SIM900_GetATResp(SIM900_Buff, &cnt, &MO CONNECTED&, 10, 1); //查询接通标志
if(error == AT_RETURN_OK)
SIM900_debug(&对方已经接听电话!\r\n&);
return SIM900_CALL_PUT;
error = SIM900_GetATResp(SIM900_Buff, &cnt, &BUSY&, 10, 1); //查询接通标志
if(error == SIM900_CALL_BUSY)
SIM900_debug(&对方占线!\r\n&);
return SIM900_CALL_PUT;
SIM900_ClearRxCnt();
//清除接收缓冲区
TimeOut --;
}while(TimeOut);
if(TimeOut == 0)
SIM900_debug(&拨打电话超时!\r\n&);
return SIM900_CALL_TIMEOUT;
return SIM900_CALL_ERROR;
/*************************************************************************************************************************
: SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut)
: 电话拨打成功后等待对方接听
: TimeOut:接听超时,1-255S
: SIM900_CALLS:电话接通状态
*最后修改时间 :
: 拨打电话成功后,等待对方接通,或不接
*************************************************************************************************************************/
SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut)
SIM900_ERROR
while(TimeOut --)
SIM900_ClearRxCnt();
//清除接收缓冲区
GSM_DelaySer(1);
error = SIM900_GetATResp(SIM900_Buff, &cnt, &MO CONNECTED&, 10, 1); //查询接通标志
if(error == AT_RETURN_OK)
SIM900_debug(&对方已经接听电话!\r\n&);
return SIM900_CALL_PUT;
error = SIM900_GetATResp(SIM900_Buff, &cnt, &NO ANSWER&, 10, 1); //查询一直未接听标志
if(error == AT_RETURN_OK)
SIM900_debug(&对方无人接听!\r\n&);
return SIM900_CALL_NO_ANSWER;
error = SIM900_GetATResp(SIM900_Buff, &cnt, &NO CARRIER&, 10, 1); //电话已经挂断
if(error == AT_RETURN_OK)
SIM900_debug(&对方拒接电话,对方已经挂断!\r\n&);
return SIM900_CALL_NO_CARRIER;
SIM900_debug(&对方接听电话超时!\r\n&);
return SIM900_CALL_TIMEOUT;
/*************************************************************************************************************************
: SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut)
: 电话接通后等待对方挂电话
: TimeOut:接听超时,1-255S
: SIM900_CALLS:电话接通状态
*最后修改时间 :
: 等待对方挂电话
*************************************************************************************************************************/
SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut)
SIM900_ERROR
while(TimeOut --)
SIM900_ClearRxCnt();
//清除接收缓冲区
GSM_DelaySer(1);
error = SIM900_GetATResp(SIM900_Buff, &cnt, &NO CARRIER&, 10, 1); //电话已经挂断
if(error == AT_RETURN_OK)
SIM900_debug(&对方电话已经挂断!\r\n&);
return SIM900_CALL_NO_CARRIER;
SIM900_debug(&对方挂电话超时!\r\n&);
return SIM900_CALL_TIMEOUT;
/*************************************************************************************************************************
: bool SIM900_TestCall(void)
: 查询模块是否可以拨打电话
: TRUE:成功;FALSE:失败
*最后修改时间 :
: 用于检查模块是否准备好拨打电话
*************************************************************************************************************************/
bool SIM900_TestCall(void)
u8 retry = SIM900_RETRY;
//重试次数
if(SIM900_TestAT(10) == FALSE) //串口同步失败
SIM900_WaitSleep(1000); //等待上一个操作完成
SIM900_SendATcom(&AT+CCALR?&);
//发送&AT+CCALR?&,查询模块是否准备好
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &OK&, 10, 20)) //等待响应,超时200MS
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &+CCALR: 1&, 10, 1))
return TRUE;
if(AT_RETURN_OK == SIM900_GetATResp(SIM900_Buff, &cnt, &+CCALR: 0&, 10, 1))
return FALSE;
SIM900_Ready(); //等待就绪
}while(retry);
if(retry == 0) return FALSE;
return FALSE;
// 7-bit编码
// pSrc: 源字符串指针
// pDst: 目标编码串指针
// nSrcLength: 源字符串长度
// 返回: 目标编码串长度
static int gsmEncode7bit(const char* pSrc,u8* pDst)
// 源字符串的计数值
// 目标编码串的计数值
// 当前正在处理的组内字符字节的序号,范围是0-7
unsigned char nLeft=0;
// 上一字节残余的数据
int nSrcLength = strlen(pSrc);
// 计数值初始化
// 将源串每8个字节分为一组,压缩成7个字节
// 循环该处理过程,直至源串被处理完
// 如果分组不到8字节,也能正确处理
while(nSrc&nSrcLength)
// 取源字符串的计数值的最低3位
nChar = nSrc & 7;
// 处理源串的每个字节
if(nChar == 0)
// 组内第一个字节,只是保存起来,待处理下一个字节时使用
nLeft = *pS
// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
*pDst = (*pSrc && (8-nChar)) + nL
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft = *pSrc && nC
// 修改目标串的指针和计数值 pDst++;
//SIM900_debug(&%c&,*pDst);
// 修改源串的指针和计数值
pSrc++; nSrc++;
//Nleft还有剩余,需要一个自己保留。
nChar = nSrc & 7;
if(nChar != 0)
//*pDst='\0';
// 返回目标串长度
// 7-bit解码
// pSrc: 源编码串指针,7bit编码
// pDst: 目标字符串指针
// nSrcLength: 源编码串长度
// 返回: 目标字符串长度
static int gsmDecode7bit(const u8 *pSrc, char *pDst, int nSrcLength)
// 源字符串的计数值
// 目标解码串的计数值
// 当前正在处理的组内字节的序号,范围是0-6
unsigned char nL
// 上一字节残余的数据
// 计数值初始化
// 组内字节序号和残余数据初始化
nByte = 0;
nLeft = 0;
// 将源数据每7个字节分为一组,解压缩成8个字节
// 循环该处理过程,直至源数据被处理完
// 如果分组不到7字节,也能正确处理
while(nSrc&nSrcLength)
// 将源字节右边部分与残余数据相加,去掉最高位,得到一个目标解码字节
*pDst = (((*pSrc) && nByte) | nLeft) & 0x7f;
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft = (*pSrc) && (7-nByte);
// 修改目标串的指针和计数值
// 修改字节计数值
// 到了一组的最后一个字节
if(nByte == 7)
// 额外得到一个目标解码字节
*pDst = nL
// 修改目标串的指针和计数值
// 组内字节序号和残余数据初始化
nByte = 0;
nLeft = 0;
// 修改源串的指针和计数值
*pDst = 0; //添加结束符
// 返回目标串长度
//SIM900.H
/*************************************************************************************************************
STM32 SIM900底层驱动函数
* 创建时间:
* 最后修改时间:
GSM_CDMA发送短信等
*************************************************************************************************************/
#ifndef SIM900_H_
#define SIM900_H_
#include &system.h&
//GSM模块相关定义
/*#define SIM900_RESET
//PBout(6) //PB6
#define SIM900_PORON
PBout(5) //PB5
#define GSM_STATUS_IN
#define GSM_BUZZ
PCout(12) //PC12*/
#define SIM900_UART_CH
UART_CH3 //串口3
//GSM底层操作宏
/*#define GSM_RESET_H() (GSM_RESET=1)
#define GSM_RESET_L() (GSM_RESET=0)
#define GSM_PORON_H() (GSM_PORON=1)
#define GSM_PORON_L() (GSM_PORON=0)
#define GSM_STATUS() (GSM_STATUS_IN)
#define GSM_BUZZ_H() (GSM_BUZZ=1)
#define GSM_BUZZ_L() (GSM_BUZZ=0)
#define GSM_Delay_MS(x) Delay_MS(x) //CDMA GSM操作延时,单位MS*/
//GSM/CDMA模块UART相关接口
#define SIM900_SendATcom(x)
UARTx_ClearRxCnt(SIM900_UART_CH);UARTx_SendString(SIM900_UART_CH,x);UARTx_SendString(SIM900_UART_CH,&\r\n&)
//调用串口发送一个AT命令,并且先清除接收计数器
#define SIM900_SendData(data,len)
UARTx_SendData(SIM900_UART_CH, data, len); //发送指定长度数据
#define SIM900_SendString(x)
UARTx_SendString(SIM900_UART_CH, x)
//发送字符串
#define SIM900_GetRxCnt()
UARTx_GetRxCnt(SIM900_UART_CH);
//获取新数据计数器
#define SIM900_ClearRxCnt()
UARTx_ClearRxCnt(SIM900_UART_CH);
//清除新数据计数器
#define SIM900_UartInit()
UARTx_Init(SIM900_UART_CH, 115200, ENABLE) //初始化串口,波特率115200,开启接收中断
#define SIM900_SetRxBuff(pBuff, size) UARTx_SetRxBuff(SIM900_UART_CH, pBuff,size) //设置串口接收缓冲区
#define GSM_DelayMS(x)
OSTimeDlyHMSM(0,0,0,x)
//延时ms,最大延时999ms
#define GSM_Delay10MS()
OSTimeDlyHMSM(0,0,0,10)
//延时10ms
#define GSM_Delay100MS()
OSTimeDlyHMSM(0,0,0,100)
//延时100ms
#define GSM_DelaySer(x)
OSTimeDlyHMSM(0,0,x,0)
//S延时,最大59S
//SIM900返回错误
typedef enum
AT_RETURN_OK
//返回成功
AT_RETURN_ERROR
//返回错误
AT_RETURN_UNKNOWN
//返回结果未知
AT_RETURN_TIME_OUT
0xf, //等待返回超时
}SIM900_ERROR;
//短信发送日期,使用字符格式
typedef __packed struct
//年20xx年
u8 Reserve1; //保留
u8 Reserve2; //保留
}SMS_TIMER ;
//短信解析相关//注意要保证数据对齐
#define SMS_NUM_LEN_MAX
//电话号码最大长度16位
typedef __packed struct
//短信发送的时间
NumBuff[SMS_NUM_LEN_MAX]; //电话号码缓冲区,使用的是字符模式
//电话号码长度
//短信有效内容长度,最大140B
TEXT_MODE;
//1:短信为TEXT模式;0:短信为PDU模式
//PDU数据,用于区分是否有短信头部信息
//DSC数据,用于区分是否为字符模式(0),PDU模式(0X08)
//当前短信总分割数
//当前位置
//当前索引位置1-50
}SMS_INFO ;
//GSM/CDMA模块型号
typedef enum
GSM_MG323 = 0,
//GSM_CDMA模块型号,MG323
CDMA_MC323 = 1,
//GSM_CDMA模块型号,MC323
GSM_SIM900A = 2,
//GSM_CDMA模块SIM900A
GSM_UNKNOWN = 0xff //未知模块
}GSM_TYPE;
//SIM900删除短信选择
typedef enum
DEL_READ_SMS = 1, //删除所有已读短信
DEL_UNREAD_SMS = 2, //删除所有未读短信
DEL_SENT_SMS = 3, //删除所有已经发送的短信
DEL_UNSENT_SMS = 4, //删除所有未发送短信
DEL_INBOX_SMS = 5, //删除所有接收短信
DEL_ALL_SMS
= 6, //删除所有短信
}SIM900_DEL;
//通话状态
typedef enum
SIM900_CALL_READY = 0, //准备就绪,当前空闲
SIM900_CALL_UNKNOWN = 1, //未知响应指令
SIM900_CALL_RING = 2, //振铃,准备好可以接通
SIM900_CALL_CENTER = 3, //呼叫进行中
SIM900_CALL_TIMEOUT = 4, //拨打电话超时
SIM900_CALL_PUT
= 5, //拨打的电话对方已经接通
SIM900_CALL_NO_ANSWER= 6, //对方无人接听
SIM900_CALL_NO_CARRIER= 7, //对方已经挂断
SIM900_CALL_BUSY = 8, //占线
SIM900_CALL_ERROR = 0xff//其他错误
}SIM900_CALLS;
//网络注册状态
typedef enum
SIM900_NET_NOT = 0, //未注册
SIM900_NET_YES = 1, //已经注册
SIM900_NET_SEA = 2, //未注册,正在搜索
SIM900_NET_TUR = 3, //注册被拒绝
SIM900_NET_UNK = 4, //未知
SIM900_NET_ROA = 5, //已经注册,但是漫游
SIM900_NET_ERROR=0XFF//错误
}SIM900_NETSTATUS;
//SIM900通信缓冲区
#define SIM900_BUFF_SIZE 2048
extern u8 SIM900_Buff[SIM900_BUFF_SIZE]; //缓冲区
#define PDU_BUFF_SIZE 1024*10
//20KB 可以一次读取50条未读短信
extern u8 SmsPduBuff[PDU_BUFF_SIZE];
//PDU数据缓冲区
//相关控制引脚
#define SIM900_GetRI()
#define SIM900_SetDTR(x)
(PBout(13)=x)
//DTR PB13
#define SIM900_SetRESET(x)
(PBout(15)=x)
//RESET PB15
#define SIM900_SetPWR(x)
(PBout(12)=x)
//PWR PB12
//电话号码结构
#define PHONE_NUMBER_MAX_LEN 24-2
//电话号码最大长度
typedef __packed struct
//电话号码长度
char PhoneNumBuff[PHONE_NUMBER_MAX_LEN + 1];//电话号码缓冲区,电话号码前面的2位为地区编号,中国为86,打电话需要跳过前面的2位数字
}PHONE_NUMBER;
//最大重试次数,防止AT指令操作失败
#define SIM900_RETRY 2
#define SIM900_Ready() if(SIM900_TestAT(10) == FALSE){SIM900_WaitSleep(1000);} //让SIM900就绪,防止卡住//串口同步失败,等待上一个操作完成
void SIM900_HardwarePowerUP(void);//SIM900硬件开机
void SIM900_HardwarePowerDOWN(void);//SIM900硬件关机
void SIM900_HardwareReset(void);//SIM900硬件复位
bool GSM_SendSMS(char *pSMS, char *pPhoneNumber);//发送短信
void SIM900_HardwareInit(void); //初始化SIM900相关的硬件
bool SIM900_ModuleInit(void); //初始化SIM900模块
bool SIM900_TestAT(u32 retry); //检测模块响应
bool SIM900_HangUp(void);
//挂掉电话
SIM900_CALLS SIM900_TestCallStatus(void);//检测电话通话状态
SIM900_ERROR SIM900_GetATResp(u8 *pRxBuff, u32 *pLen, const char *pKeyword, u32 ByteTime, u32 TimeOut);//获取SIM900的AT指令响应
int SIM900_GetSmsNum(void); //获取SIM卡存储的短信数量
bool GSM_ParsePDUSMS(char *pPDU, char *pSMS, u32 PDUSize, SMS_INFO *pInfo);//解析一条PDU格式短信
SIM900_ERROR SIM900_GetUnreadSMS(u8 *pUnreadSMSBuff, u32 BuffSize, u32 *pPDUCnt);//读取SIM900所有的未读短信
SIM900_ERROR SIM900_ReadTextSMS(char *pSMS, SMS_INFO *pInfo, u16 IndexNum);//用text格式读取短信
bool GSM_ParseTextSMS(char *pText, char *pSMS, u32 TextSize, SMS_INFO *pInfo);//解析一条TEXT格式短信
bool SIM900_DelMultiSMS(SIM900_DEL DelStatus); //批量删除SIM900短信
bool SIM900_GetServeNumber(PHONE_NUMBER *pServeNumber); //获取短信服务中心号码
bool SIM900_GetPhoneNumber(PHONE_NUMBER *pPhoneNumber); //获取本机号码
bool GSM_SendOneSMS(char *pSMS, u8 *pPDU, char *pServeNumber, char *pPhoneNumber); //发送一条短信
int SIM900_GetSignal(void); //获取信号强度
SIM900_CALLS SIM900_MakingCall(const char *pPhoneNumber, u8 TimeOut);//拨打电话
bool SIM900_TestCall(void);//检查是否可以拨打电话
void SIM900_SetSMSServeNumber(char *pSMSServeNumber,u8 NumLen);//设置短信中心号码
bool SIM900_WaitSleep(u32 TimeOut); //等待模块空闲
SIM900_CALLS SIM900_WaitGetThrough(u8 TimeOut);//等待对方接听电话
SIM900_CALLS SIM900_WaitHangUP(u8 TimeOut);
//等待对方挂电话
SIM900_NETSTATUS SIM900_GetNetworkStatus(void); //获取网络注册状态
u32 GSM_StringToDec(char *pStr, u8 NumDigits);
//将10进制样式字符串转换为整型数(必须保证完全为数字字符
#endif /*SIM900A_H_*/
unicode_gbk.c
/*************************************************************************************************************
* 文件名: unicode_gbk.c
汉字编码转换
* 创建时间:
* 最后修改时间:
需要码表支持
*************************************************************************************************************/
#include &system.h&
#include &unicode_gbk.h&
#define GBK_UNICODE_IS_SDCARD 0 //GBK,UNICODE编码表在SD卡或其它存储器中
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//码表在SD卡中
#if GBK_UNICODE_IS_SDCARD
#include &ff.h&
#define GtoU &0:/GtoU.sys&
//GBK 转 UCICODE 编码表位置
#define UtoG &0:/UtoG.sys&
//UCICODE 转 GBK 编码表位置
//GtoU 文件工作区
//UtoG 文件工作区
/*************************************************************************************************************************
* 函数 : u8 GBK_UNICODE_Init(void)
* 功能 : 初始化GBK,UNICODE编码表
* 参数 : 无
* 返回 : 0:初始化成功;其它:初始化失败
* 依赖 : 底层读写函数
* 最后修改时间 :
*************************************************************************************************************************/
u8 GBK_UNICODE_Init(void)
status = f_open(&UtoG_File, UtoG, FA_OPEN_EXISTING | FA_READ); //以只读方式打开UNICODEtoGBK码表,打开失败返回错误
if(status != FR_OK) //打开失败
lcd_printf(&open %s error (%d)!\r\n&,UtoG, status);
status = f_open(&GtoU_File, GtoU, FA_OPEN_EXISTING | FA_READ); //以只读方式打开GBKtoUNICODE码表,打开失败返回错误
if(status != FR_OK) //打开失败
lcd_printf(&open %s error (%d)!\r\n&,GtoU, status);
/*************************************************************************************************************************
* 函数 : u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能 : 将GBK编码转换为unicode编码
* 参数 : GBK
* 返回 : unicode
* 依赖 : 底层读写函数
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
u16 OneGBKtoUNICODE(u16 GBKCode)
ch = GBKCode && 8;
cl = GBKCode & 0x00
ch -= 0x81;
cl -= 0x40;
f_lseek(&GtoU_File, (ch*0xbf+cl)*2);
//文件指针调到偏移位置
if(f_read(&GtoU_File, (u8 *)&data, 2, &bw) != FR_OK)
//读取2字节
return 0x1
return (ch&=0x7d && cl&=0xbe) ? data : 0x1
/* ch = GBKCode && 8;
cl = GBKCode & 0x00
ch -= 0x81;
cl -= 0x40;
return (ch&=0x7d && cl&=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1
/*************************************************************************************************************************
* 函数 : u16 OneUNICODEtoGBK(u16 unicode)
* 功能 : 将unicode编码转换为GBK编码
* 参数 : unicode
* 返回 : GBK
* 依赖 : 底层读写函数
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
u16 OneUNICODEtoGBK(u16 unicode)
//用二分查找算法
u8 buff[2];
if(unicode&=0X9FA5)
if(unicode&=0X4E00)
offset=unicode-0X4E00;//0x1b87
//0X4E00,汉字偏移起点
return 0x2020;
//不能显示的字符就给两个空格填充,否则乱码
else if(unicode&0X9FA5)//是标点符号
if(unicode&0XFF01||unicode&0XFF61)
return 0x2020;//没有对应编码 //不能显示的字符就给两个空格填充,否则乱码
offset=unicode-0XFF01+0X9FA6-0X4E00;
offset *= 2;
f_lseek(&UtoG_File, offset);
//文件指针调到偏移位置
if(f_read(&UtoG_File, buff, 2, &bw) != FR_OK) //读取2字节
return 0x2020;
temp = buff[0];
temp &&= 8;
temp += buff[1];
//返回找到的编码
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//码表直接在代码中
#include &unicode_gbk_code.h&
/*************************************************************************************************************************
* 函数 : u8 GBK_UNICODE_Init(void)
* 功能 : 初始化GBK,UNICODE编码表
* 参数 : 无
* 返回 : 0:初始化成功;其它:初始化失败
* 依赖 : 底层读写函数
* 最后修改时间 :
*************************************************************************************************************************/
u8 GBK_UNICODE_Init(void)
/*************************************************************************************************************************
* 函数 : u16 OneGBKtoUNICODE(u16 GBKCode)
* 功能 : 将GBK编码转换为unicode编码
* 参数 : GBK
* 返回 : unicode
* 依赖 : 底层读写函数
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
u16 OneGBKtoUNICODE(u16 GBKCode)
ch = GBKCode && 8;
cl = GBKCode & 0x00
ch -= 0x81;
cl -= 0x40;
return (ch&=0x7d && cl&=0xbe) ? wUnicodes[ch*0xbf+cl] : 0x1
/*************************************************************************************************************************
* 函数 : u16 OneUNICODEtoGBK(u16 unicode)
* 功能 : 将unicode编码转换为GBK编码
* 参数 : unicode
* 返回 : GBK
* 依赖 : 底层读写函数
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
u16 OneUNICODEtoGBK(u16 unicode)
//用二分查找算法
if(unicode&=0X9FA5)
if(unicode&=0X4E00)
offset=unicode-0X4E00;//0x1b87
//0X4E00,汉字偏移起点
return 0x2020;
//不能显示的字符就给两个空格填充,否则乱码
else if(unicode&0X9FA5)//是标点符号
if(unicode&0XFF01||unicode&0XFF61)
return 0x2020;//没有对应编码 //不能显示的字符就给两个空格填充,否则乱码
offset=unicode-0XFF01+0X9FA6-0X4E00;
offset *= 2;
temp = wGBKs[offset];
temp &&= 8;
temp += wGBKs[offset+1];
//返回找到的编码
#endif //GBK_UNICODE_IS_SDCARD
/*************************************************************************************************************************
* 函数 : void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
* 功能 : 将多个GBK编码转换为UNICODE
* 参数 : pGBK:GBK编码缓冲区
pUnicode:UNCODE编码缓冲区
cnt:转换编码个数
* 返回 : 无
* 依赖 : OneGBKtoUNICODE
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt)
while(cnt --)
*pUnicode = OneGBKtoUNICODE(*pGBK ++);
pUnicode ++;
/*************************************************************************************************************************
* 函数 : void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
* 功能 : 将多个UNICODE编码转换为GBK
* 参数 : pUnicode:UNCODE编码缓冲区
pGBK:GBK编码缓冲区
cnt:转换编码个数
* 返回 : 无
* 依赖 : OneUNICODEtoGBK
* 最后修改时间 :
需要flash中的码表支持
GBK码范围,高8位:0x81~0低8位:0x40~0xfe
*************************************************************************************************************************/
void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt)
while(cnt --)
*pGBK = OneUNICODEtoGBK(*pUnicode ++);
unicode_gbk.h
/*************************************************************************************************************
* 文件名: unicode_gbk.h
汉字编码转换
* 创建时间:
* 最后修改时间:
需要码表支持
*************************************************************************************************************/
#ifndef UNICODE_GBK_H_
#define UNICODE_GBK_H_
#include &system.h&
u8 GBK_UNICODE_Init(void);
u16 OneGBKtoUNICODE(u16 GBKCode);
u16 OneUNICODEtoGBK(u16 unicode);
void GBKToUnicode(u16 *pGBK, u16 *pUnicode, u32 cnt); //将多个GBK编码转换为UNICODE
void UnicodeToGBK(u16 *pUnicode, u16 *pGBK, u32 cnt); //将多个UNICODE编码转换为GBK
#endif /*UNICODE_GBK_H_*/
//短信接收
if(SIM900_GetSmsNum() & 0) //有消息
uart_printf(&有短信需要读取!\r\n&);
SIM900_TestAT(100);
error = SIM900_GetUnreadSMS(SmsPduBuff, PDU_BUFF_SIZE, &cnt);
//读取SIM900所有的未读短信
if(error == AT_RETURN_OK)
p = (char *)SmsPduB
//循环解析所有短信
p = (char *)strstr(p, &+CMGL:&);
if(p == NULL)
if(GSM_ParsePDUSMS(p, SMS_Buff,cnt-((u32)p - (u32)SmsPduBuff) , &SMS_Info) ==TRUE)
uart_printf(&\r\n***************************************************\r\n&);
uart_printf(&短信索引:%d\r\n&,SMS_Info.IndexNum);
//打印短信索引
uart_printf(&电话号码:%s\r\n&,SMS_Info.NumBuff);
//打印电话号码
uart_printf(&发送时间:20%d-%d-%d %d:%d:%d\r\n&, SMS_Info.Timer.Year, SMS_Info.Timer.Month, SMS_Info.Timer.Day, SMS_Info.Timer.Hour, SMS_Info.Timer.Minute, SMS_Info.Timer.Second);
//打印发送时间
uart_printf(&短信长度:%d\r\n&,SMS_Info.SMS_Size);
//打印发送时间
uart_printf(&短信内容:%s\r\n&,SMS_Buff);
//短信内容
uart_printf(&***************************************************\r\n\r\n&);
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:487012次
积分:5620
积分:5620
排名:第4368名
原创:84篇
转载:17篇
评论:585条
(1)(1)(1)(5)(1)(1)(2)(2)(2)(1)(2)(1)(2)(1)(1)(1)(2)(2)(1)(1)(7)(1)(1)(1)(1)(2)(4)(2)(1)(4)(9)(6)(5)(5)(4)(5)(3)(6)(2)(2)

我要回帖

更多关于 sim900a模块介绍 的文章

 

随机推荐