?? serialcom.c
字號:
/*
* FileName : <serialCom.c>
* Description : 二個函數(shù) 供 操作串口 使用
*
*
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"reg51.h"
#include"serialCom.h"
//子程序聲明
void createFrame(unsigned char protocol,unsigned char cmd);
void Com_Transmit(void);
//變量定義
unsigned char idata _aFrameHeader[1][2] = {{0x55,0xAA}}; //RSX協(xié)議的幀頭"55AA"
Structserial idata serial[1];//COM1
unsigned char idata _aInBuffer[SIZE_IN_BUFFER];//64byte接收緩沖區(qū)
unsigned char idata _aOutBuffer[SIZE_OUT_BUFFER];//64byte發(fā)送緩沖區(qū)
//---------------------------------------------------------------
// 函數(shù)名稱 : Com_Open
// 詳細(xì)說明 : 首先關(guān)中斷,根據(jù)入口參數(shù),完成COM1的 初始化,開中斷
// 入口參數(shù) : <1> comport---初始化某個串口
// <2> mode---[ b7 <=> 0 = RS232; 1 = RS485 ]
// [b3~b0 <=> 指定協(xié)議類型 ]
// <3> baudNumber---[ 1~255 <=> 300bps * 1~255]
// [ 0 <=> default = ? ]
// 出口參數(shù) : 無
// 備注: 其中涉及對串口變量 serial[0]---公共變量
//----------------------------------------------------------------
void Com_Open(unsigned char mode, unsigned char baudNumber)
{
//關(guān)各級中斷
EA = 0;
RI = 0;
TI = 0;
//初始化 串口
SCON = 0x50; // 串口工作方式1 : 8-bit UART, REN = 1 : 使能接收
PCON = 0x80; // B7 -> SMOD = 0 波特率不變;SMOD = 1 波特率 x 2
//定時器1裝入默認(rèn)參數(shù)
TMOD = (TMOD & 0x0f) | 0x20; // 定時方式2,八位自動重裝入
switch (baudNumber)
{
case 0x01 : TH1 = 0x8a; break; // 300bps X 1
case 0x02 : TH1 = 0xc5; break; // 300bps X 2
case 0x03 : TH1 = 0xd8; break; // 300bps X 3
case 0x04 : TH1 = 227; break; // 300bps X 8 = 2400bps
case 0x08 : TH1 = 241; break; // 300bps X 16 = 4800bps
case 0x10 : TH1 = 249; break; // 300bps X 32 = 9600bps
case 0x20 : TH1 = 252; break; // 300bps X 64 = 19200bps
default: TH1 = 241; break; // 300bps X 8 = 2400bps
}
//串口結(jié)構(gòu)體的初始化
serial[0].status = 0x00; //準(zhǔn)備讀取幀頭
serial[0].mode = 0x80 & mode; //取最高位b7 [b7==1 232] [b7==0 485]
serial[0].protocol = 0x0f & mode; //取低四位b3~b0 默認(rèn)是 0 => RSX protocol
serial[0].local = 0x99; //串口設(shè)備地址 = 99H
serial[0].cmd = 0x00; //命令字 ->默認(rèn) 0
serial[0].length = 0; //報文字節(jié)長度 ->默認(rèn) 0
serial[0].checkSum = 0x00; //檢驗和 初始化 ->0
serial[0].inAddress = 0x00; //存數(shù)據(jù)偏置 初始化 ->0
serial[0].outNumber = 0x00; //取數(shù)據(jù)偏置 初始化 ->0
serial[0].outAddress = 0x00; //存數(shù)據(jù)偏置 初始化 ->0
serial[0].timer = 0xFF; //這個常數(shù)與 中斷時間 最長報文長度 有關(guān)系
serial[0].token = 0x00; // 初始狀態(tài) 發(fā)送緩沖區(qū)空
//初始化 接收 發(fā)送 緩沖區(qū)
memset(_aInBuffer,'\0',SIZE_IN_BUFFER);
memset(_aOutBuffer,'\0',SIZE_OUT_BUFFER);
//使能各級中斷
EA = 1; // 使能全局中斷
ES = 1; // 使能串口中斷
TR1 = 1; // 使能串口接收中斷
}
//---------------------------------------------------------------
// 函數(shù)名稱 : Com_Event
// 詳細(xì)說明 : 中斷服務(wù)子程序,完成接收和發(fā)送任務(wù)
// 接收時完成報文解析;發(fā)送時由outNumber字段控制
//---------------------------------------------------------------
void Com_Event(void) interrupt 4
{
unsigned char ch;
if (RI)
{
RI=0;
ch = SBUF;
if (serial[0].token == 0x0F) //在緩沖區(qū)不滿的情況下,接收數(shù)據(jù)
{
return;
}
switch (serial[0].status )//解釋報文-根據(jù)接收到的字節(jié)轉(zhuǎn)移狀態(tài)
{
case 0x00 :
if (ch == _aFrameHeader[serial[0].protocol][serial[0].status])//
{
serial[0].status = 0x01;
serial[0].timer = 0xFF;
}else
{
serial[0].status = 0x00;
}
break;
case 0x01 :
if (ch == _aFrameHeader[serial[0].protocol][serial[0].status])
{
serial[0].status = 0x02;
serial[0].checkSum = 0x00;//使用前清零
}else
{
serial[0].status = 0x00;
}
break;
case 0x02 ://比較是否是 發(fā)給自己的報文
if (ch == serial[0].local)
{
serial[0].status = 0x03;
serial[0].checkSum += serial[0].local;//校驗和
}else
{
serial[0].status = 0x00;
}
break;
case 0x03 ://接收 CMD 1byte
serial[0].cmd = ch;
serial[0].checkSum += serial[0].cmd;
serial[0].status = 0x04;
break;
case 0x04 ://接收 報文長度 1byte
serial[0].length = ch;
serial[0].checkSum += serial[0].length;
serial[0].status = 0x05;
break;
case 0x05 ://接收 報頭檢驗和 1byte
if ( ch == serial[0].checkSum )
{
serial[0].status = 0x06;
serial[0].checkSum = 0x00;//準(zhǔn)備為后面報文接收做校驗和
if (serial[0].length == 0)
{
serial[0].token = 0xF0; //完整接收到報文
serial[0].status = 0x00; //
}else//有正文
{
//在這里還應(yīng)該判斷 是否上次報文處理已經(jīng)不再需要 接收緩沖區(qū)里的正文 如果有正文的話
serial[0].inAddress = 0; //準(zhǔn)備將正文存入數(shù)據(jù)緩沖區(qū)
}
}else//報頭校驗和 出錯
{
serial[0].status = 0x00;
}
break;
case 0x06 ://接收 報文內(nèi)容 Xbyte 根據(jù)前面接收到的長度
serial[0].checkSum += ch;
*(_aInBuffer + serial[0].inAddress++) = ch;
if (serial[0].inAddress == SIZE_IN_BUFFER) //接收緩沖區(qū) 滿
{
serial[0].token = 0x0F; //置標(biāo)志位
serial[0].inAddress = 0; //接收指針到棧頂
}
if ( (--serial[0].length) == 0 )
{
serial[0].status = 0x07;
serial[0].length = serial[0].inAddress;
}
break;
case 0x07 ://接收 報文內(nèi)容校驗和 1byte
if ( ch == serial[0].checkSum )
{
//置報文接收完整標(biāo)志
serial[0].token = 0xF0;//收到完整報文
serial[0].status = 0x00;
}else//報文內(nèi)容校驗和出錯
{
serial[0].status = 0x00;
serial[0].inAddress = 0x00;
}
break;
default :
//將串口狀態(tài)重置為 0x00
serial[0].status = 0x00;
serial[0].inAddress = 0x00;
break;
}//end switch(_sserial[1].status)
}// end if (RI)
if (TI)
{
TI = 0; //軟件請零
serial[0].token = 0xF8;//應(yīng)答報文中
if (serial[0].outNumber == 0)//判斷是否發(fā)完
{
serial[0].token = 0xff;//應(yīng)答報文完成
return; //退出中斷
}
SBUF = *(_aOutBuffer + serial[0].outAddress); //發(fā)送緩沖區(qū)數(shù)據(jù)送入SBUF
serial[0].outAddress++; //發(fā)送偏置 + 1
serial[0].outNumber--; //待發(fā)送的數(shù)據(jù)個數(shù) - 1
}// end if (TI)
}//end Com_Event
//-----------------------------------------------------------------------------------
// 函數(shù)名稱 : Com_Operate(unsigned char comport)
// 詳細(xì)說明 : 解釋報文
// 入口參數(shù) : comport---選擇要操作的串口
// 出口參數(shù) : 無
// 備注:當(dāng) comport = 0x01 時 作測試發(fā)送用例,只是發(fā)送 012345
// 當(dāng) comport = 0x00 時 作測試接收發(fā)送用例
//-----------------------------------------------------------------------------------
void Com_Operate(unsigned char comport)
{
switch (comport)
{//選擇 串口
case 0x00://COM1
//判斷當(dāng)前串口要進行的操作
//if (serial[0].token == 0xff) return;//應(yīng)答報文處理完成
//if (serial[0].token == 0xf8) return;//應(yīng)答報文處理中
if (serial[0].token == 0xF0) //收到了完整報文
{
//有沒有可能在報文應(yīng)答未結(jié)束時,又收到新的待處理報文
createFrame(serial[0].protocol,serial[0].cmd);
Com_Transmit();//TI = 1
return;
}
break;
// end case 0x00 COM1
case 0x01://COMX
break;
default://使用COM1 這個可以用來測試
//在報文組裝完成,確定發(fā)送 起始地址 發(fā)送個數(shù)
createFrame(0,0);//收到 05 05 99 00 01 9A 發(fā)送 012345
// 啟動發(fā)送中斷
Com_Transmit();//TI = 1
break;
}//end switch(comport)
}//end Com_Operate()
//-----------------------------------------------------------------------------------
// 函數(shù)名稱 : createFrame(unsigned char protocol,unsigned char cmd)
// 詳細(xì)說明 : 按幀結(jié)構(gòu)組織報文
// 入口參數(shù) : <1> protocol---組織報文要使用的協(xié)議
// <2> cmd---協(xié)議中具體的命令字
//-----------------------------------------------------------------------------------
void createFrame(unsigned char protocol,unsigned char cmd)
{
unsigned char i = 0; //循環(huán)計數(shù)
unsigned char num = 0; //取數(shù)控制
unsigned char checksum = 0x00; //校驗和計算
unsigned char code *pflash;
switch (cmd)//根據(jù)命令字
{
case 0x00://測試 收到 05 05 99 00 01 9A 發(fā)送 012345
for (i = 0; i < 6; i++)
{
_aOutBuffer[i] = i + 0x30; //計算校驗和
}
serial[0].outNumber = 6; //包含 幀頭的報文 字節(jié)個數(shù) 控制發(fā)送
serial[0].outAddress = 0; //發(fā)送的起始地址
break;
case 0x01://讀取片內(nèi)Flash數(shù)據(jù) 起始地址 起的 N個byte 數(shù)據(jù)
//注意應(yīng)答報文中數(shù)據(jù)最大長度不應(yīng)超過 64-7
memcpy(_aOutBuffer,_aFrameHeader[protocol],2); //55 AA
*(_aOutBuffer+2) = serial[0].local; //99
*(_aOutBuffer+3) = serial[0].cmd; //01
num = _aInBuffer[2]; //要取數(shù)據(jù)的個數(shù)
*(_aOutBuffer+4) = num; //正文長度
checksum = 0;
for (i = 2; i < 5; i++)
{
checksum += _aOutBuffer[i]; //計算校驗和
}
*(_aOutBuffer+5) = checksum;
pflash = (unsigned char code *)(_aInBuffer[0] + (_aInBuffer[1]<<8)); //要取數(shù)據(jù)的起始地址
checksum = 0;
for (i = 0; i < num; i++)
{
_aOutBuffer[6+i] = *pflash; //數(shù)據(jù)存入發(fā)送緩沖區(qū)
checksum += *pflash++; //計算校驗和
}
*(_aOutBuffer+6+num) = checksum; //添入校驗和字段
serial[0].outNumber = num + 7; //包含 幀頭的報文 字節(jié)個數(shù) 控制發(fā)送
serial[0].outAddress = 0; //發(fā)送的起始地
break;
default:// 收到 05 05 99 01 00 9A 發(fā)送 05 05 99 81 00 1A
memcpy(_aOutBuffer,_aFrameHeader[protocol],2); //幀頭 根據(jù)協(xié)議
*(_aOutBuffer+2) = serial[0].local; //串口設(shè)備地址
*(_aOutBuffer+3) = serial[0].cmd + 0x80; //命令字 + 80H
*(_aOutBuffer+4) = serial[0].length; //報文長度
checksum = 0;
for (i = 2; i < 5; i++)
{
checksum += _aOutBuffer[i]; //計算校驗和
}
*(_aOutBuffer+5) = checksum; //填入 校驗和 字段
checksum = 0; //校驗和清零
num = serial[0].length;//接收到的報文中有正文,將正文拷貝至發(fā)送緩沖區(qū)
for (i = 0; i < num; i++)//這樣應(yīng)該是安全的,num = 0
{
_aOutBuffer[6+i] = _aInBuffer[i];
checksum += _aInBuffer[i];
}
*(_aOutBuffer+6+num) = checksum; //正文校驗和
serial[0].outNumber = num + 7; //包含 幀頭的報文 字節(jié)個數(shù) 控制發(fā)送
serial[0].outAddress = 0; //發(fā)送的起始地址
break;
}//end switch(protocol)
}
//-----------------------------------------------------------------------------------
// 函數(shù)名稱 : Com_Transmit()
// 詳細(xì)說明 : 發(fā)幀 一次發(fā)完
//-----------------------------------------------------------------------------------
void Com_Transmit(void)
{
TI = 1; //啟動 中斷 發(fā)數(shù)
}
/*
//-----------------------------------------------------------------------------------
// 函數(shù)名稱 : overTime()
// 詳細(xì)說明 : 檢測報文是否接收超時
// 備注: 到底用那個定時器 尚未定下來
//-----------------------------------------------------------------------------------
void overTime(void)
{
if ( serial[0].status>0x00 && serial[0].status<0x08)
{
serial[0].timer--;
if (serial[0].timer == 0)
{
serial[0].status = 0;
}
}
}
*/
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -