注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一车,一房,一个温暖家

10万左右的车,80平方的房子,这是我奋斗的暖暖的家

 
 
 

日志

 
 

引用 上位机与单片机的互动-协议的改变(五)   

2015-03-22 14:54:04|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

今天是3月27号,在经历种种困难后终于把上位机驱动小车给写出来了,其功能为:

上位机输入PWM值及电机转向,单片机收到相应数据后进行解码来按照相应的转向和PWM值进行运动。

虽然功能看上去简单,但是刚接触写上位机的我来说很多细节上都出现了问题,有些小问题牵引着大问题,但最后我还是弄出来了。其中协议跟以前比起来有较大差异,以下是VB的新协议:

二、上位机

(MSB)结束(0x50)、数据域(右电机PWM(1字节),左电机PWM(1字节),右电机方向(1字节),左电机方向(1)字节)字节、命令(n字节)、地址(1字节)、校验码(2字节)LSB

基本与单片机相同。

例:0x5080700x200x020x900x100xbd(高位)0xc0(低位)

0xbd0xc0CRC

0x10:单片机地址[2]

0x90:驱动电机命令[3]

0x02:左侧电机方向(0x02正转,0x04反转,0x00刹车,0x06惰行)[4]

0x20:右侧电机方向(0x20正转,0x40反转,0x00刹车,0x60惰行)[5]

70:左侧电机PWM[6]

80:右侧电机PWM[7]

0x50:告诉单片机数据已经传输完毕了[8]

上位机地址: 0x01

上位机命令集:

      0x20 – 左侧电机正转,数据域为PWM

      0x91 – 左侧电机反转,数据域为PWM

      0x92 – 左侧电机刹车,数据域为0

      0x93 – 左侧电机惰性,数据域为0

 

    0x80 – 左侧电机正转,数据域为PWM

      0x81 – 左侧电机反转,数据域为PWM

      0x82 – 左侧电机刹车,数据域为0

      0x83 – 左侧电机惰性,数据域为0

 

由于还没用到单片机向上位机发送数据帧,所以单片机协议先不管,以下是C最新代码:

(新代码优化了单片机计算CRC的负担,使用了联合体来缓解计算压力)

#include<STC12C5410AD.h>
#include<CRC16.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long

/*电机状态定义*/
#define  motorDrv P2   //电机驱动IO口
//左侧电机定义
#define  ML_FORWARD 0x02  //电机正转
#define  ML_BACK  0x04  //电机反转
#define  ML_FLOAT 0x06  //电机惰行, 此时停止PWM输出
#define  ML_BRAKE 0x00  //电机刹车
#define  ML_REMOVE 0xF8  //清除左侧电机状态
//右侧电机定义
#define  MR_FORWARD 0x20  //电机正转
#define  MR_BACK  0x40  //电机反转
#define  MR_FLOAT 0x60  //电机惰行, 此时停止PWM输出
#define  MR_BRAKE 0x00  //电机刹车
#define  MR_REMOVE 0x8F  //清除右电机状态

//接收数据定义
uchar ga_ucRcvBuf[4]; //接收数据寄存器
uchar gc_uCount;  //接收计数器
uchar gc_ucNum;   //接收计数器,累积数据个数
bit g_bRcvCount;  //接收完毕标志
bit g_bCheckRcvData; //数据正确性标志

/********************************************/
/* 名称:init_SIO       */
/* 用途:初始化串口,       */
/* 参数: 波特率 , 模式固定为:1     */
/*   1 START 8 DATA 1 STOP     */
/********************************************/
uchar text;
void init_SIO()
{
 TMOD = TMOD|0x20|0x00;   //设定T1为定时器模式
 PCON = 0;
 AUXR = AUXR|0x00;   //Set 12T
 SCON = SCON|0x40|0x10;  
 TH1 = 0xFA;
 TL1 = 0xFA;
 TR1 = 1;
 EA = 1;
 ES = 1;

}

void delay_1ms(uchar a)
{
 uchar x,y;
 for(x = a;x > 0;x--)
 {
  for(y = 220;y > 0;y--);
 }
}


/********************************************************************
* 名称 : checkData()
* 功能 : 检测接收到的数据是否正确?
* 输入 : 无
* 输出 : g_bCheckRcvData(返回1则为数据正确)
*********************************************************************/
/*
bit checkData(void)
{
 ulong g_ulCrcLow;   //存储计算后的低位CRC
 ulong g_ulCrcHigh;   //存储计算后的高位CRC
 uchar g_ucRcvCrcLow;  //暂储接收到的低位CRC
 uchar g_ucRcvCrcHigh;  //暂储接收到的高位CRC
 uchar g_uCrcHigh;   //将计算后的高位CRC转换成uchar类型
 if(ga_ucRcvBuf[2] == 0x10)
 {
  g_ucRcvCrcLow = ga_ucRcvBuf[0];
  g_ucRcvCrcHigh = ga_ucRcvBuf[1];
  ga_ucRcvBuf[0] = 0;
  ga_ucRcvBuf[1] = 0;
  g_ulCrcLow = cal_crc(ga_ucRcvBuf,5);
  g_ulCrcLow = g_ulCrcLow & 0xFF;  //舍去低位CRC以外的其他位
  if(g_ucRcvCrcLow == g_ulCrcLow)
  {
   g_ulCrcHigh = cal_crc(ga_ucRcvBuf,5);
   g_ulCrcHigh = g_ulCrcHigh >> 8;
   g_uCrcHigh = g_ulCrcHigh;
   if(g_ucRcvCrcHigh == g_uCrcHigh)
   { 
   //这里可以处理校验成功后的功能
   //这里为单片机接收到正确指令后给上位机回应
    g_bCheckRcvData = 1; //表明接收数据正确
   }
  }else
  {g_bCheckRcvData = 0;}
 }
 return g_bCheckRcvData;
}
*/

/********************************************************************
* 名称 : checkData()更新版
* 功能 : 检测接收到的数据是否正确?
* 输入 : 无
* 输出 : g_bCheckRcvData(返回1则为数据正确)
*********************************************************************/
bit checkData(void)
{
 union  //定义一个联合体
 {
  uint allCrc;
  uchar b[2]; //b[0]为高位crc,b[1]为低位crc
 }crcBuf;
 ulong crcSav;    //存储计算后的CRC
 uchar g_ucRcvCrcLow;  //暂储接收到的低位CRC
 uchar g_ucRcvCrcHigh;  //暂储接收到的高位CRC
 if(ga_ucRcvBuf[2] == 0x10)
 {
  g_ucRcvCrcLow = ga_ucRcvBuf[0];
  g_ucRcvCrcHigh = ga_ucRcvBuf[1];
  ga_ucRcvBuf[0] = 0;
  ga_ucRcvBuf[1] = 0;
  crcSav = cal_crc(ga_ucRcvBuf,gc_ucNum);
  crcBuf.allCrc = (uint)crcSav;
  if(g_ucRcvCrcLow == crcBuf.b[1])  //比较低位CRC
  {
   if(g_ucRcvCrcHigh == crcBuf.b[0]) //比较高位CRC
   { 
   //这里可以处理校验成功后的功能
   //这里为单片机接收到正确指令后给上位机回应
    g_bCheckRcvData = 1; //表明接收数据正确
   }
  }else
  {
   g_bCheckRcvData = 0;
  }
 }
 gc_ucNum = 0;
 return g_bCheckRcvData;
}

/*PWM输出参数设置*/
void pwmOutput(uchar mModeAdd,uchar cuCycle) 
{
 uchar ucCexCl,ucCexCh;
 ucCexCh = 255 - (cuCycle * 2.55);  //根据占空比计算比较值
 //这里是CL>=CCAPnL时PWM输出为1,所以越低的数据PWM越高
 ucCexCl = ucCexCh;
 SBUF = ucCexCl;
 switch(mModeAdd)       //检测模块地址
 {
  case 0:       
  {
   CCAPM0 = 0x42;
   CCAP0L = ucCexCl;
   CCAP0H = ucCexCh;
   break;
  }
  case 1:
  {
   CCAPM1 = 0x42;
   CCAP1L = ucCexCl;
   CCAP1H = ucCexCh;
   break;
  }
  case 2:
  {
   CCAPM2 = 0x42;
   CCAP2L = ucCexCl;
   CCAP2H = ucCexCh;
   break;
  }
  case 3:
  {
   CCAPM3 = 0x42;
   CCAP3L = ucCexCl;
   CCAP3H = ucCexCh;
   break;
  }
  default: break;
 } 
}

/*    给2侧电机运行方向  */
void motorDrive(uchar lMotordt,uchar rMotordt)  
{
 motorDrv = 0x00;   //复位P2口为0000 0000
 motorDrv |= lMotordt;
 motorDrv |= rMotordt;
}

/********************************************************************
* 名称 : Com_Int()
* 功能 : 串口中断子函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void comInt() interrupt 4 using 3
{
 EA = 0;
 if(RI == 1)   //当硬件接收到一个数据时,RI会置位
 {
  RI = 0;
  /***************************成功
  ga_ucRcvBuf[0] = SBUF;
  Delay_1ms(1);
  ************************/
  ga_ucRcvBuf[gc_uCount] = SBUF;
  gc_uCount ++;
  if(SBUF == 0x50)
  {
   gc_ucNum = gc_uCount;
   gc_uCount = 0;
   g_bRcvCount = 1;
  }
  //gc_uNum ++;
 }
 if(TI == 1)
 {
  TI = 0;
 }
 EA = 1;
}

/*PCA中断*/
void PCATimer() interrupt 6 using 2   
{
 if(CCF0 == 1)
 {
  CCF0 = 0;
 }
 if(CCF1 == 1)
 {
  CCF1 = 0;
 }
}

void main()
{
 gc_uCount = 0;
 g_bRcvCount = 0;   //接收数据计数器
 text = 0;
 P2M0 = 0x00;      //将P20,P24设置成强推挽输出
 P2M1 = 0x01;
 CMOD |= 0x02;      ////PCA模式寄存器,Fosc/2
 CL = 0x00;
 CH = 0x00;
 init_SIO();   //波特率为9600
 EPCA_LVD = 1;  //开PCA中断
 while(1)
 {
  if(g_bRcvCount == 1)
  {
   g_bRcvCount = 0;
   EA = 0;
   if(checkData())    //数据正确性检测
   {
    g_bCheckRcvData = 0;  //将数据判断器复位
    motorDrive(ga_ucRcvBuf[4],ga_ucRcvBuf[5]);
    pwmOutput(2,ga_ucRcvBuf[6]);
    pwmOutput(3,ga_ucRcvBuf[7]);
    CR = 1;
   }
   EA = 1;
  }
  delay_1ms(1);
 }
}

以下是VB修改部分代码:

Private Sub Command3_Click()        '输出电机的PWM与方向命令
    Dim lSende(0 To 8) As Byte
    Dim rSende(0 To 4) As Byte
    Dim g_lcrcLow As Byte
    Dim g_lcrcHigh As Byte
    Dim lmotordp As Byte
    Dim rMotordp As Byte
    Dim lpwm As Byte
    Dim rpwm As Byte
    'left motor
    If (Combo2(0).Text = "正转") Then
        lmotordp = &H2
    ElseIf (Combo2(0).Text = "反转") Then
        lmotordp = &H4
    ElseIf (Combo2(0).Text = "刹车") Then
        lmotordp = &H0
    ElseIf (Combo2(0).Text = "惰行") Then
        lmotordp = &H6
    End If
    'right motor
       If (Combo2(1).Text = "正转") Then
        rMotordp = &H20
    ElseIf (Combo2(1).Text = "反转") Then
        rMotordp = &H40
    ElseIf (Combo2(1).Text = "刹车") Then
        rMotordp = &H0
    ElseIf (Combo2(1).Text = "惰行") Then
        rMotordp = &H60
    End If
    lSende(0) = &H0
    lSende(1) = &H0
    lSende(2) = &H10
    lSende(3) = &H90
    lSende(4) = lmotordp
    lSende(5) = rMotordp
    'left motor PWM
    lpwm = Val(Text1(0).Text)
    If (lpwm <= 0) Then
        lpwm = 0
    ElseIf (lpwm >= 100) Then
        lpwm = 100
    End If
    'right motor PWM
    rpwm = Val(Text1(1).Text)
    If (rpwm <= 0) Then
        rpwm = 0
    ElseIf (rpwm >= 100) Then
        rpwm = 100
    End If
    lSende(6) = lpwm
    lSende(7) = rpwm
    lSende(8) = &H50
    'sende(4) = 10
    g_lcrcLow = bCRC(lSende, 9) And &HFF
    g_lcrcHigh = bCRC(lSende, 9) \ 256
    lSende(1) = g_lcrcHigh
    lSende(0) = g_lcrcLow
   ' Print "HIGH=" & g_lcrcLow
    ' Print "HIGH=" & sende(4)
     MSComm1.Output = lSende
'right motor
End Sub

虽然代码写的有点烂,但功能究竟是实现了,代码的完善等有时间了再改吧。

  评论这张
 
阅读(3)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018