51单片机PCF8591转换电位器数字量为模拟量当作设定速度经PID控制直流电机实际转速的项目工程

180it 2022-04-09 PM 740℃ 0条
#include <reg51.h>
#include< intrins.h>
#define uchar unsigned char
#define uint unsigned int
//#define ulong unsigned long
#define KeyPort P1//自定义按键端
#define AD_IN0  0x40////自定义PCF8591的AD转换通道1
#define AD_IN1  0x41//自定义PCF8591的AD转换通道2
#define AD_IN2  0x42//自定义PCF8591的AD转换通道3
#define AD_IN3  0x43//自定义PCF8591的AD转换通道4
#define  CYCLE 100 //限定的最大转速 
sbit pwm=P2^0;//位定义脉冲输入端口
sbit IN1=P2^1;//位定义L298输入端1
sbit IN2=P2^2;//位定义L298输入端2
sbit SDA=P2^3;//位定义PCF8591的I2C总线数据端
sbit SCL=P2^4;//位定义PCF8591的I2C总线时钟端
sbit RS = P2^5;//LCD1602数据命令选择端口 
sbit RW = P2^6;//LCD1602读写选择端口
sbit EN = P2^7;//LCD1602使能端口
sbit zhongduan=P3^2;//位定义中断次数变量
int out;//声明PID调节后输出偏差值变量 
uint value;//声明经PID函数PID调节后输出偏差值返回值变量
uint expc_speed; //设定速度
uint real_speed; //实际速度
uint Inlpuse;//脉冲计数变量
uint time,count;//定时器0中断次数变量、定时器1中断次数变量
uint Proportion=8;//比例常数 Proportional Const
uint Integral=3;//积分常数 Integral Const
uint Derivative=1;//微分常数 Derivative Const 
uint Error;//Error[0]为声明当前偏差值变量
uint LastError;//Error[-1]为声明之后偏差值变量
uint PrevError;//Error[-2]为声明再后偏差值变量
uchar code table[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
  void delay(void)  
{ 
   uchar i;
   for(i=1;i>0;i--);
  }
  void delay_ms(uchar x)
{
   uint i,j;
   for(i=x;i>0;i--)
    for(j=50;j>0;j--);
   }
  uchar KeyScan(void)//按键扫描函数
{
   uchar keyvalue;
   if(KeyPort!=0xff)
 {
    delay_ms(10);
    if(KeyPort!=0xff)
  {
     keyvalue=KeyPort;
     while(KeyPort!=0xff);
     switch(keyvalue)
   {
      case 0xfe:
                return 1;
                break;
      case 0xfd:
                return 2;
                break;
      case 0xfb:
                return 3;
                break;
      case 0xf7:
                return 4;
                break;
      case 0xef:
                return 5;
                break;
      case 0xdf:
                return 6;
                break;
      case 0xbf:
                return 7;
                break;
      case 0x7f:
                return 8;
                break;
      default:
              return 0;
              break;
     }
    }
   }
    return 0;
  }
  void write_com(uchar com)//lcd1602写命令函数
{
   RS=0;
   RW=0;
   P0=com;
   delay_ms(5);
   EN=1;
   delay_ms(5);
   EN=0;
  }
  void write_data(uchar date)//lcd1602写一个字符函数
{
   RS=1;
   RW=0;
   P0=date;
   delay_ms(5);
   EN=1;
   delay_ms(5);
   EN=0;
  }
  void lcd_display(uchar position,uint speed)//lcd1602显示函数
{
   write_com(0x80+position);//LCD1602字符型液晶显示器第一行第显示
   write_data(table[speed]);//显示字符串
   write_com(0x80+0x40+position);//LCD1602字符型液晶显示器第二行显示
   write_data(table[speed]);//显示字符串
  }
  void lcd_init()//lcd1602初始化函数
{
   write_com(0x38);
   write_com(0x0c);
   write_com(0x06);
   write_com(0x01);
  }
  int PIDControl()//PID偏差计算函数
{
   Error=expc_speed-real_speed;//计算偏差
   //进行增量式PID计算
   out=out+Proportion*(Error-LastError)+Integral*Error+Derivative*(Error+PrevError-2*LastError);
   //进行误差更新
   PrevError=LastError;
   LastError=Error;
   //上下限幅处理
   if(out<0)
   out=0;//驱动电机的电压不可能小于零,故当输出小于零时,输出应该值为零。
   if(out>255)
   out=255;//DA转换为8位,最大数值为255,故当大于255时,限制为255。
   return out;
  }
  void iic_init()//iic初始化函数       
{
   SDA=1;
   delay();
   SCL=1;
   delay();    
  }                      
  void start()//iic开始信号函数
{
   SDA=1;
   delay();
   SCL=1;
   delay();
   SDA=0;
   delay();
  }
  void stop()//iic停止信号函数    
{
   SDA=0;
   delay();
   SCL=1;
   delay();
   SDA=1;
   delay();
  }                                                                               
  void respons()//iic应答函数 ,相当于一个智能的延时函数。 
{
   uchar i;
   SCL=1;
   delay();
   while((SDA==1)&&(i<250))
   i++;
   SCL=0;
   delay();
  }
//  uchar read_byte()//iic读一个字节数据函数
//{
//   uchar i,k;
//   SCL=0;
//   delay();
//   SDA=1;
//   delay();
//   for(i=0;i<8;i++)
// {
//    SCL=1;
//    delay();
//    k=(k<<1)|SDA;//先左移一位,再在最低位接受当前位。
//    SCL=0;
//    delay();
//   }
//   return k;  
//  }                                                                              
  void write_byte(uchar date)//iic写一字节数据函数      
{
   uchar i,temp;
   temp=date;
   for(i=0;i<8;i++)
 {
    temp=temp<<1; //左移一位,移出的一位在CY中。
    SCL=0;//只有在scl=0时sda能变化值 
    delay();
    SDA=CY; 
    delay();
    SCL=1; 
    delay();            
   }   
    SCL=0;
    delay();
    SDA=1;
    delay();
   }           
  void write_add(uchar control,uchar date)//PCF8591的DA转换函数  
{ 
   start(); 
   write_byte(0x91);
   respons(); 
   write_byte(control); 
   respons(); 
   write_byte(date);
   respons(); 
   stop();  
  }             
//  uchar read_add(uchar control)//PCF8591的AD转换函数
//{
//   uchar date; 
//   start();
//   write_byte(0x91); 
//   respons(); 
//   write_byte(control); 
//   respons(); 
//   start();
//   write_byte(0x91+1);//把最后一位变成1,读数据。 
//   respons(); 
//   date=read_byte();
//   stop(); 
//   return date; 
//  }
  void SystemInit()//
{
   TMOD=0x21;//设定时器0为工作方式1,定时器1为工作方式2(自动重装初值)。
   TH0=0x3c;//设定50ms一次中断
   TL0=0xb0;
   TH1=0x9c;//设定100us一次中断
   TL1=0x9c;
   EA=1;//开总中断    
   EX0=1;//开外部中断0
   IT0=1;//启动下降沿触发有效
   ET0=1;//开定时器0中断
   ET1=1;//开定时器1中断
   TR0=1;//启动定时器0
   TR1=1;//启动定时器1
  }
  void exter0() interrupt 0//外部中断0函数
{
   Inlpuse++;//M法测速度(外部中断0和定时器0用在M法测速上)
  }
  void timer0() interrupt 1//定时器0中断函数
{
   TH0=0x3c;//重装初值
   TL0=0xb0;
   time++;
   if(time>=20)//1s钟读取一次转速
 {
    EX0=0;
    TR0=0;
    real_speed=Inlpuse;//计算转速
    Inlpuse=0;
    value=PIDControl();
    write_add(0x40,value);//进行DA转换,将数字量转换为模拟量。
    EX0=1;
    TR0=1;
   }
  }
  void time1() interrupt 3//定时器1中断函数
{
   count++;
   if(count>=100)
   count=0;
   if(count<out)
   pwm=1;
   else
   pwm=0;
  } 
  void main()
{
   unsigned char num;                 
   SystemInit();
   lcd_init();
   iic_init();                        
   while (1)//主循环
 {
    num=KeyScan();//循环调用按键扫描
    switch (num)
  {
     case 1:
   {
      if(expc_speed<CYCLE)
      expc_speed++;
     } 
     break;
     case 2:
   {
      if(expc_speed>0)
      expc_speed--;
     } 
    } 
   lcd_display(4,expc_speed);
   lcd_display(5,real_speed);   
  }  
 }

https://www.cnblogs.com/AChenWeiqiangA/p/12850554.html

支付宝打赏支付宝打赏 微信打赏微信打赏

如果文章或资源对您有帮助,欢迎打赏作者。一路走来,感谢有您!

标签: none

51单片机PCF8591转换电位器数字量为模拟量当作设定速度经PID控制直流电机实际转速的项目工程