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

📄 fiber-232-485-422.c.bak

📁 串口通信的光纤调制解调产品“光猫”的AT89C2051单片机完整源代码及其说明
💻 BAK
字号:
////////////////////////////////////
//  产品名称:RS232-485-422/光纤
// ================
//  1、编程:黄华林
//  2、日期:2003-09-30
////////////////////////////////////

//  维护记录
// ==========
// 1、黄华林,2003-09-30完成程序编写,确定为V1.0;
//

#include <CPU_AT89C2051.H>

// 类型定义
#define BYTE char
#define UINT unsigned int
#define BOOL char

//////////////////////
// 硬件引脚功能定义 //
//////////////////////
sbit b485_232 = P1 ^ 6;  // 硬件接口模式检测:0-RS232模式,1-RS485/422模式(方向:输入)
sbit b_RE485  = P1 ^ 7;  // 全半双工检查,RS485收发控制:0-RS485接收使能(状态),1-RS485发送使能(状态)(方向:输入/出)
sbit bWdiClr  = P3 ^ 0;  // 看门狗清零(方向:输出)
sbit bRxdTTL  = P3 ^ 2;  // 接收电平
sbit bRunLed  = P3 ^ 7;  // 运行指示LED(方向:输出)

BYTE bHardMode; // 外部硬件接口模式

#define cnRS485_RecvMode  0x00 // 使RS485处于接收状态
#define cnRS485_SendMode  0xFF // 使RS485处于发送状态

#define cnFull232 0 // 半双工232
#define cnHalf485 1 // 半双工485
#define cnFull422 2 // 半双工422

//////////////
// 时钟计数 //
//////////////
UINT uiUs10Count; // 用于10us计时
UINT uiU10Sec250; // 用于250毫秒钟计时
bit  b250MilSecPassed; // 已经过了250毫秒, LED-RUN

// 运行/调试状态指示LED:强制闪烁,使RUN状态LED闪烁周期小于1.5s
void vHitWdFlashRunLed()
{
	bRunLed  = ~bRunLed; // 为程序运行指示,低电平亮;
	bWdiClr  = ~bWdiClr; // 看门狗清零;
}

// 中断服务初始化
void vInterruptInitialize()
{
	// =====================================================
	// IE:中断允许寄存器;复位后:IE = 0x00;1允许,0-禁止;
	// =====================================================
	//   D7    D6    D5    D4    D3    D2    D1    D0
	// -----------------------------------------------------
	//   EA          ET2   ES    ET1   EX1   ET0   EX0
	// -----------------------------------------------------
	//  EX0,EX1:外部中断0、1的中断允许位;
	//  ET0,ET1:定时器/计数器0、1(T/C0,T/C1)溢出中断允许位;
	//  ES:串口中断允许位;
	//  ET2:定时器/计数器2(T/C2)溢出中断允许位;
	//  EA:CPU总的中断允许;
	// -----------------------------------------------------

	// =================================================
	// IP:中断优先级寄存器;复位后:IP = 0x00;1→高,0→低;
	// =================================================
	//   D7    D6    D5    D4    D3    D2    D1    D0
	// -------------------------------------------------
	//               PT2   PS    PT1   PX1   PT0   PX0
	// -------------------------------------------------
	// PX0,PX1:外部中断0、1中断优先级控制位;
	// PT0,PT1:定时器/计数器0、1中断优先级控制位;
	// PS:串口中断优先级控制位;
	// PT2:定时器/计数器2(T/C2)中断优先级控制位;
	// -------------------------------------------------

	// ======================================================
	// TCON:定时器/计数器控制寄存器;复位后:TCON = 0x00
	// ======================================================
	//   D7    D6    D5    D4    D3    D2    D1    D0
	// --------------------------------------------------------
	//   TF1   TR1   TF0   TR0   IE1   IT1   IE0   IT0
	// --------------------------------------------------------
	// TF1,TF0:定时器x溢出中断标志,当定时器x溢出时由内部硬件至置位,
	//          当CPU转向中断服务程序时,由内部硬件清除;
	// TR1,TR0:定时器运行控制位,由软件置位、清除来控制定时器开启、关闭;
	// IE1,IE0:外部触发中断请求标志;
	// IT1,IT0:外部中断触发方式,1-下降沿触发;0-低电平触发;
	// --------------------------------------------------------

	EA = 0;  // 中断允许总控制

	EX0 = 1; // 外部中断0允许
	ET1 = 0; // 定时器1禁止中断
	EX1 = 0; // 外部中断1禁止
	PS = 0;  // 串口中断优先级低
	ES = 0;  // 串口中断禁止
	IT0 = 1; // 外部中断0外下降沿有效
	IT1 = 1; // 外部中断1外下降沿有效
	PX0 = 1; // 外部中断0优先级高
	PX1 = 0; // 外部中断0优先级低

	// =================================================
	// TMOD: 定时器工作方式控制寄存器,复位后TMOD = 0x00
	// =================================================
	//  D7   D6   D5   D4   D3   D2   D1   D0
	// -------------------+---------------------------
	//  GATE C//T M1   M0 | GATE C//T M1   M0
	// -------------------+---------------------------
	// ------ 定时器1 -----+--- 定时器0 ---------------
	// M1、M0:工作方式设置;
	//       00-13位计数器;
	//       01-16位计数器;
	//       10-可自动再装入的8位计数器(从THx中自动装到TLx中);
	//       11-把定时器分为两个8为的计数器或关闭定时器1;
	// C//T:1-计数器功能,0-定时器功能;
	// GATE:选通控制;1-同时/INTx为高电平且TRx为1时选通定时器x;
	//       0-每当TRx为1时就选通定时器x;
	// -----------------------------------------------------

    // 定时器/计数器0初始化
	TMOD = (TMOD & 0xF0) | 0x2; // T0工作于:10-可自动再装入的8位计数器(从THx中自动装到TLx中);
	// 22.11824MHz / 12分频 = 计数频率为1.8432MHz,10个us的设置(115200bps)
	// (2^8 - TL) / (1.8432 * 10^6) = 10 * 10^(-6) ==> TL ≈ 238
	TH0 = TL0 = 238;
	ET0 = 1; // 定时器0允许中断
	TR0 = 1; // T0使能

	EA = 1;  // 中断允许总控制
}

// T0中断服务程序: 10us中断一次
void timer0() interrupt 1
{
	uiUs10Count ++; // 用于10us计时

	uiU10Sec250 ++; // 用于250毫秒钟计时
	if (uiU10Sec250 >= 25000)
	{
		uiU10Sec250 = 0;
		b250MilSecPassed = 1; // 已经过了250毫秒, LED-RUN
	}
}

// 外部中断0服务程序
void extINT0() interrupt 0
{
	if (bHardMode == cnHalf485) // 半双工485
	{
		if (b_RE485 == cnRS485_RecvMode) // 若RS485处于接收状态
		{
			b_RE485 = cnRS485_SendMode; // 使RS485处于发送状态		
			uiUs10Count = 0; // 重新计数
		}
	}
}

main()
{
	long lCharDelay; // 1个字节的时间要求(按1B、8D、1P、1S计算)

	// 一个字节的延时 = 11 * 1000000 / Baudrate
	//       Baudrate = 75 * (1 << ((P1 >> 2) & 0x0F))
	//    1位时间结果 = 1000000 / (75 * (1 << ((P1 >> 2) & 0x0F))
	//
	lCharDelay = (P1 >> 2) & 0x0F; // P1.5432(实际波特率 = 2^P1.5432 * 75 bps,范围:75~2,457,600 bps),默认为9600、0111
	lCharDelay = 1 << lCharDelay; // 计算 2^P1.5432
	lCharDelay = 75 * lCharDelay; // 波特率 = 计算 2^P1.5432 * 75
	lCharDelay = 1000000 / lCharDelay; // 1位时间 = 1000000 / 75 /(2^P1.5432)
	lCharDelay = 11 * lCharDelay; // 11位时间

	uiUs10Count = 0; // 用于10us计时
	uiU10Sec250 = 0; // 用于250毫秒钟计时
	b250MilSecPassed = 0; // 已经过了250毫秒, LED-RUN

	bRunLed = 0; // 运行指示LED
	bWdiClr = 0; // 看门狗清零

	//////////////////////
	// 硬件引脚功能定义 //
	//////////////////////
	b485_232 = 0xFF; // 硬件接口模式检测:0-RS232模式,1-RS485/422模式(方向:输入)
	if (b485_232) // 1-RS485/422
	{
		b_RE485 = 0xFF; // 全半双工检查,RS485收发控制:0-RS485接收使能(状态),1-RS485发送使能(状态)(方向:输入/出)
		if (b_RE485) 
			bHardMode = cnHalf485; // 半双工485
		else
			bHardMode = cnFull422; // 半双工422
			
		b_RE485 = cnRS485_RecvMode; // 使RS485处于接收状态
	}
	else // 0-RS232
	{
		bHardMode = cnFull232; // 半双工232
		b_RE485 = cnRS485_SendMode; // 使RS485处于发送状态
	}
	
	vInterruptInitialize(); // 中断初始化

	do
	{
		if (b250MilSecPassed)
		{
			b250MilSecPassed = 0; // 已经过了250毫秒, LED-RUN
			vHitWdFlashRunLed(); // 运行/调试状态指示LED:强制闪烁,使RUN状态LED闪烁周期小于1.5s

			// 提高外部硬件接口的可靠性
			switch(bHardMode)
			{
				case cnFull232: // 全双工232
					b_RE485 = cnRS485_SendMode; // 使RS485处于发送状态
					break;
				case cnHalf485: // 半双工485
					// nothing					
					break;
				case cnFull422: // 全双工422
					b_RE485 = cnRS485_RecvMode; // 使RS485处于接收状态
					break;
			}
		}
		
		if (bHardMode == cnHalf485) // 半双工485
			if (b_RE485 == cnRS485_SendMode) // 若RS485处于发送状态
				if (bRxdTTL) // 接收TTL处于“1”状态
					if (uiUs10Count >= lCharDelay) // 已经达到1个字节的时间要求
						b_RE485 = cnRS485_RecvMode; // 使RS485处于接收状态
	} while(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -