功能简介
通过蓝牙发送命令控制小车移动
代码
#include<reg52.h>
#include<intrins.h>
#include<math.h> //内涵abs函数
#include<string.h>
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200 //System frequency
#define BAUD 9600 //UART baudrate
#define P_OUT P1
bit flag_execute = 0;
bit flag_TRX = 0;
bit flag_A5 = 1;
uint HighTimer0Value = 10000;//定时器T0高电平预装值
uint LowTimer0Value = 10000;//定时器T0低电平预装值
uint HighTimer1Value = 10000;//定时器T2高电平预装值
uint LowTimer1Value = 10000;//定时器T2低电平预装值
static uchar Receive[7]=0,Transmit[7]="0000000";
// 0.........包头
// 123......数据位
// 4.....状态位
// 5....校验位
// 6...尾字节
//
//把字符串赋值给数组时会在数组末尾加一个空字符\0
//单独定义数组时不会在末尾加入空字符
//0123456789
//四个轮子的速度(PWM占空比),范围1~99
char RightFrontSpeed = 20;
char LeftFrontSpeed = 20;
//uchar RightBackSpeed = 20;
//uchar LeftBackSpeed = 20;
//--定义使用的IO口--//
sbit RightFrontPwm = P1^6;
sbit RightFrontDir = P1^7;
sbit LeftFrontPwm = P1^0;
sbit LeftFrontDir = P1^1;
sbit RightBackPwm = P1^4;
sbit RightBackDir = P1^5;
sbit LeftBackPwm = P1^2;
sbit LeftBackDir = P1^3;
void CtrlSpeed();
char receive(char *s,char num);
void send(char *s,char num);
char analysis(char *R,char *T);
void Init_Uart(void);
void execute(void);
void CountDutyCycle(bit dir);
void main()
{
Init_Uart();
//T0用作PWM发生器0
TMOD &= 0xF0;
TMOD |= 0x01;
TH0=(uchar)(HighTimer0Value>>8);
TL0=(uchar)HighTimer0Value;
ET0 = 0; //关闭T0中断
//T1用作PWM发生器1
TMOD &= 0x0F;
TMOD |= 0x10;
TH1=(uchar)(HighTimer1Value>>8);
TL1=(uchar)HighTimer1Value;
ET1 = 0; //关闭T1中断
PCON = 0X00; //SMOD=0
TR1 = 1; //T1计时器开启
TR0 = 1; //T0计时器开启
EA = 1;
while(1)
{
if (flag_execute) //如果执行标识开启
{
execute(); //对命令进行执行
flag_execute = 0; //清除标志位
}
}
}
//初始化串口
void Init_Uart(void)
{
//T2用于波特率 9600
T2CON = 0x34;
TL2 = RCAP2L =(65536-(FOSC/32/BAUD)); //Set auto-reload vaule
TH2 = RCAP2H =(65536-(FOSC/32/BAUD)) >> 8;
TH2 = 0xFF;
TL2 = 0xC3;
TR2 = 1;
SCON = 0x50;
ES = 1;
}
void T0_Interrupt() interrupt 1 //生成PWM波
{
if(RightFrontPwm==0)
{
TH0=(uchar)(HighTimer0Value>>8);
TL0=(uchar)HighTimer0Value;
RightFrontPwm = 1;
RightBackPwm = 1;
}
else if(RightFrontPwm==1)
{
TH0=(uchar)(LowTimer0Value>>8);
TL0=(uchar)LowTimer0Value;
RightFrontPwm = 0;
RightBackPwm = 0;
}
}
void T1_Interrupt() interrupt 3 //生成PWM波
{
if(LeftFrontPwm==0)
{
TH1=(uchar)(HighTimer1Value>>8);
TL1=(uchar)HighTimer1Value;
LeftFrontPwm = 1;
LeftBackPwm = 1;
}
else if(LeftFrontPwm==1)
{
TH1=(uchar)(LowTimer1Value>>8);
TL1=(uchar)LowTimer1Value;
LeftFrontPwm = 0;
LeftBackPwm = 0;
}
}
//命令执行函数,配置dir口方向,并调用占空比计算函数
void execute(void)
{
bit flag_dir; //flag_move;
char y_spd = Receive[1];
if(y_spd==0)
{
P_OUT = 0XFF; //停止
// flag_move = 0;
ET0 = 0;
ET1 = 0; //关闭中断,禁止修改P1口
}
else
{
// flag_move = 1;
if(y_spd>0)
{
P_OUT = 0X00; //前进
flag_dir = 0;
}
else if(y_spd<0)
{
P_OUT = 0XFF; //后退
flag_dir = 1;
}
CountDutyCycle(flag_dir); //计算占空比,重载预装值
}
}
//占空比计算函数,并调用了预装值重载函数
void CountDutyCycle(bit dir)
{
char y_spd = Receive[1]; //前进分量,提供前进程度(-99~99)
char x_tur = Receive[2]; //转向分量,提供转向程度(-99~99)
char speed = Receive[3]; //基础速度,提供基础占空比(1~99)
speed = speed*abs(y_spd)/100; //为speed加入前进分量
RightFrontSpeed = speed;
LeftFrontSpeed = speed;
if(x_tur > 0) //向右转向
{
RightFrontSpeed = RightFrontSpeed*(100-abs(x_tur))/100;
}
else if(x_tur<0) //向左转向
{
LeftFrontSpeed = RightFrontSpeed*(100-abs(x_tur))/100;
}
if(dir==1) //后退则占空比取反
{
RightFrontSpeed = 100-RightFrontSpeed;
LeftFrontSpeed = 100-LeftFrontSpeed;
}
CtrlSpeed();
}
//控制小车速度的函数
//(通过控制定时器预装值,控制PWM的占空比)
//(无法控制PWM引脚的电平和T0计时器的开关)
void CtrlSpeed()
{
static uint freq = 100; //PWM频率为100Hz
HighTimer0Value=65535 - 11059200/12/freq*RightFrontSpeed/100;
LowTimer0Value=65535 - 11059200/12/freq*(100-RightFrontSpeed)/100;
HighTimer1Value=65535 - 11059200/12/freq*LeftFrontSpeed/100;
LowTimer1Value=65535 - 11059200/12/freq*(100-LeftFrontSpeed)/100;
ET0 = 1;
ET1 = 1;
}
void Bluetooth() interrupt 4
{
if(RI) //接收后服务程序
{
RI = 0;
if(receive(Receive,7)) //接收完一组数据
{
if(analysis(Receive,Transmit))//对接收数据进行分析并写入发送数组
{
flag_execute = 1;//插个旗,到主函数去执行算法
}
flag_TRX = 1;
TI = 1; //发送数组Transmit
}
}
if(TI) //发送后服务程序
{
TI = 0;
if(flag_TRX)
send(Transmit,7);
}
}
//接收数据分析函数,判断接收数据是否合法
//如果合法则将数据赋给发送数组,并在发送数组末尾写66
//如果有不合法数据,则将0赋给发送数组,并在发送数组末尾写0
//参数:接收数组,发送数组
//返回:0:有非法数据 1:无非法数据
char analysis(char *R,char *T)
{
char i,j,check;
bit flag = 0;
for(i=0;i<7;i++) //第七位是空字符
{
if((i==0)|(i==6))
{
*(T+i)=*(R+i); //复制包头 包尾
}
else if(i<4) //3位数据位
{
*(T+i)=*(R+i);
if((*(R+i)<-99)&(*(R+i)>99)) //读取Y轴速度/x轴差速
{
flag = 1; //错误标志 //Y轴速度/x轴差速正常,无动作
}
}
else if(i==4) //1 位状态位
{
if(flag==0)
{
*(T+i) = 1;
}
else
{
*(T+i) = 0;
}
}
else if(i==5) //1位校验位
{
check=0;
for(j=1;j<i;j++)
check+=*(T+j);
*(T+i)=check;
}
}
if(flag==0)
return 1;
else
flag=0;
return 0;
}
//串口接收函数
//参数:
//地址S,选择接收数组的首地址
//长度L,选择一次接收的字节个数
//返回值:
//未接收到足够的字节,返回0
//已接收到足够的字节,返回1
char receive(char *s,char num)
{
static char i=0;
*(s+i)=SBUF; //此处应添加包头检测语句
i++;
if(i==num)
{
i=0;
flag_A5 = 0;
return 1;
}
else
return 0;
}
//串口发送函数
//参数:
//地址S,选择要发送数组的首地址
void send(char *s,char num)
{
static char i=0;
if(i<num)
{
SBUF=*(s+i);
i++;
}
else //当一个字符串发送完毕后会进入这里
{
flag_TRX = 0;
i=0;
}
}