?? 利用modem實現單片機與pc通信.txt
字號:
#include <string.h>
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define MAXLEN 14
#define DELAY 120
/************
fsec 秒標志 1為到一秒,必須進入加秒處理
mstat MODEM狀態, 0 為命令狀態,1為數據狀態
Wrec 等待回應標志。wsec為等待時間上限
Wsend 發送標志,為1時表示有內容要發送
WARN 報警標志,為1時要拔號
stat為狀態指示
00 空閑
0* 表示拔號進程
01 發送初始化指令 ATZ 等待回應時間限為2秒 wait for OK
02 發送置MODEM用數字回應指令 ATV0 等待回應時間限為2秒 wait for 0
03 發送拔號指令 ATDT?????? 等待回應時間限為59秒 wait for connect
04 已連通進入數據傳送 等待回應時間限為30秒 wait for time out or no carry
05 發送 +++返回命令狀態指令, 等待回應時間限為2秒 wait for 0
06 發送 ATH 掛機指令 等待回應時間限為5秒 wait for 0
1* 表示接收呼叫進程
11..15 收到第一至五次鈴 , 等待時間限為5秒 wait for 2
16 已發送ATA指令 等待回應時間限為59秒 wait for connect
17 已連通進入數據傳送M_STAT=1, 等待命令時間為30秒 wait form time out or no carry
18 當超時或掉線時,發送+++返回命令狀態,等待回應時間限為2秒。WAIT FOR 0
19 發送 ATH掛機指令,等待回應時間限為5秒 WAIT FOR 0
2* 表示進入初始化進程
21 發送 ATZ
22 發送 ATE0V0
23
MODEM的初始化內容
ATE0 不回顯
ATV0 數字回應結果
ATS0=12
AT&W0 寫入0號記憶
*********/
void jl(uint);
void init(void);
void clock(void);
void puttimeout(void);
void settimeout(uchar []);
void putc(uint);
void command(uint);
void modem_com(void);
void no_echo(void);
void resetsys(void);
void serial_init(void);
void clear_dial(void);
void checkequ(uint *,uint *,uint *);
void inttostr(uchar *,uint,uint);
struct jl{
uint hour,min,stat;
};
uchar s_buff[15],r_buff[15],number[12]={"9580900009"};
/* 時,分,秒,秒計數,等待回應秒,modem運行狀態,重拔次數,收指針,設備操作延時 */
uint day,hour,min,sec,count,wsec=0,stat=0,redial=0,rptr,WN_sec=0;
/* 標志,緊急呼叫標志,等待回應標志,內容待發標志,收到內容標志,MODEM狀態標志,設備操作延時標志 */
bit fSec=0,WARN=0,W_rec=0,W_send=0,Rec, M_stat=0,WNWT;
struct jl gzm[3];
main()
{
uint kb1=0,kb2=0,kb3=0;
serial_init();
init();
while(!fSec);
rptr=0;
while(1){
if( fSec ) { /* 到一秒處理 */
fSec=0;
clock();
}
checkequ(&kb1,&kb2,&kb3); /* 檢查設備狀態 */
if( WARN && stat==0 ){ /* 如MODEM空閑且要報警,則開始拔號進程 */
P20=WARN;
P21=!WARN;
W_send=1;
strcpy(s_buff,"ATDT0W"); /* 已自動回拔0和等待二次拔號音 */
putc(0);
strcpy(s_buff,number);
putc(0);
strcpy(s_buff,"779");
stat=3;
wsec=59;
W_rec=1; /* 置等待標志 */
}
if(W_send ) { /* 有內容待發 */
putc(1);
W_send=0;
continue; /* 因為發送內容可能占用較多時間,為了保證秒處理先循環 */
}
if ( Rec ){ /* 收到字串處理 */
if ( M_stat ) /* 如果是數據狀態則為命令處理 */
command(kb1);
else
modem_com(); /* MODEM控制處理 */
Rec=0;
}
else /* 無收到內容則 */
{
if( W_rec && wsec==0 ) /* 等待時間已超出上限*/
no_echo(); /* 超時無回應處理 */
}
}
}
void no_echo() /* 在指定時間內無回應 */
{
W_rec=0;
rptr=0;
switch(stat){
case 3: /* 拔號后無任何回應 */
redial++;
if( redial<3 ) /* 三次重拔 */
stat=0;
else{
jl(01); /* 進行狀態記錄 */
resetsys(); /* RESET 系統 */
WARN=0;
clear_dial();
}
break;
case 4: /* 連通后無回應 */
case 17:
strcpy(s_buff,"+++"); /* 掛機 */
M_stat=0; /* MODEM入指令狀態 */
stat=5;
W_rec=1;
wsec=5;
putc(0);
break;
case 5: /* 發+++后無回應 */
clear_dial();
break;
case 10:
case 11:
case 12:
case 13:
case 14:
stat=0;
break;
case 16: /* 發 ATA無回應 */
strcpy(s_buff,"ATH");
stat=0;
W_send=1;
break;
}
}
void modem_com() /* MODEM控制處理 */
{
uint i;
W_rec=1;
switch(stat){
case 0:
if( r_buff[0]=='2' ){
stat=12;
wsec=7;
}
break;
case 12:
case 13:
if( r_buff[0]=='2'){
stat++;
wsec=7;
}
break;
case 14: /* 鈴響五次了 */
if( r_buff[0]=='2'){
stat=16;
strcpy(s_buff,"ATA"); /* 發應答命令 */
wsec=59;
W_send=1;
}
break;
case 16: /* 已發過應答命令 */
if( r_buff[0]=='1' ) /* 已握手 */
{
stat++;
wsec=60;
M_stat=1;
。。。。。。 /* PC與單片機之間的通迅 */
}
else
clear_dial();
break;
case 5:
strcpy(s_buff,"ATH");
W_send=1;
clear_dial();
break;
case 3: /* 已發過號,等待連接有回應,檢查回應 */
stat=4;
WARN=0;
M_stat=0;
wsec=5;
break;
case 17:
if( r_buff[0]=='0' )
stat=0;
}
}
void clear_dial(void)
{
WARN=0;
P20=WARN;
P21=!WARN;
redial=0;
stat=0;
W_rec=0;
}
void jl(uint i)
{
}
void command(uint kb)
{
uint i;
W_rec=1;
wsec=60;
switch( r_buff[0] ){
...
...
... /* 根據收到的內容解釋命令,進行相應的動作*/
default:
strcat(s_buff,"無此命令!");
}
W_send=1;
}
void putc(uint k) /* 發送子程序*/
{
uint i=0;
while( s_buff[i] ){
TI=0;
SBUF=s_buff[i];
s_buff[i++]=0;
while(!TI);
}
if( k){
TI=0;
SBUF=0xa;
while(!TI);
TI=0;
SBUF=0xd;
while(!TI);
}
}
void clock(void)
{
sec++;
P23=sec%2;
if( W_rec) wsec--;
if ( sec>=60 ){
sec=0;
min++;
if ( min>=60 ){
min=0;
hour++;
if( hour>=24 ){
day++;
if( day>31) day=0;
hour=0;
}
}
}
}
void serial_init(void) { /* 初始化串口設定波特率為2400 ,晶振為 6M */
s_buff[0]=0; // TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 (TCON BIT MAP )
TMOD &= 0x0F; // CLEAR T1 TMOD.
TMOD |= 0x20; // SET T1 TO MODE 2
PCON = 0X80; // SET SMOD=1; AUTO FULL.
TH1 = TL1 = 0xf3; // When osc=6Mhz, 2400bps use 0xf3
REN=1;
EX1=0;
EX0=0;
EA=1; // open all ir
ES= 1; // OPEN SERIAL IR
TR1=1; // ENABLE T1
RI=0; // CLEAR RI
SCON=0x50; // 11000000 mode=3 speed can change.
}
void init(void) {
P1=0;
P2=0;
hour=min=sec=count=0;
fSec = 0;
TCON &= 0xCF; // Timer0
TMOD &= 0xF0;
TMOD |= 0x01;
TH0 = TL0 = 0;
ET0 = 1;
TR0 = 1;
}
timerint () interrupt 1 {
EA=0;
TR0 = 0;
TL0 = 0x12;
TH0 = 0xf7; // 0xf712 for 4.5ms
TR0 = 1;
count++;
if(count==217) { // 215, fast, 2m/4h; 218 slow 5m/10h;
count = 0; fSec = 1;
}
EA=1;
}
void SerInt() interrupt 4
{
uchar c;
ES=0;
if(RI&&(!Rec)) { /* 如果上次收到的內容沒處理完就不接收 */
c=SBUF;
if (M_stat) SBUF=c; /* MODEM為數據狀態時回送字符 */
RI=0;
if( rptr>=MAXLEN||c==0x0d||c==0x0a ){
c=0;
r_buff[rptr]=c;
rptr=0;
Rec=1; /* 收到標志 */
}
else
r_buff[rptr++]=c;
}
/***********
if( (s_buff[0])&&(TI) ){
TI=0;
SBUF= s_buff[sptr];
sptr++;
if( sptr>19||s_buff[sptr]==0 ){
sptr=0;
s_buff[0]=0;
}
}
*************/
ES=1;
}
/* 計劃將P0口接設備,應將SW8全部放在OFF位置 */
/* P00-NORMAL, P01-FAULT, P02-MAIN1, P03-MAIN2; P04-M1, P05-M2,P06-RESET,P07-OFF */
/* S0 S4 S8 SC 對應開關位置*/
/* P0在設備正常時應全為1 */
/* P2接到幾個發光二極管上,用于指示工作狀態 */
void checkequ(uint *kb1, uint *kb2,uint *kb3)
{
uint i,k;
P0=0x0f;
k=P0;
if( (!(k&2)) &&(*kb1<DELAY ) )
(*kb1)++;
else
(*kb1)=0;
if( (!(k&4))&&(*kb2<DELAY) )
(*kb2)++;
else
(*kb2)=0;
if ( (!(k&8) )&&(*kb3<DELAY) )
(*kb3)++;
else
(*kb3)=0;
if ( ( (*kb1>=DELAY)||( *kb2>=DELAY && *kb3>=DELAY) )&& (!WARN ) ){
WARN=1;
if( gzm[0].stat!=k ){
for( i=2;i>0;i--){
gzm[i].stat=gzm[i-1].stat;
gzm[i].hour=gzm[i-1].hour;
gzm[i].min=gzm[i-1].min;
}
gzm[0].stat=k;
gzm[0].hour=hour;
gzm[0].min=min;
}
}
}
void inttostr(uchar *ch,uint k,uint m)
{
if( m>2 ){
*ch++=k/100+'0';
k%=100;
}
if( m>1 ){
*ch++=k/10+'0';
k%=10;
}
*ch++=k+'0';
*ch=0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -