标题:
单片机垂直起降控制程序 PWM输出,PCF8591读取角度
[打印本页]
作者:
liusang
时间:
2020-12-13 09:09
标题:
单片机垂直起降控制程序 PWM输出,PCF8591读取角度
垂直起降悬臂控制,代码可以实现指定角度悬停,采用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)
2020-12-13 09:06 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
51hei团团
时间:
2020-12-13 16:52
没有原理图 楼主能分享一下吗?
作者:
啤酒瓶子老大
时间:
2020-12-13 19:37
我是小白,看过很多设计。看了你的设计,我没明白的是用读取电位器角度。没搞错吧。你设计的是一个飞机啊。难道你要在飞机的电位器上挂个重锤?来读取电位器的角度?
作者:
liusang
时间:
2020-12-16 20:57
啤酒瓶子老大 发表于 2020-12-13 19:37
我是小白,看过很多设计。看了你的设计,我没明白的是用读取电位器角度。没搞错吧。你设计的是一个飞机啊。 ...
阿。这就是一个小diy作品,就控制了单个悬臂
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1