下面是下位机的接收代码片断:
// SCI 变量 .h 文件:
#define SciHeader 0xee // 包头和包尾字节的选取关系到 maxInfoLen 的最大允许值,不可以乱改。
#define SciHeaderH 0xee00 // 把这个值手动修改为上一个值 * 256
#define SciTeil 0xef
#define MaxInfoLen 64 // 单位为:字(word),最大值为 116。
struct sciMessage {
Uint16 addr; // 接收后变成地址,发送时不用管。
Uint16 cmd; // 接收后变成命令,发送时不用管。
Uint16 info[MaxInfoLen]; // 发送与接收的信息内容,发送要填充,接收要读取。
Uint16 len; // 接收后变成上面数组实际接收的长度,发送时不用管。
};
struct sciMessage sciTxMessage, sciRxMessage;
Uint16 baudrate, address;
volatile Uint16 sciTxCounter, sciTxLength, sciRxCounter, sciRxLength, sciCheckSum;
// .c 文件:
sci(){
register Uint16 schedulerTemp;
/*头******* 支持 SCI **************************************************************************************/
if (delayms[0] == 0) {
sciRxCounter = 0;
}
// send
while (sciTxLength > sciTxCounter && SciaRegs.SCICTL2.bit.TXRDY == 1) {
if ((sciTxCounter & 1) == 0) // 编译成汇编时可以发现, == 0 的写**比 == 1 的写法速度快。
SciaRegs.SCITXBUF = *(&sciTxMessage.addr + (sciTxCounter >> 1)) >> 8; // 先发高位,再发低位。
else
SciaRegs.SCITXBUF = *(&sciTxMessage.addr + (sciTxCounter >> 1)) & 0xFF;
sciTxCounter++;
}
// receive
// 00000 Receive FIFO is empty, 00001 Receive FIFO has 1 word,... 00100 Receive FIFO has 4 words
while (SciaRegs.SCIFFRX.bit.RXFFST != 0) {
// 要读出数据以清空缓存。
schedulerTemp = SciaRegs.SCIRXBUF.all;
delayms[0] = 20; //
if (sciRxCounter == 0) { // 认 SciHeader ,但又不是 ,这时丢弃数据
if (schedulerTemp != SciHeader)
continue;
sciRxLength = 2;
} else if (sciRxCounter == 1) { // == 1 表示前一字节收到了包头,这一字节接收到了地址。
if (schedulerTemp == address || schedulerTemp == 0) {
// 包头 + 地址 已经 OK ,将进入新一轮接收,清除上一次接收成功
sciCheckSum = 0;
} else {
sciRxCounter = 0;
}
} else if (sciRxCounter == 2) {
if (schedulerTemp > MaxInfoLen) {
sciRxCounter = 0;
} else
sciRxLength = (schedulerTemp << 1) + 5; // MaxInfoLen 的限制保证接收数据放入数组时不越界。
} else if (schedulerTemp == SciTeil && sciRxCounter == sciRxLength) {
sciRxMessage.len = sciRxMessage.cmd >> 8; // length
if ((sciCheckSum & 0xff) == 0) { // 校验和 OK
sciRxMessage.cmd &= 0xff; // cmd
// force(0);// 接收完,接下来就是分析数据。不能使用这一行,因为那个函数会重开 INT14。
// 再加入这个线程到执行队列,使它在执行完 currentTcb 指向的线程后立即执行。
force(0, 1); //
// tcbs[0].nextTcb = currentTcb->nextTcb;
// tcbs[0].previousTcb = currentTcb->nextTcb->previousTcb;
// tcbs[0].nextTcb->previousTcb = &tcbs[0];
// tcbs[0].previousTcb->nextTcb = &tcbs[0];
// 关闭接收,只有在 SCI 线程执行完一圈后,才能重开,这样可以保证不出执行队列中不会出现两个 tcbs[0] 线程。
SciaRegs.SCICTL1.bit.RXENA = 0; // disable receive,保护接收缓冲区。
} // else 如果校验和不匹配,直接跳过。
// sciRxMessage.cmd = 0xFF; // cmd == 0xFF --> checkSum error
}
if (sciRxCounter < sciRxLength) {
sciCheckSum += schedulerTemp;
if (sciRxCounter & 1)
*(&sciRxMessage.addr + (sciRxCounter >> 1)) += schedulerTemp;
else
*(&sciRxMessage.addr + (sciRxCounter >> 1)) = schedulerTemp << 8;
sciRxCounter++;
} else
sciRxCounter = 0;
}
/*尾****** 支持 SCI ***************************************************************************************/
}
// 应用:
void sciTask(void) { // 这个函数不能被调用,当接收到了数据后,自动被唤醒。
Uint16 i; // 注意,死循环内部不允许定义变量。
// 下面的 死循环由接收到完整的数据包后自动进入。
for (;;) {
sciRxMessage.addr &= 255;
switch (sciRxMessage.cmd) {
case 0x00:
// echo back
for (i = 0; i < sciRxMessage.len; i++)
sciTxMessage.info[i] = sciRxMessage.info[i];
send(InfoOK, sciRxMessage.len);
break;
}
}
// 发送:
/*
* 定义 CRC16。
* SCI 如果有 DE 控制,定义 SciDE
*/
#define CRC16
#define SciDE
#define SciDEOff() GpioDataRegs.GPASET.bit.GPIO7 = 1 // == 1 receive
#define SciDEOn() GpioDataRegs.GPACLEAR.bit.GPIO7 = 1 // == 0 send
#define HalfDuplex // 半双工时,接收完成后主动延时 8ms 后再发送。
// 半双工时,主动延时。如果有收发控制,发送之后要等待一定时间才切换为接收。
// 全双工时,直接调用 sciSend(returnNo, length) 函数。
#ifdef HalfDuplex
#pragma CODE_SECTION(send, "ramfuncs"); // 这个将用于 bootloader,一定要放入 ram 区。
void send(Uint16 returnNo, Uint16 length);
void send(Uint16 returnNo, Uint16 length) {
#ifdef SciDE
if(sciRxMessage.addr == 0) // 如果是广播命令,不操作 DE。
return;
SciDEOn();
sleep(8);
sciSend(returnNo, length);
sleep(2);// 这里启动发送
while(SciaRegs.SCICTL2.bit.TXEMPTY == 0)// 这里发送完成。多级缓冲发送,把缓冲区发送至空,只有发完的时候才可能出现。
sleep(1);
SciDEOff();
#else // SciDE
sleep(8);// 半双工时,主动延时。
sciSend(returnNo, length);
sleep(2);// 这里启动发送
while(SciaRegs.SCICTL2.bit.TXEMPTY == 0)// 这里发送完成。多级缓冲发送,把缓冲区发送至空,只有发完的时候才可能出现。
sleep(1);
#endif // SciDE
}
#else // HalfDuplex
#define send(returnNo, length) sciSend(returnNo, length)
#endif // HalfDuplex
void sciSend(Uint16 returnNo, Uint16 length) {
Uint16 i, sum;
if (length > MaxInfoLen || sciRxMessage.addr == 0) // 忽略广播命令
return;
sciTxMessage.addr = SciHeaderH + address;
sciTxMessage.cmd = (length << 8) + returnNo;
for (i = 1, sum = 0xff00 - address; i < length + 2; i++) {
sum -= (*(&sciTxMessage.addr + i) & 0xff);
sum -= (*(&sciTxMessage.addr + i) >> 8);
}
*(&sciTxMessage.addr + i) = (sum << 8) + SciTeil; // 这里一定在 sciTxMessage 结构体内,这是正确的。
sciTxCounter = 0; // 立即发送。
sciTxLength = 6 + length + length;
}
|