SIM900B GPRS模块————打电话、发短信、接电话

1、简介

SIM900B是一款新型无线模块,属于B2B类型的四频GSM/GPRS模块,采用非常强大的AMR926EJ-S单芯片处理器,可完全兼容于SIM300/340 。其性能稳定,外观小巧,性价比高,能满足您的多种需求。SIM900B采用工业标准接口,工作频率为GSM/GPRS 850/900/1800/1900MHz,可以低功耗实现语音、SMS、数据和传真信息的传输。

2、AT指令集

要与GPRS进行通信,首先要了解AT指令,AT指令集是从终端设备(Terminal Equipment,TE)或数据终端设备(Data Terminal Equipment,DTE)向终端适配器(Terminal Adapter, TA)或数据电路终端设备(Data Circuit Terminal Equipment,DCE)发送的。通过TA,TE发送AT指令来控制移动台(Mobile Station,MS)的功能,与GSM 网络业务进行交互。用户可以通过AT指令进行呼叫、短信、电话本、数据业务、传真等方面的控制。

2.1 、常用AT指令

这里我就列出我在编程当中所用到的一些AT命令,更多的命令详见http://wenku.baidu.com/view/f8168c50f01dc281e53af0d4.html
1、检测SIM卡是否注册上
AT+CPIN?返回值:READY
2、检测SIM卡的信号强度
AT+CSQ返回值:+CSQ 29,99
3、查询模块版本
AT+CGMR返回值:R4A021      CXC1122528 (版本信息)
4、拨打电话
ATD+号码+;
5、发英文短信
AT+CMGF=1/0(PS:1是文本模式;0是PDU模式)
AT+CMGS="号码"
>短信内容(只能是英文或者数字,要发中文,要进行PDU编码,比较麻烦,想学的可以直接百度)
Ctrl+Z(发送)

3、串口

因为我们的开发板是通过串口向GPRS模块发送命令的,所以这里我们先来了解一下串口。在Linux中,它给我们提供了一个termios结构体,这使得我们更方便的在程序中对串口进行初始化。

(更详细的信息请参考:http://baike.sogou.com/v53994134.htm?fromTitle=Termios)

让我们先来看一下termios结构体内部信息:

struct termios {

    unsigned short c_iflag;              /* 输入模式标志*/
    unsigned short c_oflag;             /* 输出模式标志*/
    unsigned short c_cflag;             /* 控制模式标志*/
    unsigned short c_lflag;              /*区域模式标志或本地模式标志或局部模式*/
    unsigned char c_line;                /*行控制line discipline */
    unsigned char c_cc[NCC];      /* 控制字符特性*/

};

常用校验位和停止位的设置:

无校验位 8位 Option.c_cflag &= ~PARENB; 
Option.c_cflag &= ~CSTOPB; 
Option.c_cflag &= ~CSIZE; 
Option.c_cflag |= ~CS8;


奇校验位 7位 Option.c_cflag |= ~PARENB; 
Option.c_cflag &= ~PARODD; 
Option.c_cflag &= ~CSTOPB; 
Option.c_cflag &= ~CSIZE; 
Option.c_cflag |= ~CS7;


校验位 7位 Option.c_cflag &= ~PARENB; 
Option.c_cflag |= ~PARODD; 
Option.c_cflag &= ~CSTOPB; 
Option.c_cflag &= ~CSIZE; 
Option.c_cflag |= ~CS7;


Space校验 7位 Option.c_cflag &= ~PARENB; 
Option.c_cflag &= ~CSTOPB; 
Option.c_cflag &= &~CSIZE; 
Option.c_cflag |= CS8;


Linux下串口的操作一般分为四个步骤:

1、打开需要使用的设备

在 Linux 下串口文件是位于 /dev 下的

串口一 为 /dev/ttyS0(/dev/ttyUSB0)

串口二 为 /dev/ttyS1(/dev/ttyUSB1)

fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);

2、获取设备的属性

struct termios options;        
tcgetattr(fd, &options);  

3、设置串口

options.c_cflag |= ( CLOCAL | CREAD ); 
options.c_cflag &= ~CSIZE;      
options.c_cflag &= ~CRTSCTS;   
options.c_cflag |= CS8;      
options.c_cflag &= ~CSTOPB; 
options.c_iflag |= IGNPAR;  
options.c_oflag = 0;            
options.c_lflag = 0;         
cfsetispeed(&options, B115200);//设置发送波特率
cfsetospeed(&options, B115200);   //设置接收波特率

4、将所设置的参数生效

tcsetattr(fd,TCSANOW,&options);

TCSANOW:   不等数据传输完毕就立即改变属性
TCSADRAIN: 等待所有数据传输结束才改变属性
TCSAFLUSH:   清空输入输出缓冲区才改变属性

4、线程

1、简介

线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程线程也有就绪阻塞运行三种基本状态。每一个程序都至少有一个线程,那就是程序本身。线程能独立执行,能充分利用和发挥处理机外围设备并行工作的能力。

2、实例代码

这是一个简单的创建线程的示例代码,能让我们更快的了解如何创建一个线程,这个例子中运用到了互斥锁,互斥锁的作用是用来保证程序在一个时间内只有一个线程运行,这样保证了线程执行的先后顺序,只有当一个线程释放锁之后,另一个上锁的线程才能运行,接下来就是代码:

#include <pthread.h>  
#include <stdio.h>  
 
pthread_mutex_t mutex ; 

void *print_msg1(void *agrs ){  
        pthread_mutex_lock(&mutex);
char led;
led=*(char*)agrs;  
if(led=='1')
{
        printf("this is print_msg1,led=%c\n",led);  
}
        usleep(100);  
        pthread_mutex_unlock(&mutex);  
}  
void *print_msg2(void *arg){  
pthread_mutex_lock(&mutex);  
printf("this is print_msg2\n");  
usleep(100);  
pthread_mutex_unlock(&mutex);  
}  
int main(int argc,char** argv){  
        pthread_t id1;  
        pthread_t id2;  

pthread_mutex_init(&mutex,NULL);  
        pthread_create(&id2,NULL,(void *)print_msg2,NULL);  
        pthread_create(&id1,NULL,(void *)print_msg1,NULL);  
sleep(1);
        pthread_join(id1,NULL);  
        pthread_join(id2,NULL);  
        pthread_mutex_destroy(&mutex);  
        return 1;
}  

5、SIM900B GPRS模块 打电话、发短信、接电话

假如说,你能了解上面我所介绍的内容,那么看懂这个代码并不是上面难事,而且,还能再我代码的基础上进行改善
/*引进编译所需要的头文件
#include <termios.h>       
#include <pthread.h>
#include <stdio.h>         
#include <stdlib.h>         
#include <unistd.h>        
#include <fcntl.h>        
#include <string.h>        
#include <sys/types.h>      
#include <sys/stat.h> 

pthread_mutex_t mutex ;  //定义一个互斥锁
int choice=0; //定义全局变量


//存储短信信息的结构体
struct message_info
{                         
char phnum[16];          
char message[128];    
}; 

//用来接电话的线程
void* thread_get_RING(void* arg)
{
char  reply[100];
int fd;

        fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);    
    if (-1 == fd)
        {
                perror("Can't Open Serial Port");
        }
//一直检测串口是否有RING 这个字符串  PS:如果向GPRS模块打电话,串口回返回RING 字符串
while(1)
{
memset(reply,0,sizeof(reply));
                read(fd,reply,sizeof(reply));//读取串口信息
                if(strstr(reply,"RING"))
                {
                        printf("=====================================================\n");
                        printf("      you have a call in,please input :\n");
                        printf("           4 to connect\n");
                        printf("           5 to hang up\n");
                        printf("=====================================================\n");

pthread_mutex_lock(&mutex);//上锁
                        switch(choice)
                        {
                                case 4: get_up_phone(fd) ;break;
                                case 5: hang_up_phone(fd) ; break;
                }
pthread_mutex_unlock(&mutex);//解锁
}
}



//初始化串口函数
void serial_init(int fd)      
{              
struct termios options;        
tcgetattr(fd, &options);   
options.c_cflag |= ( CLOCAL | CREAD ); 
options.c_cflag &= ~CSIZE;      
options.c_cflag &= ~CRTSCTS;   
options.c_cflag |= CS8;      
options.c_cflag &= ~CSTOPB; 
options.c_iflag |= IGNPAR;  
options.c_oflag = 0;            
options.c_lflag = 0;         
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);       
tcsetattr(fd,TCSANOW,&options);
}   


//挂断电话的函数
int hang_up_phone(int fd)
{
        getchar(); //PS:吃掉缓冲区中的回车符
        char buff[10];
        char reply[20];
        int nwrite;
        int nread;


        memset(buff,0,sizeof(buff));
        memset(reply,0,sizeof(reply));


        strcat(buff,"ath\r");
        nwrite=write(fd,buff,sizeof(buff)); //向串口发送AT命令
        printf("nwrite=%d,%s,\n",nwrite,buff);
        sleep(1);
        nread=read(fd,reply,sizeof(reply)); //读取返回值
        printf("nread=%d,%s\n",nread,reply); //打印返回值的信息
}


//接电话的函数
int get_up_phone(int fd)
{
getchar();
        char buff[10];
        char reply[20];
        int nwrite;
        int nread;


        memset(buff,0,sizeof(buff));
        memset(reply,0,sizeof(reply));


        strcat(buff,"ata\r");
        nwrite=write(fd,buff,sizeof(buff));
        printf("nwrite=%d,%s,\n",nwrite,buff);
        sleep(1);
        nread=read(fd,reply,sizeof(reply));
        printf("nread=%d,%s\n",nread,reply);
}


//获取用户所拨打的手机号函数
int get_phonenumber(int fd,char *phnum)
{
        getchar();
        int counter=0;
        char phonenum[20]={'\0'};
        printf("please enter the phone number who do you want to call:\n");
        gets(phnum);
        while(strlen(phnum) != 12)
        {
                if(counter >= 3)                                                  
                {
                        printf("conter out !\n");
                        return -1;
                }
                printf("number shuld be --11-- bits ! enter agin :\n");
               gets(phnum);
                counter ++;
        }
        strcat(phonenum,"atd");
        strcat(phonenum,phnum);
        strcat(phonenum,";\r");
        called(fd,phonenum);
}


//拨打电话的函数
int called(int fd,char *atd)
{
        int nread,nwrite;
        char buff[100];
        char reply[100];
        char hang_up;




        memset(buff,0,sizeof(buff));
        memset(reply,0,sizeof(reply));
        strcpy(buff,"at\r");
        nwrite=write(fd,buff,strlen(buff));
        printf("nwrite=%d,%s\n",nwrite,buff);
        sleep(1);
        nread=read(fd,reply,strlen(reply));
        printf("reply=%d,%s\n",nread,reply);
        memset(buff,0,sizeof(buff));
        memset(reply,0,sizeof(reply));
        strcat(buff,atd);
        nwrite=write(fd,buff,sizeof(buff));
        printf("nwrite=%d,%s\n",nwrite,buff);
        sleep(1);
        nread=read(fd,reply,sizeof(reply));
        printf("nread=%d,%s\n",nread,reply);




        printf("==================================\n");
        printf("if you want to hang up this dialog,\n please enter 2\n");
        printf("==================================\n");




        hang_up=getchar();
        if(hang_up=='2')
        {
                hang_up_phone(fd);
        }
}


//发送信息的函数
int send(int fd,char *cmgf,char *cmgs,char *message)    
{               
int nread,nwrite;            
char buff[128];            
char reply[128];      
memset(buff,0,sizeof(buff));
strcpy(buff,"at\r");
nwrite = write(fd,buff,strlen(buff));
printf("nwrite=%d,%s\n",nwrite,buff); 
memset(reply,0,sizeof(reply));         
sleep(1);              
nread = read(fd,reply,sizeof(reply));  
printf("nread=%d,%s\n",nread,reply);     
memset(buff,0,sizeof(buff));          
strcpy(buff,"AT+CMGF=");          
strcat(buff,cmgf);          
strcat(buff,"\r");           
nwrite = write(fd,buff,strlen(buff));  
printf("nwrite=%d,%s\n",nwrite,buff);
memset(reply,0,sizeof(reply));        
sleep(1);           
nread = read(fd,reply,sizeof(reply));         
printf("nread=%d,%s\n",nread,reply);    
memset(buff,0,sizeof(buff));             
strcpy(buff,"AT+CMGS=");             
strcat(buff,cmgs);               
strcat(buff,"\r");         
nwrite = write(fd,buff,strlen(buff));    
printf("nwrite=%d,%s\n",nwrite,buff);    
memset(reply,0,sizeof(reply));       
sleep(1);             
nread = read(fd,reply,sizeof(reply));  
printf("nread=%d,%s\n",nread,reply);     
memset(buff,0,sizeof(buff));       
strcpy(buff,message);         
nwrite = write(fd,buff,strlen(buff));   
printf("nwrite=%d,%s\n",nwrite,buff);    
memset(reply,0,sizeof(reply));         
sleep(1);              
nread = read(fd,reply,sizeof(reply));     
printf("nread=%d,%s\n",nread,reply);   



//获取用户所输入的短信收件人
int send_en_message(int fd,struct message_info info)    
{            
getchar(); 
char cmgf[] = "1";      
int conter = 0;         
char cmgs[16] = {'\0'};      
printf("enter recever phnumber :\n");       
fgets(info.phnum,15,stdin);           
while(strlen(info.phnum) != 12)
{                    
if(conter >= 3)
{                  
printf("conter out !\n");         
return -1;                 
}                     
printf("number shuld be --11-- bits ! enter agin :\n");      
fgets(info.phnum,11,stdin);      
conter ++;           
}       
printf("enter you message !\n");       
fgets(info.message,128,stdin);              
strcat(info.message,"\x1a");  
strcat(cmgs,"\"");
strcat(cmgs,info.phnum);
strcat(cmgs,"\"");   
send(fd,cmgf,cmgs,info.message);   
}  


int main()       
{             
int ret;
int fd;      
char phnum[15];
struct message_info info;     
pthread_t id;


pthread_mutex_init(&mutex,NULL);  //初始化互斥锁


fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);    //打开串口设备    
if (-1 == fd)
{                
perror("Can't Open Serial Port");          
}            
serial_init(fd); //初始化串口


ret=pthread_create(&id,NULL,(void *)thread_get_RING,NULL);//创建线程
usleep(100);
        if(ret!=0)
        {
                printf("create thread failed!!\n");
                exit (1);
        }




printf("\n============================================\n");       
printf("\tthis is a gprs test program !\n");              
printf("\tcopyright fj@farsight 2016\n");            
printf("============================================\n");      
printf("enter your selete :\n");        
printf("1.send english message.\n");                   
printf("2.call to someone. \n");
        printf("3.exit.\n");
while(1)
        {
                pthread_mutex_lock(&mutex); //上锁
scanf("%d",&choice);


                switch(choice)
                {
                        case 1: send_en_message(fd,info);         break;
                        case 2: get_phonenumber(fd,phnum);        break;
                        case 3: printf("Quite!!\n");              break;
                        default : printf("Quite!!\n");            break;
                }

pthread_mutex_unlock(&mutex);//解锁
sleep(1);




                printf("\n============================================\n");
                printf("\tthis is a gprs test program !\n");
                printf("\tcopyright for huangan 2016\n");
                printf("============================================\n");
                printf("enter your selete :\n");
                printf("1.send english message.\n");
                printf("2.call to someone. \n");
                printf("3.exit.\n");
        }
pthread_join(id,NULL); //等待线程的结束
pthread_mutex_destroy(&mutex);  //毁掉互斥锁
close(fd);              //关闭设备
return 0; 
}  

6、总结

这个模块我玩了十天,在这个过程中我学到了很多东西,但是遇到的问题也是很多的,比如刚开始都不知道线程的工作原理,也不知道如何创建线程,这是最难的,但是经过各种百度,请教同学,终于是把这个模块完成,后面还有PPP拨号上网,这个将在后面介绍

猜你喜欢

转载自blog.csdn.net/huangan_xixi/article/details/50875578