发送短信的时候,我们是确切地知道何时发送的;而接收数据的时候, 我们则不知道何时数据会到来,因此,在短信到达时,我们需要一种方式来获知它的到来并将其读出来。有两种方式:一是查询,二是触发事件。前一种方式我们不会用的,后一种方式是上选。我们可以预先对GSM模块设置一些参数,那么当它收到短信的时候,就会自动将数据送到串口上,我们就可以接着控制我们的程序去读取它了。
在这里,你必须非常清楚一些概念。不要以为短信到来的时候,GSM模块就一定可以将短信的内容直接送到串口上,然后我们直接读就可以了。如果你这样想,那么只能说你把事情想得太美好。事实上,模块给我们的回复是比较“乱”的,需要做不少处理(例如里面不仅有PDU串的内容,还有其他字符(串));不仅如此,甚至于很多GSM模块根本就不能在接收到短信的时候自动把PDU串送到串口上!例如,我所使用的GSM模块(它里面用的是西门子MC39i芯片)就是这样一个“弱智”的模块,你要使用事件触发的方式,最多最多只能让它做到:短信到来的时候,它会把短信写入SIM卡中(MC39i唯一的选择就是写存储器,然后再读出来),然后它会送一些提示信息到串口上,这时,你便可以监测到串口有数据来了,然后你再分析串口中数据的格式(里面包含了收到的短信写入了SIM卡上的位置号),然后再去SIM卡上找到那条短信,再读出来。是不是超级麻烦?的确!认了吧!
文章来源:http://www.codelast.com/
下面我们来看看怎么做:
(1)在初始化模块的函数中,你需要对GSM模块施以AT+CNMI命令,例如我对模块写入的命令是:AT+CNMI=1,1,0,0,1<回车>
5个参数的含义分别为:
<mode>=1:直接发送到TE
<mt>=1:如果接收到的SMS存储在ME,则返回+CMTI:<mem>,<index>
<bm>=0:小区广播不通知
<ds>=0:状态报告不通知
<bfr>=1:该值始终为1
对于<mt>这个参数,我想提醒一下大家:它本应可以取值2和3的,当它取2时,含义为:2——除了Class2 SMS,新的SMS直接发送到终端,返回:
+CMT:<length><CR><LF><PDU>
哇,大家一看,多么美好的返回结果!里面已经有PDU串了耶,可以直接读出来了!但是我很遗憾地告诉你:MC39i这个芯片就不支持!而且不支持的远不止一种两种模块,所以你必须先用串口调试工具或Windows的超级终端去测试你用的模块是否支持,如果不支持,那么再次很遗憾,你只能像我一样,取值1,然后在短信到来之后读SIM卡。题外话:有人说,SIM卡这样读写多了不是弄坏了啊?那要看你读写到底有多少了,如果真的非常多,也只能认了,要不,您换模块去?
上述命令中,五个参数的其他取值的含义请参阅相关文档。这条命令后,模块的返回值为“OK”,就表明设置成功了。这时,你再向模块发一条短信试试?肯定可以监测到串口上自动送回的数据了,格式为:
+CMTI: “MT”,1
其中,MT表示设备的所有可用储存位置,1表示短信存储位置索引值。然后呢,我们就可以用AT+CMGR命令去读取短信啦!关于AT+CMGR命令的具体参数,很多中文资料上均有详述,在此就不多言。
文章来源:http://www.codelast.com/
(2)以使用Win32 API为例,我们在初始化串口的时候,可以用SetCommMask函数来设置数据到达事件,例如
SetCommMask(hPort, EV_RXCHAR);
第一个参数就是你的端口句柄,第二个参数表明了收到一个字符,并且写入缓冲区后,将触发这个事件,然后,你在某一个等待事件的线程中的WaitCommEvent函数就可以不再阻塞线程了,你就可以读取数据了。注意,我这里的函数的参数是这样设置的:
WaitCommEvent(channelGSM.m_hPort, &dwEvtMask, NULL);
第三个参数设置为NULL使得以阻塞的方式等待事件发生,第二个参数是一个DWORD变量,当指定事件发生时,该函数会将发生的事件的值写入这个变量中,我们就可以在事件触发了以后接着判断是不是已经发生了我们想要的事件。
你也可以用CreateEvent配合WaitForSingleObject的方案来实现上面的效果。这是串口通信的知识,请参阅有关书籍。
(3)关于短信的删除,只想提醒大家一句:不是每个模块都支持一次删除所有短信的,就比如我用的MC39i芯片的模块(天啊我太不幸了,坏事全都赶上了),你必须要一条一条地删除,例如你可以用一个for循环配合AT+CMGD的命令来实现短信的逐条删除。
文章来源:https://www.codelast.com/
➤➤ 版权声明 ➤➤
转载需注明出处:codelast.com
感谢关注我的微信公众号(微信扫一扫):