📄 main.c
字号:
{0x15,0x0D,0x0E,0x14,0x1E}, // ID:6, -LEdn,即-LEDN
{0x0A,0x0C,0x0E,0x14,0x1E}, // ID:7, -LECa,即-LECA(在V1.01版本中未用)
{0x16,0x0C,0x0E,0x14,0x1E}, // ID:8, -LECo,即-LECO(在V1.01版本中未用)
{0x19,0x0E,0x1C,0x16,0x1E}, // ID:9, -ouEr,即-OVER
{0x15,0x0E,0x0D,0x13,0x19}, // ID:10,ridEn,即RIDEN
#if METER_RANGE == A150CN
{0x15,0x0C,0x00,0x05,0x01} // ID:11,150Cn,即150Cn
#else
{0x15,0x0C,0x00,0x00,0x02} // ID:11,200Cn,即200Cn
#endif
};
/************************************************
** 为了加快Decode算法的计算速度,在存储器中生成一
** 个0~10000、按10倍递增的数组序列。
************************************************/
UINT16 code TAB_COEF[] = {0, 10, 100, 1000, 10000};
/************************************************
** 各分组参数在EEPROM中的地址
** 共10组参数,每组包含9个参数,每组的最后两个参
** 数分别是流量分段最大值和流量分段系数,因软件中
** 只使用了3组流量校准系数,因此其余7组实际上并没
** 有利用上,这里仍列出以作将来扩展使用。
************************************************/
UINT16 code PARAM_ADDR[][9] =
{
{ 0, 4, 8, 12, 16, 20, 24, 28, 32}, // GroupID:0,ParamID:0-8
{ 36, 40, 44, 48, 52, 56, 60, 64, 68}, // GroupID:1,ParamID:0-8
{ 72, 76, 80, 84, 88, 92, 96,100,104}, // GroupID:2,ParamID:0-8
{108,112,116,120,124,128,132,136,140}, // GroupID:3,ParamID:0-8
{144,148,152,156,160,164,168,172,176}, // GroupID:4,ParamID:0-8
{180,184,188,192,196,200,204,208,212}, // GroupID:5,ParamID:0-8
{216,220,224,228,232,236,240,244,248}, // GroupID:6,ParamID:0-8
{252,256,260,264,268,272,276,280,284}, // GroupID:7,ParamID:0-8
{288,292,296,300,304,308,312,316,320}, // GroupID:8,ParamID:0-8
{324,328,332,336,340,344,348,352,356} // GroupID:9,ParamID:0-8
};
// ------------------------------------------------------------------------------------------------------
/* 函数声明 */
void DeviceInit(void);
void SysInit(void);
void SetRxd0OK(void);
void SetRxd1OK(void);
void CheckPress(void);
void AdjustPress(void);
void GetKey(void);
void DoneRxd0(void);
void DoneRxd1(void);
void DoneTest(void);
void DoneDisplay(void);
void DoneKey(void);
void DoneFuncKey(void);
void DoneSetKey(void);
void DoneLeftKey(void);
void DoneRightKey(void);
void DoneUpKey(void);
void DoneDownKey(void);
void DoneStartKey(void);
void DoneStopKey(void);
void Decode(UINT16 nData, UINT8 nBuf[]);
void Encode(UINT16 *nData, UINT8 nBuf[]);
void LoadGroup(void);
void LoadParam(void);
void LoadLeakCoef(void); // V1.01
bit DecBuf(UINT8 nBuf[], UINT8 nStartID);
bit GetMemAddr(UINT16 nAddr);
void SMB_Read(UINT16 nAddr, UINT8 *nData);
void SMB_Write(UINT16 nAddr, UINT8 nData);
void ReadParams(UINT16 nAddr, UINT8 nNums, UINT8 *nData);
void WriteParams(UINT16 nAddr, UINT8 nNums, UINT8 *nData);
// ------------------------------------------------------------------------------------------------------
/********************************************************************************************************
** 函数名称: main
** 功能描述: 主程序。
** 输 入: 无
** 输 出: 无
** 全局变量: 略
** 全局常量:略
** 调用模块:略
** 其它说明:
** 设 计 者:罗建 日 期:2008年02月16日
** 版 本:V1.00,原始版本
**-------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void main(void)
{
UINT8 i;
WDTCN = 0xDE; // 禁止看门狗定时器
WDTCN = 0xAD;
DeviceInit(); // 初始化片上系统外围设备
SysInit(); // 初始化系统变量
LED_PASS = OPEN; // 打开LED指示灯进行自检
LED_FAIL = OPEN;
LED_WARN = OPEN;
for (i=0;i<5;i++) // 准备LOGO字符
{
gnSegBuf[0][i] = FIX_CODE[10][i];
gnSegBuf[1][i] = FIX_CODE[11][i];
}
while (!gbLogoOver) // 显示LOGO画面4秒
{
if (gb100msOver)
{
gb100msOver = FALSE;
if (gnCntLogo++ == LOGO_WAIT)
gbLogoOver = TRUE;
}
}
for (i=0;i<5;i++) // 清除LOGO字符
{
gnSegBuf[0][i] = 0x00;
gnSegBuf[1][i] = 0x00;
}
gnDisBuf[0][4] = NONE; // 左边第5位不显示字符
gnDisBuf[1][4] = NONE; // 右边第5位不显示字符
LED_PASS = CLOSE; // 自检完毕
LED_FAIL = CLOSE;
LED_WARN = CLOSE;
while (TRUE) // 主程序循环
{
DoneRxd0(); // 处理UART0接收数据事件
DoneRxd1(); // 处理UART1接收数据事件
if (gb100msOver) // 检查定时间隔是否到(0.1秒)
{
gb100msOver = FALSE; // 准备重新延时
if (gbADC0OK) // 检查ADC0转换是否完成,完成则重新启动下一轮转换
{
gnADC0Res = gnADC0Res/ADC0_SAMPLE_NUMS; // 计算平均值
gnADC0Res = gnADC0Res*VREF0*25/32768; // 进行工程量转换,如果值小于0,则认为是0
if (gnADC0Res <= 1250)
gnPressGet = 0;
else
gnPressGet = gnADC0Res - 1250;
if (gnCntPressDis++ == PRESS_DIS_WAIT) // 压力显示刷新时间到,刷新压力显示值
{
gnCntPressDis = 0;
if ((gnWorkState != wsParamSet) && (gnWorkState != wsCoefSet)) // 如果不是在参数修改状态,则分解并显示压力值
{
if (gbPressStabled) // 压力稳定时只显示压力设计值
Decode(gnPressSet, gnSegBuf[0]); // 分解压力值
else // 压力波动时显示实测压力值
Decode(gnPressGet, gnSegBuf[0]); // 分解压力值
}
}
CheckPress(); // 检查是否超压
AdjustPress(); // 进行压力调节
gbADC0OK = FALSE; // 复位ADC0转换结束标志
AD0EN = TRUE; // 重新启动下一轮AD转换
}
if (gnCntFlash++ == FLASH_WAIT) // 实现闪烁控制
{
gnCntFlash = 0;
gbCanFlash = !gbCanFlash;
}
DoneKey(); // 处理按键事件
DoneTest(); // 执行流量测试
}
}
}
/********************************************************************************************************
** 函数名称: UART0_ISR
** 功能描述: 串行口UART0中断(仅处理数据接收中断)服务程序。
** 输 入: 无
** 输 出: 无
** 全局变量: 略
** 全局常量:无
** 调用模块: 无
** 其它说明:1、RIDen A50流量传感器的通讯协议
** 1)波特率:19200bps;
** 2)数据位:8位;
** 3)停止位:1位;
** 4)奇偶校验:none;
** 5)协 议:none;
** 6)回 波:传感器保证一个回波。
** 7)数据格式:接收到的数值是一个表示两种含义的有符号的16位整型数。标定后的数据是原始接收数据除
** 以一个常系数而得来的,由此转成小数。对于A50_V型,流量系数为128,温度系数为100。例:接收到
** 的数值为+1234(十进制),在流量模式中表示的相应流量值为9.641Ln/min,在温度模式中表示的温度
** 为12.34℃。
** 8)帧格式:0x7F,0x7F,MSB,LSB
** 由于最大量程为0x7852,高位字节不包含0x7F。因此,最糟糕的情况就是较低位的字节中包含有0x7F。
** 在这种情况下,0x7F在一行中出现3次。例如:
** 值为:7C 7F,则接收数串为:7F 7F 7C 7F 7F 7F 7C 7F。在假码中找出同步的最好方法如下:
** 如果Buf[i]=7F,且Buf[i+1]=7F,且Buf[i+2]<>7F,则Buf[i]和Buf[i+1]就是同步字节。
** 9)对整型数值的解释如下:
** 接收值(16进制) 接收值(10进制) 流量(Ln/min) 温度(℃)
** 0x7852 30802 overflow ----
** 0x7851 30801 peak overflow ----
** 0x7850 30800 +240.600 +308.00
** ...... ..... ........ .......
** ...... ..... ........ .......
** 0x0001 1 +0.007813 0.01
** 0x0000 0 0.000000 0.00
** 0xFFFF -1 -0.007813 -0.01
** ...... ..... ........ .......
** ...... ..... ........ .......
** 0x87B0 -30800 -240.600 -380.00
** *************************************************************
** 负数与正数是对称的,可用以下公式计算负数A对应的正数B:
** B = ~(A-1)
**
** 2、工程量(流量)转换问题
** 对于A50_V型,流量系数为128。为了不使用浮点数进行计算,且又希望保留2位小数精度,因此可采用将
** 串口接收值先乘以100,再除以128(用右移7位实现)的方法来实现。这样,如果接收到的数值为十进制
** 的+1234,则在流量模式中利用上述方法计算的流量值为9.64Ln/min,所得的测量精度为±0.01Ln/min,
** 可以满足使用要求。
**
** 3、显示与储存冲突防治
** 由于串口接收数据是随机的,且数据有多字节(至少为2字节),在显示过程中,如果主程序刚访问了第1
** 个字节,这时发生了串口中断,并且更新了要显示的数据,当串口中断返回时,主程序继续显示第2个字
** 节,这时显示结果将可能是不正确的。
** 为防止上述冲突现象的发生,可采用Win32 API中的“临界区”思想来实现,即在主程序中读取数据前,
** 先关闭串口中断允许标志ES,在读取完数据后再打开串口中断允许标志ES的方法。
**
** 设 计 者:罗建 日 期:2008年02月03日
** 版 本:V1.00,原始版本
**-------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void UART0_ISR(void) interrupt INT_UART0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -