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方波来进行控制,可调速。.
代码:
#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; //关闭看门狗
}
不错的开发板,要是在分享一下原理图就更完美啦。