/********************************************************************************************************
* 文 件 名 : REM.c
* 程 序 员 : (CaiJie) hnclcj@gmail.com
* (c) Copyright 2007-2007, CaiJie
* All Rights Reserved
* 说 明 : avr 3.55MHz情况下的用ADC实现的可以在3~6KM距离上通讯的程序包含数据发送/接收
* 通讯速度默认为250bps/s 可以更加线路远近来调整
********************************************************************************************************/
#define REM_GLOBALS
#include "includes.h"
#if REM_MODULE_EN > 0
/********************************************************************************************************
* 常数
********************************************************************************************************/
const INT8U REM_MsgChgTbl[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
/********************************************************************************************************
* 全局变量和数据类型
********************************************************************************************************/
#if REM_MODULE_EN > 0
#if REM_RXD_N_BUF == 0 || REM_RXD_N_BUF >= 8
#error "接收数据包缓存区数量 必须>=1 && <8! 1<=REM_RXD_N_BUF<8 "
#endif
static BOOL volatile REM_bCErr; // 可能由于继电器没有吸合 采样不到C线电压时的故障标志位
static BOOL volatile REM_bRxTxMux; // 发送跟接收互斥 0接收 1发送
static BOOL volatile REM_bTxAsk; // 发送中标志 0未发送 1已发送
static BOOL volatile REM_bTxBusy; // 总线空闲 0总线不忙 1总线不忙
static BOOL volatile REM_bTxDat; // BIT数据信息缓存器(内部使用)
static BOOL volatile REM_bTxKeep; // 发送保持变量 当高电平一直为高超过700MS时才设置这个标志
static BOOL volatile REM_bTxRTS; // 发送请求标志 0未申请 1已申请
static BOOL volatile REM_bTxTmo; // 发送超时 0未超时 1已超时
static INT8U volatile REM_RxEnd; // 接收完成标志 (第nBIT对应第n接收缓存 0LSB优先)
static INT8U volatile REM_RxEndCnt; // 接收数据缓存选择 0=1缓存 1=2缓存 2=3缓存...
static INT8U volatile REM_BitCtr; // 字节内BIT计数器
static INT8U volatile REM_BitHigh; // 每BIT里面的高电平宽度
static INT8U volatile REM_BitLow; // 每BIT里面的低电平宽度
static INT8U volatile REM_ByteCtr; // 字节计数器
static INT8U volatile REM_LowCtr; // 低电平宽度计数器
static INT8U volatile REM_LenCtr; // 数据长度计数器
static INT8U volatile REM_StepCtr; // 发送/接收步骤计数器
static INT8U volatile REM_TBaseCtr; // 时基计数器
static INT8U volatile REM_TxTmoDly; // 发送后台超时时间
static INT16U volatile REM_iHighCtr; // 高电平宽度计数器(为了能区分980远播 检测时间为20MS*4BIT)
static INT16U volatile REM_iOSpLowCtr; // 接收总线超长低电平检测计数器 overstep
static INT16U volatile REM_iTxTmo; // 发送超时
static INT16S volatile REM_AdcRef; // 通讯参考电压 启动时测量得到 也是一个变化的数值
static INT16S volatile REM_Adc; // 实时通讯电压ADC
static INT16U volatile REM_VrefAdc; // 参考电压(稳定电压)
static INT16U volatile REM_VrefCtr; // 稳定电压计数器
static INT16U volatile REM_VrefTmo; // 稳定电压定时器
static INT8U REM_RxBuf[REM_RXD_N_BUF][REM_RXD_SIZE]; // 串行接收分配缓存 暂定为4个接收缓存
static INT8U REM_TxBuf[REM_TXD_SIZE]; // 串行发送分配缓存
#endif
/********************************************************************************************************
* 局部函数
********************************************************************************************************/
static void RemAdAdjust (void);
static void RemCVref (void);
static void RemInitVar (void);
static void RemInitHard (void);
static void RemRxBufSel (void);
static void RemRxClrState (INT8U ch);
static BOOL RemRxGetState (INT8U ch);
static void RemTxEmptyWait (void);
static void RemTxEn (void);
static void RemTxTmo (void);
/********************************************************************************************************
* 功 能 : 1线通讯中断响应函数
* 入 口 : 无
* 返 回 : 无
* 说 明 : 1> 使用1线通讯前 先用RemInit 函数配置好时基
* 2> 使用1线通讯前 再调用RemInit 函数初始化工作环境 否则工作可能出错
* 3> 250us周期进入中断一次
* 4> 为了能区分980在发送数据 发送检测提高到20MS*4BIT(980最多只连续出现3BIT的高电平)的高电平检测时间
* 980每BIT宽度是20MS 4000以上是5MS 同步检测是10MS能够自动区分980的低电平
* 5> 检测980远播的数据发送状态
* a. 如果检测到980远播正在发送数据则4000远播暂停发送数据 并重新检测总线空闲情况第1次需要检测
* 700MS的空闲 并设置标志 如果这个标志一直存在 则后续数据可以立即发送 不需要额外的640MS
* b. 如果检测到C总线一直为低(有标志记录) 并且超过3S 则每次主机申请发送的数据不会发送 直接抛弃
* 如果REM_RXD有_|-变化后清除这个标志位 以后就按4000远播协议标准发送
* 6> 这个版本的发送采用反电平方式传送 即实际的0为逻辑1
* 7> 这里是读REM_RXD的ADC数据 并转换为REM_RXD数据
********************************************************************************************************/
ISR (SIG_OVERFLOW2)
{
TCNT2 = 0x99; // 248.076us
RemCVref(); // 处理C线电压值 跟随处理
RemAdAdjust(); // 处理REM_RXD状态<15.75+5us
if (REM_bTxAsk) { // 是在发送状态吗?(发送超过5S自动清除本次发送)
REM_iTxTmo--; // 发送定时处理
if (REM_iTxTmo == 0) { // 发送定时时间到?
REM_iTxTmo = 20000; // 复位定时时间5S
REM_bTxTmo = 1; // 发送已经超时
}
}
if (!REM_RXD) { // 长时间的低电平 是不发送数据到C线上 实现主机速度最优化
if (REM_iOSpLowCtr >= 12000) { // 暂定为3S
REM_bTxTmo = 1; // 如果REM_RXD长期为低电平 则直接要求清除发送申请
} else {
REM_iOSpLowCtr++; // 计数器加
}
} else {
REM_iOSpLowCtr = 0; // 如果是高电平则复位这个超长低电平时间计数器检测
}
if (REM_bTxTmo) { // 发送超时处理
REM_bTxTmo = 0; // 复位发送超时标志位
REM_bTxAsk = 0; // 当前的数据包不再发送
REM_bRxTxMux = 0; // 进入到数据接收/发送检测步骤
REM_StepCtr = 0; // 处理步骤计数器复位
}
if (!REM_bRxTxMux) { // 接收跟发送互斥判断 0为接收 1为发送
switch (REM_StepCtr) {
case 0 : // 变量初始化 (提前一个时基进入这里?
CLRBIT(REM_TXD_PORT, REM_TXD); // 复位发送I/O为输入方式
//REM_RXD = 1; // 设置接收I/O为输入方式
if(REM_RXD) { // 根据当前的通讯I/O决定是接收还是发送
REM_LowCtr = 0; // 复位低电平宽度计数器
if (!REM_bTxKeep) { // 判断是否需要先检测1次700MS的C总线空闲
if (REM_iHighCtr >= 2800) { // 确认总线是空状态(700MS)
REM_bRxTxMux = 1;