基于MSP430的太阳能热水器上水控制器V10.1
发布时间:2008-11-5 11:56
发布者:MSP430
原程序中在TACTL中都使用了TACLR清除TAR计数,但此方式是错误的,它同时置位了分频等参数,应改为TAR=0的方式,在阀门动作开始时使用,以使每次阀门动作时间准确。
基本测试完成的程序代码:
/********************************************************************
* *
* 太阳能热水器自动上水控制 *
* V10.1 *
* yajou 2008-09-25 *
*********************************************************************
更新内容: *
1. DS18B20的CRC校验; *
2. 增基本定时器定时1s,每5秒采集显示温度数据 *
3. P1.2中断进行电源电压判断 *
4. V10.0 增加在V3.4版的太阳能热水器阀控功能 *
5. V10.1 开关阀动作前先判断阀门状态 *
*********************************************************************
<<>> *
P1.2: 欠压判断 *
P1.6: 上水按键 *
P1.7: 停止按键 *
P2.0: DS18B20温度信号线 *
P2.2: 开阀到位 *
P2.3: 关阀到位 *
P6.3: Beep 完成一个操作后鸣叫,错误连叫3声 *
P6.7: LED 上水开阀时长亮,开阀完成上水时瞬闪(长时间灭,瞬间亮),*
水满后关阀时长亮,结束后灭。 *
********************************************************************/
#include //系统文件夹内找
#include "main.h" //当前文件夹内找
int main(void)
{
Sys_Init();
//DS18B20初始化,开始温度转换---------
while(Ds18b20_Init() && (--i) ); //2008.10.14修改:&改为&&
Ds18b20_WriteByte(SkipROM);
Ds18b20_WriteByte(Convert);
Delayms(900);
//ReleaseDQ(); //寄生电源时要拉高DQ
//------------------------------------
while(1)
{
if(enable_tmptest)
{
enable_tmptest = 0;
if(TempCal(&wendu_fuhao, &wendu_zhensu, &wendu_yusu))
i_tmp++; //测温错误计次加1
else
i_tmp = 0;
}
Display();
LPM3; //进入低功耗模式n,n:0~4。
}
}
/********************************************************
* Display *
********************************************************/
void Display(void)
{
uchar temp_wendu_zhensu;
if(wendu_fuhao)
LCDMEM[0] = digit[10]; //显示"-"
else
LCDMEM[0] = digit[12]; //不显示
LCDMEM[3] = digit[wendu_zhensu%10];
LCDMEM[3] |= 0x10; //小数点
temp_wendu_zhensu = wendu_zhensu / 10;
LCDMEM[2] = digit[temp_wendu_zhensu%10];
LCDMEM[1] = digit[temp_wendu_zhensu/10];
LCDMEM[4] = (digit[wendu_yusu/10] & 0x0f)<<4; //取低位放在高位,低位为标志符
LCDMEM[5] = (digit[wendu_yusu/10] & 0xf0)>>4; //取高位放在低位
LCDMEM[5] |= (digit[wendu_yusu%10] & 0x0f)<<4;
LCDMEM[6] = (digit[wendu_yusu%10] & 0xf0)>>4;
if(enable_famenoperate == 0)
LCDMEM[2] |= BIT4 ; //显示"阀门关"
else
LCDMEM[2] &= ~BIT4 ;//不显示"阀门关"
if(i_tmp > 5)
{
i_tmp = 5;
LCDMEM[5] |= BIT0; //显示"插卡错"
}
}
/*****************************************************************************
* SYS初始化 *
*****************************************************************************/
void Sys_Init(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
/*时钟初始化 //MCLK:2031616Hz*/
FLL_CTL0 |= XCAP14PF; // Configure load caps
SCFI0 |= FN_2; //频率范围
SCFQCTL =30; //N,如不设置默认=31
SCFI0 |= FLLD_2; //D=2,PUC后的默认值=2
//FLL_CTL1 |= FLL_DIV_4; //4分频,P1.5输出:f=32768/4
FLL_CTL0 |= DCOPLUS;//在MCLK前分频 f=D*(N+1)*faclk,2*(30+1)*32768=2031616Hz
/*LCD初始化*/
LCDCTL = LCDON + LCD4MUX + LCDP0; // STK LCD 4Mux, S0-S15
BTCTL = BTFRFQ1; // STK LCD freq, 基本定时器输出fLCD=fACLK/64
P5SEL = 0xFC; // Common and Rxx all selected,公共极和 Rxx 选择
for(i=0;i<12;i++) //清显示
LCDMEM = digit[12];
_EINT(); //打开全局中断控制,若不需要打开,可以屏蔽本句
/*基本定时器初始化*/
IE2 |= BTIE; //打开基本定时器中断
BTCTL |= BTDIV + BTIP1+ BTIP2; // 1s interrupt
/*外部中断初始化*/
P1IES = BIT2 + BIT6 + BIT7; //P1.2,P1.6,P1.7中断为1->0
P2IES = BIT2 + BIT3; //P2.2,P2.3中断为1->0
P1IE = BIT2 + BIT6 + BIT7; //允许P1.2,P1.6中断,P1.7中断,欠压-开阀-关阀
P2IE = BIT2 + BIT3; //允许P2.2,P2.3中断,开阀到位-关阀到位
/*定时器A初始化*/
TACTL = TASSEL0 + TACLR +ID0; //时钟用ACLK, clear TAR,二分频
TACTL |= MC0; //选择模式,Up to CCR0
// TACTL |= TAIE; //Timer_A interrupt enable,这句不能加,加了运行出错
CCTL0 &= ~CCIE; //禁止CCR0 interrupt,开关阀中断中打开
CCR0 = 65535; //预置值,二分频后定时为4s
/*端口初始化*/
P6DIR |= BIT3 + BIT4 + BIT5 + BIT7;//蜂鸣器+阀门控制信号P6.4&P6.5+LED
P6OUT = 0x00;
TingZhi();//阀门初始化为停
}
/*****************************************************************************
基本定时器中断函数 *
*****************************************************************************/
#pragma vector=BASICTIMER_VECTOR
__interrupt void BasTimer()
{
static uchar times;
if(enable_guanfajishi) //开阀上水后进行关阀延时计时,以防溢水信号失效
{
n_guanfa++;
if(n_guanfa > 15) //(>3600)1h后
{
LPM3_EXIT; //退出中断后退出低功耗模式。
enable_guanfajishi = 0;
n_guanfa = 0;
Guanfa(); //关阀门
TAR = 0; //Timer_A 清除原计时
CCTL0 = CCIE; //允许CCR0 interrupt
Ledon(); //开LED
enable_famenoperate = 2; //阀门状态为关动作中
enable_LED = 0; //关瞬闪
}
}
if(enable_LED) //瞬闪LED:开阀停止后打开此瞬闪,关阀信号中断时关闭此瞬闪
{
Ledon();
Delayms(20);
Ledoff();
}
times++;
if(times > time_yanshi)
{
times = 0;
enable_tmptest = 1; //允许温度测试
LPM3_EXIT; //退出中断后退出低功耗模式。
}
}
/*****************************************************************************
定时器A中断函数 *
中断源:CC0 *
*****************************************************************************/
#pragma vector=TIMERA0_VECTOR //定时4s,防止阀门到位信号失效
__interrupt void TimerA0()
{
CCTL0 &= ~CCIE; //禁止CCR0 interrupt
CCR0 = 65535; //预置值,4s
LPM3_EXIT; //退出中断后退出低功耗模式。
TingZhi(); //阀门动作停止
if(enable_famenoperate == 3) //判断之前是开阀还是关阀动作
{ //之前为开阀
enable_famenoperate = 1;//阀门状态为开
enable_LED = 1; //开瞬闪
}
else if(enable_famenoperate == 2)
{ //之前为关阀
enable_famenoperate = 0;//阀门状为关
}
}
/*****************************************************************************
端口1中断函数 *
多中断中断源:P1IFG.0~P1IFG7 *
进入中断后应首先判断中断源,退出中断前应清除中断标志,否则将再次引发中断 *
*****************************************************************************/
#pragma vector=PORT1_VECTOR
__interrupt void Port1()
{
if((P1IFG&BIT2) == BIT2) //处理P1IN.2中断
{
P1IFG &= ~BIT2; //清除中断标志
P1IES ^= BIT2; //P1.2中断为0->1和1->0切换
P1DIR&=~BIT2; //P1.2为输入方式
if(P1IN&BIT2 ) //判断P1.2电平高低
{
LCDMEM[0] &= ~BIT4;
IE2 |= BTIE;//打开基本定时器中断
}
else
{
LCDMEM[0] |= BIT4 ; //显示"换电池"
IE2 &= ~BTIE; //关闭基本定时器中断
}
}
else if((P1IFG&BIT6) ==BIT6) //处理P1IN.6中断,开阀上水
{
P1IFG &= ~BIT6; //清除中断标志
//在此先判断阀门状态,如为关才开阀
if((P2IN&BIT2 == BIT2) && ~(P2IN&BIT3)) //P2.2开阀到位线为1,P2.3关阀到位线为0,关阀状态
{
if(wendu_zhensu < 20)
{
LPM3_EXIT; //退出中断后退出低功耗模式。
Kaifa(); //开阀
TAR = 0; //Timer_A 清除原计时
CCTL0 = CCIE; //允许CCR0 interrupt
Ledon(); //亮LED
enable_famenoperate = 3; //阀门状态为开动作中
enable_guanfajishi = 1; //开阀上水后进行关阀延时计时,以防溢水信号失效
}else
{
for(i = 0; i < 3; i++) //温度高不能上水,鸣叫3声
{
BeepOn(); //要先退出LPM3吗???
Delayms(100);
BeepOff();
Delayms(100);
}
}
}
}
else if((P1IFG&BIT7) ==BIT7) //处理P1IN.7中断,关阀
{
P1IFG &= ~BIT7; //清除中断标志
//在此先判断阀门状态,如为开才关阀
if((~P2IN&BIT2) && (P2IN&BIT3 == BIT3)) //P2.2开阀到位线为0,P2.3关阀到位线为1,开阀状态
{
LPM3_EXIT; //退出中断后退出低功耗模式。
Guanfa(); //关阀
TAR = 0;//Timer_A 清除原计时
CCTL0 = CCIE; //允许CCR0 interrupt
Ledon(); //开LED
enable_famenoperate = 2; //阀门状态为关动作中
enable_guanfajishi = 0; //关闭关阀延时计时
n_guanfa = 0; //关阀延时计时清零
enable_LED = 0; //关瞬闪
}
}
}
/*****************************************************************************
端口2中断函数 *
*****************************************************************************/
#pragma vector=PORT2_VECTOR
__interrupt void Port2()
{
LPM3_EXIT; //退出中断后退出低功耗模式。若退出中断后要保留低功耗模式,将本句屏蔽
CCTL0 &= ~CCIE; //禁止CCR0 interrupt
CCR0 = 65535; //预置值,4s
if((P2IFG&BIT2) == BIT2) //处理P2IN.2中断,开阀到位
{
P2IFG &= ~BIT2; //清除中断标志
TingZhi();
enable_famenoperate = 1;//阀门状态为开
enable_LED = 1; //开瞬闪
}
else if((P2IFG&BIT3) == BIT3)//处理P2IN.3中断,关阀到位
{
P2IFG &= ~BIT3; //清除中断标志
TingZhi();
enable_famenoperate = 0;//阀门状为关
}
}
/********************************************************
* DS18B20初始化 *
********************************************************/
uchar Ds18b20_Init(void) //存在返0,否则返1
{
uchar temp = 1;
uchar uttime = ReDetectTime; //超时时间
while(outtime-- && temp)
{
IoOut_DQ();
Delayms(2); //2ms
ReleaseDQ();
Delayus(2);
PullDownDQ();
Delayus(600); //614us(480-960)
ReleaseDQ();
Delayus(70); //73us(>60)
IoIn_DQ();
temp = ReadDQ();
Delayus(500); //us
}
return temp;
}
/********************************************************
* 写bit2DS18B20 *
********************************************************/
void Ds18b20_WriteBit(uchar bitdata)
{
IoOut_DQ();
if(bitdata)
{
PullDownDQ();
Delayus(2); //2us(>1us)
ReleaseDQ(); //(上述1-15)
Delayus(85); //86us(45- x,总时间>60)
}else
{
PullDownDQ();
Delayus(85); //86us(60-120)
}
ReleaseDQ();
Delayus(2); //2us(>1us)
}
/********************************************************
* 写Byte DS18B20 *
********************************************************/
void Ds18b20_WriteByte(uchar chrdata)
{
uchar ii;
for(ii = 0; ii < 8; ii++)
{
Ds18b20_WriteBit(chrdata & 0x01);
chrdata >>= 1;
}
}
/********************************************************
* 写 DS18B20 *
********************************************************/
//void Ds18b20_Write(uchar *p_readdata, uchar bytes)
//{
// while(bytes--)
// {
// Ds18b20_WriteByte(*p_readdata);
// p_readdata++;
// }
//}
/********************************************************
* 读bit From DS18B20 *
********************************************************/
uchar Ds18b20_ReadBit(void)
{
uchar bitdata;
IoOut_DQ();
PullDownDQ();
Delayus(2); //2us( >1us)
ReleaseDQ();
Delayus(8); //8us( <15us)
IoIn_DQ();
bitdata = ReadDQ();
Delayus(85); //85us(上述总时间要>60us)
return bitdata;
}
/********************************************************
* 读Byte DS18B20 *
********************************************************/
uchar Ds18b20_ReadByte(void)
{
uchar ii,chardata;
for(ii = 0; ii < 8; ii++)
{
chardata >>= 1;
if(Ds18b20_ReadBit()) chardata |= 0x80;
}
return chardata;
}
/********************************************************
* 读 DS18B20 ROM *
********************************************************/
//bit Ds18b20_ReadRom(uchar *p_readdata) //成功返0,失败返1
//{
// uchar ii = 8;
// if(Ds18b20_Init()) return 1;
// Ds18b20_WriteByte(ReadROM);
// while(ii--)
// {
// *p_readdata = Ds18b20_ReadByte();
// p_readdata++;
// }
// return 0;
//}
/********************************************************
* 读 DS18B20 EE *
********************************************************/
uchar Ds18b20_ReadEE(uchar *p_readdata) //成功返0,失败返1
{
uchar ii = 9;
if(Ds18b20_Init()) return 1;
Delayus(1);
Ds18b20_WriteByte(SkipROM);
Delayus(1);
Ds18b20_WriteByte(ReadScr);
Delayus(1);
while(ii--)
{
*p_readdata = Ds18b20_ReadByte();
p_readdata++;
}
return 0;
}
/********************************************************
* 温度采集计算 *
********************************************************/
uchar TempCal(uchar *p_fuhao,uchar*p_wendu_zhensu,uchar *p_wendu_yusu) //成功返0,失败返1 (温度范围-55 --- +128)
{
uchar temp[9],ii,crc_data = 0;
uint tmp = 0;
uchar tmp_ys = 0;
*p_fuhao = 0;
//读暂存器和CRC值-----------------------
if(Ds18b20_ReadEE(temp))
return 1;
//CRC校验------------------------------
for(ii = 0; ii < 9; ii++)
crc_data = CrcTable[crc_data^temp[ii]];
if(crc_data == 0)
{
tmp = temp[1]; //
tmp <<= 8; //
tmp |= temp[0]; //组成温度的两字节合并
//温度正负数处理-----------------------
if(temp[1] >>= 4) //温度为负
{
tmp = ~tmp + 1;
*p_fuhao = 1; //返回值,1为负0为正
}
//温度计算-----------------------------
tmp_ys =tmp % 16; //取十进制温度的余数
tmp_ys = (tmp_ys * 10) / 16; //十进制温度的小数*10(取小数点后一位)
*p_wendu_zhensu = tmp / 16;
*p_wendu_yusu = tmp_ys;
}
//开始温度转换-------------------------
while(Ds18b20_Init() & (--ii) );
Ds18b20_WriteByte(SkipROM);
Ds18b20_WriteByte(Convert);
return 0;
}
/********************************************************
* 阀门动作停止 *
********************************************************/
void TingZhi(void)
{
TingZ();
Ledoff();
BeepOn();
Delayms(100);
BeepOff();
}
头文件main.h
/********************************************************
* 命令字定义 *
********************************************************/
#define uchar unsigned char
#define uint unsigned int
/***精确定时方法*****/
#define CPU_F ((double)2031616) //8000000为 MCLK=8MHZ的意思*
#define Delayus(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define Delayms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
/***调用此程序时实参必是数字,而不能使用变量作为实参。
Delayus(1); //这是产生1微秒的延时
Delayms(1); //这是产生1毫秒的延时
Delayus(3.5); //延时3.5毫秒,还是可以这样呢
Delayms(3.5); //延时3.5毫秒…是不是很实用?
***精确定时方法*****/
//设置重复检测次次数,超出次数则超时
#define ReDetectTime 20
/***ds18b20命令***/
#define SkipROM 0xCC
#define MatchROM 0x55
#define ReadROM 0x33
#define SearchROM 0xF0
#define AlARMSearch 0xEC
#define Convert 0x44
#define WriteScr 0x4E
#define ReadScr 0xBE
#define CopyScr 0x48
#define RecallEE 0xB8
#define ReadPower 0xB4
/***P2.0接DS18B20的DQ,//P2.1为DQ的上拉电源***/
#define ReleaseDQ() P2OUT |= BIT0 //上拉/释放总线
#define PullDownDQ() P2OUT &= ~BIT0 //下拉总线
//#define vcc() P2OUT |= BIT1
#define ReadDQ() P2IN&BIT0
#define IoIn_DQ() P2DIR&=~BIT0
#define IoOut_DQ() P2DIR|=BIT0
#define time_yanshi 5 //每5秒采集并显示温度
/***开关阀门控制部分***/
#define Ledon() P6OUT |= BIT7 //点亮批示灯P6.7
#define Ledoff() P6OUT &= ~BIT7 //熄灭批示灯P6.7
#define BeepOn() P6OUT |= BIT3 //蜂鸣器on,开关阀结束时鸣叫提示P6.3
#define BeepOff() P6OUT &= ~BIT3 //蜂鸣器off
//#define KF0() P6OUT &= ~BIT4 //开阀IO输出为0 P6.4
//#define KF1() P6OUT |= BIT4 //开阀IO输出为1
//#define GF0() P6OUT &= ~BIT5 //关阀0 P6.5
//#define GF1() P6OUT |= BIT5 //关阀1
#define Kaifa() P6OUT |= BIT4![]() ![]() ![]() |
网友评论