单片机教程网

电脑版
提示:原网页已由神马搜索转码, 内容由www.51hei.com提供.
查看:4098|回复:0

单片机+PWM控制直流电机程序 小车制作详解

[复制链接]
ID:693716发表于 2020-2-27 22:47|显示全部楼层
       最近学习单片机想做个项目试试,其实这个想法在好几年前就有的,但因为工作原因,没有时间和精力做这些东西
今年宅在家没事做,翻出了几年前遗弃的东东重新摆弄。
硬件介绍:

底部

底部

底部

底部

顶部

顶部


1、两个扫地机器人上的减速马达(带红外光电编码器);
2、MPU6050模块,淘宝买的,GY-521模块(当时买成10元左右,现在3元就能买到)
3、L298电机驱动模块;
4、51单片机最小系统;
5、STC12C5A60S2单片机1片
6、外置电源1个(12V的电瓶,有点重,实验时没有加装到车子上,准备车子能站立了再加装上)
/*------------------------------------------------------------------------------------------------------------------------------------------*/
但刚开头就遇到了问题,
1、电机驱动问题;
  • 编码器,因为是红外线的,开始不知道有一个已经坏了,后面拆卸后用手机摄像头查看才知道有个红外发送管被我没有加装限流电阻的情况下烧坏了。在网上淘了些红外发射二极管回来修复了。
  • 编码器计数,开始预计用外部中断计数的,确实很快,外部中断很快,但也是因为太快了,每转动一下就发出2000~5000的脉冲,用逻辑分析仪抓了下脉冲波形,发现光电编码有抖动。能看到的最小时间间距居然只有几十个纳秒,完全不符合我的想法。后面想到用定时器的方式采样计数。
  • 电机同步的问题,两个电机时运行时无法做到同步,程序是根据脉冲个数进行控制的,同时开始,同时结束,停止时两个电机的计数变量不一样,估计是电机机械性能的问题。
  • 测试了电机往返运动,通过脉冲计数的方式可以控制往返几圈后返回起始点(空载,低速),告诉不能保证,会超出预定位置50~120个脉冲(刹不住车

2、MPU6050模块的数据读取,测试用代码可以直接用范例的代码改,但不知道读取的数据是不是要的数据(Y轴的旋转角度,Y轴的旋转加速度)测试了这连个值好像是正确的,不过网上资料所MPU6050需要用卡尔曼滤波什么的,但不会,很可惜,希望直接读出的数据能比较稳定。
3、电机的加减速控制,虽然通过PWM进行调速,但启动和停止时,PWM值太高电机的反作用力太大,PWM值太小又无法启动电机。我想通过程序调制PWM值实现启动时线性加速,要停止时线型减速,以降低电机启动或停止时的惯性。
电机控制是第一次做,希望有类似经验的朋友给我点拨点拨
测试代码如下:
#include "stc12c5a60s2.h"


#define FOSC 11035000L //晶振频率


///*声明与PCA关联的SFR */
//sfr CCON       =   0xD8;         //PCA控制寄存器
//sbit CCF0     =   CCON^0;       //PCA模块-0中断标志
//sbit CCF1     =   CCON^1;       //PCA模块1中断标志
//sbit CR       =   CCON^6;       //PCA定时器运行控制位,置1启动PCA定时器
//sbit CF       =   CCON^7;       //PCA计时器溢出标志
//sfr CMOD       =   0xD9;         //PCA模式寄存器
//sfr CL       =   0xE9;         //PCA基本计时器低
//sfr CH       =   0xF9;         //PCA基本计时器高
//sfr CCAPM0     =   0xDA;         //PCA模块-0模式寄存器
//sfr CCAP0L     =   0xEA;         //PCA模块-0捕捉寄存器低
//sfr CCAP0H     =   0xFA;         //PCA模块-0捕捉寄存器高
//sfr CCAPM1     =   0xDB;         //PCA模块1模式寄存器
//sfr CCAP1L     =   0xEB;         //PCA模块1捕获寄存器低
//sfr CCAP1H     =   0xFB;         //PCA模块1捕捉寄存器高
//sfr PCAPWM0     =   0xf2;         //PWM0第9位,8位PWM未用到
//sfr PCAPWM1     =   0xf3;         //PWM1第9位,8位PWM未用到
sbit k0=P2^0;
sbit k1=P2^1;
sbit mL1=P3^6; //左电机方向控制为1
sbit mL0=P3^7; //左电机方向控制为0
sbit mR1=P3^4; //右电机方向控制为1
sbit mR0=P3^5; //右电机方向控制为0
sbit LT0 =P3^2; //左电机转动脉冲传感位
sbit LT1 =P3^3; //右电机转动脉冲传感位


bit LTT0=0,LTT1=0;//转动脉冲备份
unsigned char quan= 0;//转动圈数
unsigned int ji=0,sd=0,jt=0,st=0;
unsigned char ptxd[8];
unsigned int sdd,stt;


bit flagt0=0;


#define MD 1000


void initPWM()
{
   CCON=0;
   CL=0;
   CH=0;
   CMOD=0X08;
   CCAP0H = 0X80;
   CCAP0L = 255 - CCAP0H;
   CCAPM0 = 0x42;
   CCAP1H = 0X80;
   CCAP1L = 255 - CCAP1H;
   CCAPM1 = 0x42;
   CR = 1;
}
unsigned char T0RH=0;T0RL=0;//全局变量,定时器0重载值


void ConfigTimer0(unsigned int x100us)  //配置T0模式1定时器 ,需要预先设置FOSC晶振频率
{
   unsigned long tmp;
       AUXR |= 0x80;           //定时器时钟1T模式
   tmp=FOSC;               //FOSC为晶振频率
   tmp=(tmp*x100us)/10000;           //计算所需计数值
   tmp=65536-tmp;             //计算定时器重载值
   tmp=tmp+31;               //修正中断响应延时找出的误差
   T0RH=(unsigned char)(tmp>>8);   //定时器重载值拆分高低字节
   T0RL=(unsigned char)tmp;       //
   TMOD&=0XF0;               //清除T0控制位
   TMOD|=0X01;               //配置T0为模式1(16位定时器)
   TH0=T0RH;                 //加载TH0初值
   TL0=T0RL;                 //加载TL0初值
   ET0=1;                   //使能T0中断
   TR0=1;                   //启动T0
   EA=1;
}
void UartInit(void)           //9600bps@11.0592MHz
{
       PCON& = 0x7F;           //波特率不倍速
       SCON = 0x50;           //8位数据,可变波特率
       AUXR |= 0x04;           //独立波特率发生器时钟为Fosc,即1T
       BRT = 0xDC;           //设定独立波特率发生器重装值
       AUXR |= 0x01;           //串口1选择独立波特率发生器为波特率发生器
       AUXR |= 0x10;           //启动独立波特率发生器
   TI=1;
}
/*----------------------------
发送串口数据
----------------------------*/
void SendData(unsigned char dat)
{
   while (!TI);           //等待前面的数据发送完成
   TI=0;
   ACC = dat;             //获取校验位P (PSW.0)
   SBUF = ACC;             //写数据到UART数据寄存器
     k0=0;
}


/*----------------------------
发送字符串
----------------------------*/
void SendString(unsigned char *s)
{
  
   while (*s)             //检测字符串结束标志
   {
         SendData(*s++);       //发送当前字符
   }
}

void mada(bit ma)
{
     if(ji>jt)
     {


       mL1=1;mL0=1;//停止
       if((ji-jt)<30)
       {
         mL1=1;mL0=0;
       }
     }
     if(ji<jt)
     {
       mR1=1;mR0=1;//停止;
       if((jt-ji)<30)
       {
         mR1=1;mR0=0;
       }
     }
//     if(!ma)
//     {
//         if(ji>=MD)
//         {
//           ji=0;
//           mL1=!mL1;mL0=!mL0;//换向
//         }
//         if(((MD-ji)<300)&& (CCAP0H<230))
//         {
//         ++CCAP0H;
//         }
//         if((ji<300)&& (ji<MD)&& (CCAP0H>1))
//         {
//         --CCAP0H;
//         }
//     }
//     else
//     {
//         if(jt>=MD)
//         {
//           jt=0;
//           mR1=!mR1;mR0=!mR0;//换向
//         }
//         if(((MD-jt)<300)&& (CCAP1H<230))
//         {
//         ++CCAP1H;
//         }
//         if((jt<300)&& (jt<MD)&& (CCAP1H>1))
//         {
//         --CCAP1H;
//         }
//     }
//
}
void main()
{
   unsigned char txt[20]="00000,00000,00000\r\n";
   unsigned int tmp=0;
   ConfigTimer0(1);
   UartInit();
   initPWM();
   PT0=1;
   mL1=1;mL0=0;
   CCAP0H=0;
   mR1=1;mR0=0;
   CCAP1H=0;
//   EX0=1;
//   IT0=1;
   while(1)
   {
     mada(0);
     mada(1);
   }
}
/*外部中断0*/
//void init0() interrupt 0
//{
//       EX0=0;
//   flagt0=1;
//}
/*定时器中断0*/
void int0() interrupt 1
{
   static unsigned int t=0;
   TH0=T0RH;                 //加载TH0初值
   TL0=T0RL;                 //加载TL0初值
   t++;
/*检测马达L计数器*/
       if(LT0 !=LTT0)
       {
         ji++;
         k0=~k0;
         LTT0=LT0;
       }
/*检测马达R计数器*/
       if(LT1 !=LTT1)
       {
         jt++;
         k1=~k1;
         LTT1=LT1;
       }
}

测试代码链接:https://pan.baidu.com/s/1EzX07Ay1S2nU1XOXJnWu4g
提取码:999o
全部资料51hei下载地址:
20-PWMmada-1.rar(44.77 KB, 下载次数: 27)

评分

黑币 +50
收起理由
+ 50
共享资料的黑币奖励!

查看全部评分

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

Powered by 单片机教程网