📄 test.cpp
字号:
*(UCHAR*)MBCR = 0x80;
// enable MBUS and its interrupt
//*(UCHAR*)MBCR = 0xc0;
// Set operation mode to query.
sMBusInfo.mode = OPMODE_QUERY;
sMBusInfo.currPackFinished = 1;
// generate stop signal
status = *(UCHAR*)MBCR;
status &= 0xd7;
*(UCHAR*)MBCR = status;
}
void MbusInterrupt()
{
asm(" LEA.L -56(A7),A7");
asm(" MOVEM.L D0-D7/A0-A5,(A7)");
//MBUS interrupt routine
Mbus_Lisr(0);
asm(" MOVEM.L (A7),D0-D7/A0-A5");
asm(" LEA.L 56(A7),A7");
asm(" RTE ");
}
/**
* PCF8591: read four channel's A/D results.
*
* @param data where to save the result
*
* @return 1 if the operation succeed.
* 0 if the operation failure because packetQue is full.
*/
CHAR PCF8591ADIn(UNCHAR *data)
{
static UNCHAR adResult[4];
MBusPackType thePack;
CHAR result, i;
thePack.txLen1 = 1;
thePack.txLen2 = 0;
thePack.rxLen = 4;
thePack.rxData = adResult;
thePack.txData[0] = PCF8591_SLAVE_ADDR | OP_READ;
thePack.repeatTimes = PCF8591_READ_REPEAT;
// transfer the pack
/* if (OPMODE_INTERRUPT == sMBusInfo.mode)
{
if (1 == MBusPackQuePut(&gPCF8591ReadPackQue, &thePack))
{
EnterInterrupt( );
result = 1;
}
else
result = 0;
}
else
*/ result = MBusTransferByQuery(&thePack);
// if transfer succeed, copy result to the given memory.
if (1 == result)
{
for (i = 0; i < 4; i ++)
data[i] = adResult[i];
}
return result;
}
/**
* Repeat transfer for given times.
* processed.
*
* @return 0 if repeat is not need or mbus is busy.
* @return 1 if repeat processed.
*/
static SHORT RepeatTransfer(void)
{
// if MBUS is not free until function return, transfer stop
if (0 == WaitForMBusFree())
return 0;
if (0 < sMBusInfo.currPack.repeatTimes)
{
sMBusInfo.currPack.repeatTimes --;
ConstructSequence(&sMBusInfo.currPack);
StartTransfer();
return 1;
}
else
{
sMBusInfo.transferFail ++;
return 0;
}
}
VOID Mbus_Lisr(int vector)
{
UCHAR status, ackNotDetected;
//clear MIF(M-Bus interrupt flag)
status = *(UCHAR*)MBSR;
// return if MIF is not set.
if (2 != (status&2) )
return;
status &= 0xfd;
*(UCHAR*)MBSR = status;
// No error detected.
ackNotDetected = 0;
sCurrentCmd ++;
// Check acknowledge signal when current command is not CMD_RECEIVE_STOP,
// because acknowledge signal will not be generated in the situation.
if (CMD_RECEIVE_STOP != sMBusCmds[sCurrentCmd])
{
if ( 1 == (status&1))
{
sMBusInfo.noAckError ++;
ackNotDetected = 1;
// cause system to generate stop signal
sMBusCmds[sCurrentCmd] = CMD_TRANSMIT_STOP;
}
}
switch (sMBusCmds[sCurrentCmd])
{
// normal transmit
case CMD_TRANSMIT:
*(UCHAR*)MBDR = *sTransmitPtr ++;
break;
// a stop after transmitting
case CMD_TRANSMIT_STOP:
status = *(UCHAR*)MBCR;
status &= 0xd7; // d7->df, why use d7? TXAK = 0?
*(UCHAR*)MBCR = status;
if( (1 == ackNotDetected) && (1 == RepeatTransfer()) )
{
// do nothing
}
else
{
// If work in query mode, don't check packet queue
if (OPMODE_QUERY == sMBusInfo.mode)
sMBusInfo.currPackFinished = 1;
/*
else
if (0 == ProcessNext() )
sMBusInfo.currPackFinished = 1;
*/
}
break;
// change to receive mode after transmitted
case CMD_TRANSMIT_RECEIVE:
// change to receive mode
status = *(UCHAR*)MBCR;
status &= 0xef;
*(UCHAR*)MBCR = status;
if (CMD_RECEIVE_STOP == sMBusCmds[sCurrentCmd+1])
{
// don't acknowledge it because it's the last byte to be received
status = *(UCHAR*)MBCR;
status |= 0x8;
*(UCHAR*)MBCR = status;
}
// Dummy read to generate clock signal
status = *(UCHAR*)MBDR;
break;
// restart then transmit
case CMD_RESTART_TRANSMIT:
// restart
status = *(UCHAR*)MBCR;
status |= 0x04;
*(UCHAR*)MBCR = status;
// then transmit
*(UCHAR*)MBDR = *sTransmitPtr ++;
break;
// receive with acknowledge
case CMD_RECEIVE_ACK:
*sReceivePtr ++ = *(UCHAR*)MBDR;
break;
// receive without acknowledge
case CMD_RECEIVE_NOACK:
// don't generate acknowledge signal
status = *(UCHAR*)MBCR;
status |= 0x08;
*(UCHAR*)MBCR = status;
*sReceivePtr ++ = *(UCHAR*)MBDR;
break;
// receive then stop
case CMD_RECEIVE_STOP:
// generate stop signal
status = *(UCHAR*)MBCR;
status &= 0xd7; // d7->df, why use d7? TXAK = 0?
*(UCHAR*)MBCR = status;
*sReceivePtr ++ = *(UCHAR*)MBDR;
// If work in query mode, don't check packet queue
if (OPMODE_QUERY == sMBusInfo.mode)
sMBusInfo.currPackFinished = 1;
/*
else
if (0 == ProcessNext() )
sMBusInfo.currPackFinished = 1;
*/
break;
default:
break;
}
}
/**
* get one MBusPacket from the given queue and save it to out
*
* @param theQue the queue to be manipulated.
* @param out the address for storing the result
*
* @return <code>0</code> if queue is empty, operation failed
* <code>1</code> if queue isnot empty, operation succeed
*/
INT16 MBusPackQueGet(MBusPackQueType *theQue, MBusPackType** out)
{
INT ptr = theQue->getPtr;
if ( ptr == theQue->putPtr )
return 0;
*out = &theQue->packQue[theQue->getPtr];
ptr ++;
if (theQue->queueLen <= ptr)
ptr = 0;
theQue->getPtr = ptr;
return 1;
}
/**
* put one MBusPacket to the queue
*
* @param theQue the queue to be manipulated.
* @param in the MBusPacket for putting
*
* @return <code>0</code> if queue is full, operation failed,
* <code>1</code> if queue is not full, success
*/
INT16 MBusPackQuePut(MBusPackQueType *theQue, MBusPackType* in)
{
INT ptr = theQue->putPtr;
ptr ++;
if (theQue->queueLen <= ptr)
ptr = 0;
if (ptr == theQue->getPtr)
return 0;
theQue->packQue[theQue->putPtr] = *in;
theQue->putPtr = ptr;
return 1;
}
/**
* Wait for some times until MBUS is not busy.
*
* @return 1 if MBUS is free when returned.
* 0 MBUS is still busy until return
*/
static UCHAR WaitForMBusFree(VOID)
{
UCHAR status;
UINT16 i;
// wait for 500 loops
for (i = 0; i < 500; i ++)
{
status = *(UCHAR*)MBSR;
if (0 == (status&0x20))
return 1;
}
return 0;
}
/**
* Wait for some times until MBUS Interrupt is set, which indicate that a data
* transfer is completed.
*
* @return 1 if MBUS is free when returned.
* 0 MBUS is still busy until return
*/
static UCHAR WaitForMIF(VOID)
{
UCHAR status;
UINT16 i;
// wait for 500 loops
for (i = 0; i < 500; i ++)
{
status = *(UCHAR*)MBSR;
if (2 == (status&2))
return 1;
}
return 0;
}
/**
* Construct command sequence according to the pack given,
* the command sequence will processed in MBus interrupt.
*
* @param pack the packet to be processed.
*/
static VOID ConstructSequence(MBusPackType *pack)
{
INT16 i, cmdNumber;
// The number of commands is 0
cmdNumber = 0;
// Commands are type of CMD_TRANSMIT at early.
for ( i = 0; i < pack->txLen1 - 1; i ++)
sMBusCmds[cmdNumber++] = CMD_TRANSMIT;
// If txLen2 is greater than 0, it means that there is a RESTART signal
// should insert here.
if (0 < pack->txLen2)
{
sMBusCmds[cmdNumber++] = CMD_RESTART_TRANSMIT;
// copy the other TRANSMIT command, remember here: the RESTART command
// was connected with a TRANSMIT command, so (pack->txLen2 - 1) is
// present here.
for ( i = 0; i < pack->txLen2 - 1; i ++)
sMBusCmds[cmdNumber++] = CMD_TRANSMIT;
}
// If want receive some characters.
if (0 < pack->rxLen)
{
// The last command is change mode to receive
sMBusCmds[cmdNumber++] = CMD_TRANSMIT_RECEIVE;
// If only receive one character, STOP after RECEIVE
if (1 == pack->rxLen)
sMBusCmds[cmdNumber++] = CMD_RECEIVE_STOP;
else
{
for ( i = 0; i < pack->rxLen - 2; i ++)
sMBusCmds[cmdNumber++] = CMD_RECEIVE_ACK;
// The second last command is CMD_RECEIVE_NOACK
sMBusCmds[cmdNumber++] = CMD_RECEIVE_NOACK;
// The last command is CMD_RECEIVE_STOP
sMBusCmds[cmdNumber++] = CMD_RECEIVE_STOP;
}
}
// Don't want receive any character, change the last command from
// TRANSMIT to TRANSMIT_STOP
else
sMBusCmds[cmdNumber++] = CMD_TRANSMIT_STOP;
sCurrentCmd = -1;
sTransmitPtr = &pack->txData[0];
sReceivePtr = pack->rxData;
}
/**
* Start a MBUS data transfer procedure.
*/
static VOID StartTransfer(VOID)
{
UCHAR status;
//clear MIF(M-Bus interrupt) flag
status = *(UCHAR*)MBSR;
status &= 0xfd;
*(UCHAR*)MBSR = status;
status = *(UCHAR*)MBCR;
// transmit mode selected
status |= 0x10;
*(UCHAR*)MBCR = status;
// master mode selected.
status |= 0x20;
*(UCHAR*)MBCR = status;
*(UCHAR*)MBDR = *sTransmitPtr ++;
}
/**
* MBUS: Transfer a packet by query.
*
* @param thePack the packet to be transfered
*
* @return 1 if the operation succeed.
* 0 if the operation failure because packetQue is full.
*/
static CHAR MBusTransferByQuery(MBusPackType *thePack)
{
// if MBUS working not in query mode, return
if (OPMODE_QUERY != sMBusInfo.mode)
return 0;
// Don't goto the following code if there another task using it.
// use the statement to protect the following code being used exclusively.
if (1 != sMBusInfo.currPackFinished)
return 0;
// packet has not been transfered
sMBusInfo.currPackFinished = 0;
// Remember the pack being transfered.
sMBusInfo.currPack = *thePack;
// construct command sequence
ConstructSequence(thePack);
// if MBUS is not free until function return, transfer stop
if (0 == WaitForMBusFree())
{
sMBusInfo.currPackFinished = 1;
return 0;
}
StartTransfer();
do
{
// if MIF has not been set until function return, transfer stop
if (0 == WaitForMIF())
{
sMBusInfo.currPackFinished = 1;
return 0;
}
// currPackFinished will be set to 1 if the packet transfered in MBusLisr
Mbus_Lisr(0);
}while (0 == sMBusInfo.currPackFinished);
return 1;
}
/**
* CAT24C021: read several bytes.
*
* @param baseAddr the first byte address
* @param byteNum the number of bytes to be read
* @param dataAddr where to store result
*
* @return 1 if the operation succeed.
* 0 if the operation failure because packetQue is full
* or byteNum is improper.
* @note A NU_Sleep will be called if MBUS operated in interupt mode.
*/
CHAR CAT24C021ReadSeqByte(UINT16 baseAddr, UINT16 byteNum, UCHAR *dataAddr)
{
MBusPackType thePack;
UCHAR sect_addr;
int k;
if (1 > byteNum || 2048 < (baseAddr + byteNum) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -