我们单片机设计要求我们用51单片机控制螺旋桨到特定角度,并通过lcd102显示出来,按键设置角度,电位器通过pcf8591读取角度
包含pcb文件,程序,仿真,设计书等。做的仍有瑕疵希望见谅。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include <reg52.h>
- #include "i2c.h"
- #include "delay.h"
- #include "1602.h"
- #include <stdio.h>
- #include <math.h>
- #define AddWr 0x90 //写数据地址
- #define AddRd 0x91 //读数据地址
- #define wait_speak 1
- #define speaked 0
- sbit PWM=P1^2;
- sbit led=P1^6;
- sbit target_up=P3^0;
- sbit target_down=P3^1;
- sbit beep=P1^5;
- float target=40.0;
- float Kp=0.05,Ki=0.4,Kd=0.15;
- unsigned int value,timer1;
- char flag=wait_speak;
- unsigned char confirtime=0;
- extern bit ack;
- unsigned char ReadADC(unsigned char Chl);
- float pid(float input);
- void control();
- void Timer1Init();
- void Timer0Init();
- void change_target();
- void beep_1s();
- void display();
- bit WriteDAC(unsigned char dat);
- void delay100us(int i) //误差 0us
- {
- unsigned char a,b;
- while(i--)
- for(b=1;b>0;b--)
- for(a=47;a>0;a--);
- }
- /*------------------------------------------------
- 主程序
- ------------------------------------------------*/
- main()
- {
-
- LCD_Init(); //初始化液晶
- DelayMs(20); //延时有助于稳定
- LCD_Clear(); //清屏
- Timer1Init();
- value=0;
- led=0;
- while (1) //主循环
- {
- control();
- change_target();
- }
- }
- /*------------------------------------------------
- 读AD转值程序
- 输入参数 Chl 表示需要转换的通道,范围从0-3
- 返回值范围0-255
- ------------------------------------------------*/
- unsigned char ReadADC(unsigned char Chl)
- {
- unsigned char Val;
- Start_I2c(); //启动总线
- SendByte(AddWr); //发送器件地址
- if(ack==0)return(0);
- SendByte(0x40|Chl); //发送器件子地址
- if(ack==0)return(0);
- Start_I2c();
- SendByte(AddWr+1);
- if(ack==0)return(0);
- Val=RcvByte();
- NoAck_I2c(); //发送非应位
- Stop_I2c(); //结束总线
- return(Val);
- }
- float pid(float input)
- {
- static float error2,error1,error3,t,Velocity;
- error1 = target-input ;
- Velocity+=(Kp*(error1-error2))+Ki*error1+Kd*(error1-2*error2+error3);
- t=error2;
- error2= error1 ;
- error3 = t;
- return Velocity;
- }
- //电压分辨率0.0196V
- //满电压3.9V所以角度分辨率0.0196/3.9*360=1.8度 所以增大角度分辨率要嘛增加满量程电压3.9V要嘛减小其对应的角度,其实就都是增大电压
- void control()
- {
-
- unsigned char num=0,i;
- int sum_num=0;
- unsigned char temp[7];//定义显示区域临时存储数组
- float Voltage,angle; //定义浮点变量
- float temp_value;
- for(i=0;i<5;i++)
- {
- sum_num+=ReadADC(0);
- }
- num=sum_num/5;
- sum_num=0;
- Voltage=(float)num;
- angle=(Voltage-16);//*1.41-23.91);
- //angle=-(((Voltage-4.96)/0.0136)+341.73);
- //pid计算
- temp_value=(int)pid(angle);
- if(temp_value<0)
- value=0;
- else if(temp_value>=100)
- value=100;
- else
- value=(int)temp_value;
-
- if(flag==wait_speak&&abs(angle-target)<=5)
- confirtime++;
- if(abs(angle-target)>=20) //如果角度差大于20度 将嗡鸣器设置为待激活状态
- flag=wait_speak;
- if(confirtime==10&&(flag==wait_speak))
- {
- //beep_1s();
- sprintf(temp,"Achieve the goal:");//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- LCD_Write_String(0,1,temp);
- delay100us(10000);
- LCD_Clear(); //清屏
- flag=speaked;
- confirtime=0;
- }
-
-
-
- sprintf(temp,"DQJD:%3.2f ", angle);
- LCD_Write_String(0,0,temp);
- sprintf(temp,"SDJD:%d",(int)target);
- LCD_Write_String(0,1,temp);
- //sprintf(temp,"PWM:%d", value);
- //LCD_Write_String(10,1,temp);
- }
- //定时器1服务函数
- void Time1(void) interrupt 3
- {
- TH1 = 0x0FF;
- TL1 = 0x9C;
- timer1++;
- if(timer1>100) //PWM周期为100*100us
- {
- timer1=0;
- }
- if(timer1 <value)
- {
- PWM=1;
- }
- else
- {
- PWM=0;
- }
-
-
- }
- //定时器1初始化函数
- void Timer1Init()
- {
- TMOD|=0X10;//选择为定时器1模式,工作方式1,仅用TR1打开启动。
- TH1 = 0x0FF;
- TL1 = 0x9C;
- ET1=1;//打开定时器1中断允许
- EA=1;//打开总中断
- TR1=1;//打开定时器
- }
- void change_target()
- {
- unsigned char temp[7];//定义显示区域临时存储数组
- if(target_up==0)
- {
- delay100us(100);
- if(target_up==0)
- { flag=wait_speak;
- while(target_up==0)
- {
- if(target<=80)
- target=45;
- sprintf(temp,"Target:%d",(int)target);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- LCD_Write_String(0,1,temp);
- delay100us(1000);
-
- }
- }
- }
- if(target_down==0)
- {
- delay100us(100);
- if(target_down==0)
- { flag=wait_speak;
- while(target_down==0)
- {
- if(target>=10)
- target=0;
- sprintf(temp,"Target:%d",(int)target);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- LCD_Write_String(0,1,temp);
- //delay10us(1000);
-
- }
- }
- }
- }
- void display()
- {
- // unsigned char temp[7];//定义显示区域临时存储数组
- // sprintf(temp,"Reality: %3.2f ", angle);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- // LCD_Write_String(0,0,temp);
- // sprintf(temp,"Target:%d",(int)target);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- // LCD_Write_String(0,1,temp);
- // sprintf(temp,"PWM:%d", value);//格式输出电压值,%3.2f 表示浮点输出,共3位数,小数点后2位
- // LCD_Write_String(9,1,temp);
- }
- void beep_1s()
- {
- unsigned char i;
- for(i=0;i<=200;i++)
- {
- delay100us(1);
- beep=~beep;
- }
- }
复制代码
所有资料51hei提供下载:
新建 好压 ZIP 压缩文件.zip
(1.38 MB, 下载次数: 114)
|