?? mss_spi.c
字號:
///////////////////////////////////////////////////////////////////////////////
//
// Hopinfo Copyright.
//
// www.chinahopeinfo.com.cn
//
// 2005.04.26
//
// 審閱:黃平生
//
// 指紋模塊(MSS)和HOST通信采用SPI通信接口,在該設計中8051作為HOST端,工作模式為
// 主設備,指紋模塊工作模式為負設備,接收/發送的時鐘由8051提供,通信速率由8051處
// 理速度決定,MSS在時鐘的下降沿對齊要發送/接收數據位的中間,MSS在時鐘的下降沿有
// 效。
// 基本通信原理是:當MSS有數據發送時向HOST申請中斷,置MSS_INT為低電平,HOST決定
// 是否接收數據;HOST有數據要發送時,直接向MSS發送,因為HOST為主設備。
//
///////////////////////////////////////////////////////////////////////////////
#include "Global.h"
///////////////////////////////////////////////////////////////////////////////
// 內部存儲區變量 0~256
// 全局變量定義
extern data uchar checksum; // 校驗和
extern data uchar testchecksum; // 接收到的校驗和
extern data uchar key; // 鍵盤值
extern data uchar MSG; // 信息號
extern data uchar CSH; // 校驗和ASC高字節
extern data uchar CSL; // 校驗和ASC低字節
extern data uint SOHptr; // SPI緩沖區頭指針
extern data uint ETXptr; // ETX位置
extern data uint CommandLen; // 命令體長度
extern data uchar pulse; // 蜂鳴次數
extern data uint time_out; // 通用超時定時器
extern data char groupclass; // 用戶分組信息
extern data char User_id[6]; // 用戶編號0~65534
extern data uchar cur_time[15]; // 系統當前時間顯示存儲區 XXXX年XX月XX日XX時XX分XX秒星期X
extern data uint index; // 數據索引
extern data uint trans_ctr; // 發送數據指針
extern data uint trans_size; // 發送數據大小
extern bdata bit reverse; // LCD底色顯示控制
extern bdata bit HandwareErr; // 指紋模塊工作狀態
extern bdata bit managemode; // 管理員比對操作
// 全局臨時變量
extern idata char Start_user_id[6]; // 開始用戶編號
extern idata char End_user_id[6]; // 終止用戶編號
extern idata char Start_time[5]; // 開始時間
extern idata char End_time[5]; // 終止時間
extern idata char Security_level; // 安全等級0~4
extern idata char ManageClass; // 管理分類'M'管理用戶'G'普通用戶
extern idata char AppClass; // 應用分類'F'指紋用戶'P'密碼用戶
extern idata char Password[7]; // 密碼
extern idata char wieformat; // 韋根通信格式
///////////////////////////////////////////////////////////////////////////////
// 內部存儲區變量 256~1280
// 全局變量定義
extern xdata uchar SPIbuf[BUFSIZE]; // SPI和串行通信緩沖區
extern xdata uchar trans_buf[TRANSBUFSIZE];// 發送數據緩沖區
///////////////////////////////////////////////////////////////////////////////
// 程序存儲區變量 0~32K
// SPI通信顯示信息
code char Putf[] =" -按下手指- ";
code char Liftf[] =" -抬起手指- ";
code char success[] =" <<成功>> ";
code char failure[] =" <<失敗>> ";
code char welcome[] ="歡迎";
code char // 指紋模塊返回信息顯示
disp_err[12][12]=
{
" -沒有手指- ",
" -圖像太差- ",
" -手指不同- ",
" -手指太偏- ",
" -不能注冊- ",
" -已 注 冊- ",
" -沒有注冊- ",
" -比對失敗- ",
" -沒有空間- ",
" -不能使用- ",
" -系統復位- ",
" -通信復位- ",
};
void disperr(uchar id); // 顯示錯誤信息
///////////////////////////////////////////////////////////////////////////////
// 十毫秒延時函數,累積系統若干條指令
///////////////////////////////////////////////////////////////////////////////
void Wait10ms()
{
idata uint i;
for(i=0;i<2700;i++){Rstwdt();}
}
///////////////////////////////////////////////////////////////////////////////
// MSS和HOST通信包結構采用標準不定長信息包結構
//
// 信息包結構定義如下:
// SOH 地址4字節ASC碼 信息號1字節ASC碼 STX 命令體ASC碼3~ ETX 校驗2字節AC碼 EOT
// 0B 1B 2B 3B 4B 5B 6B NB N+1B N+2B N+3B N+4B
// 01H 30H 31H 30H 32H 30H~39H 02H 03H 04H
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// SPI_Transfer
// 使用SPI 協議同時發送<SPI_byte>
// SCK 空閑為高 在SCK 下降時位鎖存
//
// 此程序的時序如下
//
// 參數 時鐘數
// MOSI 有效到SCK 下降沿 6
// SCK 上升到 MISO 鎖存 2
// SCK 下降到 MOSI 有效 7
// SCK 高時間 13
// SCK 低時間 8
///////////////////////////////////////////////////////////////////////////////
char SPItrans(char SPI_byte)
{
idata uchar i;
SCK=1;
MSS=0; // SPI選通
_nop_();
_nop_();
for(i=8;i>0;i--)
{
MOSI=SPI_byte&0x80; // 移下一位到 MSB
SPI_byte=SPI_byte<<1;
SCK=0; // 時鐘下降沿發送
SPI_byte|=MISO; // 時鐘下降沿接收
_nop_();
_nop_();
_nop_();
SCK=1;
}
_nop_();
_nop_();
MSS=1;
SCK=1;
return(SPI_byte);
}
///////////////////////////////////////////////////////////////////////////////
// 生成信息包的信息號'0~'9'
///////////////////////////////////////////////////////////////////////////////
void NewMsgNum()
{
MSG++;
if(MSG>0x39){MSG=0x30;}
}
///////////////////////////////////////////////////////////////////////////////
// 將16進制數據校驗和轉換為ASC碼校驗和,以便發送
///////////////////////////////////////////////////////////////////////////////
void CS_ASCII()
{
checksum=~checksum+1; // 校驗和求補
CSH=((checksum>>4)&0x0f)+0x30;
if(CSH>0x39)
{CSH+=0x07;}
CSL=(checksum&0x0f)+0x30;
if(CSL>0x39)
{CSL+=0x07;} // 校驗和轉換成兩位ASCII碼 高位CSH 低位 CSL
}
///////////////////////////////////////////////////////////////////////////////
// 將ASC碼校驗和轉換為16進制校驗和,以便比較
///////////////////////////////////////////////////////////////////////////////
{
CSH-=0x30;
if(CSH>9){CSH-=0x07;}
CSL-=0x30;
if(CSL>9){CSL-=0x07;}
checksum=((CSH<<4)&0xf0)+CSL;
}
///////////////////////////////////////////////////////////////////////////////
// 將ASC碼數據轉換為16進制數據
///////////////////////////////////////////////////////////////////////////////
uchar Asc_hex(char alpha)
{
alpha=alpha-0x30;
if(alpha>0x09)alpha=alpha-0x07;
return alpha;
}
///////////////////////////////////////////////////////////////////////////////
// 將16進制數據轉換為ASC碼數據
///////////////////////////////////////////////////////////////////////////////
char Hex_ascii(uchar h)
{
h=h+0x30;
if(h>0x39)
{h+=0x07;}
return h;
}
///////////////////////////////////////////////////////////////////////////////
// 組織發送命令頭
///////////////////////////////////////////////////////////////////////////////
void Preamble()
{
Rstwdt(); // 喂狗
SPItrans(SOH);
SPItrans('0');
SPItrans('1');
SPItrans('0');
SPItrans('2');
SPItrans(MSG);
checksum=MSG;
SPItrans(STX);
checksum+=0xc6; // 校驗和
Rstwdt(); // 喂狗
}
///////////////////////////////////////////////////////////////////////////////
// 組織發送命令體,命令不同,對應的命令體內容和長度也不相同
///////////////////////////////////////////////////////////////////////////////
void Command()
{
idata uchar i;
for(i=0;i<CommandLen;i++)
{
Rstwdt(); // 喂狗
SPItrans(SPIbuf[i]); // 發送命令體
checksum+=SPIbuf[i]; // 校驗和
}
}
///////////////////////////////////////////////////////////////////////////////
// 組織發送命令尾
///////////////////////////////////////////////////////////////////////////////
void Postamble()
{
Rstwdt(); // 喂狗
SPItrans(ETX);
checksum+=ETX; // 校驗和
CS_ASCII();
SPItrans(CSH);
SPItrans(CSL);
SPItrans(EOT);
SPItrans(0);
Rstwdt(); // 喂狗
}
///////////////////////////////////////////////////////////////////////////////
// 組織發送整個命令包
///////////////////////////////////////////////////////////////////////////////
void SendMsg()
{
Preamble(); // SPI前導數據結構
Command(); // 命令體
Postamble(); // SPI校驗和結束符
}
///////////////////////////////////////////////////////////////////////////////
// 向MSS發送"ACK"或"NAK"
///////////////////////////////////////////////////////////////////////////////
void SendNACK(uchar NACK)
{
Rstwdt(); // 喂狗
SPItrans(SOH);
SPItrans('0');
SPItrans('1');
SPItrans('0');
SPItrans('2');
SPItrans(MSG);
SPItrans(NACK);
SPItrans(EOT);
Rstwdt(); // 喂狗
}
///////////////////////////////////////////////////////////////////////////////
// HOST接收MSS數據,按照標準信息包進行檢查
// 如果接收錯誤向MSS發送NAK,如果3次發送錯誤返回失敗
// 如果接收成功向MSS發送ACK
// 如果15秒內不能檢測到MSS的數據發送中斷,那么MSS可能故障
///////////////////////////////////////////////////////////////////////////////
bit SPIReceive()
{
idata uchar temp; // 臨時變量
idata uchar NAKcounter; // NAK計數器
idata uint R_BUF; // 接收緩沖區指針
idata uint i; // 計數器
NAKcounter=4; // NAK計數器
do
{
for(R_BUF=0; R_BUF<BUFSIZE; R_BUF++)
SPIbuf[R_BUF]=0; // 接收緩沖區清零
time_out=600; // 如果6000ms內MSS無數據返回退出錯誤
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
}while(MSS_INT); // 檢測MSS通信中斷
R_BUF=0; // 接收緩沖區計數
SOHptr=0; // 數據頭指針
ETXptr=0; // 命令尾指針
MSS=1;
time_out=100; // 1000msSPI數據傳輸一個包時間
do
{
Rstwdt(); // 喂狗
do
{
Rstwdt(); // 喂狗
temp=SPItrans(0); // 接收數據
}while(temp==0||temp==0xff&&time_out>0);
SPIbuf[R_BUF]=temp; // 非零數據存入緩沖區
R_BUF++;
if(R_BUF>BUFSIZE)break; // 緩沖區滿
}while((temp!=EOT)&&(time_out>0)); // 通信結束
temp=SPItrans(0); // 接收數據
i=0;
do
{
if(SPIbuf[i]==SOH) // 定位數據頭
{
SOHptr=i;
break;
}
i++;
Rstwdt(); // 喂狗
}while(i<R_BUF);
if(i>=R_BUF)
goto SPIerr; // 沒有發現SOH
if(R_BUF>=1)
{
if(SPIbuf[R_BUF-1]!=EOT)
goto SPIerr; // 找到SOH,且沒有發現EOT,數據丟失
}
if((SOHptr+6)>=R_BUF)
{
goto SPIerr; // 發現SOH和EOT,但中間可能有數據丟失
}
if(SPIbuf[SOHptr+6]!=STX)
{
goto SPIerr; // STX錯誤
}
else if(SPIbuf[R_BUF-4]!=ETX)
{
goto SPIerr; // ETX錯誤
}
else
{
MSG=SPIbuf[SOHptr+5]; // 保存信息號
ETXptr=R_BUF-4;
Rstwdt(); // 喂狗
checksum=0;
CSH=SPIbuf[ETXptr+1];
CSL=SPIbuf[ETXptr+2];
HEX_CS(); // 接收到的校驗和
testchecksum=0;
for(i=0;i<ETXptr-SOHptr+1;i++) // 計算校驗和
{
Rstwdt(); // 喂狗
testchecksum+=SPIbuf[SOHptr+i];
}
temp=testchecksum+checksum;
temp=temp&0xff;
if(temp!=0)
goto SPIerr; // 校驗和錯
SendNACK(ACK); // 發送 ACK
return OK;
}
SPIerr:
Rstwdt();
SendNACK(NAK); // 發送 NAK 重新接收DSP數據
NAKcounter--;
}while(NAKcounter>0);
HandwareErr=ERROR; // MSS可能故障
return ERROR;
}
///////////////////////////////////////////////////////////////////////////////
// HOST接收MSS發送的NAK或ACK數據,按照標準信息包進行檢查
// 如果2秒內不能檢測到MSS的數據發送中斷,那么MSS可能故障
///////////////////////////////////////////////////////////////////////////////
uchar ACKReceive()
{
idata uchar temp; // 臨時變量
idata uint i;
idata uint R_BUF; // 接收緩沖區計數
for(R_BUF=0; R_BUF<BUFSIZE; R_BUF++)
SPIbuf[R_BUF]=0; // 接收緩沖區清零
time_out=100; // 如果1000ms內MSS無數據返回退出錯誤
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
}while(MSS_INT); // 檢測MSS通信中斷
R_BUF=0;
time_out=50; // 500ms接收SPI數據包
do
{
Rstwdt(); // 喂狗
do
{
Rstwdt(); // 喂狗
temp=SPItrans(0); // 接收SPI字節
}while(temp==0||temp==0xff&&time_out>0); // 空字符不接收
SPIbuf[R_BUF]=temp;
R_BUF++;
if(R_BUF>BUFSIZE) break; // 緩沖區溢出
}while((temp!=EOT)&&(time_out>0)); // 通信結束
temp=SPItrans(0); // 接收數據
i=0;
do
{
if(SPIbuf[i]==SOH) // 定位數據頭
{
SOHptr=i;
break;
}
i++;
Rstwdt(); // 喂狗
}while(i<R_BUF);
if(i>=R_BUF)
return ERROR; // 沒有發現SOH
if((SOHptr+7)>=R_BUF)
return ERROR; // 數據丟失
if(R_BUF>=1)
{
if(SPIbuf[R_BUF-1]!=EOT) // 數據丟失
return ERROR;
}
if(SPIbuf[SOHptr+6]==ACK)
{
return ACK; // 返回ACK
}
else if(SPIbuf[SOHptr+6]==NAK)
{
return NAK; // 返回NAK
}
}
///////////////////////////////////////////////////////////////////////////////
// MSS上電復位函數
// MSS電源芯片采用TPS70145,該芯片具備可編程供電能力,當使能端為低電平時,MSS
// 上電,MSS上電后進入自檢狀態,當自檢完成后向HOST申請中斷,發送自檢結果信息。
// MSS自檢成功發送'HHHF0'信息,否則發送'HHHFX',X表示MSS模塊硬件故障代碼。
// MSS自檢成功后,HOST設置MSS系統安全等級。
// 當MSS在10秒內不能完成自檢,置MSS故障標志。
///////////////////////////////////////////////////////////////////////////////
void TURN_ON()
{
idata uint i;
idata uchar count=3;
MSS_INT=1; // 清MSS中斷位
MSS_PWR_ON=1; // 清MSS電源使能位
Rstwdt(); // 喂狗
init_again:
MSS_PWR_ON=0; // 打開MSS電源
for(i=0;i<20;i++)
{
Wait10ms(); // 等待200ms
Rstwdt(); // 喂狗
}
time_out=50; // 如果500ms秒內MSS無數據返回退出錯誤
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
if(count==0)
{
HandwareErr=ERROR; // MSS可能故障
time_out=0;
count=0;
return; // 返回
}
else
goto power_off;
}
}while(MSS_INT); // 檢測MSS通信中斷
if(!SPIReceive())
{
goto power_off; // 重新對MSS上電
}
if(SPIbuf[SOHptr+7]=='H'&&SPIbuf[SOHptr+8]=='H'&&SPIbuf[SOHptr+9]=='H'
&&SPIbuf[SOHptr+10]=='F'&&SPIbuf[SOHptr+11]=='0')
{
if(Set_class())
{
for(i=0; i<BUFSIZE; i++)
SPIbuf[i]=0;
HandwareErr=OK; // MSS工作正常
return;
}
else
goto power_off;
}
if(count==0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -