这几天研究了一下pdu信息收发,今天花了大半天写出了不完善的pdu信息发送程序并调试成功了,由于竞赛时间有限,暂时不对这个发短信模块进行优化了,等有时间再重新整理好这个,完善其功能
由于此程序用于初步的测试,并且本人没有多少写程序的经验,下面的东西有点儿乱。
发送的pdu串格式:信息服务中心地址+pdutype+mr+接收方手机地址+pid+dsc+vp+udl+ud
一下是一个发送的pdu串
+8613010670500
13211147412
AT+CMGF=0
AT+CMGS=28
0891683110600705F011000B813112117414F20008A70E6A215757521D59CB53166210529F
分析一下:0891 683110600705F0 1100 0B81 3112117414F2 0008A7 0E 6A215757521D59CB53166210529F
长度类型 奇偶兑换加F的信息中心地址
下面是完整的c语言实现,只能发送信息到11位号码的手机,16位编码no class,发送Unicode文字代码
/* * GSM模块收发短信打电话,pdu模式 * 德国西门子TC35I GSM 模块 * 基于GSM的单片机无线通讯模块程序 * * 实现发送pdu短信,只需设置信息中心与收信人电话号码,发送Unitcode码。 * 接收短信,只分辨是否为预置号码的短信,提取信息内容(Unicode码) * 16bit no class编码 * * gsm.h * * 使用说明: 须设置主人电话与信息中心号码: * uchar code phone[] = "13211145418"; //主人电话号码 * uchar code sms_center[] = "+8613010200500";//广州联通 * * GSM开关机控制线: * sbit gsm_igt = P0^3;// 点火线 * sbit gsm_emergoff = P0^4;//关机线 * * 波特率设置: * uchar code AT_IPR[] = "AT+IPR=2400"; //设置波特率 * void gsm_uart_init(void);函数中定时器(定时器1) * * 拨打主人电话: * gsm_call(); * * 处理主人来信,内容已经存在gsm_sms_ud[]中: * gsm_sms_host(); * * 处理非主人信息,内容已经存在gsm_sms_ud[]中: * gsm_sms_unknow(); * * 主函数调用模块如下: * #include <reg52.h> * #include "gsm.h" * #define uchar unsigned char * * void main(void) * { * gsm_init();//初始化gsm(包括串口通信设置) * while(1){ * gsm_scan(); //处理gsm消息 * } * } * * CopyRight(C) 2010 CrazyLeen <[email protected]> * 注意: 使用外部函数delay_s(); delay_ms(); * 使用了定时器1 */ #ifndef __GSM_H__ #define __GSM_H__ #include <reg52.h> #include <string.h> #include "delays.h" #define uchar unsigned char //===========================================GSM模块===================================================== //引脚定义 sbit gsm_igt = P0^4;// 点火线 sbit gsm_emergoff = P0^3;//关机线 uchar code phone[] = "13211145418"; //主人电话号码 uchar code sms_center[] = "+8613010200500";//广州联通 //SMU uchar code gsm_password[] = "0053004D0055"; //============================================内置短信================================================= //Unicode字符代码for sms //您好,GSM远程控制系统初始化成功。欢迎使用GSM远程控制系统^_^... uchar code ud_init_ok[] = "60A8597DFF0C00470053004D8FDC7A0B63A752367CFB7EDF521D59CB53166210529F30026B228FCE4F7F752800470053004D8FDC7A0B63A752367CFB7EDF005E005F005E002E002E002E"; //您好,防盗系统已开启,请放心外出,enjoy your time... uchar code ud_alarm_on[] = "60A8597DFF0C963276D77CFB7EDF5DF25F00542FFF0C8BF7653E5FC3591651FAFF0C0065006E006A006F007900200079006F00750072002000740069006D0065002E002E002E"; //您好,防盗系统已成功关闭,出门记得及时开启防盗系统(⊙o⊙)哦 uchar code ud_alarm_off[] = "60A8597DFF0C963276D77CFB7EDF5DF26210529F517395EDFF0C51FA95E88BB05F9753CA65F65F00542F963276D77CFB7EDF00282299006F2299002954E6"; //您好,有客人按响您家的门铃...您可以打我电话与客人进行通话。 uchar code ud_guest_ring[] = "60A8597DFF0C67095BA24EBA630954CD60A85BB6768495E894C3002E002E002E60A853EF4EE56253621175358BDD4E0E5BA24EBA8FDB884C901A8BDD3002"; //您好,操作已完成啦~~~ uchar code ud_operation_s[] = "60A8597DFF0C64CD4F5C5DF25B8C62105566007E007E007E"; //您好,当前报警状态停止了,恢复正常防盗状态。 uchar code ud_alarm_cancel[] = "60A8597DFF0C5F53524D62A58B6672B66001505C6B624E86FF0C6062590D6B635E38963276D772B660013002"; //注意:防盗系统触发了 uchar code ud_alarm_started[] = "6CE8610FFF1A963276D77CFB7EDF89E653D14E86"; //===============================================短信指令=========================================================== //开防盗 uchar code ud_alarm_start[] = "5F00963276D7"; //关防盗 uchar code ud_alarm_stop[] = "5173963276D7"; //开继电器一 uchar code ud_relay_1_on[] = "5F007EE7753556684E00"; //开继电器二 uchar code ud_relay_2_on[] = "5F007EE7753556684E8C"; //开继电器三 uchar code ud_relay_3_on[] = "5F007EE7753556684E09"; //开继电器四 uchar code ud_relay_4_on[] = "5F007EE77535566856DB"; //开继电器五 uchar code ud_relay_5_on[] = "5F007EE7753556684E94"; //开继电器六 uchar code ud_relay_6_on[] = "5F007EE775355668516D"; //开继电器七 uchar code ud_relay_7_on[] = "5F007EE7753556684E03"; //开继电器八 uchar code ud_relay_8_on[] = "5F007EE775355668516B"; //开全部继电器 uchar code ud_relay_all_on[] = "5F00516890E87EE775355668"; //关继电器一 uchar code ud_relay_1_off[] = "51737EE7753556684E00"; //关继电器二 uchar code ud_relay_2_off[] = "51737EE7753556684E8C"; //关继电器三 uchar code ud_relay_3_off[] = "51737EE7753556684E09"; //关继电器四 uchar code ud_relay_4_off[] = "51737EE77535566856DB"; //关继电器五 uchar code ud_relay_5_off[] = "51737EE7753556684E94"; //关继电器六 uchar code ud_relay_6_off[] = "51737EE775355668516D"; //关继电器七 uchar code ud_relay_7_off[] = "51737EE7753556684E03"; //关继电器八 uchar code ud_relay_8_off[] = "51737EE775355668516B"; //关全部继电器 uchar code ud_relay_all_off[] = "5173516890E87EE775355668"; //? uchar code ud_inquiry[] = "FF1F";//查询继电器状态 //? uchar code ud_inquiry2[] = "003F"; //=======================AT指令=================================== uchar code ATD[] = "ATD"; uchar code AT[] = "AT"; uchar code ATE[] = "ATE"; //关回显指令 uchar code AT_IPR[] = "AT+IPR=2400"; //设置波特率 uchar code ATH[] = "ATH"; //挂断 uchar code ATA[] = "ATA"; //接听 uchar code AT_CLIP[] = "AT+CLIP=1"; //设置来电显示 uchar code AT_CPMS[] = "AT+CPMS=sm,sm,sm"; //短信存储在sim卡中 uchar code AT_CNMI[] = "AT+CNMI=2,2"; //设置信息提示,新信息到达直接打到串口上 uchar code AT_CMGF[] = "AT+CMGF=0"; //设置短信的格式为pdu格式 uchar code AT_CMGS[] = "AT+CMGS="; //发送短信指令 uchar code AT_CSCA[] = "AT+CSCA="; //设置短信中心号码 //======================SMS PDU MODE================================================= uchar idata pdu_cmgs_length[3]; //at+cmgs=*的长度,计算得到,去掉信息中心后的字符长度 uchar code pdu_sca_len_type[] = "0891"; //服务中心地址的长度与类型 uchar idata pdu_sms_center[15]; //转换后的信息中心号码//////////////////////////需要更改 uchar code pdu_type_mr[] = "1100";//pdu类型与信息参考 uchar code pdu_phone_length_type[] = "0B81";//发送目标手机号码的长度与类型 uchar pdu_phone[13]; //转换后的电话///////////////、//////////////////需要更改 uchar code pdu_pid[] = "00"; //协议标识 uchar code pdu_dcs[] = "08"; //数据编码方式,这里是16bit方式编码(汉字) uchar code pdu_vp[] = "A7"; //信息有效期 uchar idata pdu_udl[3]; //用户数据长 uchar *pdu_ud; //用户数据 //========================================GSM状态标志============================================= uchar code OK[] = "OK"; //回显的OK uchar code sms_new[] = "089168";//新信息关键字 bit gsm_send_ready = 1;//串口发送标志位 bit at_ok = 0; //TC35I回显了OK的标志位 bit gsm_ring = 0;//响铃标志位 bit gsm_sms_new = 0;//新信息标志 uchar gsm_sms_state = 0;//新信息状态,1为有信息,而且是主人信息,2为信息非主人信息 #define GSM_SMS_UD (4*13) //接收信息的用户数据长度,四的倍数 uchar gsm_sms_ud[GSM_SMS_UD + 1]; //接收到的信息数据,须是内部RAM以减少运行时间 //==========================================函数声明部分============================================ //GSM基本操作部分 void gsm_power_on(void);//开机 void gsm_power_off(void);//关机 void gsm_uart_init(void);//串口设置 void gsm_init(void); void gsm_send_byte(uchar c);//向GSM发送一个字节 void gsm_send_str(uchar *p);//发送一串字符 void gsm_at(uchar *p);//发送一个at指令 void gsm_receive(uchar sbuf);//中断接收一字节的处理 void gsm_call(void);//拨打电话主人 void gsm_poweroff(void);//关机 void gsm_start(void);//开机 void gsm_reboot(void);//重启 //发pdu信息相关函数 void gsm_sms_init(void);//初始化pdu短信发送相关数据 void gsm_conver_pdu(uchar *p, uchar *pdu); //地址或电话号码转换,偶+F void gsm_work_out_data(uchar *p_data); //算出pdu_udl和cmgs的长度 void gsm_send_sms(uchar *p_data);//发送一条 短信 (Unitcode码) //GSM消息处理函数 void gsm_error(void);//GSM错误处理 //void gsm_scan(void);//这个是处理gsm模块消息的,须经常扫描 //void gsm_sms_unknow();//处理非主人信息 //void gsm_sms_host();//处理主人来信 //=================================函数定义部分===================================================== //点火线开机 void gsm_power_on(void) { gsm_igt = 0; delay_s(1); gsm_igt = 1; } //强制关机 void gsm_power_off(void) { gsm_emergoff = 0; delay_s(3); gsm_emergoff = 1; } //初始化串口,300 void gsm_uart_init(void) { TMOD = 0x20; SCON = 0x50; TH1 = 0xF4; TL1 = TH1; PCON = 0x00; EA = 1; ES = 1; TR1 = 1; } //中断 //接受一字节 void gsm_interrupt(void) interrupt 4 { uchar sbuf; if(RI){ sbuf = SBUF; RI = 0; gsm_receive(sbuf);//接收一个字节 } else { TI = 0; gsm_send_ready = 1;//允许发送了 } } //发送一字节 void gsm_send_byte(uchar c) { while(!gsm_send_ready); //允许发送后在发送 SBUF = c; gsm_send_ready = 0; } //向gsm发送字符串 void gsm_send_str(uchar *p) { at_ok = 0; //清除OK标志 for(; *p != '\0'; p++)//发送字符串 gsm_send_byte(*p); } //发送一个at指令 void gsm_at(uchar *p) { gsm_send_str(p); gsm_send_byte('\r');//发送回车 } //处理接收到的字符,来电判断,OK判断,信息接收 void gsm_receive(uchar sbuf) { static uchar i = 0; //处理OK回显 static uchar j = 0; //处理来电 static uchar k = 0; //处理新信息 static uchar n = 0; //接收新信息 static bit new_sms_flag = 0; //新信息到来寄存器 //OK查询 if(sbuf == OK[i++]){ if(i == 2) at_ok = 1;//接收到ok回显 } else i = 0; //处理来电部分(只接听主人电话) if(sbuf == phone[j++]){ if(j == 11) gsm_ring = 1;//写来电标志 } else j = 0; //检测处理新信息 if(sbuf == sms_new[k++]){ if(k == 6){ new_sms_flag = 1;//新信息到 } } else k = 0; if(new_sms_flag == 1){ //接收新信息 ++n; if(n < 20) return; //检测手机号码 n=31为手机末尾号码,n = 20为手机第一个字码 if(n < 32){ if(n == 20) gsm_sms_state = 100; if(pdu_phone[n - 20] == sbuf) gsm_sms_state++;//这个累加到112则信息为主人发送的 pdu_phone[n - 20] = sbuf;//存放来信号码 } else if(n >= 52){ //存放信息数据部 if(n - 51 <= GSM_SMS_UD && sbuf != '\r') gsm_sms_ud[n - 52] = sbuf; else {//接收完毕 gsm_sms_ud[n - 52] = '\0'; new_sms_flag = 0;//清除信息接收标志 n = 0; if(gsm_sms_state == 112) gsm_sms_state = 1;//主人信息 else gsm_sms_state = 2;//非主人信息 } } } } void gsm_init(void) { gsm_uart_init();//初始化串口 gsm_power_on(); delay_s(3); gsm_at(AT); delay_ms(200); gsm_at(ATE); //关指令回显 delay_ms(200); gsm_at(AT_IPR);//设置波特率 delay_ms(200); gsm_send_str(AT_CSCA); //设置中心号码 gsm_at(sms_center); delay_ms(200); gsm_at(AT_CLIP);//设置来电显示 delay_ms(200); gsm_at("AT^SNFS=2");//audio mode 2, using ep2,mic2,handset free, adjustable delay_ms(200); gsm_at(AT_CPMS);//设置短信存储在sim卡中 delay_ms(200); gsm_at(AT_CNMI);//设置新信息提示方式 delay_ms(200); gsm_sms_init();//初始化sms发送 delay_ms(200); gsm_send_sms(ud_init_ok);//发送成功开机短信 //gsm_call(); } void gsm_send_sms(uchar *p_data) { gsm_at(AT); pdu_ud = p_data;//用户数据Unicode代码 gsm_work_out_data(pdu_ud);//计算出cmgs发送的长度与udl delay_ms(200); gsm_at(AT); delay_s(1); gsm_at(AT_CMGF);//设置pdu模式 delay_s(1); gsm_send_str(AT_CMGS); gsm_at(pdu_cmgs_length); //开始发送短信 delay_s(1); gsm_send_str(pdu_sca_len_type);//服务中心地址的长度与类型 gsm_send_str(pdu_sms_center);//转换后的信息中心号码 gsm_send_str(pdu_type_mr);//pdu类型与信息参考 gsm_send_str(pdu_phone_length_type);//发送目标手机号码的长度与类型 gsm_send_str(pdu_phone);//转换后的电话 gsm_send_str(pdu_pid);//协议标识 gsm_send_str(pdu_dcs);//数据编码方式 gsm_send_str(pdu_vp);//信息有效期 gsm_send_str(pdu_udl);//用户数据长度 gsm_send_str(pdu_ud);//用户数据 gsm_send_byte(0x1A); gsm_send_byte('\t'); delay_s(5); //等待模块发送信息完毕 } //计算pdu短信中的未知数 void gsm_work_out_data(uchar *p_data) { uchar i; uchar word;//用户数据长度 for(i = 0; *p_data != '\0'; i++, p_data++);//计算用户数据的长度 word = i;//用户数据长度 i /= 2; //完成pdu_udl的字符串 if(i / 16 >= 10) pdu_udl[0] = i / 16 - 10 + 'A'; else pdu_udl[0] = i / 16 + '0'; if(i % 16 >= 10) pdu_udl[1] = i % 16 - 10 + 'A'; else pdu_udl[1] = i % 16 + '0'; pdu_udl[2] = '\0'; word += 28;//去掉信息中心后(PDU 数据包字符数-2)/2 word /= 2; pdu_cmgs_length[0] = word / 10 + '0';//cmgs的长度,用字符表示 pdu_cmgs_length[1] = word % 10 + '0'; pdu_cmgs_length[2] = '\0'; } //把p号码奇偶对换,非偶加'F',转换后存放在pdu中 void gsm_conver_pdu(uchar *p, uchar *pdu) { uchar i = 0; while(p[i++] != '\0');//算出长度 i-=2; if(i % 2 == 0){//基数添加F pdu[i] = 'F'; pdu[i + 1] = p[i]; pdu[i + 2] = '\0'; i--; } else pdu[i+1] = '\0'; for(; i < 30; i -= 2){ pdu[i] = p[i - 1]; pdu[i - 1] = p[i]; } } //发送pdu短信的前提工作 void gsm_sms_init(void) { gsm_conver_pdu(&sms_center[1], pdu_sms_center);//转换信息中心号码 gsm_conver_pdu(phone, pdu_phone);//转换电话号码 } //拨打电话主人 void gsm_call(void) { gsm_at(AT); delay_s(1); gsm_send_str(ATD); gsm_send_str(phone); gsm_at(";"); delay_s(20); } //GSM错误处理 void gsm_error(void) { gsm_at("AT^SMSO");// 关机指令 delay_s(1); gsm_power_off(); //强制关机 gsm_init(); //开机初始化 } /* //这个是处理gsm模块消息的,须经常扫描 void gsm_scan(void) { uchar i; if(gsm_ring){//主人来电 // gsm_at(ATA);//接听来电 gsm_at(ATH);//测试用------------------------------------------------ delay_s(2); gsm_ring = 0; } for(i = 0; i < 200; i++){ //检测GSM gsm_at(AT); delay_ms(200); if(at_ok == 1) i = 250; //GSM正常 } if(i != 251) gsm_error();//GSM错误处理 if(gsm_sms_state == 1){ gsm_sms_host();//处理主人来信 gsm_sms_state = 0; } else if(gsm_sms_state == 2){ gsm_sms_unknow();//处理非主人信息 gsm_sms_state = 0; } } */ /* //处理主人来信,内容已经存在gsm_sms_ud[]中 void gsm_sms_host(void) { gsm_send_sms(gsm_sms_ud);////测试用-------------------------------------- if(strcmp(gsm_sms_ud, ud_help) == 0)//帮助指令 gsm_sms_help(); } //处理非主人信息 void gsm_sms_unknow(void) { gsm_send_sms(gsm_sms_ud);////测试用-------------------------------------- delay_s(3); gsm_call();//测试用-------------------------------------- } */ //============================================================================================================= #endif //附加说明: // 通过gsm_init();初始化GSM模块,包括设置串口通信,波特率设置为2400,关指令回显,开来电显示号码,新信息直接 // 输出到mcu不作存储,初始化完毕后,须经常执行gsm_scan();以处理GSM的消息