找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1706|回复: 3
收起左侧

单片机垂直起降控制程序 PWM输出,PCF8591读取角度

[复制链接]
ID:849756 发表于 2020-12-13 09:09 | 显示全部楼层 |阅读模式
垂直起降悬臂控制,代码可以实现指定角度悬停,采用PWM输出,PCF8591读取角度,八位数码管显示设定角度与实时角度。

单片机源程序如下:
  1. #include<reg52.h>
  2. #include<intrins.h>
  3. #define DataPort P0
  4. #define CYCLE 10
  5. typedef unsigned char uint8;
  6. typedef unsigned int uint16;
  7. typedef unsigned long uint32;
  8. void Display(unsigned char FirstBit,unsigned char Num);
  9. void PWMOUT();
  10. void wucha();
  11. void scan();
  12. void xianshi();
  13. void DelayUs2x(unsigned char t);//us级延时函数声明
  14. void DelayMs(unsigned char t); //ms级延时
  15. void Init_Timer0(void);
  16. bit flag_300ms = 0;
  17. sbit LATCH1=P2^2;
  18. sbit LATCH2=P2^3;
  19. sbit K1 = P3^0;
  20. sbit K2 = P3^1;
  21. sbit PWM = P1^3;
  22. sbit I2C_SDA = P2^1;
  23. sbit I2C_SCL = P2^0;//I2C通信的两个引脚
  24. uint8 AD_value = 0;//AD值
  25. key=0;
  26. TempData[8];
  27. angle=0;
  28. sangle=0;
  29. Proportion=1.5;
  30. Integral=0;
  31. Derivative=0;
  32. Error;
  33. LastError;
  34. PrevError;
  35. out=20;
  36. count=0;
  37. uint8 get_ADC_vaule(uint8 chn);
  38. code dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};// 显示段码值0~9
  39. code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
  40. void main()
  41. {
  42. Init_Timer0();
  43.          while(1)
  44.          {
  45.                   xianshi();
  46.                  scan();
  47.                  wucha();
  48.                  xianshi();
  49.          }
  50. }
  51. void DelayUs2x(unsigned char t)
  52. {   
  53. while(--t);
  54. }
  55. void DelayMs(unsigned char t)
  56. {

  57. while(t--)
  58. {
  59.      //大致延时1mS
  60.      DelayUs2x(245);
  61.          DelayUs2x(245);
  62. }
  63. }
  64. void scan()
  65. {
  66.         P3 = 0xff;
  67.         
  68.         if (P3==0xfe) key=1;
  69. if (P3==0xfd) key=2;
  70. if (P3==0xfb) key=3;
  71. if (P3==0xf7) key=4;
  72. if (P3==0xef) key=5;
  73. if (P3==0xdf) key=6;
  74. if (P3==0xbf) key=7;
  75. if (P3==0x7f) key=8;
  76.                 switch (key)
  77.                 {
  78.                 case 1:
  79.                         {
  80.                  sangle=0;
  81.                                         Proportion=3;
  82. Integral=0;
  83. Derivative=0;
  84.                         }
  85.                 break;
  86.                 case 2:
  87.                 {                        
  88.          sangle=35;
  89.                         Proportion=1.7;
  90. Integral=0.1;
  91. Derivative=0.1;
  92.                 }
  93.                 break;
  94.                 case 3:
  95.                         {
  96.                  sangle=45;
  97.                         Proportion=1.85;
  98. Integral=0;
  99. Derivative=0;}
  100.                 break;
  101.                 case 4:
  102.                 {                        
  103.          sangle=45;
  104.                         Proportion=1.85;
  105. Integral=0.2;
  106. Derivative=0;
  107.                 }
  108.                 break;
  109.                 case 5:
  110.                         {
  111.                  sangle=45;
  112.                         Proportion=1.85;
  113. Integral=0.3;
  114. Derivative=0.1;}
  115.                 break;
  116.                 case 6:
  117.                 {                        
  118.          sangle=50;
  119.                         Proportion=1.5;
  120. Integral=0;
  121. Derivative=0;
  122.                 }
  123.                 break;
  124.                 case 7:
  125.                         {
  126.                  sangle=55;
  127.                         Proportion=1.8;
  128. Integral=0.01;
  129. Derivative=0;}
  130.                 break;
  131.                 case 8:
  132.                 {                        
  133.          sangle=60;
  134.                         Proportion=1.5;
  135. Integral=0;
  136. Derivative=0;
  137.                 }
  138.         }
  139. }
  140.         void xianshi()
  141.         {DelayMs(1);
  142.                         AD_value = get_ADC_vaule(0);//读取通道0的AD值
  143.         
  144.         angle=(float)AD_value*1.41-21;
  145.         TempData[3]=dofly_DuanMa[angle%10];
  146.   TempData[2]=dofly_DuanMa[angle/10%10];
  147.         TempData[1]=dofly_DuanMa[angle/100];
  148.   TempData[7]=dofly_DuanMa[sangle%10];
  149.         TempData[6]=dofly_DuanMa[sangle/10%10];
  150.   TempData[5]=dofly_DuanMa[sangle/100];
  151. }
  152. void wucha()
  153.          {
  154.                  angle=(float)AD_value*1.41-21;
  155.                 Error=sangle-angle;
  156.   PrevError+=Error;
  157.                  out=out+Proportion*Error+Integral*PrevError+Derivative*(LastError-Error);
  158.                  //out=out+Proportion*(Error-LastError)+Integral*Error+Derivative*(Error+PrevError-2*LastError);
  159.    LastError=Error;
  160.                  //out=50;
  161.                  //out=out+Proportion*Error+Integral*Error*0.02+Derivative*Error/0.02;
  162. if(out<0)
  163.    out=0;
  164.    if(out>100)
  165.    out=100;        
  166.         }

  167. void I2C_delay()//I2C延时函数
  168. {
  169.         _nop_();
  170.         _nop_();
  171.         _nop_();
  172.         _nop_();
  173. }

  174. void I2C_start()//I2C起始信号
  175. {
  176.         I2C_SDA = 1;
  177.         I2C_SCL = 1;
  178.         I2C_delay();
  179.         I2C_SDA = 0;
  180.         I2C_delay();
  181.         I2C_SCL = 0;
  182.         I2C_delay();
  183. }

  184. void I2C_stop()//I2C停止信号
  185. {
  186.         I2C_SDA = 0;
  187.         I2C_SCL = 0;
  188.         I2C_delay();
  189.         I2C_SCL = 1;
  190.         I2C_delay();
  191.         I2C_SDA = 1;
  192.         I2C_delay();
  193. }

  194. bit I2C_write(uint8 dat)//I2C写一个字节
  195. {
  196.         bit ack = 0;
  197.         uint8 mask = 0;
  198.         for(mask=0x80;mask!=0;mask>>=1)
  199.         {
  200.                 if((mask&dat) == 0)
  201.                         I2C_SDA = 0;
  202.                 else
  203.                         I2C_SDA = 1;
  204.                 I2C_delay();
  205.                 I2C_SCL = 1;
  206.                 I2C_delay();
  207.                 I2C_SCL = 0;
  208.                 I2C_delay();
  209.         }
  210.         I2C_SDA = 1;
  211.         I2C_delay();
  212.         I2C_SCL = 1;
  213.         I2C_delay();
  214.         ack = I2C_SDA;
  215.         I2C_delay();
  216.         I2C_SCL = 0;
  217.         I2C_delay();
  218.         
  219.         return (~ack);        
  220. }

  221. uint8 I2C_read_ACK()//I2C读一个字节,并发送应答位
  222. {
  223.         uint8 dat = 0;
  224.         uint8 mask = 0;
  225.         I2C_SDA = 1;
  226.         for(mask=0x80;mask!=0;mask>>=1)
  227.         {
  228.                 if(I2C_SDA == 0)
  229.                         dat = dat & (~mask);
  230.                 else
  231.                         dat = dat | mask;
  232.                 I2C_delay();
  233.                 I2C_SCL = 1;
  234.                 I2C_delay();
  235.                 I2C_SCL = 0;
  236.                 I2C_delay();
  237.         }
  238.         I2C_SDA = 0;
  239.         I2C_delay();
  240.         I2C_SCL = 1;
  241.         I2C_delay();
  242.         I2C_SCL = 0;
  243.         I2C_delay();

  244.         return dat;
  245. }

  246. uint8 I2C_read_NACK()//I2C读一个字节,并发送非应答位
  247. {
  248.         uint8 dat = 0;
  249.         uint8 mask = 0;
  250.         I2C_SDA = 1;
  251.         for(mask=0x80;mask!=0;mask>>=1)
  252.         {
  253.                 if(I2C_SDA == 0)
  254.                         dat = dat & (~mask);
  255.                 else
  256.                         dat = dat | mask;
  257.                 I2C_delay();
  258.                 I2C_SCL = 1;
  259.                 I2C_delay();
  260.                 I2C_SCL = 0;
  261.                 I2C_delay();
  262.         }
  263.         I2C_SDA = 1;
  264.         I2C_delay();
  265.         I2C_SCL = 1;
  266.         I2C_delay();
  267.         I2C_SCL = 0;
  268.         I2C_delay();
  269.         return dat;
  270. }

  271. uint8 get_ADC_vaule(uint8 chn)//获取AD值
  272. {
  273.         uint8 value;
  274.         I2C_start();//I2C起始信号
  275.         if(!I2C_write(0X90))//写入PCF8591地址及读写选择位为写
  276.         {
  277.                 I2C_stop();
  278.                 return 0;
  279.         }
  280.         I2C_write(0X40 | chn);//写入PCF8591通道0
  281.         I2C_write(0x00 | chn);//写入PCF8591通道0
  282.         I2C_start();//I2C起始信号
  283.         I2C_write(0x48<<1 | 0x01);
  284.         I2C_read_ACK();//提供转换所需的时钟信号
  285.         value = I2C_read_NACK();//读取上一次转换的结果
  286.         I2C_stop();//I2C结束信号

  287.         return value;
  288. }
  289. void Init_Timer0(void)
  290. {
  291. TMOD |= 0x01;          //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响                     
  292. TH0=0x00;              //给定初值
  293. TL0=0x00;
  294. EA=1;            //总中断打开
  295. ET0=1;           //定时器中断打开
  296. TR0=1;           //定时器开关打开
  297. }
  298. void Timer0_isr(void) interrupt 1
  299. {
  300. static unsigned char count;
  301. TH0=(65536-10)/256;                  //重新赋值 2ms
  302. TL0=(65536-10)%256;

  303. Display(0,8);                // 调用数码管扫描
  304.   count++;
  305. if (count<out)
  306. PWM= 1;
  307. else
  308. PWM=0;
  309. if(count==100)
  310.                 count= 0;
  311.     }
  312. void Display(unsigned char FirstBit,unsigned char Num)
  313. {
  314.       static unsigned char i=0;
  315.          

  316.            DataPort=0;   //清空数据,防止有交替重影
  317.        LATCH1=1;     //段锁存
  318.        LATCH1=0;

  319.        DataPort=dofly_WeiMa[i+FirstBit]; //取位码
  320.        LATCH2=1;     //位锁存
  321.        LATCH2=0;

  322.        DataPort=TempData[i]; //取显示数据,段码
  323.        LATCH1=1;     //段锁存
  324.        LATCH1=0;
  325.            i++;
  326.        if(i==Num)
  327.               i=0;
  328. }
复制代码

全部程序51hei下载地址:
第四次.rar (40.58 KB, 下载次数: 16)
回复

使用道具 举报

ID:328014 发表于 2020-12-13 16:52 | 显示全部楼层
没有原理图 楼主能分享一下吗?
回复

使用道具 举报

ID:230742 发表于 2020-12-13 19:37 | 显示全部楼层
我是小白,看过很多设计。看了你的设计,我没明白的是用读取电位器角度。没搞错吧。你设计的是一个飞机啊。难道你要在飞机的电位器上挂个重锤?来读取电位器的角度?
回复

使用道具 举报

ID:849756 发表于 2020-12-16 20:57 | 显示全部楼层
啤酒瓶子老大 发表于 2020-12-13 19:37
我是小白,看过很多设计。看了你的设计,我没明白的是用读取电位器角度。没搞错吧。你设计的是一个飞机啊。 ...

阿。这就是一个小diy作品,就控制了单个悬臂
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表