#include "msp430x14x.h"
#include "cry12864.h"
#include "12864.c"
#define Num_of_Results 32
/*typedef unsigned char uchar;
typedef unsigned int uint;*/
/************************PID结构体和函数声明**********************/
struct PID
{
float SetSpeed; //定义设定值
float ActualSpeed; //定义实际值
float err; //定义偏差值
float err_next; //定义上一个偏差值
float err_last; //定义最上前的偏差值
float Kp,Ki,Kd; //定义比例、积分、微分系数
}pid;
void PID_init();
void int_clk();
void int_pwm();
void init_TB(void);
float PID_realize(float speed);
uint tamp;
void int_ADC(void);
/*******************12864显示声明******************/
uint T=20;//初始化目标温度
const uchar hang1[] = {"温度测量与控制 "};
const uchar hang2[] = {"当前电压:"};
const uchar hang3[] = {"当前温度:"};
const uchar hang4[] = {"目标温度:"};
uint wendu;
unsigned long sum = 0;
void mubiaowendu(uint T);
sta
tic uint results[Num_of_Results]; //保存ADC转换结果的数组
void Trans_val(uint Hex_Val);
uchar shuzi[] = {"0123456789.V℃:"};
/************按键声明************/
void P1_IODect();
void P10_Onclick();
void P11_Onclick();
void P12_Onclick();
void P13_Onclick();
void GPIO_init();
/***************************主函数*************************/
void main( void )
{
/*下面六行程序关闭所有的IO口*/
P1DIR = 0XFF;P1OUT = 0XFF;
P2DIR = 0XFF;P2OUT = 0XFF;
P3DIR = 0XFF;P3OUT = 0XFF;
P4DIR = 0XFF;P4OUT = 0XFF;
P5DIR = 0XFF;P5OUT = 0XFF;
P6DIR = 0XFF;P6OUT = 0XFF;
WDTCTL = WDTPW + WDTHOLD; //关狗
P6DIR |= BIT2;P6OUT |= BIT2; //关闭电平转换
Ini_Lcd(); //初始化液晶
mubiaowendu(T);
Disp_HZ(0x80,hang1,8); //第一行显示“温度测量与控制”
GPIO_init();//IO初始化
int_clk();
PID_init();
int_pwm();
int_ADC();
init_TB();
_EINT();//使能总中断
while(1)
{
pid.ActualSpeed = wendu/100.0; //当前温度
if(pid.ActualSpeed<=(T-10))
TBCCR1=0; //如果温差小于10度就全速加热
else //温差大于10度启用PID控制
TACCR1=800-(uint)tamp*10;
}
}
/*******************************************
函数名称:ADC12ISR
功 能:ADC中断服务函数,在这里用多次平均的
计算P6.0口的模拟电压数值
参 数:无
返回值 :无
********************************************/
#pragma vector=ADC_VECTOR
__interrupt void ADC12ISR (void)
{
static uint index = 0;
results[index++] = ADC12MEM0; // Move results
if(index == Num_of_Results)
{
uchar i;
index = 0;
for(i = 0; i < Num_of_Results; i++)
{
sum += results[i];
}
sum >>= 5; //除以32
Trans_val(sum);
}
}
/*******************************************
函数名称:Trans_val
功 能:将16进制ADC转换数据变换成三位10进制
真实的模拟电压数据,并在液晶上显示
参 数:Hex_Val--16进制数据
n--变换时的分母等于2的n次方
返回值 :无
********************************************/
void Trans_val(uint Hex_Val)
{
unsigned long caltmp;
uint Curr_Volt;
uint a=137;//温度系数
uchar t1,i,j;
uchar ptr[5];
uchar tmp[6];
caltmp = Hex_Val;
caltmp = (caltmp << 5) + Hex_Val; //caltmp = Hex_Val * 33
caltmp = (caltmp << 3) + (caltmp << 1); //caltmp = caltmp * 10
Curr_Volt = caltmp >> 12; //Curr_Volt = caltmp / 2^n
ptr[0] = Curr_Volt / 100; //Hex->Dec变换
t1 = Curr_Volt - (ptr[0] * 100);
ptr[2] = t1 / 10;
ptr[3] = t1 - (ptr[2] * 10);
ptr[1] = 10; //shuzi表中第10位对应符号"."
ptr[4] = 11; //第11位表示符号"V"
//在液晶上显示变换后的结果
wendu = ((Curr_Volt)-100)*a;
tmp[5]=12;//第12位表示符号"℃"
tmp[4]=wendu%10;
tmp[3]=wendu/10%10;
tmp[2]=10;
tmp[1]=wendu/100%10;
tmp[0]=wendu/1000%10;
Disp_HZ(0x90,hang2,5);
for(i=0;i<5;i++)
{ //这部分显示第二行的“当前电压:”和数值
Delay_Nms(10);
Write_Data(shuzi[ptr[i]]);
}
Disp_HZ(0x88,hang3,5);
for(j=0;j<6;j++)
{ //这部分显示第三行的“当前温度:”和数值
Delay_Nms(10);
Write_Data(shuzi[tmp[j]]);
}
}
/**********在液晶上第四行显示“目标温度:”和数值*********/
void mubiaowendu(uint T)
{
uchar k;
uchar MBWD[6];
MBWD[5]=12;//第12位表示符号"℃"
MBWD[1]=T%10;
MBWD[0]=T/10%10;
MBWD[2]=10;
MBWD[3]=T/100%10;
MBWD[4]=T/1000%10;
Disp_HZ(0x98,hang4,5);
for(k=0;k<6;k++)
{
Delay_Nms(10);
Write_Data(shuzi[MBWD[k]]);
}
}
/********************按键部分处理函数*********************/
void GPIO_init()
{
//-----设定P1.6的输出初始值-----
//P1DIR |= BIT6;//设定P1.6为输出
//P1OUT &= ~BIT6;//设定P1.6初值
//-----配置P1.3中断参数-----
P1DIR &= ~(BIT0+BIT1+BIT2+BIT3); //设P1.0~P1.3为输入
P1IES |= (BIT0+BIT1+BIT2+BIT3); // P1.0~P1.3设为下降沿中断
P1IE |= (BIT0+BIT1+BIT2+BIT3) ; // 允许P1.0~P1.3中断
}
#pragma vector = PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
//-----启用Port1事件检测函数-----
P1_IODect();//事件检测通过,则会调用事件处理函数
P1IFG=0; //退出中断前必须手动清除IO口中断标志
}
void P1_IODect()
{
uint Push_Key=0;
//-----排除输出IO的干扰后,锁定唯一被触发的中断标志位-----
Push_Key = P1IFG&(~P1DIR);
//-----延时一段时间,避开机械抖动区域-----
__delay_cycles(10000);
//消抖延时
//----判断按键状态是否与延时前一致-----
if((P1IN&Push_Key)==0)
//如果该次按键确实有效
{
//----判断具体哪个IO被按下,调用该IO的事件处理函数-----
switch(Push_Key){
case BIT0: P10_Onclick();
break;
case BIT1: P11_Onclick();
break;
case BIT2: P12_Onclick();
break;
case BIT3: P13_Onclick();
break;
default:
break;
//任何情况下均加上default
}
}
}
void P10_Onclick()
{
T=40;
mubiaowendu(T);
}
void P11_Onclick()
{
T=60;
mubiaowendu(T);
}
void P12_Onclick()
{
T++;
mubiaowendu(T);
}
void P13_Onclick()
{
T--;
mubiaowendu(T);
}
/********************初始化ADC****************************/
void int_ADC(void)
{
/*P5DIR|=BIT5;P5OUT&=~BIT5; //关闭数码管显示
P6DIR|=BIT6;P6OUT&=~BIT6; //半闭数码管显示
P6DIR|=BIT5;P6OUT&=~BIT5;*/ //半闭数码管显示
P6SEL |= 0x01; // 使能ADC通道P6.0
ADC12CTL0 = ADC12ON+SHT0_8+MSC; // 打开ADC,设置采样时间
ADC12CTL1 = SHP+CONSEQ_2; // 使用采样定时器
ADC12IE = 0x01; // 使能ADC中断
ADC12CTL0 |= ENC; // 使能转换
ADC12CTL0 |= ADC12SC; // 开始转换
}
/*************************初始化时钟*********************************/
void int_clk()
{
uchar i;
BCSCTL1&=~XT2OFF; //打开XT振荡器
BCSCTL2|=SELM1+SELS;//MCLK 8M and SMCLK 1M
do
{
IFG1 &= ~OFIFG; //清除振荡错误标志
for(i = 0; i < 100; i++)
_NOP(); //延时等待
}
while ((IFG1 & OFIFG) != 0); //如果标志为1继续循环等待
IFG1&=~OFIFG;
}
/*************************初始化PWM*****************************/
void int_pwm()
{
P2DIR |= 0x02;
P2SEL |= 0x02;
TACCR0 = 800; // PWM Period/2
TACCTL1 = OUTMOD_7; // CCR1 toggle/set
TACCR1 = 400; // CCR1 PWM duty cycle
TACTL = TASSEL_2 + MC0; // ACLK, up-down mode
}
/************************Time_B初始化*************************/
void init_TB(void)
{
TBCCTL0 = CCIE; // TBCCR0 interrupt enabled
TBCCR0 = 20000;
TBCTL = TBSSEL_2 + MC_1; // SMCLK, upmode
}
/************************Time_B中断*************************/
#pragma vector=TIMERB0_VECTOR
__interrupt void Timer_B (void)
{
tamp = (uint)PID_realize(T);
}
/*****************PID变量初始化函数**************************/
void PID_init()
{
pid.SetSpeed=0.0;
pid.ActualSpeed=0.0;
pid.err=0.0;
pid.err_last=0.0;
pid.err_next=0.0;
pid.Kp=1.0;
pid.Ki=0.0;
pid.Kd=0.0;
}
/*************************PID运算函数 ***************************/
float PID_realize(float speed)
{
float incrementSpeed;
pid.SetSpeed=speed;
pid.err=pid.SetSpeed-pid.ActualSpeed;
incrementSpeed=pid.Kp*(pid.err)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);
pid.ActualSpeed+=incrementSpeed;
pid.err_last=pid.err_next;
pid.err_next=pid.err;
return incrementSpeed;
}
一周热门 更多>