📄 scanner.c
字号:
//********************采集机程序**************************************
//name: scanner.c
//******************************************************************************
//输出管脚说明:
// P3.6 tx_en 当开始发送一帧时使能,当一帧发送完毕后禁止。软件上,在SendByte子函使能,在发送中断$的处理部分进行
//******************************************************************************
#include <msp430x13x.h>
#include "scanner.h"
void main(void)
{
unsigned int k=0;
unsigned int i=0;
unsigned char tmp,tmp1;
P4OUT = 0X00;
P4DIR = 0XFF; //强制输出低电平,防止继电器闭合
P5OUT = 0X00;
P5DIR = 0XFF;
//上电后给运放一个输入,防止输出过高。
P1DIR = 0XFF;
P2DIR = 0X0F;
P3DIR = 0xDB; // P3.5,P3.2为输入
P1OUT = 0X00;
P2OUT = 0X00;
P3OUT = 0X18; //同时禁止发送,防止个别没有复位的单板拉死总线,防止继电器闭合,点灯
WDTCTL = WDTPW + WDTCNTCL; //clear wdt WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
for(i=0;i<10;i++)
{
P3OUT ^= 0x02;
DelayAMoment();
}
//-----系统基础时钟初始化--------
//从内部振荡器切换到外部8M的晶振,切换不成功时靠硬件狗复位
BCSCTL1 &= ~XT2OFF;
do
{
IFG1 &= ~OFIFG; // Clear OSCFault flag
for (i = 0xFF; i > 0; i--); // Time for flag to set
} while ((IFG1 & OFIFG) == OFIFG); // OSCFault flag still set?
BCSCTL2|= SELM1 + SELS; //选择外部晶振,MCLK=8Mhz SMCLK=8Mh
//------初始化TimerA--------------
//该定时器用于在自检中的超时定时,保证自检中某些操作在硬件不正常时能够超时返回
TACTL = TASSEL1 + TACLR +ID0+ID1; // SMCLK, 8DIV =1M;clear TAR, UP TO CCR0 MODE
//
CCTL0 = CCIE; // CCR0 interrupt enabled
CCR0 = 50000; // 50ms 中断一次
TACTL |= MC0; // Start Timer_A in up mode
//-----系统自检,覆盖到大部分硬件的可用性-------------
// if(SelfTest()== 0) //系统自检测试
// SelfTest();
//------系统软硬件资源初始化---------------
InitSys(); //初始化系统硬件资源和软件资源
//------读取本板ID号,若没有则置为00------
ptrFlashData = (char *)IDADDRESS;
if((*ptrFlashData) == 0x55)
{
ptrFlashData--;
m_IDL = *ptrFlashData;
ptrFlashData--;
m_IDH = *ptrFlashData;
}
else
{
m_IDH = 00;
m_IDL =0x0;
}
//
WDTCTL = WDTPW + WDTCNTCL; //clear wdt
//------主循环----------
for (;;) //主循环
{
//这部分代码的作用是,对18路电池电压分别采集1024次,取均值,
//假设一次AD转换需要15us,则大约需要15*18*1024=276ms完成一次扫描。计工频周期,干扰很小
//*****************************************************************
if(ScanInitRes)
{
ScanInitRes = FALSE; //清楚初始化采集请求
//bypass 发送的命令采集:m_ResID = 0x99;
//bypass 处于bypass采集状态:scanres = 1, m_resid =0, m_residbuf = 0x99;
//其他发送的采集命令:m_ResID!=0x99
//处于其他发送的采集状态:scanres =1,m_resid=0,m_residbuf!=0x99
//现在暂时不区分采集状态,仅判断采集命令的发出者和目的,设定一个低优先级,m_ResID=0x99,其他
// 优先级的采集命令都可以中断当前的采集任务,处于主动采集的查询状态时,m_residBuf = 0x88,这一点暂仅用于上传数据响应中。
if(ScanRes&&(m_ResID==0x99)) //当bypass功能发送采集请求,但已经处于采集状态时
{
//已经清除采集请求,直接退出
}
else if(OwnScanReady) //若有主动采集的数据时,等待一秒再开始下一次采集
{
if(OwnScanReady == 0x55)
{
OwnScanReady = FALSE;
}
else
{
OwnScanReady = 0x55;
}
}
else
{
if(ScanRes&&(m_ResID!=0x99)) //当是其他模块发送的采集请求,但此时已经采集状态时
{
while(!(ADC12IFG & ADC12BUSY)); //等待转换完成后,不理睬数据,直接重新置变量
// ADC12CTL0 &= &ENC; //停止当前的采集,丢弃数据
}
//上述语句中不甚严谨,应再判断是否是bypass的状态,若不是则不应中断,但当前考虑不会有此情况,故以下语句也先省略
// if(m_ResID==0x99)
// {
// m_ResIDbuf = 0x99; //当是bypass发送的采集请求时,将Buf也置为99,标志进入bypas采集状态
// }
m_ResID = 0x00; //将m_ResID置0
// ta =0; //使时钟同步,这样单板看起来比较整齐,步调一致
k = 0;
ChAdder = 0;
// m_TotalChannelCur = 0; //通道电压之和
ChNum = 0;
ADC12CTL0 |= ENC; // Enable conversions
ScanRes = TRUE; //要求进行一次电池电压采集
ptrFlashData = (char *)P1DATAADDRESS; //存储P1OUTDATA的地址
P1OUT = *ptrFlashData; //P1OUTDATA[0]; //设置4051通道
ptrFlashData = (char *)P2DATAADDRESS+ChNum; //存储p2outdata的地址
P2OUT = *ptrFlashData;
//读取CH1的采集增益
ChTimes = DEFAULTTIMES; //读取设定的增益
if(ReadPara(2))
{
ChTimes = FlashPara;
}
ptrFlashData +=35; //指向本通道的零点存储位置;
tmp = *ptrFlashData; //times的值放在FLASH中,地址从TIMESADDRESS开始
ptrFlashData++;
tmp1 = *ptrFlashData;
if((tmp == 0xff) &&(tmp1 == 0xff)) //当无效时
{
ChZero = 0x00; //DEFAULTTIMES; //默认值
}
else
{
ChZero = (unsigned int)(tmp&0x0f)*100+tmp1;
if(tmp&0xe0) //若高位为1,则为负数,这是自定义的负数格式,尽量遵守了常用方法
{
ChZero = -ChZero;
}
ChZero = ChZero*100; //对于2048次的和,此值需要放大100倍,否则没有效果
}
ADC12CTL0 |= ADC12SC; // Start conversion
for(tmp=0;tmp<18;tmp++) //保存上一次采集到的电压值
{
m_ChannelHis2[tmp] = m_ChannelCur[tmp];
}
}
}
//**************************
if(k>4000)k = 1; //此处限定K值不大于4000,大于4000可能造成异常。
if(ScanRes == TRUE&&((ADC12IFG & ADC12BUSY)== 1)) //当使能了一次采集 且转换已经完成后
{
if(k<= ChTimes) //当尚未达到本通道采集数目时
{
ChAdder += ADC12MEM0; //累加 CHNUM 从0~17对应第1~18通道
ADC12CTL0 |= ADC12SC; // Start conversion ,同时启动采样,
k++;
}
else
{
ChAdder = ChAdder+ChZero; //调整零点
ChAdder += 512; //四舍五入
ChAdder = ChAdder/1024; //为了仅使用两字节通讯,牺牲了部分精度,最完美的做法是将1024次采集的结果全部读出
if(ChAdder>0xfe00){ChAdder = 0;}; //当无电压输入时,消除负零点电压的影响
m_ChannelCur[ChNum] = ChAdder;
// m_TotalChannelCur += ChAdder; //计算总电压,当前仅有主动采集功能使用,但我认为会有其他功能使用,故放在此处
ChNum++; //采集下一个通道
k = 0;
if(ChNum < 18)
{
ptrFlashData = (char *)P1DATAADDRESS+ChNum; //存储P1OUTDATA的地址
P1OUT = *ptrFlashData; //P1OUTDATA[0]; //设置4051通道
ptrFlashData = (char *)P2DATAADDRESS+ChNum; //存储p2outdata的地址
P2OUT = *ptrFlashData;
ChTimes = DEFAULTTIMES; //读取设定的增益
if(ReadPara(2*(ChNum+1)))
{
ChTimes = FlashPara;
}
ptrFlashData +=35; //指向本通道的零点存储位置;
tmp = *ptrFlashData; //times的值放在FLASH中,地址从TIMESADDRESS开始
ptrFlashData++;
tmp1 = *ptrFlashData;
if((tmp == 0xff) &&(tmp1 == 0xff)) //当无效时
{
ChZero = 0x00; //DEFAULTTIMES; //默认值
}
else
{
ChZero = (unsigned int)(tmp&0x0f)*100+tmp1;
if(tmp&0xe0) //若高位为1,则为负数,这是自定义的负数格式,尽量遵守了常用方法
{
ChZero = -ChZero;
}
ChZero = ChZero*100;
}
//debug03041
P3OUT ^= 0x02;
Delay1ms(); //用于避免通道间的干扰,使4051的输出可靠建立
ADC12CTL0 |= ADC12SC; // Start conversion
}
else //当完成全部18个通道的采集时
{
ScanRes = FALSE;
ADC12CTL0 &= ~ENC; // Disable conversions
m_ResID = m_ResIDbuf; //刷新命令ID,以使上位机确认是最新的数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -