?? uart.c
字號:
// Copyright (c)2005 - 2006 by Laser Electronics, All Rights Reserved.
/*----------------------------------------------------------------------------+
| File Name: UART.c, v1.0.1 |
| Author: |
| Date: |
+-----------------------------------------------------------------------------+
| Description: 聯網型智能樓宇對講系統 -- 管理中心機異步串口驅動程序 |
| 器件選擇 -- STC89C58RD+, PQFP-44 |
| 時鐘頻率 -- 24.000 MHz |
+-----------------------------------------------------------------------------+
/*----------------------------------------------------------------------------+
| Include files |
+----------------------------------------------------------------------------*/
#include "Main.h"
#include "UART.h"
#include "LCD.h"
/*----------------------------------------------------------------------------+
| Type Definition & Macro |
+----------------------------------------------------------------------------*/
#define RS232RXD P3_3
#define RS232TXD P3_4
/*----------------------------------------------------------------------------+
| Global Variables |
+----------------------------------------------------------------------------*/
extern bit TxOK;
/*----------------------------------------------------------------------------+
| Internal Variables |
+----------------------------------------------------------------------------*/
idata FRAME RxFrame; // 接收數據幀緩沖
data BYTE RxFrameLength;// 接收到的數據幀的長度
idata FRAME TxFrame; // 發送數據幀緩沖
data BYTE TxFrameLength;// 要發送的數據幀的長度,不包括校驗和以及幀結束字節
bit bFrameStart; // 當前是否開始在接收數據
/*----------------------------------------------------------------------------+
| System Initialization Routines |
+----------------------------------------------------------------------------*/
void InitUART(void)
{
// serial_init: Setup the serial port for 10.417Kbps baud at 24MHz.
// SM0 SM1 SM2 REN TB8 RB8 TI RI
// 1 1 1 1 0 0 0 0
/*
UART所需的定時器由T1或T2提供
SCON:串行口控制寄存器
SM0(9F),SM1(9E)
SM0,SM1 |工作方式| 說明 |所用波特率
--------+--------+--------------+----------------
0,0 | 方式0 |同步移位寄存器|Fosc/12
0,1 | 方式1 | 10位異步收發 |由定時器控制
1,0 | 史澆2 | 11位異步收發 |Fosc/32或Fosc/64
1,1 | 方式3 | 11位異步收發 |由定時器控制
SM2(9D) 多機通信0:單機,1:多機
REN(9C) 接收控制0:禁止接收,1:允許接收
TB8 (9B) 發送數據第九位
RB8 (9A) 接收數據第九位
TI (99) 發送中斷標記
RI (98) 接收中斷標志
*/
ES = 0; // 關閉串行中斷
SCON = 0xE0; // Mode 3: 9-bit UART, enable receiver
PCON = 0x80; // 波特率倍增
TMOD &= 0x0F; // take care of TMOD, SCON setting, because Timer 0&1 use them together
TMOD |= 0x20; // Timer 1 mode 2: 8-Bit reload
TH1 = UART_RATE9600; // Reload value
TL1 = UART_RATE9600;
TxOK = TRUE;
bFrameStart = FALSE;
SM2 = 0; // 允許接收任何數據
REN = 1; // 開機時UART會接收到一個不定的數據,要先TI=0,RI=0后REN=1,這個有待進一步的考證.
ES = 1; // Enable serial port interrupt
TR1 = 1; // Start timer 1
EX1 = ENABLE; // 允許模擬串口管腳接收中斷
}
/*----------------------------------------------------------------------------+
| General Subroutines |
+----------------------------------------------------------------------------*/
#if 0
void RS485SendBuffer(BYTE *pSource, BYTE nLength)
{
while (nLength > 0)
{
TxOK = FALSE;
SBUF = *pSource;
pSource ++;
nLength --;
while (!TxOK) ;
}
}
/*void RS485SendByte(BYTE aData)
{
while (!TxOK);
TxOK = FALSE;
SBUF = aData;
while (!TxOK);
}*/
#endif
// 通過RS485總線向剛才收到的數據幀返回斷開連接的命令
void RS485AckCancelCommand(void)
{
TxFrame.Frame.Addr[0] = RxFrame.Frame.Addr[0];
TxFrame.Frame.Addr[1] = RxFrame.Frame.Addr[1];
TxFrame.Frame.Addr[2] = RxFrame.Frame.Addr[2];
TxFrame.Frame.Addr[3] = RxFrame.Frame.Addr[3];
TxFrame.Frame.nLength = 1;
TxFrame.Frame.aData[0] = Command_Disconnect;
TxFrameLength = 6; // 發送數據幀的長度為6個字節,不包括校驗和停止字節
RS485SendWaitTimer = 0;
RS485SendTxFrame();
}
// 通過RS485總線發送取消連接命令
void RS485SendCancelCommand(void)
{
TxFrame.Frame.Addr[0] = ConnectingAddr[0];
TxFrame.Frame.Addr[1] = ConnectingAddr[1];
TxFrame.Frame.Addr[2] = ConnectingAddr[2];
TxFrame.Frame.Addr[3] = ConnectingAddr[3];
TxFrame.Frame.nLength = 1;
TxFrame.Frame.aData[0] = Command_Disconnect;
TxFrameLength = 6; // 發送數據幀的長度為6個字節,不包括校驗和停止字節
RS485SendWaitTimer = 0;
RS485SendTxFrame();
}
// 通過RS485總線發送一個數據幀
void RS485SendTxFrame(void)
{
BYTE i;
BYTE TxCheckSum;
WaitForLineIdle(); // 等待線路空閑
// 將MAX485置為發送狀態
if (TxFrameLength <= 5) // 如果數據長度小于6,則不是一個完整的幀,以普通字符串發送
{
for (i=0; i<TxFrameLength; i++)
{
TxOK = FALSE;
SBUF = TxFrame.aData[i];
while (!TxOK) ;
}
}
else
{
TxCheckSum = 0x00;
// 發送幀起始字節
TB8 = 1; //
TxOK = FALSE;
SBUF = TxFrame.aData[0];
TxCheckSum += TxFrame.aData[0];
while (!TxOK) ;
TB8 = 0; //
// 發送后面所有的數據
for (i=1; i<TxFrameLength; i++)
{
TxOK = FALSE;
SBUF = TxFrame.aData[i];
TxCheckSum += TxFrame.aData[i];
while (!TxOK) ;
}
// 發送校驗和字節
TxOK = FALSE;
SBUF = TxCheckSum;
while (!TxOK) ;
// 發送幀結束字節
TB8 = 1; //
TxOK = FALSE;
SBUF = 0xFF;
while (!TxOK) ;
TB8 = 0; //
}
// 將MAX485置為接收狀態
}
/*----------------------------------------------------------------------------+
| Interrupt Service Routines |
+----------------------------------------------------------------------------*/
// UART Interrupt Service
void serial_ISR( void ) interrupt 4
{
BYTE i;
BYTE RxData;
BYTE xdata *pBuf;
static BYTE RxChecksum; // 根據接收到的數據計算出的校驗和
static BYTE nRxFrameLength; // 接收到的這一幀數據的長度
if (RI == 1) // If reception occur
{
RI = 0; // clear reception flag for next reception
RxData = SBUF; // 保存接收到的數據
/*
RxFrame.Frame.Addr[0] = 0x00;
RxFrame.Frame.Addr[1] = 0x02;
RxFrame.Frame.Addr[2] = 0x01;
RxFrame.Frame.Addr[3] = RxData;
RxFrame.Frame.nLength = 0x01;
RxFrame.Frame.aData[0] = Command_Alarm;
SendMessage(MSG_RS485_RX_FRAME);
return;
//*/
if (RB8 == 1) //
{
if (RxData == 0xFF) // 幀結尾標志
{
// 首先判斷長度
if (nRxFrameLength == (RxFrame.Frame.nLength + 6))
{
// 判斷校驗和是否正確,由于RxChecksum把校驗和也加進去,所以要將接收到的校驗和乘2再比較
RxData = RxFrame.Frame.aData[RxFrame.Frame.nLength];
RxData <<= 1;
if (RxChecksum == RxData)
{
pBuf = MsgGetBuf();
if (pBuf != NULL)
{
for (i=0; i<sizeof(t_Frame); i++)
{
pBuf[i] = RxFrame.aData[i];
}
i = PostMessage(MSG_RS485_RX_FRAME, (UINT)pBuf);
if (i != OK) // 如果再這兒沒有發送消息成功,則需要將剛才申請的緩沖區釋放
{
MsgPutBuf(pBuf);
}
}
else // 申請緩沖區失敗
{
BEEP = P_ON;
// memcpy(&DispBuffer[0][1], "申請緩沖區失敗!", DISP_BUF_LENGTH);
// memcpy(&DispBuffer[1][1], " ", DISP_BUF_LENGTH);
// SystemStatus.Status = Status_ShowingMessage;
// MessageShowTimer = 0;
// UpdateDisp(TRUE);
}
}
}
bFrameStart = FALSE;
}
else // 幀起始
{
nRxFrameLength = 0;
RxChecksum = 0x00;
bFrameStart = TRUE;
}
}
if (bFrameStart == TRUE)
{
if (nRxFrameLength < sizeof(t_Frame)) // 當接收到的數據不到一幀時
{
RxFrame.aData[nRxFrameLength] = RxData;
nRxFrameLength ++;
RxChecksum += RxData;
}
}
}
else // if ( TI==1 ) // If emission occur
{
TI = 0; // clear emission flag for next emission
TxOK = TRUE; // set transmit success flag
}
}
// Externl Interrupt 1
// 接收模擬串口接收到的數據
//void extern1_ISR( void ) interrupt 2
//{
/*-----------------------------------------------------------------------------
| 與計算機通信,波特率:9600bps,停止位:1位,校驗位:無/奇校驗(奇數個"1"時校驗位為"1")
-----------------------------------------------------------------------------*/
/* BYTE i;
BYTE RxData; // 從樓層控制器接收到的數據
bit OldEA;
bit bParity; // 校驗位,根據接收到的位求出校驗位然后與接收到的校驗位進行比較
OldEA = EA;
EA = DISABLE; // 關閉所有中斷,在接收主機數據的時候不能被中斷打斷
Delayus(50);
if (RS232RXD == 0) // 起始位不為0,出錯退出
{
RxData = 0x00;
bParity = 0; // 奇校驗,初始值賦為'0'
// 數據位
for (i=0; i<8; i++)
{
Delayus(100);
RxData >>= 1;
if (RS232RXD == 1)
{
RxData |= 0x80;
bParity = !bParity; // 如果有奇數個'1'則校驗位為'1'
}
}
Delayus(100);
// 校驗位
if (RS232RXD == bParity)
{
Delayus(100);
// 停止位
if (RS232RXD == 1) // 接收到停止位
{
// 將數據發送出去
PostMessage(MSG_RS232_RX, RxData);
}
}
PostMessage(MSG_RS232_RX, RxData);
}
EA = OldEA;
}
// 通過模擬串口向外發送一個字節的數據
void RS232SendByte(BYTE aData)
{
bit bCheck;
BYTE i;
bCheck = 0;
// 發送起始位
RS232TXD = LOW;
Delayus(100);
// 發送數據位
for (i=0; i<8; i++)
{
if (aData & 0x01)
{
RS232TXD = HIGH;
bCheck = !bCheck;
}
else
{
RS232TXD = LOW;
}
Delayus(98);
aData >>= 1;
}
// 發送校驗位
if (bCheck)
{
RS232TXD = HIGH;
}
else
{
RS232TXD = LOW;
}
Delayus(100);
// 發送停止位
RS232TXD = HIGH;
Delayus(100);
} */
/*----------------------------------------------------------------------------+
| End of source file |
+----------------------------------------------------------------------------*/
/*------------------------ Nothing Below This Line --------------------------*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -