📄 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 + -