智能车制作

 找回密码
 注册

扫一扫,访问微社区

查看: 5144|回复: 3
打印 上一主题 下一主题

[咨询] 我想用51单片机IO模拟个PWM控制直流电机转速的的快慢,用红外实行调速,液晶屏能显示

[复制链接]

1

主题

1

帖子

0

精华

注册会员

Rank: 2

积分
32
威望
32
贡献
1
兑换币
6
注册时间
2013-7-14
在线时间
1 小时
毕业学校
中南林业科技大学
跳转到指定楼层
1#
发表于 2013-7-18 10:25:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
5贡献
我想用51单片机IO模拟个PWM控制直流电机转速的的快慢,用红外实行调速,液晶屏能显示遥控数据 ,能控制小车左转右转正常  、就是用PWM控制前进(advance)直流电机始终不转,着实蛋疼

求大神 指出程序的错误。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
uchar code jianma1[]="advance /stop    /left    /right   ";  
void delay(uchar x);  //x*0.14MS
void delay1(uint ms);
void beep();

void pwm_control (uchar k);
sbit IRIN = P3^2;         //红外接收器数据线
sbit BEEP = P1^5;         //蜂鸣器驱动线
sbit RELAY= P1^4;         //继电器驱动线

sbit PWM  = P1^2;    //pwm输出口
sbit PWM1 = P1^3;
uchar IRCOM[7];

sbit LCD_RS = P2^6;            
sbit LCD_RW = P2^5;
sbit LCD_EN = P2^7;
uchar code  cdis1[ ] = {" Speed: "};
uchar code  cdis2[ ] = {"IR-CODE:"};

unsigned int timer1;
uchar speed;
uchar flag_stop,flag_ad;

/*void system_Ini()
{
    TMOD|= 0x10;    //定时器1 工作方式 为16位
TCON = 0x01;               //int0 触发方式为脉冲负边沿触发
// TH1 = 0xfe;     //11.0592
// TL1 = 0x33;
TR1  = 1;
    IE =0x89;       //开T1 INT0 中断
}*/
/*******************************************************************/
/*                                                                 */
/*检查LCD忙状态                                                    */
/*lcd_busy为1时,忙,等待。lcd-busy为0时,闲,可写指令与数据。      */
/*                                                                 */
/*******************************************************************/

bit lcd_busy()
{                          
    bit result;
    LCD_RS = 0;
    LCD_RW = 1;
    LCD_EN = 1;
    delayNOP();
    result = (bit)(P0&0x80);
    LCD_EN = 0;
    return(result);
}

/*******************************************************************/
/*                                                                 */
/*写指令数据到LCD                                                  */
/*RS=L,RW=L,E=高脉冲,D0-D7=指令码。                             */
/*                                                                 */
/*******************************************************************/

void lcd_wcmd(uchar cmd)
{                          
   while(lcd_busy());
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_EN = 0;
    _nop_();
    _nop_();
    P0 = cmd;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0;  
}

/*******************************************************************/
/*                                                                 */
/*写显示数据到LCD                                                  */
/*RS=H,RW=L,E=高脉冲,D0-D7=数据。                               */
/*                                                                 */
/*******************************************************************/

void lcd_wdat(uchar dat)
{                          
   while(lcd_busy());
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_EN = 0;
    P0 = dat;
    delayNOP();
    LCD_EN = 1;
    delayNOP();
    LCD_EN = 0;
}

/*******************************************************************/
/*                                                                 */
/*  LCD初始化设定                                                  */
/*                                                                 */
/*******************************************************************/

void lcd_init()
{
    delay1(15);                  
    lcd_wcmd(0x38);      //16*2显示,5*7点阵,8位数据
    delay1(5);
    lcd_wcmd(0x38);         
    delay1(5);
    lcd_wcmd(0x38);         
    delay1(5);

    lcd_wcmd(0x0c);      //显示开,关光标
    delay1(5);
    lcd_wcmd(0x06);      //移动光标
    delay1(5);
    lcd_wcmd(0x01);      //清除LCD的显示内容
    delay1(5);
}

/*******************************************************************/
/*                                                                 */
/*  设定显示位置                                                   */
/*                                                                 */
/*******************************************************************/

void lcd_pos(uchar pos)
{                          
  lcd_wcmd(pos | 0x80);  //数据指针=80+地址变量
}

/*******************************************************************/
void main()
{
  uchar m;
   
    IRIN=1;                    //I/O口初始化
    BEEP=1;
    RELAY=1;


    delay1(10);                 //延时
    lcd_init();
lcd_pos(0);                //设置显示位置为第一行的第1个字符
   
     m = 0;
    while(cdis1[m] != '\0')
     {                         //显示字符
       lcd_wdat(cdis1[m]);
       m++;
     }

    lcd_pos(0x40);             //设置显示位置为第二行第1个字符
     m = 0;
    while(cdis2[m] != '\0')
     {
       lcd_wdat(cdis2[m]);      //显示字符
       m++;
     }                   //初始化LCD            
                       
     TCON = 0x01;   //触发方式为脉冲负边沿触发
  TMOD |=0x10;   //定时器1 工作方式 为16位
     TH1 = 0xfe;     //11.0592
     TL1 = 0x33;
  TR1=1;
  IE = 0x89;        //允许总中断中断,使能 INT0 外部中断 T1中断
                                                                                 
      
    while((flag_ad==1)&&(flag_stop!=1))
    {
       pwm_control(speed);
    }
   
   }



/*************************************
红外中断

*************************************/
void IR_IN() interrupt 0 using 0
{
  unsigned char i,j,k,N=0;
     EX0 = 0;       //关掉外部中断防止中断的再次发生进入检测引导码阶段(9ms的低电平4.5ms的高电平)
  delay(15);
  if (IRIN==1)
     { EX0 =1;     //9ms的检测检测结束从新打开外部中断
    return;
   }
                           //确认IR信号出现
  while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
    {delay(1);}
for (j=0;j<4;j++)         //收集四组数据
{
   for (k=0;k<8;k++)        //每组数据有8位
   {
     while (IRIN)            //等 IR 变为低电平,跳过4.5ms的引导高电平信号。
       {delay(1);}
      while (!IRIN)          //等 IR 变为高电平
       {delay(1);}
       while (IRIN)           //计算IR高电平时长(0和1的低电平的时长一样的,只要判断高电平时长超过0.56ms并小于1.12ms为1否则为0)
        {
       delay(1);
       N++;           
    if (N>=30)
      {
       EX0=1;
       return;
      }                  //0.14ms计数过长自动离开。
        }                        //高电平计数完毕               
       IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
       if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}  //高电平持续时间大于1.12ms则数据最高位补“1”
       N=0;
   }
}
   
   if (IRCOM[2]!=~IRCOM[3])    // 判断有没有误码(有责放弃没有判断键码)
   {
     EX0=1;
     return;
}
  switch(IRCOM[2])
  {
     case 0x18:
     lcd_pos(0x49);
     for(i=0;i<=7;i++)
         lcd_wdat(jianma1);
       flag_ad=1;
       flag_stop=0;
          break;                          

  case 0x52:
      lcd_pos(0x49);
      for(i=9;i<=16;i++)           //停止
         lcd_wdat(jianma1);
      PWM=0WM1=0;
      flag_stop=1;
      break;

  case 0x08:   lcd_pos(0x49);          //左转
      for(i=18;i<=25;i++)
         lcd_wdat(jianma1);
       PWM=0;PWM1=1;delay1(20);PWM=0;PWM1=0;
        break;
  
  case 0x5a:  lcd_pos(0x49);            //右转
      for(i=27;i<=35;i++)
         lcd_wdat(jianma1);
       PWM=1;PWM1=0;delay1(20);PWM=0;PWM1=0;
        break;
  case 0x15:    lcd_pos(0x09) ;
       lcd_wdat(0x31);
   
       speed=20;
       break;
  case 0x09:    lcd_pos(0x09);
       lcd_wdat(0x32);
      
   
       speed=40;
       break;

  case 0x19:   lcd_pos(0x09);
       lcd_wdat(0x33);
      
       speed=60;
       break;
  case 0x0d:   lcd_pos(0x09);
       lcd_wdat(0x34);
     
       speed=80;
       break;
   }
   beep();
   EX0=1;
}
/**********************************************************/
void beep()
{
  unsigned char i;
  for (i=0;i<100;i++)
   {
   delay(4);
   BEEP=!BEEP;                 //BEEP取反
   }
  BEEP=1;                      //关闭蜂鸣器
}
/*************************************
[ t1 (0.5ms)中断] 中断中做 PWM 输出
  ------------1000/(0.02ms*250)=200Hz
*************************************/
void T1zd(void) interrupt 3      //3 为定时器1的中断号  1 定时器0的中断号 0 外部中断1 2 外部中断2  4 串口中断
{
TH1 = 0xfe;  //11.0592
TL1 = 0x33;
  timer1++;
   
}
/**********************************************************/
void pwm_control (uchar k)
{            
  if(timer1>100) timer1=0;
  if(timer1<k)
  { PWM=1;PWM1=1;}
  else
  { PWM=0;PWM1=0;}
}
/**********************************************************/
void delay(unsigned char x)    //x*0.14MS
{
unsigned char i;
  while(x--)
{
  for (i = 0; i<13; i++) {}
}
}
/**********************************************************/
void delay1(uint ms)
{
unsigned char y;
  while(ms--)
{
  for(y = 0; y<250; y++)
  {
   _nop_();
   _nop_();
   _nop_();
   _nop_();
  }
}
}


8

主题

266

帖子

0

精华

常驻嘉宾

Rank: 8Rank: 8

积分
3743

优秀会员奖章活跃会员奖章在线王奖章论坛元老奖章

威望
1374
贡献
973
兑换币
642
注册时间
2012-12-4
在线时间
698 小时
2#
发表于 2013-7-18 12:53:46 | 只看该作者
  没事儿不要贴程序出来,没人会看的,仔细分析分析是哪儿出问题了吧!
回复

使用道具 举报

2

主题

39

帖子

0

精华

高级会员

Rank: 4

积分
833
威望
333
贡献
204
兑换币
208
注册时间
2013-5-1
在线时间
148 小时
3#
发表于 2013-7-18 21:53:56 | 只看该作者
51的IO口驱动能力很差,要配合三极管或者继电器来驱动电机,但这也失去了PWM的意义
回复

使用道具 举报

0

主题

16

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
282
威望
148
贡献
108
兑换币
98
注册时间
2013-7-18
在线时间
13 小时
毕业学校
xioauasbf
4#
发表于 2013-7-19 19:23:20 | 只看该作者
用红外中断调转向还可以,但是调转速不行,因为红外中断不固定,占空比不确定,如果用51的IO口驱动能力很差,占空比低的话很可能不转。
回复

使用道具 举报

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

本版积分规则

关于我们|联系我们|小黑屋|智能车制作 ( 黑ICP备2022002344号

GMT+8, 2024-6-16 12:14 , Processed in 0.083917 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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