找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1079|回复: 0
打印 上一主题 下一主题
收起左侧

才入门的单片机新手请教大家关于直流电机调速的问题

[复制链接]
跳转到指定楼层
楼主
不是一般的pwm控制,就是几个AD/DA的转换,用三极管放大控制电枢电流..........第一次写这种几百行的大程序感觉好难啊

问题是在proteus上调试发现速度只能加,设置速度比实际速度小的时候就不能降速了,代码也不能发现问题,来求助大家

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


以下是单片机代码
  1. #include <reg52.h>
  2. #define  digital P0                 //DAC0832 数据管脚
  3. #define  leddat  P1                   //数码管数据管脚
  4. #define   en    1    //电机一圈的脉冲数 根据电机实际参数设定
  5. #define uint unsigned int
  6. #define uchar unsigned char
  7. #define ufloat unsigned float
  8. sbit scl=P3^5;
  9. sbit sda=P3^7;
  10. sbit Y3 = P3^0;              //数码管段选脚定义
  11. sbit Y2 = P3^1;
  12. sbit Y1 = P3^2;
  13. sbit Y0 = P3^3;
  14. sbit Y7 = P2^0;              //数码管段选脚定义
  15. sbit Y6 = P2^1;
  16. sbit Y5 = P2^2;
  17. sbit Y4 = P2^3;
  18. sbit LSA = P2^4;             //138译码器管脚定义
  19. sbit LSB = P2^5;
  20. sbit LSC = P2^6;
  21. sbit  LSG1 = P2^7;
  22. char code Led_dat[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};       //共阴数码管段码 0123456789
  23. long double speed=0;
  24. long int count=0;  //记录脉冲数量
  25. void Delay10us()
  26. {
  27.         unsigned char a,b;
  28.         for(b=1;b>0;b--)
  29.                 for(a=2;a>0;a--);

  30. }

  31. void delay()  //延时几微秒。延时函数在很多函数里都要用它。至少要大于4.7us
  32. {;;}          //当你把这个函数写在用它这个函数的前面就不用声明了

  33. void init()  //初始化总线。将总线都拉高以释放
  34. {
  35.         scl=1;
  36.         delay();  //I2C总线使用时一般都要延时5us左右
  37.         sda=1;
  38.         delay();
  39. }

  40. void start() //启始信号。 时钟信号为高电平期间,数据总线产生下降沿。
  41. {            //为什么要下降沿,且sda先要为1。因为先要保证数据线为空才能工作
  42.         sda=1;   //先释放数据总线。高电平释放
  43.         delay();
  44.         scl=1;
  45.         delay();
  46.         sda=0;
  47.         delay();
  48. }

  49. void stop()
  50. {
  51.         sda=0;  //先要有工作状态才能释放,sda=0时在工作状态
  52.         delay();
  53.         scl=1;
  54.         delay();
  55.         sda=1;  //释放数据总线
  56.         delay();
  57. }

  58. void respons()  //应答函数
  59. {
  60.         uchar i=0;
  61.         scl=1;  //每个字节发送完后的第九个时钟信号的开始
  62.         delay();
  63.         while((sda==1)&&(i<255))   //此处i的定义使用了uchar.只要填一个小于255的就行
  64.         i++;                       //此处的sda是从机的
  65.         scl=0; //表示主器件默认从器件已经收到而不再等待。不再等待之后,时钟的高电平过了就是低电平,所以scl=0
  66.                //此时第酒个时钟信号结束
  67. }

  68. void writebyte(uchar d)  //写一字节,每次左移一位
  69. {
  70.         uchar i,temp;
  71.         temp=d;
  72.         for(i=0;i<8;i++)
  73.         {
  74.                 temp=temp<<1;
  75.                 scl=0;        //数据传输期间要想sda可变,先把时钟拉低。此处要给sda赋值
  76.                 delay();
  77.                 sda=CY;       //CY为左移移入PSW寄存器中的的CY位。
  78.                 delay();
  79.                 scl=1;        //sda有数据了。保持数据稳定
  80.                 delay();
  81.         }
  82.         scl=0;            //此处是写数据,是属于数据传输过程中。只有在时钟信号为低电平期间
  83.         delay();          //数据总线才可以变化。
  84.         sda=1;            //所以要想释放数据总线,就必须先把时钟拉低
  85.         delay();         
  86.         /*此处释放总线写在末尾是因为调用它时,前面有起始函数释放了总线*/
  87. }

  88. uchar readbyte()
  89. {
  90.         uchar i,k;
  91.         scl=0;
  92.         delay();
  93.         sda=1;
  94.         delay();
  95.         /*此处释放总线放在前面是因为一般都是先写后读,保险起见,释放一下总线*/
  96.         for(i=0;i<8;i++)
  97.         {
  98.                 scl=1;     //一个时钟信号的开始
  99.                 delay();
  100.                 k=(k<<1)|sda;    //实质是把sda的数据,最先传来的放在最高位,依次往下排
  101.                 scl=0;    //一个时钟信号结束
  102.                 delay();
  103.         }
  104.         return k;
  105. }
  106. void write(uchar addr,uchar dat)
  107. {
  108.         start();          //初始化
  109.         writebyte(0x90);      //调用写一字节函数.PCF8591为1001。此处是给从机发送写信号(最低位是0)
  110.         respons();            //调用应答函数让从机应答
  111.         writebyte(addr);      //写入地址
  112.         respons();            //每写一字节都要应答
  113.         writebyte(dat);
  114.         respons();
  115.         stop();
  116. }

  117. uchar read(uchar addr)
  118. {
  119.         uchar dat;
  120.         start();
  121.         writebyte(0x90);      //从此处的发送地址和方向位0到从机
  122.         respons();            //此处的从机产生应答。属于“伪写”。用于确定和哪台机子通信
  123.         writebyte(addr);
  124.         respons();
  125.         start();
  126.         writebyte(0x91);      //从此处开始,从机向主机写数据。读的方向位为1
  127.         respons();
  128.         dat=readbyte();
  129.         stop();
  130.         return dat;           //读得的数据要返回
  131. }


  132. void delay1(int i)           //延时函数
  133. {
  134.                 while(i--);
  135. }

  136. void display(int x,int y)           //数码管操作函数
  137. {

  138.         delay1(100);
  139.         leddat = ~0x00;                       //清屏消隐
  140.         Y0=0;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1;                     //段选1
  141.         leddat = ~Led_dat[x%10];               //取余数 取出个位数
  142.         
  143.         delay1(100);
  144.         leddat = ~0x00;
  145.         Y0=1;Y1=0;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1;                  //段选2
  146.                 leddat = ~Led_dat[x/10%10];         //取出十位数
  147.         
  148.         delay1(100);
  149.         leddat = ~0x00;
  150.    Y0=1;Y1=1;Y2=0;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1;                  //段选3
  151.                 leddat = ~Led_dat[x/100%10];         //取出百位数
  152.         
  153.         delay1(100);
  154.         leddat = ~0x00;
  155.    Y0=1;Y1=1;Y2=1;Y3=0;Y4=1;Y5=1;Y6=1;Y7=1;                    //段选4
  156.                  leddat = ~Led_dat[x/1000];            //取出千位数
  157.         
  158.         delay1(100);
  159.         leddat = ~0x00;                       //清屏消隐
  160.         Y0=1;Y1=1;Y2=1;Y3=1;Y4=0;Y5=1;Y6=1;Y7=1;                     //段选5
  161.         leddat = ~Led_dat[y%10];               //取余数 取出个位数
  162.         
  163.         delay1(100);
  164.         leddat = ~0x00;
  165.         Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=0;Y6=1;Y7=1;                  //段选6
  166.                 leddat = ~Led_dat[y/10%10];         //取出十位数
  167.         
  168.         delay1(100);
  169.         leddat = ~0x00;
  170.    Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=0;Y7=1;                  //段选7
  171.                 leddat = ~Led_dat[y/100%10];         //取出百位数
  172.         
  173.         delay1(100);
  174.         leddat = ~0x00;
  175.    Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=0;                    //段选8
  176.                  leddat = ~Led_dat[y/1000];            //取出千位数
  177. }

  178. void timerInit()
  179. {

  180.         TMOD=0x15;                 //模式设置,00000001
  181.         TR0=1;                         //打开计数器
  182.         ET0=1;                         //开计数器0中断
  183.         
  184.         TR1=1;                         //打开计数器
  185.         ET1=1;                         //开计数器0中断
  186.         TH1=(65536-45872)/256;         //50ms
  187.         TL1=(65536-45872)%256;
  188.         TH0=0;
  189.         TL0=0;
  190.         
  191.         EA=1;                         //开总中断
  192. }

  193. uint T0_read()
  194. {
  195.         uchar tl,th1,th2;
  196.         uint val;
  197.         while(1)
  198.         {
  199.                 th1=TH0;
  200.                 tl=TL0;
  201.                 th2=TH0;
  202.                 if(th1==th2)
  203.                         break;
  204.         }
  205.         val=th1*256+tl;
  206.         return val;
  207. }



  208. void main()
  209. {
  210.     double dat = 0;
  211.                 int dig=0;
  212.           int i;
  213.         int  x_speed=150;   //速度增量
  214.         
  215.          LSA = 0;                //138译码器 YC2输出低
  216.         LSB = 1;
  217.         LSC = 0;
  218.         LSG1 = 1;
  219.         WR = 0;                  //打开dac0830转换 WR输出低
  220.   timerInit();
  221.                 while(1)
  222.                 {
  223.                         dat=read(0x00);
  224.                         dat = (dat*67)/255 + 17;    //设定的每秒转速    17~84r/s  对应 1020~5040r/min
  225.                                 
  226.                           speed = count/en;   //当前速度
  227.                                 
  228.                         if(speed < dat) x_speed+=1;    //如果实际速度小于设定速度 速度增量加
  229.                         else x_speed-=1;               //反之则减
  230.                         if(x_speed > 255)x_speed = 255;             //速度增量最大255 最小0
  231.                         if(x_speed < 0) x_speed = 0;
  232.                         digital =x_speed;  //电机输出速度为 设定速度加上速度增量
  233.                         
  234.                         i=10;
  235.                         while(i--)
  236.                         {
  237.                                 i--;
  238.                          display(speed*60,dat*60);     //显示当前速度 每分钟转速  
  239.             }
  240.                         
  241.                 }
  242. }

  243. void timer_T1() interrupt 3      //定时器中断
  244. {
  245.         static int i = 0;               
  246.         TH1=(65536-45872)/256;         //50ms
  247.         TL1=(65536-45872)%256;
  248.         i++;
  249.     if(i>=20)         //20*50=1000ms  定时1s
  250.                 {     
  251.                         TR0=0;                       //关闭计数器 记录脉冲数量
  252.                         count=T0_read();
  253.                   TH0=0;
  254.                         TL0=0;
  255.                         i=0;                //脉冲清零 重新开始计数
  256.                         TR0=1;
  257.                 }

  258. }
复制代码
全部资料51hei下载地址:
调速.zip (115.21 KB, 下载次数: 14)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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