- /********************************************************************
- * 文件名 : 简易风洞程序
- * 描述 :
- * 创建人 : 王东表哥 2014年8月14日
- * 版本号 : 2.0
- ***********************************************************************/
- #include<STC12C5A60S2.h>
- #include <string.h>
- #include <stdio.h>
- #include <math.h>
- #include<absacc.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define KSP 0.18 // 比例 0.18
- #define KSI 0.0045 // 积分 0.0045
- #define KSD 0.0001 // 微分 0.0001
- #define KSP1 0.14 // 比例
- #define KSI1 0.0018 // 积分
- #define KSD1 0.0001 // 微分
- uchar code IC_DAT[];
- uchar code pic1[];
- uchar code pic2[];
- uchar code pic3[];
- uint size=0; //位置
- uint sizechange,changesize=150; //高度变化停止用
- uint displaytime; //定义屏幕刷新时间
- uint Timetime; //计时
- uint RTimetime; //响应
- uint MTimetime; //保持
- uint ZTimetime; //总时间
- uint Beep1stime; //蜂鸣器1s定时时间
- uchar flagchangeStar; //任务变化标志位
- uchar shuzi;
- uchar code IC_DAT[]={
- "任务要求: "
- "响应时间: s"
- "小球位置: mm"
- "保持时间: s"
- };
- sbit RS = P1^4;
- sbit WRD = P1^5;
- sbit E = P1^6;
- sbit RES = P1^7;
- sbit RX = P3^7;
- sbit TX = P3^6;
- sbit BEEP = P3^5;
- uchar key,keysign,beeptime;
- bit flag =0;
- uchar flagStart=0; //启动标志位
- uchar flagStart7=0; //启动标志位7
- uchar flagStart6=0; //启动标志位7
- uchar flagSep=0; //任务要求标志位
- uchar pidchang=0; //任务要求标志位
- uchar flagStart60=0; //任务6要求标志位
- uchar flagStart61=0; //任务6要求标志位1
- uchar beepchange1;
- uint time=0;
- int pwm=255;
- uint S=0,S1;
- void TransferData(char data1,bit DI);
- void display(void);
- void display_grapic(void);
- void delayms(uint n);
- void DisplayLine(uchar line1,uchar line2);
- void DisplayGraphic(uchar code *adder);
- void delay(uint m);
- void lcd_mesg(uchar code *adder1);
- void delay25us(void);
- /*====================================================================================================
- PID Function
- The PID (比例、积分、微分) function is used in mainly
- control applications. PIDCalc performs one iteration of the PID
- algorithm.
- While the PID function works, main is just a dummy program showing
- a typical usage.
- 以下为PID参数定义
- =====================================================================================================*/
- typedef struct PID {
- float SetPoint; // 设定目标 Desired Value(期望值)
- float Proportion; // 比例常数 Proportional Const
- float Integral; // 积分常数 Integral Const
- float Derivative; // 微分常数 Derivative Const
- float LastError; // Error[-1] 最后一个误差
- float PrevError; // Error[-2]
- float SumError; // Sums of Errors 总误差
- }PID ;
- /*====================================================================================================
- PID计算部分
- =====================================================================================================*/
- float PIDCalc( PID *pp, float NextPoint )
- {
- float dError,
- Error,
- DUTY;
- Error = pp->SetPoint - NextPoint; // 偏差 设定 - 下一点
- pp->SumError += Error; // 积分 误差和
- dError = pp->LastError - pp->PrevError; // 当前微分 上一个 - 上上个
- pp->PrevError = pp->LastError; //移位 上一个》上上个
- pp->LastError = Error; //移位 上上个》误差
- DUTY=
- ( pp->Proportion * Error // 比例项 比例*误差
- + pp->Integral * pp->SumError // 积分项 积分*误差和
- + pp->Derivative * dError // 微分项 微分*误差变化
- );
- if(DUTY>255){DUTY=255;}
- if(DUTY<-255){DUTY=-255;}
- return DUTY;
- }
- /*====================================================================================================
- Initialize PID Structure
- =====================================================================================================*/
- void PIDInit (PID *pp)//将PID各个参数初始化为0
- {
- memset ( pp,0,sizeof(PID)); //MEM组
- }
- /*====================================================================================================
- Main Program
- =====================================================================================================*/
- float sensor (void) // Dummy Sensor Function 虚拟传感器功能
- {
- while(!S);
- return (float)S; //(S/255.0)*5.0;
- }
- void actuator(float rDelta) // Dummy Actuator Function 虚拟致动器的功能
- {
- pwm=rDelta; //(rDelta/5.0)*255;
- if(pwm<0){pwm=0;} //高
- if(pwm>255) pwm=255; //低
- pwm=255-pwm;
- }
- /********************************************************************
- * 名称 : 计数器 设T0为方式1,GATE=1
- * 功能 :
- * 输入 :
- * 输出 :
- ***********************************************************************/
- void InitTimer0(void)
- {
- TMOD = 0x11;
- TH0 = 0x10;
- TL0 = 0x00;
- TR0 = 1;
- }
- /********************************************************************
- * 名称 : T0中断用来计数器溢出,超过测距范围
- * 功能 :
- * 输入 :
- * 输出 :
- ***********************************************************************/
- void Timer0Interrupt(void) interrupt 1 //T0中断用来计数器溢出,超过测距范围
- {
- flag=1; //中断溢出标志
- }
- void StartModule() //启动发射
- {
- TX=1;
- delay25us();
- TX=0;
- }
- /********************************************************************
- * 名称 : Convert(uchar In_Date)
- * 功能 : 因为电路设计时,P0.0--P0.7接法刚好了资料中的相反,所以设计该函数。
- * 输入 : 12864资料上的值
- * 输出 : 送
- ***********************************************************************/
- unsigned char Convert(unsigned char In_Date)
- {
- unsigned char i, Out_Date = 0, temp = 0;
- for(i=0; i<8; i++)
- {
- temp = (In_Date >> i) & 0x01;
- Out_Date |= (temp << (7 - i));
- }
- return Out_Date;
- }
- /********************************************************************
- * 名称 : LCD字库初始化程序
- * 功能 : 主函数
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void initinal(void) //LCD字库初始化程序
- {
- delay(40); //大于40MS的延时程序
- // PSB=1; //设置为8BIT并口工作模式
- delay(1); //延时
- RES=0; //复位
- delay(1); //延时
- RES=1; //复位置高
- delay(10);
- TransferData(0x30,0); //Extended Function Set :8BIT设置,RE=0: basic instruction set, G=0 :graphic display OFF
- delay(100); //大于100uS的延时程序
- TransferData(0x30,0); //Function Set
- delay(37); ////大于37uS的延时程序
- TransferData(0x08,0); //Display on Control
- delay(100); //大于100uS的延时程序
- TransferData(0x10,0); //Cursor Display Control光标设置
- delay(100); //大于100uS的延时程序
- TransferData(0x0C,0); //Display Control,D=1,显示开
- delay(100); //大于100uS的延时程序
- TransferData(0x01,0); //Display Clear
- delay(10); //大于10mS的延时程序
- TransferData(0x06,0); //Enry Mode Set,光标从右向左加1位移动
- delay(100); //大于100uS的延时程序
- }
- /********************************************************************
- * 名称 : 显示文字
- * 功能 : 主函数
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void lcd_mesg(unsigned char code *adder1)
- {
- unsigned char i;
- TransferData(0x80,0); //设置图形显示内存addressset图形显示内存地址
- delay(100);
- for(i=0;i<32;i++)
- {
- TransferData(*adder1,1);
- adder1++;
- }
- TransferData(0x90,0); //设置图形显示内存地址
- delay(100);
- for(i=32;i<64;i++)
- {
- TransferData(*adder1,1);
- adder1++;
- }
- }
- /********************************************************************
- * 名称 : 传送数据或者命令
- * 功能 :
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void TransferData(char data1,bit DI) //传送数据或者命令,当DI=0时,传送命令,当DI=1时,传送数据.
- {
- WRD=0;
- RS=DI;
- delay(1);
- P0=Convert(data1);
- E=1;
- delay(1);
- E=0;
- }
- void Conut(void)
- {
- time=TH0*256+TL0;
- TH0=0;
- TL0=0;
- S=time*0.179; //算出来是CM 11。0592M晶振
- if(flag==1) //超出测量
- {
- flag=0;
- }
- else
- {
- if(S>480) S1=0;
- else S1=480-S;
-
- }
- }
- void Distance(void)
- {
- StartModule(); //计算
- while(!RX); //当RX为零时等待
- TR0=1; //开启计数
- while(RX); //当RX为1计数并等待
- TR0=0; //关闭计数
- Conut();
- }
- /********************************************************************
- * 名称 : 毫秒延时
- * 功能 :
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void delayms(unsigned int xms) //延时xms毫秒
- {
- unsigned int i,j;
- for(i=xms;i>0;i--)
- for(j=1320;j>0;j--);
- }
- /********************************************************************
- * 名称 : 10us延时程序
- * 功能 :
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void delay(unsigned int m) //延时程序
- {
- unsigned int i,j;
- for(i=0;i<m;i++)
- for(j=0;j<13;j++);
- }
- /********************************************************************
- * 名称 : 25us延时程序
- * 功能 :
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void delay25us(void) //延时25us误差 0us
- {
- unsigned char a,b;
- for(b=33;b>0;b--)
- for(a=3;a>0;a--);
- }
- void InitTimer1(void) //定时器初始化
- {
- TMOD = 0x11;
- TH1 = 0x0EC;
- TL1 = 0x78;
- EA = 1;
- ET1 = 1;
- TR1 = 1;
- }
-
- void Timer1Interrupt(void) interrupt 3
- {
- TH1 = 0x0EC;
- TL1 = 0x78;
- displaytime++;
- Timetime++; //计时
- }
- /********************************************************************
- * 名称 : 显示图形
- * 功能 : 主函数
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void DisplayGraphic(unsigned char code *adder)
- {
- int i,j;
- //显示上半屏内容设置
- for(i=0;i<32;i++)
- {
- TransferData((0x80 + i),0); //SET 垂直地址 VERTICAL ADD
- TransferData(0x80,0); //SET 水平地址 HORIZONTAL ADD
- for(j=0;j<16;j++)
- {
- TransferData(*adder,1);
- adder++;
- }
- }
- //显示下半屏内容设置
- for(i=0;i<32;i++)
- {
- TransferData((0x80 + i),0); //SET 垂直地址 VERTICAL ADD
- TransferData(0x88,0); //SET 水平地址 HORIZONTAL ADD
- for(j=0;j<16;j++)
- {
- TransferData(*adder,1);
- adder++;
- }
- }
- }
- /*******************************************************************/
- /* */
- /* 矩阵键盘扫描 */
- /* */
- /*******************************************************************/
- uchar keyscan(void)//键盘扫描函数,使用行列反转扫描法 比如:行为低电位,列为高四位
- {
- uchar cord_h,cord_l;//行列值
- P2=0x0f;//行线输出全为0
- cord_h=P2&0x0f;//读入列线值
- if(cord_h!=0x0f) //先检测有无按键按下
- {
- delay(1); //去抖
- if(cord_h!=0x0f)
- {
- cord_h=P2&0x0f; //读入列线值
- P2=cord_h|0xf0; //输出当前列线值
- cord_l=P2&0xf0; //读入行线值
- return(cord_h+cord_l);//键盘最后组合码值
- }
- }
- else return(0xff);//返回该值
- }
- /**********************************************************/
- void beep()
- {
- uchar i;
- for (i=0;i<100;i++)
- {
- delay(10);
- BEEP=!BEEP; //BEEP取反
- }
- BEEP=1; //关闭蜂鸣器
- }
- void beepchange() //变音蜂鸣器
- {
- uchar i;
- for (i=0;i<(20-beeptime)*10;i++)
- {
- delay((beeptime+2)*3);
- BEEP=!BEEP; //BEEP取反
- }
- BEEP=1; //关闭蜂鸣器
-
- }
- /********************************************************************
- * 名称 : Main()
- * 功能 : 主函数
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void main(void)
- {
- PID sPID; // PID Control Structure PID控制结构
- float rOut; // PID Response (Output) PID控制器的响应(输出)
- float rIn; // PID Feedback (Input) PID反馈(输入)
-
- PIDInit ( &sPID ); // Initialize Structure
- if(pidchang==0) // 准
- {
- sPID.Proportion = KSP; // Set PID Coefficients 比例
- sPID.Integral = KSI; // 积分
- sPID.Derivative = KSD; // 微分
- }
- if(pidchang==1) // 稳
- {
- sPID.Proportion = KSP1; // Set PID Coefficients 比例
- sPID.Integral = KSI1; // 积分
- sPID.Derivative = KSD1; // 微分
- }
- sPID.SetPoint = size; // Set PID Setpoint 设定值
- P4SW = 0x70;
- initina2(); //调用LCD显示图片(扩展)初始化程序
- beep();
- beep();
- delayms(200);
- initinal(); //调用LCD字库初始化程序
- delay(100); //大于100uS的延时程序
- lcd_mesg(IC_DAT); //显示中文汉字1
- InitTimer0(); //计时器
- InitTimer1(); //中断初始化
- CCON = 0; //主控制寄存器的初始
- //PCA timer 停止运行
- //清除CF标志
- //清除所有中断标志模块
- CL = 0; //复位 PCA base timer
- CH = 0;
- CMOD = 0x02; //设置 PCA timer 时钟源在 Fosc/2
- //禁用PCA timer溢出中断
- CCAP0H = CCAP0L = 0xff; //pwm0端口输出的50%占空比的矩形波
- CCAPM0 = 0x42; //PCA模块工作在8位PWM模式 禁止PCA中断
- CCAP1H = CCAP1L = 0xff; //PWM1输出端口0方波的占空比
- CCAPM1 = 0x42; //PCA模块工作在8位PWM模式 禁止PCA中断
- CR = 1; //PCA timer 启动运行
- beep();
- beep();
- while(1)
- {
-
- sPID.SetPoint = 480-size; // Set PID Setpoint 设定值
- Distance();
- delayms(10);
- // CCAP1H = CCAP1L = pwm; //pwm0端口输出的50%占空比的矩形方波
- CCAP0H = CCAP0L = pwm; //pwm0端口输出的50%占空比的矩形方波
- key=keyscan();//调用键盘扫描,
- switch(key)
- {
- case 235:key=0;break; //0 按下相应的键显示相对应的码值 原理就是高四位一列低四位一列的组
- //合。0111 1110 7e 0表示按键后为0,1表示没有按键按下的。
- //其他类推。
- case 119:key=1;break; //1
- case 123:key=2;break; //2
- case 125:key=3;break; //3
- case 183:key=4;break; //4
- case 187:key=5;break; //5
- case 189:key=6;break; //6
- case 215:key=7;break; //7
- case 219:key=8;break; //8
- case 221:key=9;break; //9
- case 126:key=10;break; //A
- case 190:key=11;break; //B
- case 222:key=12;break; //C
- case 238:key=13;break; //D
- case 231:key=14;break; //*
- case 237:key=15;break; //#
- case 255:key=16;break; //空
- }
- if(key==16)
- {
- if(keysign!=16)
- {
- beeptime=keysign;
- if(beeptime!=14)
- {
- if((flagStart==1)&&(beeptime<=9)) {flagStart=1; beepchange1=1;}
- else beepchange();
- }
- if((flagStart==0)&&(keysign<=9)) {flagSep=keysign; shuzi=keysign;} //任务显示
- if((flagStart==1)&&(keysign<=9)) { size=200-keysign*10; pidchang=1;} //任务3
- if((shuzi==2)&&(flagSep==1))
- {
- } //任务3
- if(keysign==15)
- {
- ZTimetime=0;
- flagStart=1; //标志位置1
- if(flagSep==1)
- {
- if(flagStart6==0)size=150;
- }//任务1 位置
- if(keysign==5) flagchangeStar=5 ; //任务5 位置
- }
- if(keysign==14) {flagStart=3;beepchange1=0; } //标志位置0 BEEP可以等于0;
- }
-
- }
- keysign=key; //上次的按键
- //***任务要求函数等等***
- if((flagStart==1)&&(flagSep==1))
- {
- rIn = sensor (); //把S转成浮点型 // Read Input 读取输入
- rOut = PIDCalc ( &sPID,rIn ); //PID // Perform PID Interation
- actuator ( rOut+pwm ); //占空比 // Effect Needed Changes
- }
- //***取消小球下降函数***
- if(flagStart==3)
- {
- rIn = sensor (); //把S转成浮点型 // Read Input 读取输入
- rOut = PIDCalc ( &sPID,rIn ); //PID // Perform PID Interation
- actuator ( rOut+pwm ); //占空比 // Effect Needed Changes
- size=sizechange+changesize;
- if(S1>=450)
- {
- sizechange=0; //最低点清 0
- flagStart=0;
- BEEP=1;
- pwm=255;
- flagSep=0;
- flagchangeStar=0;
-
- }
- }
- if((flagSep==5)&&(flagStart==1))
- {
- pidchang=1;
- if(S1>100) pwm=95;
- if(S1<150) {flagSep=1;size=1;}
-
-
- }
- /********************************************************************
- * 名称 : 屏幕数据刷新
- * 功能 :
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- if(displaytime>=100 )
- {
- if(flagStart==3) sizechange=sizechange+40; //下降专用 距离下降 左后停止
- TransferData(0x95,0);
- TransferData(0x17,1); //高度显示
- TransferData(S1%1000/100+0x30,1);
- TransferData(S1%100/10+0x30,1);
- TransferData(S1%10+0x30,1);
- TransferData(0x8D,0); //响应时间显示
- TransferData(RTimetime/100%10+0x30,1);
- TransferData(RTimetime%100/10+0x30,1);
- TransferData(0x2E,1);
- TransferData(RTimetime%10+0x30,1);
- TransferData(0x9d,0); //保持时间显示
- TransferData(MTimetime/100%10+0x30,1);
- TransferData(MTimetime%100/10+0x30,1);
- TransferData(0x2E,1);
- TransferData(MTimetime%10+0x30,1);
- displaytime=0;
- TransferData(0x85,0); //任务要求显示
- TransferData(0x20,1);
- if(flagStart==1) TransferData(0x11,1);
- else TransferData(0x3C,1);
- TransferData(shuzi+0x30,1);
- if(flagStart==1) TransferData(0x10,1);
- else TransferData(0x3E,1);
- }
-
- if((Timetime>=22)&&(flagStart==1)) //0.1s的保持与采样时间计算
- {
- ZTimetime++; //总时间
- if((flagSep==5)&&(S1>=100))
- {
- RTimetime=ZTimetime; //响应时间S
- }
- if((size==301)&&(S1<200))
- {
- size=50;
-
- }
-
- if((flagSep==1)&&((110>=S1)|(S1>=190))&&(size==150))
- {
- RTimetime=ZTimetime; //响应时间S
- pidchang=1;
- }
- if((flagSep==1)&&((10>=S1)|(S1>=90))&&(size==50))
- {
- RTimetime=ZTimetime; //响应时间S
- pidchang=1;
- }
- if((flagSep==1)&&((210>=S1)|(S1>=290))&&(size==250))
- {
- RTimetime=ZTimetime; //响应时间S
- pidchang=1;
- }
- else
- {
- Beep1stime++;
- if(Beep1stime>=1) BEEP=1;
- if((Beep1stime>=10)&&(beepchange1!=1)) {BEEP=0;Beep1stime=0; }
- }
- MTimetime=ZTimetime-RTimetime; //保持时间
- Timetime=0;
- if(size==301) MTimetime=0;
- }
- if(flagSep==6)
- {
- flagStart6=1;
- flagSep=1;
- size=301;
- pidchang=0;
- }
-
- if ((MTimetime>=30)&&(flagStart6==1))
- {
- flagStart61++;
- if (flagStart60==0)
- {
- size=250;
- flagStart60=1;
- pidchang=0;
- }
- else
- {
- size=50;
- flagStart60=0;
- pidchang=0;
- }
- MTimetime=0;
- ZTimetime=0;
- RTimetime=0;
- }
- if (flagStart61>=4){pwm=0; flagSep=0;}
-
-
- if(flagSep==7) //要求7功能
- {
-
- if((S1>=2)&&(flagStart7==0)){pwm=0;flagStart7=1;} //启动标志位
- else
- if(flagStart7==1)
- {
- if (S1>=140) {flagSep=1; size=150;}
- }
- }
-
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
下载:
简易风洞程序(2).zip
(72.04 KB, 下载次数: 54)
|