Bootstrap

06:PWM与电机驱动【MSP430F5529】

目录

电机型号

驱动方式

工作方式

代码

drive.c

drive.h

main.c

智能送药小车

car.h

car.c

main.c


电机型号

        步进电机:图解: 步进电机原理与驱动方式 - 知乎 (zhihu.com)

驱动方式

        L298N:L298N 电机驱动板 - 详细介绍 - 知乎 (zhihu.com)

工作方式

        PWM驱动,控制电机运动的速度、力矩

代码

drive.c

参考官方的代码,输出程序:drive.c

#include <drive.h>
/*
 *  函数:PWM_Init()
 *  功能:初始化PWM
 *  P1.2
 *  P1.3
 */
void PWM_Init(void)
{
    //TA0CTL = 0;     //清除以前的设置
    //TA0CTL = MC_1;  //定时器TA选择为增记数模式

    TA0CTL |= ID_0; //设置分频系数

    /*设置PWM通道一P1.2的输出模式*/
    //TA0CCTL1 = OUTMOD_7;    //高电平PWM输出,占空比设置的是高电平的占空比
    TA0CCTL1 = OUTMOD_3;    //低电平PWM输出,占空比设置的是低电平的占空比
    P1DIR |= BIT2;          //P1.2为输出
    P1SEL |= BIT2;          //P1.2为输出

    /*设置PWM通道二P1.3的输出模式*/
    TA0CCTL2 = OUTMOD_7;    //高电平PWM输出
    P1DIR |= BIT3;          //P1.3为输出
    P1SEL |= BIT3;          //P1.3为输出

    TA0CTL = TASSEL_2 + MC_1;
}
/*
 * 函数:TAPwmSetPermill(char Channel,unsigned int Percent)
 * 功能:设置每一路的参数
 * 入口参数:
 *          Channel:当前设置的通道数
 *          Percent:PWM有效时间的千分比(0~1000)
 */
void TAPwmSetPermill(char Channel,unsigned int Percent)
{
    unsigned long int Period;
    unsigned int Duty;
    Period = TA0CCR0;
    Duty   = Period * Percent /1000;
    switch(Channel)
    {
        case 1:
            TA0CCR1 = Duty;
            break;
        case 2:
            TA0CCR2 = Duty;
            break;
        case 3:
            TA0CCR3 = Duty;
            break;
        case 4:
            TA0CCR4 = Duty;
            break;
    }
}

drive.h

#ifndef __DRIVE_H
#define __DRIVE_H
#include <msp430.h>
#include <stdio.h>

void PWM_Init(void);
void TAPwmSetPermill(char Channel,unsigned int Percent);

#endif  

main.c

/*
 * 通道1:P1.2
 * 通道2:P1.3
 * 通道1输出PWM信号,200HZ,20%占空比
 */

#include <msp430.h> 
#include <drive.h>

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;	// stop watchdog timer

	PWM_Init();

	TA0CCR0 = 5000;

	TAPwmSetPermill(1,400);     //1通道,40%的占空比
	TAPwmSetPermill(2,500);     //2通道,50%的占空比

	while(1);
}

        (后面好像使用的时候会有什么冲突导致1或者2通道无法正常运行,不太记得了,可以到实物上实验一下子)

智能送药小车

        下面是部分智能送药小车使用PWM驱动电机相关代码与注释

car.h

#ifndef __CAR_H
#define __CAR_H
#include <msp430.h>

void CAR_PWM_Init(void);
void CAR_RUN_Init(void);
void Capture_Init(void);
void CAR_Init(void);

void TAPwmSetPermill(char Channel,unsigned int Percent);

#endif

car.c

#include <car.h>

/*******************************
 * PWM初始化
 * 前轮:  左——P1.2    右——P1.3
 * 后轮:  左——P1.4    右——P1.5
 *******************************/
void CAR_PWM_Init()
{
    TA0CTL |= ID_0;

    P1DIR |= BIT2 + BIT3 + BIT4 + BIT5;
    P1SEL |= BIT2 + BIT3 + BIT4 + BIT5;

    TA0CCTL1 = OUTMOD_7;
    TA0CCTL2 = OUTMOD_7;
    TA0CCTL3 = OUTMOD_7;
    TA0CCTL4 = OUTMOD_7;

    TA0CTL = TASSEL_2 + MC_1 + TACLR;
    TA0CCR0 = 1000;

}
/*
 * 电机控制端GPIO设置
 *           AIN1        AIN2
 *  左前                  P6.0        P6.1
 *  右前                  P6.2        P6.3
 *  左后                  P6.4        P7.0
 *  右后                  P6.5        P6.6
 */
void CAR_RUN_Init(void)
{
    P6DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6;
    P6OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6);

    P7DIR |= BIT0;
    P7OUT &= ~BIT0;
}

/***************************
 * 输入捕获:
 * 前轮:  左——P2.0    右——P2.1
 * 后轮:  左——P2.2    右——P3.6
 ***************************/
//IO口存在冲突,待改进,改为两个PWM以及两个输入捕获端口,解决定时器不足问题
/*void Capture_Init(void)
{
    P2DIR &= ~(BIT4 + BIT5);
    P2SEL |=   BIT4 + BIT5;

    TA2CTL   = MC_2 + TASSEL_2 + ID_0 + TACLR;
    TA2CCTL1 = CM_1 + SCS + CAP + CCIE + CCIS_0;
    TA2CCTL2 = CM_1 + SCS + CAP + CCIE + CCIS_0;

    P3DIR &= ~(BIT5 + BIT6);
    P3SEL |=   BIT5 + BIT6;

    TB0CTL   = MC_2 + TASSEL_2 + ID_0 + TACLR;
    TB0CCTL1 = CM_1 + SCS + CAP + CCIE + CCIS_0;
    TB0CCTL2 = CM_1 + SCS + CAP + CCIE + CCIS_0;
}*/

void CAR_Init(void)//初始化
{
    CAR_PWM_Init();
    CAR_RUN_Init();
    //Capture_Init();
}

void TAPwmSetPermill(char Channel,unsigned int Percent)//选择通道,设置该通道输出的占空比,改变小车速度
{
    unsigned long int Period;
    unsigned int Duty;
    Period = TA0CCR0;
    Duty   = Period * Percent /1000;
    switch(Channel)
    {
        case 1:
            TA0CCR1 = Duty;
            break;
        case 2:
            TA0CCR2 = Duty;
            break;
        case 3:
            TA0CCR3 = Duty;
            break;
        case 4:
            TA0CCR4 = Duty;
            break;
    }
}

main.c

/*
 * 第四个版本
 * 红外循迹四轮小车,旋转式转向,可前进与倒退
 *
 * 下一个版本改进计划:
 *          小车改为两个PWM驱动
 *          添加输入捕获,更新为闭环控制
 *          添加PID算法,运动控制更稳定
 *          修改定时器工作方式,精确计算时间,计算行驶路程
 *          添加OLED,实时显示参数
 */

#include <msp430.h> 
#include <car.h>
#include <redled.h>

void delay(int ms);
void RED_LED_Flag(void);

void CAR_F_R(int mode_1);
void CAR_R_F(unsigned int a,unsigned int b,unsigned int c,unsigned int d);
void CAR_TEXT(void);

int main(void)
{
	WDTCTL = WDTPW | WDTHOLD;

	//RED_LED_Init();//开启红外功能,初始化
	CAR_Init();
	
	while(1)
	{
	    //RED_LED_Flag();//开启小车全部功能
	    CAR_TEXT();//测试小车功能
	}
}
void CAR_TEXT(void)
{
    CAR_R_F(200,200,200,200);
    CAR_F_R(0);

}

//延时函数——伪
void delay(int ms)
{
    int i,j;
    for( i = 0; i < ms; i ++)
    {
        for( j = 0; j < 240; j ++);
    }
}

void RED_LED_Flag(void) //小车功能实现
{
    if( (P4IN & BIT1) != 0 && (P4IN & BIT2) != 0)//都识别到黑线
    {
        CAR_F_R(4);     //停止
        CAR_R_F(000,000,000,000);
    }
    if( (P4IN & BIT1) == 0 && (P4IN & BIT2) == 0)//都未识别到黑线
    {
        CAR_F_R(0);     //前进
        CAR_R_F(200,200,200,200);
    }
    if( (P4IN & BIT1) != 0 && (P4IN & BIT2) == 0)//左识别到黑线,左转
    {
        CAR_F_R(6);     //旋转左转
        CAR_R_F(300,300,300,300);
    }
    if( (P4IN & BIT1) == 0 && (P4IN & BIT2) != 0)//右识别到黑线,右转
    {
        CAR_F_R(5);     //旋转右转
        CAR_R_F(300,300,300,300);
    }
}

void CAR_F_R(int mode_1)//控制前后行动,控制IN1,IN2
{
    switch(mode_1)
    {
       case 0://前行
            P6OUT &= ~(BIT0 + BIT2 + BIT4 + BIT5);      //0
            P6OUT |= BIT1 + BIT3 + BIT6;                //1
            P7OUT |= BIT0;
            break;

       case 1://后退
            P6OUT |= BIT0 + BIT2 + BIT4 + BIT5;     //1
            P6OUT &= ~(BIT1 + BIT3 + BIT6);         //0
            P7OUT &= ~BIT0;                         //0
            break;

       case 2://左转
           P6OUT &= ~BIT0;      //0,P6.0
           P6OUT &= ~BIT1;      //0

           P6OUT &= ~BIT2;      //0,P6.2
           P6OUT |= BIT3;       //1

           P6OUT &= ~BIT4;      //0,P6.4
           P7OUT &= ~BIT0;      //0

           P6OUT &= ~BIT5;      //0
           P6OUT |= BIT6;       //1
           break;

       case 3://右转
           P6OUT &= ~BIT0;      //0
           P6OUT |= BIT1;       //1

           P6OUT &= ~BIT2;      //0
           P6OUT &= ~BIT3;      //0

           P6OUT &= ~BIT4;      //0
           P7OUT |= BIT0;       //1

           P6OUT &= ~BIT5;      //0
           P6OUT &= ~BIT6;      //0
           break;

       case 4://停止
           P6OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6);      //0
           P7OUT &= ~BIT0;
           break;

       case 5://左旋转
           P6OUT &= ~BIT0;      //0
           P6OUT |=  BIT1;      //1

           P6OUT |=  BIT2;      //1
           P6OUT &= ~BIT3;      //0

           P6OUT &= ~BIT4;      //0
           P7OUT |=  BIT0;      //1

           P6OUT |=  BIT5;      //1
           P6OUT &= ~BIT6;      //0
           break;

       case 6://右旋转
           P6OUT |=  BIT0;      //1
           P6OUT &= ~BIT1;      //0

           P6OUT &= ~BIT2;      //0
           P6OUT |=  BIT3;      //1

           P6OUT |=  BIT4;      //1
           P7OUT &= ~BIT0;      //0

           P6OUT &= ~BIT5;      //0
           P6OUT |=  BIT6;      //1
           break;

        default:
            break;
    }
}

void CAR_R_F(unsigned int a,unsigned int b,unsigned int c,unsigned int d)//控制速度
{

    TAPwmSetPermill(1,a);
    TAPwmSetPermill(2,b);
    TAPwmSetPermill(3,c);
    TAPwmSetPermill(4,d);
}
;