多足机器人,是我大二暑假和大三开始玩的东西,刚好大四暑假留校又接触了MSP430,就想着把原来写的的代码也放到这里
控制多组舵机驱动机器人动作,用MSP430F5438A当主控器,PCA9685当驱动输出PWM方波的发生器,那下子驱动方式弄的我脑壳疼的哟,想想也是好笑。、
emmmm….PCA9685的手册好像没有中文,那下子也是看的脑袋大,好像这里有以前写的驱动原理,写完的就忘更新了….暑假就拿来看怎么驱动了。只记得个大概,IIC通讯协议方式通讯,先发送驱动器的物理地址确认是这个驱动器,得到应答后再开始发送数据,数据用数值形式发送到每个PWM方波输出口,一共可发送16路PWM方波。附上驱动代码。
IIC协议头文件
#ifndef _IIC_H_
#define _IIC_H_
#include "msp430.h"
typedef unsigned int uint;
typedef unsigned char uchar;
//引脚
#define IIC_SDA_PIN (BIT0)
#define IIC_SCL_PIN (BIT1)
//位宏
#define READ_SDA() P2IN&BIT0
#define IIC_SDA_LO P2OUT&=~BIT1
#define IIC_SDA_HI P2OUT|=BIT1
#define IIC_SCL_LO P2OUT&=~BIT3
#define IIC_SCL_HI P2OUT|=BIT3
//SDA设置为输出输入
#define SDA_OUT() P2DIR|=BIT1
#define SDA_IN() P2DIR&=~BIT1
//SCL设置为输出输入
#define SCL_OUT() P2DIR|=BIT3
#define SCL_IN() P2DIR&=~BIT3
//本构件所实现的函数列表
void IIC_Init(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_NAck(void);
void IIC_Ack(void);
void IIC_SendByte(uint dat);
uchar IIC_ReadByte(uchar ack);
uchar I2C_ReadByte(uchar DiviceID ,uchar address);
void I2C_WriteByte(uchar ,uchar address,uchar );
void I2C_ReadNByte(uchar ,uchar address,uchar ,uchar* );
#endif
IIC协议函数
#include "iic.h"
void IIC_delay_us(uchar x)//延时
{
if(x==0)
x=2;
while(x--);
}
void IIC_Init(void)
{
SDA_OUT();
IIC_delay_us(2);
SCL_OUT();
IIC_delay_us(2);
}
void IIC_Start(void)//初始化IIC接口
{
SDA_OUT();
IIC_SDA_HI;
IIC_delay_us(2);
IIC_SCL_HI;
IIC_delay_us(2);
IIC_SDA_LO;
IIC_delay_us(2);
IIC_SCL_LO;
IIC_delay_us(2);
}
void IIC_Stop(void)//停止IIC接口
{
SDA_OUT();
IIC_SCL_LO;
IIC_SDA_LO;
IIC_delay_us(2);
IIC_SCL_HI;
IIC_SDA_HI;
IIC_delay_us(2);
}
void IIC_NAck(void)//非应答信号
{
IIC_SCL_LO;
SDA_OUT();
IIC_delay_us(2);
IIC_SDA_HI;
IIC_delay_us(2);
IIC_SCL_HI;
IIC_delay_us(2);
IIC_SCL_LO;
}
void IIC_Ack(void)//应答信号
{
IIC_SCL_LO;
SDA_OUT();
IIC_SDA_LO;
IIC_delay_us(2);
IIC_SCL_HI;
IIC_delay_us(2);
IIC_SCL_LO;
}
void IIC_SendByte(uint dat)//送入字节
{
uchar i;
SDA_OUT();
for(i=0;i<8;i++)
{
if(dat&0x80)
IIC_SDA_HI;
else IIC_SDA_LO;
dat<<=1;
IIC_delay_us(2);
IIC_SCL_HI;
IIC_delay_us(2);
IIC_SCL_LO;
}
IIC_NAck();
}
uchar IIC_ReadByte(uchar ack)//读出字节
{
uchar i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL_LO;
IIC_delay_us(0);
IIC_SCL_HI;
receive<<=1;
if(READ_SDA())receive++;
IIC_delay_us(0);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
void I2C_WriteByte(uchar DiviceID ,uchar address,uchar thedata)
{
IIC_Start(); //
IIC_SendByte(DiviceID);//写<<1
IIC_SendByte(address); //
IIC_SendByte(thedata); //
IIC_Stop();
}
uchar I2C_ReadByte(uchar DiviceID ,uchar address)
{
uchar ret = 100;
IIC_Start();
IIC_SendByte((DiviceID)); //先写寄存器的地址再读<<1
IIC_SendByte(address);//写寄存器地址
IIC_Start();
IIC_SendByte((DiviceID)|1);//读寄存器<<1
ret = IIC_ReadByte(0);
IIC_Stop();
return ret;
}
void I2C_ReadNByte(uchar DiviceID ,uchar address,uchar n,uchar* data)
{
uchar i;
IIC_Start();
IIC_SendByte((DiviceID)); //先写寄存器的地址再读<<1
IIC_SendByte(address);//写寄存器地址
IIC_Start();
IIC_SendByte((DiviceID)|1);//读寄存器<<1
for(i=0;i<n-1;i++)
data[i] = IIC_ReadByte(1);
data[i] = IIC_ReadByte(0);//最后一个数据发送NACK
IIC_Stop();
}
PCA9685驱动函数
#include "iic.h"
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
void delayms(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=148;y>0;y--);
}
void PCA9685_write(uint address, uint data)//address:数据地址 data:写入的数据参数
{
IIC_Init();
IIC_Start();
IIC_SendByte(0x80);//硬件地址
IIC_SendByte(address);
IIC_SendByte(data);
IIC_Stop();
}
void AngleSet(uint num, uint on, uint off)//参照PCA9685手册,一个输出口用四个8位定义
{
PCA9685_write(LED0_ON_L+4*num,on);
PCA9685_write(LED0_ON_H+4*num,on>>8);
PCA9685_write(LED0_OFF_L+4*num,off);
PCA9685_write(LED0_OFF_H+4*num,off>>8);
}
/*---------------------------------------------------------------
PCA9685修改频率函数
----------------------------------------------------------------*/
void setPWMFreq(float freq)
{
uint prescale,oldmode=0x00,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
//oldmode = PCA9685_read(0x00);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(0x00, newmode); // go to sleep
PCA9685_write(0xfe, prescale); // set the prescaler
PCA9685_write(0x00, oldmode);
delayms(2);
PCA9685_write(0x00, oldmode | 0xa1); //10100001
}
//PCA9685_write(0x00, 0x00);//PCA9685初始化
// AngleSet(1,0,615);//0度值,
// AngleSet(0,0,2048);//180度值
// AngleSet(2,0,1332);//90度值
//}
主函数
#include <msp430.h>
#include "iic.h"
void main()
{
WDTCTL = WDTPW + WDTHOLD; //关看门狗
int num=0;
PCA9685_write(0x00, 0x00);
//初始化控制板
while(1)
{
for(num=0;num<8;num++)
{
AngleSet(num,0,1332);//90度值
if(num==7)
num=0;
}
}
}
//void main(void)//频闪
//{
// WDTCTL = WDTPW + WDTHOLD; // 看门狗
// P8DIR |= 0x01; // P1.0 输出
// TBCCTL0 = CCIE; // CCR0 中断使能
// TBCCR0 = 50000; // CCR0配置初始值
// TBCTL = TBSSEL_2 + TACLR; // SMCLK, 清除为1
// TBCTL |= MC_3;
// _BIS_SR(LPM0_bits + GIE); // 进入低功耗0
//}
//
///****** Timer B0 中断服务程序*******/
//
//#pragma vector=TIMERB0_VECTOR
//__interrupt void Timer_B (void)
//{
// P8OUT ^= 0x01; //反转LED1
// TBCCR0 += 50000; // 增加定时偏移量
//}