目录
电机型号
步进电机:图解: 步进电机原理与驱动方式 - 知乎 (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);
}