找回密码
 立即注册

QQ登录

只需一步,快速开始

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

单片机PWM+红外对管控制直流电机设计源码

[复制链接]
跳转到指定楼层
楼主
设计中采用了专门的芯片组成了PWM信号的发生系统并且对PWM信号的原理、产生方法以及如何通过软件编程对PWM信号占空比进行调节从而控制其输入信号波形等均作了详细的阐述。另外本系统中使用了红外对管对直流电机的转速进行测量,经过整形电路后将测量值送到单片机,并且最终作为反馈值输入到单片机进行PID运算从而实现了对直流电机速度的控制。在软件方面,文章中详细介绍了PID运算程序初始化程序等的编写思路和具体的程序实现。

1 单片机最小系统:单片机最小系统由51单片机,晶振电路,复位电路,电源组成。大家都比较熟悉,这里不再赘述。
2 四位数码管显示:在应用系统中,设计要求不同,使用的LED显示器的位数也不同,因此就生产了位数,尺寸,型号不同的LED显示器供选择,在本设计中,选择4位一体的数码型LED显示器,简称“4-LED”。本系统中前三位显示电压的整数位,最后一位显示转速的小数位。4-LED显示器引脚如图2所示,是一个共阴极接法的4位LED数码显示管,其中a,b,c,e,f,g为4位LED各段的公共输出端,1、2、3、4分别是每一位的位数选端,dp是小数点引出端,4位一体LED数码显示管的内部结构是由4个单独的LED组成,每个LED的段输出引脚在内部都并联后,引出到器件的外部。
3 电机驱动电路:电机驱动电中是采用ULN2003来驱动。ULN2003是高耐压、大电流达林顿陈列,由七个硅NPN达林顿管组成。该电路的特点:ULN2003的每一对达林顿都串联一个2.7K的基极电阻,在5V的工作电压下它能与TTL和CMOS电路直接相连,可以直接处理原先需要标准逻辑缓冲器来处理的数据,输入5VTTL电平,输出可达500mA/50V。ULN2003的引脚图,其中IN1~IN7为输入控制端;OUT1~OUT7为输出端;8脚为芯片的接地端;9脚为公共端,该脚是内部7个续流二极管负极的公共端,各二极管的正极分别接各达林顿管的集电极。用于感性负载时,该脚接负载电源正极,实现续流作用。如果该脚接地,实际上就是达林顿管的集电极对地接通。
当P1.0中为高电平时,其内部三极管导通,使电机转动。当P1.0为低电平时,内部三极管截止,电路断开,电机停止转动。所以在程序中可以利用P1.0口输出PWM波来控制电机的转速。
4 红外测速电路:发射管工作时发出红外线,当接收管收到红外信号时,其电阻变小(本设计相当于从无穷大变到1k左右)。利用其电阻变化,改变接收管分压情况。挡片是利用圆盘上剪四个孔,当挡片随电机转动时,接收管两端电平发生变化,产生脉冲。
5 整形电路:本设计的整形电路是用555定时器接成的施密特触发器。

6 源程序:
  1. #include "reg52.h"
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. uchar code table[10]={0x3f,0x06,0x5b,
  5. 0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴数码管显示码(0-9)
  6. sbit xiaoshudian=P0^7;
  7. sbit wei1=P2^4; //数码管位选定义
  8. sbit wei2=P2^5;
  9. sbit wei3=P2^6;
  10. sbit wei4=P2^7;
  11. sbit beep=P2^3; //蜂鸣器控制端
  12. sbit motor = P1^0; //电机控制
  13. sbit s1_jiasu = P1^4; //加速按键
  14. sbit s2_jiansu= P1^5; //减速按键
  15. sbit s3_jiting=P1^6; //停止/开始按键
  16. uint pulse_count; //INT0接收到的脉冲数
  17. uint num=0; //num相当于占空比调节的精度
  18. uchar speed[3]; //四位速度值存储
  19. float bianhuasudu; //当前速度(理论计算值)
  20. float reallyspeed; //实际测得的速度
  21. float vv_min=0.0;vv_max=250.0;
  22. float vi_Ref=60.0; //给定值
  23. float vi_PreError,vi_PreDerror;
  24. uint pwm=100; //相当于占空比标志变量
  25. int sample_time=0; //采样标志
  26. float v_kp=1.2,v_ki=0.6,v_kd=0.2; //比例,积分,微分常数
  27. void delay (uint z)
  28. {
  29. uint x,y;
  30. for(x=z;x>0;x--)
  31. for (y=20;y>0;y--);
  32. }
  33. void time_init()
  34. {
  35. ET1=1; //允许定时器T1中断
  36. ET0=1; //允许定时器T0中断
  37. TMOD = 0x15; //定时器0计数,模式1;定时器1定时,模式1
  38. TH1 = (65536-100)/256; //定时器1值,负责PID中断 ,0.1ms定时
  39. TL1 = (65536-100)%6;
  40. TR0 = 1; //开定时器
  41. TR1 = 1;
  42. IP=0X08; //定时器1为高优级
  43. EA=1; //开总中断
  44. }
  45. void keyscan()
  46. {
  47. float j;
  48. if(s1_jiasu==0) //加速
  49. {
  50. delay(20);
  51. if(s1_jiasu==0)
  52. vi_Ref+=10;
  53. j=vi_Ref;
  54. }
  55. while(s1_jiasu==0);
  56. if(s2_jiansu==0) //减速
  57. {
  58. delay(20);
  59. if(s2_jiansu==0)
  60. vi_Ref-=10;
  61. j=vi_Ref;
  62. }
  63. while(s2_jiansu==0);
  64. if(s3_jiting==0)
  65. {
  66. delay(20);
  67. motor=0;
  68. P1=0X00;
  69. P3=0X00;
  70. P0=0x00;
  71. }
  72. while(s3_jiting==0);
  73. }
  74. float v_PIDCalc(float vi_Ref,floatvi_SpeedBack)
  75. {
  76. register floaterror1,d_error,dd_error;
  77. error1=vi_Ref-vi_SpeedBack; //偏差的计算
  78. d_error=error1-vi_PreError; //误差的偏差
  79. dd_error=d_error-vi_PreDerror; //误差变化率
  80. vi_PreError=error1; //存储当前偏差
  81. vi_PreDerror=d_error;
  82. bianhuasudu=(v_kp*d_error+v_ki*vi_PreError+v_kd*dd_error);
  83. return (bianhuasudu);
  84. }
  85. void v_Display()
  86. {
  87. uint sudu;
  88. sudu=(int)(reallyspeed*10); //乘以10之后强制转化成整型
  89. speed[3]=sudu/1000; //百位
  90. speed[2]=(sudu00)/100; //十位
  91. speed[1]=(sudu0)/10; //个位
  92. speed[0]=sudu; //小数点后一位
  93. wei1=0; //第一位打开
  94. P0=table[speed[3]];
  95. delay(5);
  96. wei1=1; //第一位关闭
  97. wei2=0;
  98. P0=table[speed[2]];
  99. delay(5);
  100. wei2=1;
  101. wei3=0;
  102. P0=table[speed[1]];
  103. xiaoshudian=1;
  104. delay(5);
  105. wei3=1;
  106. wei4=0;
  107. P0=table[speed[0]];
  108. delay(5);
  109. wei4=1;
  110. }
  111. void BEEP()
  112. {
  113. if((reallyspeed)>=vi_Ref+5||(reallyspeed
  114. {
  115. beep=~beep;
  116. delay(4);
  117. }
  118. }
  119. void main()
  120. {
  121. time_init();
  122. motor=0;
  123. while(1)
  124. {
  125. v_Display();
  126. BEEP();
  127. }
  128. if(s3_jiting==0) //对按键3进行扫描,增强急停效果
  129. {
  130. delay(20);
  131. motor=0;
  132. P1=0X00;
  133. P3=0X00;
  134. P0=0x00;
  135. }
  136. while(s3_jiting==0);
  137. }
  138. void timer0() interrupt 1
  139. {
  140. }
  141. void timer1() interrupt 3
  142. {
  143. TH1 = (65536-100)/256; //1ms定时
  144. TL1 = (65536-100)%6;
  145. sample_time++;
  146. if(sample_time==5000) //采样时间0.1ms*5000=0.5s
  147. {
  148. TR0=0; //关闭定时器0
  149. sample_time=0;
  150. pulse_count=TH0*255+TL0; //保存当前脉冲数
  151. keyscan(); //扫描按键
  152. reallyspeed=pulse_count/(4*0.6); //计算速度
  153. pwm=pwm+v_PIDCalc(vi_Ref,reallyspeed);
  154. if(pwm
  155. if(pwm>100)pwm=100;
  156. TH0=TL0=0;
  157. TR0=1; //开启定时器0
  158. }
  159. num++;
  160. if(num==pwm) //此处的num值,就是占空比
  161. {
  162. motor=0;
  163. }
  164. if(num==100) //100相当于占空比调节的精度
  165. {
  166. num=0;
  167. motor=1;
  168. }
  169. }
复制代码


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

使用道具 举报

沙发
ID:249808 发表于 2018-4-23 14:53 | 只看该作者
谢谢分享……
回复

使用道具 举报

板凳
ID:435423 发表于 2020-1-13 13:00 来自手机 | 只看该作者
reallyspeed=pulse_count/(4*0.6); //计算速度
回复

使用道具 举报

地板
ID:435423 发表于 2020-1-13 13:01 来自手机 | 只看该作者
reallyspeed=pulse_count/(4*0.6); //计算速度     这里的0.6是秒数吗,采样时间是0.5s,为什么不是0.5呢?
回复

使用道具 举报

5#
ID:375228 发表于 2020-1-29 22:07 | 只看该作者
谢谢分享,很好的学习资料
回复

使用道具 举报

6#
ID:726416 发表于 2020-6-22 15:27 | 只看该作者
q786299029 发表于 2020-1-13 13:01
reallyspeed=pulse_count/(4*0.6); //计算速度     这里的0.6是秒数吗,采样时间是0.5s,为什么不是0.5呢?

复制人家的,哪里能解释
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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