[分享] 基于MSP430红外循迹小车

火辣西米秀   2020-9-14 20:35 楼主

1、P6简单,是输入嘛,肯定就是接受寻迹模块红外的返回值了,没有什么疑义。

2、P4和P1共同控制电机,P1的存在是干什么的?这就与L298N的工作模式相关了,下面有个L298N的图示,对照那个图示来说。

输出A和输出B是连接电机的,电机串联也好,并联也罢,这无所谓。逻辑输入端连接的是P4,也就是控制每个电机的正转反转,逻辑表下面也有,这也没啥问题。

输出通道A和B使能端,使能是啥意思?就是赋予权利,让它可以工作呗,我们先不管P1,也就是不连接P1,在跳线帽连接的状态下,A、B两个使能端都是高电平的,或理解为3.3V,这时候输出通道A和B是可以工作的,再配合上边的P4的逻辑输入,小车无论前进、倒退或转弯都是全速前进的,没办法控制速度。想要控制速度,就要用到PWM,这时候把使能端的跳线帽拔掉,连接P1,也就是两个PWM输出端,通过控制P1端输出的占空比,就能实现调速,而不是一直全速前进后退。其中代码里注释有个地方也写了,转弯的时候由于速度太快有时候是反应不过来的,怎么办?左转的时候让左边反转,右边正转,转弯的速度就提上来了。

----------------------------手动分割线-----------------------------

2019.08.08补充:

这篇博客最近访问有点频繁,,

1、小车循迹的轨道是用黑色绝缘胶带贴出来的轨道。

2、工程中需要加入Config.h文件,里面包含了时钟配置,文件在最底部,copy一份导入到工程中即可。

3、我用的单片机型号为MSP430f149,不同系列寄存器可能不同,但PWM的原理是不变的。

4、循迹采用了小车前部放置红外,四路循迹,下图这玩意。

----------------------------------------------------------------------------------------------------------------

利用红外避障模块进行三路循迹,小车采用直流电机,用L298N驱动电机以及给单片机供电,循迹模块由于红外的不用,中间模块对于黑色的返回值是1, 白色返回值是0,而两侧的模块对于黑色的返回值是0,白色的返回值是1,(当然,红外连接的是有AD转换作用的模块);

  电机的控制利用MSP430生成的PWM方波来进行控制,可调速。.

image.png image.png

  代码:

 

#include <msp430x14x.h>  
#include "Config.h"     
uchar count = 0;
void Init_PWM(void)
{
   P1SEL |= BIT2;  //TA1从P1.2输出
   P1DIR |= BIT2;  //TA1从P1.2输出
   P1SEL |= BIT3;  //TA2从P1.3输出
   P1DIR |= BIT3; //TA2从P1.3输出 
   P6SEL = 0x00;
   P6DIR = 0x00;    //设置P6为输入模式,读取来自红外避障模块的信息
   TACTL |= MC_1 + TASSEL_1;  //时钟源选择ACLK,增计数模式 TA设置 
   TACCTL1 = OUTMOD_7; //模式7 高电平PWM输出 PWM设置
   TACCTL2 = OUTMOD_7; //模式7 高电平PWM输出
   TACCR0 = 33-1;  //PWM总周期=32个ACLK周期 约等于1000Hz 设置PWM的周期
   //TACCR1 = 16;    //TA1 占空比= 16/32=50% 设置占空比
   //TACCR2 = 16;    //TA2 占空比= 16/32=50% 
}
void Set_PWM1_Duty(uchar duty)    //设置PWM占空比
{
     TACCR1 = duty;
}
void Set_PWM2_Duty(uchar duty)
{
     TACCR2 = duty;
}
void stop()
{
    P4OUT=0X0f;
}
void zhizou(char D)
{
    if(D==1)
    {
     P4OUT = 0X05;
     Set_PWM1_Duty(12);
     Set_PWM2_Duty(12);
    }
    if(D==2)
    {
        P4OUT = 0x0a;
        Set_PWM1_Duty(10);
        Set_PWM2_Duty(10);
    }
}
void left(char L)
{
    P4OUT = 0x09;
    if(L==1)
    {
        Set_PWM1_Duty(24);    //左转采用左轮倒转右论正转的方式,这种转弯方式比较快,右转同理
        Set_PWM2_Duty(32);
    }
    if(L==2)
    {
        Set_PWM1_Duty(50);
        Set_PWM2_Duty(50);
    }
}
void right(char R)
{
    P4OUT = 0x06;
    if(R==1)
    {
        Set_PWM1_Duty(32);
        Set_PWM2_Duty(24);
    }
    if(R==2)
    {
        Set_PWM1_Duty(50);
        Set_PWM2_Duty(50);
    }
}
void main()
{
  WDTCTL = WDTPW + WDTHOLD ;   //关闭开门狗
  Clock_Init();
  UART_Init();
  Init_PWM();
  P4SEL = 0x00;
  P4DIR = 0xff;    //设置为输出模式用来控制电机
  //Set_PWM1_Duty(16);
  //Set_PWM2_Duty(16);
  while(1)
  {
      //zhizou(1);
      switch(P6IN&0x0e)
        {
            case 0x0e:zhizou(1);break;
            //case 0x1c:left(2);break;
             case 0x02:left(1);break;
              //case 0x07:right(2);break;
              case 0x08:right(1);break;
              default:zhizou(1); break;
         }
  }
}
Config.h
********************************************************************/
//延时函数,IAR自带,经常使用到
#define CPU_F ((double)8000000)   //外部高频晶振8MHZ
//#define CPU_F ((double)32768)   //外部低频晶振32.768KHZ
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0)) 
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0)) 
 
//自定义数据结构,方便使用
#define uchar unsigned char
#define uint  unsigned int
#define ulong unsigned long
 
//8个LED灯,连接在P6口,可通过断开电源停止使用,ADC使用时断开电源
#define LED8DIR         P6DIR
#define LED8            P6OUT                             //P6口接LED灯,8个
 
//4个独立按键连接在P10~P13
#define KeyPort         P1IN                              //独立键盘接在P10~P13
 
//串口波特率计算,当BRCLK=CPU_F时用下面的公式可以计算,否则要根据设置加入分频系数
#define baud           9600                                //设置波特率的大小
#define baud_setting   (uint)((ulong)CPU_F/((ulong)baud))  //波特率计算公式
#define baud_h         (uchar)(baud_setting>>8)            //提取高位
#define baud_l         (uchar)(baud_setting)               //低位
 
//RS485控制管脚,CTR用于控制RS485处于收或者发状态
#define RS485_CTR1      P5OUT |= BIT2;          //控制线置高,RS485发送状态
#define RS485_CTR0      P5OUT &= ~BIT2;         //控制线置低,RS485接收状态
 
//2.8寸TFT彩屏显示控制相关硬件配置
#define RS_CLR            P5OUT &= ~BIT5           //RS置低
#define RS_SET            P5OUT |=  BIT5           //RS置高
 
#define RW_CLR            P5OUT &= ~BIT6           //RW置低
#define RW_SET            P5OUT |=  BIT6           //RW置高
 
#define RD_CLR            P5OUT &= ~BIT7           //E置低
#define RD_SET            P5OUT |=  BIT7           //E置高
 
#define CS_CLR            P5OUT &= ~BIT0            //CS置低
#define CS_SET            P5OUT |=  BIT0            //CS置高
 
#define RST_CLR            P5OUT &= ~BIT3            //RST置低
#define RST_SET            P5OUT |=  BIT3            //RST置高
 
#define LE_CLR            P5OUT &= ~BIT1            //LE置低
#define LE_SET            P5OUT |=  BIT1            //LE置高
 
//2.8寸TFT彩屏触摸屏控制相关硬件配置
#define PEN_CLR            P2OUT &= ~BIT0           //PEN置低,触碰触摸屏时,Penirq引脚由未触摸时的高电平变为低电平
#define PEN_SET            P2OUT |=  BIT0           //PEN置高
#define PEN             (P2IN & 0x01)            //P2.0输入的值
 
#define TPDO_CLR    P2OUT &= ~BIT1           //TPDO置低
#define TPDO_SET    P2OUT |=  BIT1           //TPDO置高
#define TPDOUT          ((P2IN>>1)&0x01)         //P2.1输入的值
 
#define BUSY_CLR    P2OUT &= ~BIT3           //BUSY置低
#define BUSY_SET    P2OUT |=  BIT3           //BUSY置高
 
#define TPDI_CLR    P2OUT &= ~BIT4            //TPDI置低
#define TPDI_SET    P2OUT |=  BIT4            //TPDI置高
 
#define TPCS_CLR    P2OUT &= ~BIT5            //TPCS置低
#define TPCS_SET    P2OUT |=  BIT5            //TPCS置高
 
#define TPCLK_CLR    P2OUT &= ~BIT6            //TPCLK置低
#define TPCLK_SET    P2OUT |=  BIT6            //TPCLK置高
 
//彩屏/12864液晶/1602液晶的数据口,三液晶共用
#define DataDIR         P4DIR                     //数据口方向
#define DataPort        P4OUT                     //P4口为数据口
 
//12864/1602液晶控制管脚
#define RS_CLR            P5OUT &= ~BIT5           //RS置低
#define RS_SET            P5OUT |=  BIT5           //RS置高
 
#define RW_CLR            P5OUT &= ~BIT6           //RW置低
#define RW_SET            P5OUT |=  BIT6           //RW置高
 
#define EN_CLR            P5OUT &= ~BIT7           //E置低
#define EN_SET            P5OUT |=  BIT7           //E置高
 
#define PSB_CLR            P5OUT &= ~BIT0            //PSB置低,串口方式
#define PSB_SET            P5OUT |=  BIT0            //PSB置高,并口方式
 
#define RESET_CLR    P5OUT &= ~BIT1            //RST置低
#define RESET_SET    P5OUT |= BIT1             //RST置高
 
//12864应用指令集
#define CLEAR_SCREEN    0x01                  //清屏指令:清屏且AC值为00H
#define AC_INIT        0x02                  //将AC设置为00H。且游标移到原点位置
#define CURSE_ADD    0x06                  //设定游标移到方向及图像整体移动方向(默认游标右移,图像整体不动)
#define FUN_MODE    0x30                  //工作模式:8位基本指令集
#define DISPLAY_ON    0x0c                  //显示开,显示游标,且游标位置反白
#define DISPLAY_OFF    0x08                  //显示关
#define CURSE_DIR    0x14                  //游标向右移动:AC=AC+1
#define SET_CG_AC    0x40                  //设置AC,范围为:00H~3FH
#define SET_DD_AC    0x80                      //设置DDRAM AC
#define FUN_MODEK    0x36                  //工作模式:8位扩展指令集
 
//颜色代码,TFT显示用
#define White          0xFFFF                                                               //显示颜色代码
#define Black          0x0000
#define Blue           0x001F
#define Blue2          0x051F
#define Red            0xF800
#define Magenta        0xF81F
#define Green          0x07E0
#define Cyan           0x7FFF
#define Yellow         0xFFE0
 
//NRF2401模块控制线
#define  RF24L01_CE_0        P1OUT &=~BIT5         //CE在P15         
#define  RF24L01_CE_1        P1OUT |= BIT5        
 
#define  RF24L01_CSN_0       P2OUT &=~BIT7         //CS在P27
#define  RF24L01_CSN_1       P2OUT |= BIT7     
 
#define  RF24L01_SCK_0       P3OUT &=~BIT3         //SCK在P33
#define  RF24L01_SCK_1       P3OUT |= BIT3   
 
#define  RF24L01_MISO_0      P3OUT &=~BIT2         //MISO在P32
#define  RF24L01_MISO_1      P3OUT |= BIT2
 
#define  RF24L01_MOSI_0      P3OUT &=~BIT1         //MOSI在P31
#define  RF24L01_MOSI_1      P3OUT |= BIT1
 
#define  RF24L01_IRQ_0       P1OUT &=~BIT4         //IRQ在P14     
#define  RF24L01_IRQ_1       P1OUT |= BIT4
 
//DS18B20控制脚,单脚控制
#define DQ_IN            P1DIR &= ~BIT7          //设置输入,DS18B20接单片机P53口
#define DQ_OUT            P1DIR |= BIT7          //设置输出
#define DQ_CLR            P1OUT &= ~BIT7              //置低电平
#define DQ_SET            P1OUT |= BIT7              //置高电平
#define DQ_R            P1IN & BIT7          //读电平
 
//红外接收头H1838控制脚,单脚控制
#define RED_IN            P1DIR &= ~BIT6              //设置输入,红外接收头接单片机PE3口
#define RED_OUT            P1DIR |=  BIT6              //设置输出
#define RED_L            P1OUT &= ~BIT6              //置低电平
#define RED_H            P1OUT |= BIT6             //置高电平
#define RED_R            (P1IN & BIT6)              //读电平
 
//***********************************************************************
//                   系统时钟初始化,外部8M晶振
//***********************************************************************
void Clock_Init()
{
  uchar i;
  BCSCTL1&=~XT2OFF;                 //打开XT2振荡器
  BCSCTL2|=SELM1+SELS;              //MCLK为8MHZ,SMCLK为8MHZ
  do{
    IFG1&=~OFIFG;                   //清楚振荡器错误标志
    for(i=0;i<100;i++)
       _NOP();
  }
  while((IFG1&OFIFG)!=0);           //如果标志位1,则继续循环等待
  IFG1&=~OFIFG; 
}
 
//***********************************************************************
//                   系统时钟初始化,内部RC晶振
//***********************************************************************
void Clock_Init_Inc()
{
  uchar i;
  
 // DCOCTL = DCO0 + DCO1 + DCO2;              // Max DCO
 // BCSCTL1 = RSEL0 + RSEL1 + RSEL2;          // XT2on, max RSEL
  
  DCOCTL = 0x60 + 0x00;                       //DCO约3MHZ,3030KHZ
  BCSCTL1 = DIVA_0 + 0x07;
  BCSCTL2 = SELM_2 + DIVM_0 + SELS + DIVS_0;
}
 
//***********************************************************************
//                   系统时钟初始化,外部32.768K晶振
//***********************************************************************
void Clock_Init_Ex32768()
{
  uchar i;
 
  BCSCTL2|=SELM1 + SELM0 + SELS;    //MCLK为32.768KHZ,SMCLK为8MHZ
  do{
    IFG1&=~OFIFG;                   //清楚振荡器错误标志
    for(i=0;i<100;i++)
       _NOP();
  }
  while((IFG1&OFIFG)!=0);           //如果标志位1,则继续循环等待
  IFG1&=~OFIFG; 
}
 
//***********************************************************************
//               MSP430内部看门狗初始化
//***********************************************************************
void WDT_Init()
{
   WDTCTL = WDTPW + WDTHOLD;       //关闭看门狗
}
 

回复评论 (2)

嗯,不错学习了

点赞  2020-9-15 17:50

不错的开发板,要是在分享一下原理图就更完美啦。

点赞  2020-9-19 09:10
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复