垂直起降悬臂控制,代码可以实现指定角度悬停,采用PWM输出,PCF8591读取角度,八位数码管显示设定角度与实时角度。
单片机源程序如下:
- #include<reg52.h>
- #include<intrins.h>
- #define DataPort P0
- #define CYCLE 10
- typedef unsigned char uint8;
- typedef unsigned int uint16;
- typedef unsigned long uint32;
- void Display(unsigned char FirstBit,unsigned char Num);
- void PWMOUT();
- void wucha();
- void scan();
- void xianshi();
- void DelayUs2x(unsigned char t);//us级延时函数声明
- void DelayMs(unsigned char t); //ms级延时
- void Init_Timer0(void);
- bit flag_300ms = 0;
- sbit LATCH1=P2^2;
- sbit LATCH2=P2^3;
- sbit K1 = P3^0;
- sbit K2 = P3^1;
- sbit PWM = P1^3;
- sbit I2C_SDA = P2^1;
- sbit I2C_SCL = P2^0;//I2C通信的两个引脚
- uint8 AD_value = 0;//AD值
- key=0;
- TempData[8];
- angle=0;
- sangle=0;
- Proportion=1.5;
- Integral=0;
- Derivative=0;
- Error;
- LastError;
- PrevError;
- out=20;
- count=0;
- uint8 get_ADC_vaule(uint8 chn);
- code dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
- code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
- void main()
- {
- Init_Timer0();
- while(1)
- {
- xianshi();
- scan();
- wucha();
- xianshi();
- }
- }
- void DelayUs2x(unsigned char t)
- {
- while(--t);
- }
- void DelayMs(unsigned char t)
- {
- while(t--)
- {
- //大致延时1mS
- DelayUs2x(245);
- DelayUs2x(245);
- }
- }
- void scan()
- {
- P3 = 0xff;
-
- if (P3==0xfe) key=1;
- if (P3==0xfd) key=2;
- if (P3==0xfb) key=3;
- if (P3==0xf7) key=4;
- if (P3==0xef) key=5;
- if (P3==0xdf) key=6;
- if (P3==0xbf) key=7;
- if (P3==0x7f) key=8;
- switch (key)
- {
- case 1:
- {
- sangle=0;
- Proportion=3;
- Integral=0;
- Derivative=0;
- }
- break;
- case 2:
- {
- sangle=35;
- Proportion=1.7;
- Integral=0.1;
- Derivative=0.1;
- }
- break;
- case 3:
- {
- sangle=45;
- Proportion=1.85;
- Integral=0;
- Derivative=0;}
- break;
- case 4:
- {
- sangle=45;
- Proportion=1.85;
- Integral=0.2;
- Derivative=0;
- }
- break;
- case 5:
- {
- sangle=45;
- Proportion=1.85;
- Integral=0.3;
- Derivative=0.1;}
- break;
- case 6:
- {
- sangle=50;
- Proportion=1.5;
- Integral=0;
- Derivative=0;
- }
- break;
- case 7:
- {
- sangle=55;
- Proportion=1.8;
- Integral=0.01;
- Derivative=0;}
- break;
- case 8:
- {
- sangle=60;
- Proportion=1.5;
- Integral=0;
- Derivative=0;
- }
- }
- }
- void xianshi()
- {DelayMs(1);
- AD_value = get_ADC_vaule(0);//读取通道0的AD值
-
- angle=(float)AD_value*1.41-21;
- TempData[3]=dofly_DuanMa[angle%10];
- TempData[2]=dofly_DuanMa[angle/10%10];
- TempData[1]=dofly_DuanMa[angle/100];
- TempData[7]=dofly_DuanMa[sangle%10];
- TempData[6]=dofly_DuanMa[sangle/10%10];
- TempData[5]=dofly_DuanMa[sangle/100];
- }
- void wucha()
- {
- angle=(float)AD_value*1.41-21;
- Error=sangle-angle;
- PrevError+=Error;
- out=out+Proportion*Error+Integral*PrevError+Derivative*(LastError-Error);
- //out=out+Proportion*(Error-LastError)+Integral*Error+Derivative*(Error+PrevError-2*LastError);
- LastError=Error;
- //out=50;
- //out=out+Proportion*Error+Integral*Error*0.02+Derivative*Error/0.02;
- if(out<0)
- out=0;
- if(out>100)
- out=100;
- }
- void I2C_delay()//I2C延时函数
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- void I2C_start()//I2C起始信号
- {
- I2C_SDA = 1;
- I2C_SCL = 1;
- I2C_delay();
- I2C_SDA = 0;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- }
- void I2C_stop()//I2C停止信号
- {
- I2C_SDA = 0;
- I2C_SCL = 0;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SDA = 1;
- I2C_delay();
- }
- bit I2C_write(uint8 dat)//I2C写一个字节
- {
- bit ack = 0;
- uint8 mask = 0;
- for(mask=0x80;mask!=0;mask>>=1)
- {
- if((mask&dat) == 0)
- I2C_SDA = 0;
- else
- I2C_SDA = 1;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- }
- I2C_SDA = 1;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- ack = I2C_SDA;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
-
- return (~ack);
- }
- uint8 I2C_read_ACK()//I2C读一个字节,并发送应答位
- {
- uint8 dat = 0;
- uint8 mask = 0;
- I2C_SDA = 1;
- for(mask=0x80;mask!=0;mask>>=1)
- {
- if(I2C_SDA == 0)
- dat = dat & (~mask);
- else
- dat = dat | mask;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- }
- I2C_SDA = 0;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- return dat;
- }
- uint8 I2C_read_NACK()//I2C读一个字节,并发送非应答位
- {
- uint8 dat = 0;
- uint8 mask = 0;
- I2C_SDA = 1;
- for(mask=0x80;mask!=0;mask>>=1)
- {
- if(I2C_SDA == 0)
- dat = dat & (~mask);
- else
- dat = dat | mask;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- }
- I2C_SDA = 1;
- I2C_delay();
- I2C_SCL = 1;
- I2C_delay();
- I2C_SCL = 0;
- I2C_delay();
- return dat;
- }
- uint8 get_ADC_vaule(uint8 chn)//获取AD值
- {
- uint8 value;
- I2C_start();//I2C起始信号
- if(!I2C_write(0X90))//写入PCF8591地址及读写选择位为写
- {
- I2C_stop();
- return 0;
- }
- I2C_write(0X40 | chn);//写入PCF8591通道0
- I2C_write(0x00 | chn);//写入PCF8591通道0
- I2C_start();//I2C起始信号
- I2C_write(0x48<<1 | 0x01);
- I2C_read_ACK();//提供转换所需的时钟信号
- value = I2C_read_NACK();//读取上一次转换的结果
- I2C_stop();//I2C结束信号
- return value;
- }
- void Init_Timer0(void)
- {
- TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
- TH0=0x00; //给定初值
- TL0=0x00;
- EA=1; //总中断打开
- ET0=1; //定时器中断打开
- TR0=1; //定时器开关打开
- }
- void Timer0_isr(void) interrupt 1
- {
- static unsigned char count;
- TH0=(65536-10)/256; //重新赋值 2ms
- TL0=(65536-10)%256;
- Display(0,8); // 调用数码管扫描
- count++;
- if (count<out)
- PWM= 1;
- else
- PWM=0;
- if(count==100)
- count= 0;
- }
- void Display(unsigned char FirstBit,unsigned char Num)
- {
- static unsigned char i=0;
-
- DataPort=0; //清空数据,防止有交替重影
- LATCH1=1; //段锁存
- LATCH1=0;
- DataPort=dofly_WeiMa[i+FirstBit]; //取位码
- LATCH2=1; //位锁存
- LATCH2=0;
- DataPort=TempData[i]; //取显示数据,段码
- LATCH1=1; //段锁存
- LATCH1=0;
- i++;
- if(i==Num)
- i=0;
- }
复制代码
全部程序51hei下载地址:
第四次.rar
(40.58 KB, 下载次数: 16)
|