📄 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 Wait10ms()
{
idata uint i;
for(i=0;i<3600;i++){}
}
///////////////////////////////////////////////////////////////////////////////
// 一秒钟延时函数,累积10ms计数
///////////////////////////////////////////////////////////////////////////////
void OneSecond()
{
idata uchar i;
for(i=0;i<100;i++)
{
Wait10ms();
}
}
///////////////////////////////////////////////////////////////////////////////
// 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;
MSS=0; // SPI选通
for(i=8;i>0;i--)
{
MOSI=SPI_byte&0x80; // 移下一位到 MSB
SPI_byte=SPI_byte<<1;
SCK=0; // 时钟下降沿接收
SPI_byte|=MISO;
SCK=1; // 时钟上升沿发送
}
MSS=1;
key=0;
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进制校验和,以便比较
///////////////////////////////////////////////////////////////////////////////
void HEX_CS()
{
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);
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; // 计数器
for(R_BUF=0; R_BUF<BUFSIZE; R_BUF++)
SPIbuf[R_BUF]=0; // 接收缓冲区清零
time_out=1500; // 如果15秒内MSS无数据返回退出错误
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
time_out=0;
return ERROR; // 返回
}
}while(MSS_INT); // 检测MSS通信中断
NAKcounter=3; // NAK计数器
do
{
R_BUF=0; // 接收缓冲区计数
SOHptr=0;
ETXptr=0;
MSS=1;
time_out=1200; // 12000msSPI数据传输一个包时间
do
{
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
temp=SPItrans(0); // 接收数据
}while(temp==0);
SPIbuf[R_BUF++]=temp; // 非零数据存入缓冲区
if(R_BUF>BUFSIZE)break; // 缓冲区满
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
}while(temp!=EOT); // 通信结束
i=0;
do
{
if(SPIbuf[i]==SOH) // 定位数据头
{
SOHptr=i;
break;
}
i++;
Rstwdt(); // 喂狗
}while(i<R_BUF);
if(SOHptr==R_BUF)
{
goto SPIerr; // 缓冲区满,数据错误
}
else 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(); // 喂狗
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 uchar R_BUF; // 接收缓冲区计数
for(R_BUF=0; R_BUF<255; R_BUF++)
SPIbuf[R_BUF]=0; // 接收缓冲区清零
time_out=200; // 如果2秒内MSS无数据返回退出错误
do
{
Rstwdt(); // 喂狗
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
time_out=0;
return ERROR; // 返回
}
}while(MSS_INT); // 检测MSS通信中断
R_BUF=0;
time_out=50; // 500ms接收SPI数据包
do
{
do
{
temp=SPItrans(0); // 接收SPI字节
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
}while(temp==0); // 空字符不接收
SPIbuf[R_BUF++]=temp;
if(R_BUF>20)
{
break; // ACK或NAK命令长度不超过20
}
if(time_out==0)
{
HandwareErr=ERROR; // MSS可能故障
return ERROR; // 返回
}
}while(temp!=EOT); // 接收到EOT结束符
if(SPIbuf[R_BUF-2]==ACK)
{
return ACK; // 返回ACK
}
else if(SPIbuf[R_BUF-2]==NAK)
{
return NAK; // 返回NAK
}
HandwareErr=ERROR; // MSS可能故障
return ERROR;
}
///////////////////////////////////////////////////////////////////////////////
// 显示公共错误信息
///////////////////////////////////////////////////////////////////////////////
void disperr(uchar id)
{
Rstwdt(); // 喂狗
GLCD_Locate(16,32);
reverse=1;
dprintf(failure,12); // 失败
reverse=0;
GLCD_Locate(0,48);
dprintf(" ",15); // 清行
GLCD_Locate(16,48);
if(id<'A')
{
dprintf(disp_err[id-0x30],12); // 显示正常错误信息
}
else
{
if(id<='F')
{
HandwareErr=ERROR; // MSS不能正常工作
dprintf(disp_err[10],12); // 显示模块复位
TURN_ON();
}
else
{
dprintf(disp_err[11],12); // 显示ACK错误
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -