请马老师帮我看看,关于gprs模块和单片机 AT+CNMI=2,2,0,0,0 的通信问题
看过马老师一篇文章 嵌入式系统中短消息实时处理的实现里面提出一种在嵌入式系统中实现短消息实时处理的方法,用ATmegal28单片机控制GSM模块,通过设置发送端和接收端的参数配置,使短消息不经过SIM卡而直接发送至单片机。短消息格式为PDU方式,增加了通用性。利用ATmegal28快速处理能力,结合状态机的程序设计方法,在接收程序中解析出必要的信息,从而实现短消息的快速处理。
论文里面说到的是pdu模式,我现在是sim300模块,128单片机,硬件结构大体一样
我现在需要实现没有pdu那么复杂,只需要用文本模式就可以了,因为只需要传输英文字母,但是却在手机发送短信控制单片机那里卡住了
我用的也是
若使短消息不经过SIM卡,直接发送至TE,可以设置:
AT+CNMI=2,2,0,0,0
但是当我用手机发送短信给模块,希望直接到达单片机从而执行我想要的中断处理函数时,单片机毫无反应
经过试验发现,单片机可以成功发送at指令给串口,从而达到通过模块向我的手机发送短信的目的,问题就出在,我用手机给单片机发送回短信这个环节 因为虽然手机发送Z给模块直接传输到串口(AT+CNMI=2,2,0,0,0指令用来设定该功能的)
但是单片机收到的确是
+CMT: "+8615862938263",,"08/09/02,15:34:01+32"
Z
这么一大串,(如果直接连接电脑串口,通过串口助手的发送Z的话,只是传送一个Z,所以中断顺利产生,但是换成手机,发1个Z就要带上那么一大串)所以可能单片机不知道一条短信是否读完就提前结束了,也就是说单片机很可能没收到Z就认为短消息已经结束,从而没有收到Z,请马老师指导下 使用GTM900的本来想直接飘过...
唉,同情楼主,折腾这么久了,还过不了关。
你的mega128的串口接收程序写的有问题,和什么模块都无关。串口中断是每收到一个字符就会产生一次的,所以你不要看到中断了
就急着处理,收的东西还没全呢,怎么处理啊,要想办法收全了再处理。建议你看看别人的串口接收中断处理代码。
最最最简单的办法,做个延时,等所有的字符都收齐了,再处理。或者开缓冲区,根据缓冲区的长度来判断是否都接收完毕。
下面是用CVAVR自动产生的串口中断接收程序,支持缓冲区,比较经典的:
#include <mega128.h>
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 255
char rx_buffer0;
#if RX_BUFFER_SIZE0<256
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
#else
unsigned int rx_wr_index0,rx_rd_index0,rx_counter0;
#endif
// This flag is set on USART0 Receiver buffer overflow
bit rx_buffer_overflow0;
// USART0 Receiver interrupt service routine
interrupt void usart0_rx_isr(void)
{
char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0=data;
if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
rx_buffer_overflow0=1;
};
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0;
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm("cli")
--rx_counter0;
#asm("sei")
return data;
}
#pragma used-
#endif
// USART0 Transmitter buffer
#define TX_BUFFER_SIZE0 8
char tx_buffer0;
#if TX_BUFFER_SIZE0<256
unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
#else
unsigned int tx_wr_index0,tx_rd_index0,tx_counter0;
#endif
// USART0 Transmitter interrupt service routine
interrupt void usart0_tx_isr(void)
{
if (tx_counter0)
{
--tx_counter0;
UDR0=tx_buffer0;
if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
};
}
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART0 Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm("cli")
if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
{
tx_buffer0=c;
if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
++tx_counter0;
}
else
UDR0=c;
#asm("sei")
}
#pragma used-
#endif 好复杂,头都大了,一定要开辟缓冲区么,我直接接收就不可以么?
1做个延时,等所有的字符都收齐了,再处理。 问题是怎么延时呢?可否简单介绍一下
2或者开缓冲区,根据缓冲区的长度来判断是否都接收完毕。 开辟缓冲区我有点思路,可以参考马老师书上的,但是根据缓冲区的长度我还不是很明白这句话,如果我能判断接收完毕后就好了,手机发送的是那么一大串字符!
本身就不是学习编程出身的,老师非让我做这个不做完不行啊! Appcat
你好,可以邮件联系你么,我想知道如何做延时,实在没这方面的经验
希望可以发邮件和你请教! 手机发送的东西,总要有个上限吧,不可能是无限的吧,所以把你系统需要处理的最长长度+1做为缓冲区长度总可以吧。其实
英文短信才几个字符啊?上面我贴的程序里边开了255个字符,绝对够用了。
仔细看看上面的程序,里边有一个变量rx_counter0,这个就是关键所在。你在主程序里边判断rx_counter0是否不为零,如果
不为零,说明串口已经有东西进来了,计算一下你的波特率和最大长度,做一个延时,保证串口缓冲区能够收到所有字符,然后
取出整个缓冲区,你的完整短信已经在里边了,该怎么处理就怎么处理了。
#define MAX_BUF_LENS 255
unsigned char buf, i
//初始化,首先清空串口缓冲区,防止残留的字符干扰
while (rx_counter0) getchar();
memset(buf, 0, MAX_BUF_LENS);
......................
//自己做循环,检测rx_counter0是否不为零
while (!rx_counter0);
//延时100毫秒,具体多少需要自己算,这个时间宜长不宜短
delay_ms(100);
i = 0;
while (rx_counter0)
{
buf = getchar();
i++;
}
//到这里,串口过来的短信已经完整的存放在buf中了,你可以对buf进行需要的操作了
btw:别给我邮件了,我现在收邮件太麻烦,就在这里讨论吧。我觉得本身这个问题不难,是你的脑子卡在这里了,一旦想通了,你会发现是很自然的事情。
希望你能静下心来看懂上面的程序,你的思路就有了。 好的,不好意思,你给我这些程序已经给我很大的帮助了,我一定认真看,谢谢
memset这个函数的意思是初始化么?? memset就是想指定的地址,填入指定长度的内容
memset(buf, 0, MAX_BUF_LENS);就是想buf指针所指的地址连续填入MAX_BUF_LENS个零.
清空串口缓冲区必须要用while (rx_counter0) getchar(); 不能直接操作缓冲区,否则会死的很难看的。
这些代码都是使用CVAVR编译的。 1还有这个时间的问题
延时100毫秒不需要修改么
这就是我要接受的内容
+CMT: "+8615862938263",,"08/09/02,15:34:01+32"
Z
不知道100ms够不够?
2这段程序要建立在2楼你给我的开缓冲区的程序吧基础上把?也就是说2楼和5楼的程序都是需要的?
3还是关于清空缓冲区的问题
while (rx_counter0) getchar(); 的意思是当rx_counter0不为0也就是表示接收到的数目不是0的时候,就进行getchat()接收
当接收数目为0的时候就跳出循环执行memset();
问题是我不明白while (rx_counter0) getchar();是怎么实现清空的作用的,因为我不知道rx_counter0何时为0,
请赐教 1、100毫秒应该足够了。实际时间还能缩短,粗略估算:你需要接收的字符数×(1 / (波特率 / 8))= 延时时间
2、你说的完全对
3、getchar()函数的源码在2楼,每执行一次就从接收缓冲区中取出一个字符,缓冲区的计数器rx_counter0就会减1,所以当getchar()
取走缓冲区内最后一个字符时,rx_counter0就为零了。所以你不需要知道rx_counter0何时为零。
2楼的代码是用CVAVR的代码向导自动生成的,非常经典,建议深刻理解,这些问题都不成问题了,而且这个串口操作模型效率很高,
很多涉及串口的地方都能用。 因为我原来uart.c用得都是轮询写getchar(),和putchar(),而我现在只需要用到接收中断,所以我想putchar()就依然按照轮询得不改变,getchar()
用你那种char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0;
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm("cli")
--rx_counter0;
#asm("sei")
return data;
}
#pragma used-
#endif
这样可以吧??? 没有问题啊 太感谢楼上了,正在修改程序移植中。。。 还有几个问题恳请大哥帮助
1 buf= getchar();
还是不理解
getchar(); 是接收函数啊,怎么能把函数付给一个元素呢
2数据到达buf[]之后
如果想表达 switch((char)UDR0)
{ case'X':
control_node1();
break;
case'Y':
control_node2();
break;
case'Z':
control_node3();
break;
}
该怎么表达因为如今的UDR0数据已经都变成buf,buf,buf....怎么写这个case语句啊 #define MAX_BUF_LENS 255
unsigned char buf, i
//初始化,首先清空串口缓冲区,防止残留的字符干扰
while (rx_counter0) getchar();
memset(buf, 0, MAX_BUF_LENS);
......................
//自己做循环,检测rx_counter0是否不为零
while (!rx_counter0);
//延时100毫秒,具体多少需要自己算,这个时间宜长不宜短
delay_ms(100);
i = 0;
while (rx_counter0)
{
buf = getchar();
i++;
}
//到这里,串口过来的短信已经完整的存放在buf中了,你可以对buf进行需要的操作了
另外这段程序放哪里比较合适,放在接收中断interrupt void usart0_rx_isr(void) 里面可以么,不会冲突么 楼上的,这个程序可以放在主程序里边:
void main(void)
{
unsigned char buf, i
//初始化,首先清空串口缓冲区,防止残留的字符干扰
while (rx_counter0) getchar();
memset(buf, 0, MAX_BUF_LENS);
while (1)
{
while (!rx_counter0);
//延时100毫秒,具体多少需要自己算,这个时间宜长不宜短
delay_ms(100);
i = 0;
while (rx_counter0)
{
buf = getchar();
i++;
}
//到这里,串口过来的短信已经完整的存放在buf中了,你可以对buf进行需要的操作了
}
}
附件是可以编译的代码,你只要在control_node函数中加上你要的处理就可以ourdev_401657.rar(文件大小:2K) (原文件名:untitled.rar) 谢谢,不过已编译无数个错误,正在调试,我已经感激的不行了,真的,如果能成功,我都不知道怎么谢谢你 记号 再请问下
+CMT: "+8615862938263",,"08/09/02,15:34:01+32"
Z
//遍历这个buf,寻找回车换行字符0x0d、0x0a,因为根据你给的格式回车换行后就是短信的那个字符了
if ((buf == 0x0d) && (buf == 0x0a))
{
key = buf;
break;
}
}
Appcat大哥的意思是不是+CMT: "+8615862938263",,"08/09/02,15:34:01+32" 经过回车换行就输出Z了,所以回车换行后就是我要的字符Z??? 不是这个意思,建议你使用sscom32作为调试串口的工具,看看SIM300给你发送的内容:
+CMT: "+8615862938263",,"08/09/02,15:34:01+32"
Z
这个内容都是SIM300一次发的,不是什么经过回车换行就输出Z,里边的0x0a,0x0a也都是SIM300发的。
http://cache.amobbs.com/bbs_upload782111/files_10/ourdev_403517.JPG
看看uedit中的16进制 (原文件名:1.JPG)
串口调试工具SSCOM32ourdev_403518.rar(文件大小:275K) (原文件名:sscom32.rar) 恩,我这就看看!问题我是用手机往模块发信息直接传到串口,如果用那个软件,单片机连接串口的话,那么模块就无法使用了
模块连接串口如果想测试的话,必须用超级终端占用串口 用sscom32是让你看看回传的什么内容,理解一下程序,不是要你测试时也挂着。不是用M128吗?它还有一个串口,你可以用来调试,接PC用SSCOM32就可以了。 恩,其实在你的提示下,我用读取指令已经反向通了,真不知道怎么感激
但是直接发串口还是有点问题,编译通过了。中断没产生,可能是我移植的问题,我一定认真看,你对我的这个程序帮助太大了
我发自内心的感激你! 记号 不知楼主做好了没有 ,我正在做类似的一个东西 能否参考一下你的项目?
不甚感谢!
QQ394220173
jzd19851102@126.com
感谢!!1111 标记 不知楼主做好了没有 ,我新手,刚开始做类似的一个东西 能否给一下相关建议?
QQ358274423
vinnar@163.com
感谢!! mark 猫猫真是热心人啊,佩服! #include<io.h>
#include<interrupt.h>
#define fosc 11059200 //时钟频率
#define baud 9600 //串口波特率
#define RXB8 1
#define TXB8 0
//#define PE 2 //M16
#define UPE 2 //M128
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
//宏定义
#define FRAMING_ERROR (1<<FE)
//#define PARITY_ERROR (1<<PE) //M16
#define PARITY_ERROR (1<<UPE) //M128
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
#define IGTON PORTD|= 0x10 //IGT点火信号
#define IGTOFF PORTD&=~0x10
#define RTSON PORTD|= 0x40 //RTS信号
#define RTSOFF PORTD&=~0x40
#define DTRON PORTD|= 0x20 //DTR信号
#define DTROFF PORTD&=~0x20
unsigned char MEMSBUF0,MEMSBUF1;
#define RX_BUFFER_SIZE0 255
volatile unsigned char rx_buffer0;
volatile unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
volatile unsigned char rx_buffer_overflow0;
#define TX_BUFFER_SIZE0 255
volatile unsigned char tx_buffer0;
volatile unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
#define RX_BUFFER_SIZE1 255
volatile unsigned char rx_buffer1;
volatile unsigned char rx_wr_index1,rx_rd_index1,rx_counter1;
volatile unsigned char rx_buffer_overflow1;
#define TX_BUFFER_SIZE1 255
volatile unsigned char tx_buffer1;
volatile unsigned char tx_wr_index1,tx_rd_index1,tx_counter1;
void mdelay(unsigned int ms) //0.1ms delay
{
unsigned int m=0;
for(;ms>0;ms--)
{
for(m=0;m<56;m++)
{;}
}
}
void delay50ms(unsigned int ms)
{
for(;ms>0;ms--)
{
mdelay(50);
}
}
void uart0_init(void) //串口初始化
{
UCSR0B = 0x00; //disable while setting baud rate
UCSR0A = 0x00;
//UCSR0C =(1<<UPM01)|(1<<UCSZ01)|(1<<UCSZ00); //8bit+1bit stop(偶校验)
UCSR0C =(1<<UCSZ01)|(1<<UCSZ00); //无校验
UBRR0L=(fosc/16/(baud+1))%256;
UBRR0H=(fosc/16/(baud+1))/256; //波特率设置
UCSR0B =(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
}
void uart1_init(void)
{
UCSR1B = 0x00; //disable while setting baud rate
UCSR1A = 0x00;
UCSR1C =(1<<UCSZ11)|(1<<UCSZ10); //8bit+1bit stop
UBRR1L=(fosc/16/(baud+1))%256;
UBRR1H=(fosc/16/(baud+1))/256;
UCSR1B =(1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); //RXCEN TXCEN
}
void putchar0(unsigned char c)
{
while (!(UCSR0A&(1<<UDRE0)));
UDR0=c;
}
void putchar1(unsigned char c)
{
while (!(UCSR1A&(1<<UDRE1)));
UDR1=c;
}
SIGNAL(SIG_USART0_RECV)
{
unsigned char status,data;
status=UCSR0A;
data=UDR0;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0=data;
if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
rx_buffer_overflow0=1;
}
}
}
unsigned char get0_char(void)
{
unsigned char data;
while (rx_counter0==0);
data=rx_buffer0;
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
cli();
--rx_counter0;
sei();
return data;
}
SIGNAL(SIG_USART1_RECV)
{
unsigned char status,data;
status=UCSR1A;
data=UDR1;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer1=data;
if (++rx_wr_index1 == RX_BUFFER_SIZE1) rx_wr_index1=0;
if (++rx_counter1 == RX_BUFFER_SIZE1)
{
rx_counter1=0;
rx_buffer_overflow1=1;
}
}
}
unsigned char get1_char(void)
{
unsigned char data;
while (rx_counter1==0);
data=rx_buffer1;
if (++rx_rd_index1 == RX_BUFFER_SIZE1) rx_rd_index1=0;
cli();
--rx_counter1;
sei();
return data;
}
int main(void)
{
unsigned char i=0,j=0,k=0;
rx_buffer_overflow0=0;
rx_wr_index0=rx_rd_index0=rx_counter0=0;
rx_buffer_overflow1=0;
rx_wr_index1=rx_rd_index1=rx_counter1=0;
PORTD = 0xF3;
DDRD= 0xff;
uart1_init();
uart0_init();
sei();
while(1)
{
i = 0;
while (!rx_counter0) ;
//delay50ms(5000);
while (rx_counter0)
{
MEMSBUF0 = get0_char();
i++;
}
for(j=0;j<i;j++)
{
putchar0(MEMSBUF0);
}
}
我使用avrstudio编译的,为什么程序最多只能接受98个字节的数据,超过98字节的数据就丢失,请帮忙分析一下原因了! 有苹果猫讲课,一定要留意一下。 标记一下。 我这里问个小问题~~~
我在设置了 at+cnmi=2,2后,用手机给modem发信息,串口终端上有信息返回
但再次给modem 发信息后,串口终端上就没有信息返回了
查看cnmi 它自动变成了2,0
在之前的设置之后都有at&w保存了的 ~~~这是为什么呢 请高人指点 顶顶你 我也遇到这个问题,查资料说是te收到短信后,没有及时给ta返回收到的响应,但是具体怎么解决不知道。
顶一下,有谁知道吗?
【32楼】 terriers 强盗
积分:4
派别:
等级:------
来自:
我这里问个小问题~~~
我在设置了 at+cnmi=2,2后,用手机给modem发信息,串口终端上有信息返回
但再次给modem 发信息后,串口终端上就没有信息返回了
查看cnmi 它自动变成了2,0
在之前的设置之后都有at&w保存了的 ~~~这是为什么呢 请高人指点 信猫 单片机GPRS/GSM开发套件主要用于客户开发基于8位用单片机和西门子MC39IGPRS模块的GPRS无线数据通讯终端,为那些没有GPRS开发经验的用户展示基于单片机的GPRS开发过程,开发人员只需将程序下载到单片机内即可实现GPRS拨号和数据传输。提供**源代码
联系方式:
QQ:84239629
淘宝网店:http://item.taobao.com/auction/item_detail-0db2-99f23cd9ea56dfe081c382c241646cf1.htm MARK 新人认真听讲 MARK {:loveliness:}非常的好。
页:
[1]