⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.c

📁 程序概述: 这是个具体产品程序
💻 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 + -