打印

第一届21ic社区DIY开源活动----图解遥控解码模块的软件设计

[复制链接]
楼主: Cortex-M0
手机看帖
扫描二维码
随时随地手机跟帖
21
zwy65182899| | 2011-8-18 09:35 | 只看该作者 回帖奖励 |倒序浏览
以前都是看的理论,,这次实际的,,真的不错啊

使用特权

评论回复
22
hwk612167| | 2011-8-18 09:36 | 只看该作者
低0.48ms?按ROSC=4.7M,fosc=4.7/(2*16),T_SHORT = 4fosc 大约为0.59ms

使用特权

评论回复
23
kfzy6| | 2011-8-18 10:21 | 只看该作者
辛苦了

使用特权

评论回复
24
雨下枫| | 2011-8-18 10:35 | 只看该作者
mark

使用特权

评论回复
25
Cortex-M0|  楼主 | 2011-8-18 16:50 | 只看该作者
低0.48ms?按ROSC=4.7M,fosc=4.7/(2*16),T_SHORT = 4fosc 大约为0.59ms
hwk612167 发表于 2011-8-18 09:36



理论计算都有误差的,另外,每个遥控器个体也有误差,不过,生产商会控制在一定范围内,窄脉冲宽度0.48ms,宽脉冲宽度1.6ms,  这一参数是 wzr200408小盆友提供的,  他条件好设备全,  俺没这条件也没这设备,  俺用0.1ms定时采样,  发现窄脉冲计数值为0x05,宽脉冲计数值为0x0f-0x10,  符合 wzr200408小盆友提供的这一技术参数,  再次感谢 wzr200408小盆友。

使用特权

评论回复
26
hwk612167| | 2011-8-19 00:40 | 只看该作者
理论计算都有误差的,另外,每个遥控器个体也有误差,不过,生产商会控制在一定范围内,窄脉冲宽度0.48ms,宽脉冲宽度1.6ms,  这一参数是 wzr200408小盆友提供的,  他条件好设备全,  俺没这条件也没这设备,  俺用 ...
Cortex-M0 发表于 2011-8-18 16:50

回来测了下,窄0.52,宽1.57 SYNC低16.24,差不多:)

使用特权

评论回复
27
Cortex-M0|  楼主 | 2011-8-19 05:55 | 只看该作者
谢谢LS的测试。

这种简易RC振荡器,随着环境温度等不同,有 10%的频率误差,也很正常。

作为一个优秀的设计,频率误差 20%都能正确解码!

因此,这点个体的差异不足为奇,只要软件解码做的足够好,再加上单片机SH88F2051/4051片内RC振荡器的温漂,都不会影响到最终解码的正确性!

使用特权

评论回复
28
wzr200408| | 2011-8-19 08:40 | 只看该作者
小弟不才,有好设备帮助,但是改了几次都没有解码成功,深表惭愧~~

使用特权

评论回复
29
好人不坏| | 2011-8-19 10:38 | 只看该作者
呵呵,顶正纳闷呢焊完板子,多出个小板是干什么用的

使用特权

评论回复
30
Cortex-M0|  楼主 | 2011-8-19 19:04 | 只看该作者
什么小板?

无图无真相~~~

使用特权

评论回复
31
靠双手奋斗| | 2011-8-19 21:03 | 只看该作者
很好啊!!

使用特权

评论回复
32
好人不坏| | 2011-8-20 10:41 | 只看该作者
315MHZ超再生接收模块
呵呵,

使用特权

评论回复
33
Cortex-M0|  楼主 | 2011-8-20 11:39 | 只看该作者
:L

使用特权

评论回复
34
Cortex-M0|  楼主 | 2011-8-20 11:40 | 只看该作者
多出来小板送俺多好啊~~~ :P

使用特权

评论回复
35
好人不坏| | 2011-8-21 08:06 | 只看该作者
告诉我你的地址,给你邮,我留着没什么用。

使用特权

评论回复
36
wzr200408| | 2011-8-21 08:38 | 只看该作者
:L 应该不是多出来的吧?我也有一个

使用特权

评论回复
37
Cortex-M0|  楼主 | 2011-8-21 10:50 | 只看该作者
315MHZ超再生接收模块
呵呵,
好人不坏 发表于 2011-8-20 10:41


少了315MHZ超再生接收模块,如何玩遥控?

呵呵~~~   :L

使用特权

评论回复
38
Cortex-M0|  楼主 | 2011-8-22 10:23 | 只看该作者
/*----------------------------------------------------------*/
/*                                                          */
/*     中颖SH88F2051/SH88F4051无线遥控接收模拟解码程序      */
/*                                                          */
/*   功能 :使用中断方式动态扫描接收信号,软件模拟解码      */
/*                                                          */
/*                                                          */
/*  入口 :指定 P3.0 为无线遥控接收信号输入                */
/*  出口 :键值存 Key 中,A键=1, B键=2, C键=3, D键=4       */
/*                                                          */
/*   资源 :占用 T1 定时中断                                */
/*                                                          */
/*                                                          */
/*   CPU  : SH88F2051/SH88F4051                             */
/*   晶振 : 片内16.6MHz高精度RC振荡器                       */
/*   作者 : 许意义                                          */  
/*   ID   : LAOXU                                           */  
/*   版本 : V1.0                                            */
/*   日期 : 2011.8.14                                       */
/*                                                          */
/*----------------------------------------------------------*/

// 引导码如下
//
// H      
//   |                    |  引导码,大干10ms低电平
// L .--------------------.   
//
//
//  A1 A0 和悬空码, 1 码, 0 码的关系如下
//  宽电平约1ms,窄电平约0.4ms
//
// H  -   ----   
//   | |  |    | |  悬空码,0.48ms高电平,1.6ms低电平,1.6ms高电平,0.48ms低电平
// L .  ----.     - .      8位内编码 0b00110110 , 0x36
//
//
// H  ----   ----   
//   |    | |    | |  1 码 ,1.6ms高电平,0.48ms低电平,1.6ms高电平,0.48ms低电平
// L .     -.     - .         8位内编码 0b01100110 , 0x66
//
//
// H  -   -   
//   | |  | | |  0 码 ,0.48ms高电平,1.6ms低电平,0.48ms高电平,1.6ms低电平
// L .  ----.  ----.      8位内编码 0b00110011 , 0x33
//
//   A1  A0   代码
//    0   0   0 码
//    0   1   悬空
//    1   0   错误
//    1   1   1 码
//
//  共计12位编码,前面8位地址编码,后面4位数据编码,每个码有三态,悬空码, 1 码, 0 码,
//  高在先低在后。
//
//  A键编码值:0b00000000 01010101 01010101 11000000 , 0x005555c0
//  B键编码值:0b00000000 01010101 01010101 00110000 , 0x00555530
//  C键编码值:0b00000000 01010101 01010101 00001100 , 0x0055550c
//  D键编码值:0b00000000 01010101 01010101 00000011 , 0x00555503
//
//  当按住无线遥控器 PT2262 的按键不放的时候, PT2262 会把编码不断的送出

#include <DEFINE51.H>
#include <SH88F4051.H>
#define Narrow_TIME  8   // 窄电平约0.48ms,判断对比时间常数
#define Wide_TIME    20   // 宽电平约1.6ms,判断对比时间常数
#define Start_TIME   50   // 宽电平约10ms,判断检测同步头, 比对时间常数
sbit RX = P3^0;           // 无线遥控接收输入端口
volatile unsigned char Key=0;    // 键值输入,A键=1,B键=2,C键=3,D键=4
// 延时100us, 定时器T1,8位自动重装入常数据138,使用片内16.6MHz片内RC振荡器
void interrupt_time1(void) interrupt 3 using 3
{ static unsigned char Time_Count=0;  // 采集接收信号时间计数器
  static unsigned char Counter=0;   // 采集接收信号时间值
  static  bit  RX_IN;      // RX输入信号
  static  bit  RX_bak=0;           // RX信号备份
  static  bit  RX_Level=0;      // 输入RX电平信号暂存
  static  bit  RX_F1=0;                  // RX信号改变标记
  static unsigned char temp_bit=0;       // 1位编码缓冲器
  static unsigned char temp_bit_Count=0; // 1位编码缓冲计数器
  static unsigned long LongData=0;   // 12位编码值
  static unsigned char Count_p=0;   // 12位编码计数器
  static unsigned char Add_p=0;       // 采集接收信号步序计数器
  RX_IN = RX;                      // 读入RX输入信号
  if(Add_p==0)               // 步序0 执行
    { if(!RX_IN)
     { Time_Count++;              // 重新检测同步头
     }
   else      
        { Time_Count = 0;
     }
   if (Time_Count >= Start_TIME)           // 采集接收信号时间计数器>Start_TIME,采集值为引导码
     { Add_p = 1;                       // 指定步序1
  }
}
  else if(Add_p==1)       // 步序1 执行
{ if(RX_IN)
     { temp_bit_Count = 0;                    // 初始化temp_bit_Count计数器
    temp_bit = 0;                       // 初始化temp_bit值
          Time_Count = 0;                       // 初始化采集接收信号时间计数器
    Count_p = 0;                       // 初始化12位编码计数值
    LongData = 0;                       // 初始化12位编码值
    RX_bak = 1;
    RX_F1 = 0;
    RX_Level = 1;
    Add_p = 2;                       // 指定步序2
     }
}
  else if(Add_p==2)        // 步序2 执行
{ if((RX_IN) && (RX_bak))               // RX信号两次是否为高
        { if (RX_Level)
      { Time_Count++;                // 如果RX_Level为1,采集接收信号时间计数器加1
   }
    else
      { RX_Level = 1;                      // RX信号电平方向记录
     if(Time_Count!=0)
       { RX_F1 = 1;             // RX信号改变,采集接收信号标记RX_F1置1
            Counter = Time_Count;          // 记录采集接收信号-->Counter
            Time_Count = 0;           // 采集接收信号时间计数器清0
       }
   }
     }
      else if(!RX_IN)
        { if(!RX_Level)
      { Time_Count++;                   // 如果RX_Level为0,采集接收信号时间计数器加1
   }
    else
      { RX_Level = 0;                   // RX信号电平方向记录
     if(Time_Count!=0)
       { RX_F1 = 1;             // RX信号改变,采集接收信号标记RX_F1置1
            Counter = Time_Count;          // 记录采集接收信号-->Counter
            Time_Count = 0;           // 采集接收信号时间计数器清0
       }
   }
        }
      else if((RX_IN) && (!RX_bak))
        { if(RX_Level)
      { Time_Count++;                   // 如果RX_Level为1,采集接收信号时间计数器加1
   }
    else
      { RX_Level = 1;                   // RX信号电平方向记录
     if(Time_Count!=0)
       { RX_F1 = 1;             // RX信号改变,采集接收信号标记RX_F1置1
            Counter = Time_Count;          // 记录采集接收信号-->Counter
            Time_Count = 0;           // 采集接收信号时间计数器清0
       }
   }
        }
   RX_bak = RX_IN;
      if(RX_F1)
     { temp_bit <<= 2;
    if(!RX_Level)             // 采集到高电平输入判断
         { if(Counter<Narrow_TIME)          // 采集接收信号时间计数器<Narrow_TIME,采集值为0.48ms
             { temp_bit |= Bin(00000000);  // 记录在temp_bit最后2bit位中,编码0b00
          }
           else if(Counter<Wide_TIME)      // 采集接收信号时间计数器<Wide_TIME,并且>=Narrow_TIME,采集值为1.6ms
             { temp_bit |= Bin(00000001);  // 记录在temp_bit最后2bit位中,编码0b01
          }
           else           // 采集接收信号时间计数器>=Wide_TIME,按键断开
             { Add_p = 0;               // 出错, 指定步序0
          }
         }
          else                             // 采集到低电平输入判断
         { if(Counter<Narrow_TIME)          // 采集接收信号时间计数器<Narrow_TIME,采集值为0.48ms
             { temp_bit |= Bin(00000010);  // 记录在temp_bit最后2bit位中,编码0b10
          }
           else if(Counter<Wide_TIME)      // 采集接收信号时间计数器<Wide_TIME,并且>=Narrow_TIME,采集值为1.6ms
             { temp_bit |= Bin(00000011);  // 记录在temp_bit最后2bit位中,编码0b11
          }
           else                               // 采集接收信号时间计数器>=Wide_TIME,按键断开
             { Add_p = 0;               // 出错, 指定步序0
          }
            }
    temp_bit_Count++;                      // temp_bit_Count计数器加1
       RX_F1 = 0;                 // 成功处理一次采集电平变化,清采集接收信号标记RX_F1
       if(temp_bit_Count>=4)                  // 如果采集当前电平变化达到4次,处理当次1bit接收码
         { LongData <<= 2;
           if(temp_bit==Bin(00110110))      // 判是否 悬空码
             { LongData |= Bin(00000001);     // 悬空码,记录在LongData最后2bit
            }
           else if(temp_bit==Bin(01100110))   // 判是否 1 码
             { LongData |= Bin(00000011);  // 1 码,记录在LongData最后2bit
            }
           else if(temp_bit==Bin(00110011))   // 判是否 0 码
             { LongData |= Bin(00000000);     // 0 码,记录在LongData最后2bit
            }
           else                            // 都不是,错误
             { //LongData |= Bin(00000010);  // 错误,记录在LongData最后2bit
               Add_p = 0;               // 出错, 指定步序0
            }
        Count_p++;          // 12位编码计数器加1
        temp_bit_Count = 0;     // 初始化temp_bit_Count计数器
        temp_bit = 0;          // 初始化temp_bit值
            }            
     }
      else                    // 采集接收信号标记 RX_F1 != 1
        { if(Count_p>=12)                      // 判是否接收完12bit编码
         { if(LongData==0x005555c0)    // 解码A键
             { Key = 1;                 // 置A键键值
            }
           else if(LongData==0x00555530)   // 解码B键
             { Key = 2;                 // 置B键键值
            }
           else if(LongData==0x0055550c)   // 解码C键
             { Key = 3;                 // 置C键键值
            }           
           else if(LongData==0x00555503)   // 解码D键
             { Key = 4;                 // 置D键键值
            }
           else ;  
     Add_p = 0;                // 12bit编码接收完,置步序0  
            }
        }
}
}

使用特权

评论回复
39
Cortex-M0|  楼主 | 2011-8-22 10:24 | 只看该作者
/*----------------------------------------------------------*/
/*                                                          */
/*     中颖SH88F2051/SH88F4051无线遥控智能小车DEMO程序      */
/*                                                          */
/*   功能 :使用中断方式动态接收遥控信号,软件模拟解码,     */
/*          硬件 PWM 控制小车运行。                         */
/*                                                          */
/*          A键:小车前进时加速,后退时减速,共有5挡速度    */
/*               供调节,2挡快慢正转,2挡快慢反转,1挡      */
/*               停止运转。                                 */
/*                                                          */
/*          B键:功能同上,小车前进时减速,后退时加速,     */
/*               共有5挡速度供调节,2挡快慢正转,2挡        */
/*               快慢反转,1挡停止运转。                    */
/*                                                          */
/*          C键:在运行时,按下小车左转,松开恢复正常运     */
/*               行,小车停止时无效。                       */
/*                                                          */
/*          D键:在运行时,按下小车右转,松开恢复正常运     */
/*               行,小车停止时无效。                       */
/*                                                          */
/*                                                          */
/*  入口 :指定 P3.0 为无线遥控接收信号输入                */
/*  出口 :键值存 Key 中,A键=1, B键=2, C键=3, D键=4       */
/*                                                          */
/*   资源 :占用 T0 定时中断, 作为20ms定时采样              */
/*          占用 PWM 中断, 刷新 PWM 输出                    */
/*          占用 INT0 中断, 作为电机运转方向动态切换        */
/*                                                          */
/*                                                          */
/*   CPU  : SH88F2051/SH88F4051                             */
/*   晶振 : 片内16.6MHz高精度RC振荡器                       */
/*   作者 : 许意义                                          */  
/*   ID   : LAOXU                                           */  
/*   版本 : V1.0                                            */
/*   日期 : 2011.8.21                                       */
/*                                                          */
/*----------------------------------------------------------*/

// 关于硬件 PWM 驱动直流电机 DEMO 示范程序声明:  
//
// 程序编写的比较烦琐, 可精简很多字节,但没有进行优化,本意是用该程序构架
// 扩充成10位硬件 PWM 输出,实现高精度的动态 PWM 电机驱动实时控制,以适应
// 21ic《两轮自平衡小车DIY》的实际需求。  
//

#include <DEFINE51.H>
#include <SH88F4051.H>
#define  Tsmp_T0  0x10000-27667   // 20ms   T0 16位向上计数计数器/定时器, 重装入定时常数
#define  Tsmp_T1  0x100-138      // 100us  T1 8位自动重装入定时常数
extern  unsigned char Key;         // 外部键值输入,A键=1,B键=2,C键=3,D键=4
sbit MA = P4^0;   // H输出高,L输出低
sbit MB = P4^1;   // H输出高,L输出低
sbit MC = P4^2;   // H输出高,L输出低
sbit MD = P3^7;   // H输出高,L输出低
//sbit C1 = P3^5;   // H输出有效,L输出关闭
//sbit C2 = P3^2;   // H输出有效,L输出关闭
#define Left_Motor_Forward()    {MA = 1; MB = 0;} // 左电机正转
#define Left_Motor_Reverse()    {MA = 0; MB = 1;} // 左电机反转
#define Right_Motor_Forward()   {MC = 0; MD = 1;} // 右电机正转
#define Right_Motor_Reverse()   {MC = 1; MD = 0;} // 右电机反转
#define Left_Motor_Stop()       {MA = 0; MB = 0;} // 左电机停止
#define Right_Motor_Stop()      {MC = 0; MD = 0;} // 右电机停止
#define Key_Stop_Time           10       // 键盘松开延时确定时间,20ms的倍数  
bit  Left_Motor_Flag;               // 左电机运行停止标记,0-->运行, 1-->停止
bit  Right_Motor_Flag;              // 右电机运行停止标记,0-->运行, 1-->停止
volatile signed char PWM_Vx=0;  // PWM 输出缓冲区
unsigned char code Char_PWM[]={0xf0, 0xb0, 0, 0xb0, 0xf0};     // 5挡 PWM 输出速度值
void interrupt_time0(void) interrupt 1 using 2     // 20ms定时中断
{ static unsigned char Time0_Count=0;
  static bit Key_Flag=0;
  TL0    = LO_BYTE(Tsmp_T0);     // 装入T0定时器的初值, 延时20ms
  TH0    = HI_BYTE(Tsmp_T0);     // T0 16位向上计数计数器/定时器, 使用片内16.6MHz片内RC振荡器, 12分频
  Time0_Count++;
  if((Key == 1) && (!Key_Flag))
{ if(++PWM_Vx >= 3)
  { PWM_Vx = 2;        // 正转加速限制
  }
   Time0_Count = 0;
      Key_Flag = 1;
}
  else if((Key == 2) && (!Key_Flag))
{ if(--PWM_Vx <= (-3))
  { PWM_Vx = (-2);       // 反转加速限制
  }
   Time0_Count = 0;
   Key_Flag = 1;
}
  else if((Key == 3) && (PWM_Vx != 0))
{ Left_Motor_Flag = 0;                 // 左电机运行
   Right_Motor_Flag = 1;          // 右电机停止运行
   Time0_Count = 0;
   Key_Flag = 1;
}         
  else if((Key == 4) && (PWM_Vx != 0))
{ Left_Motor_Flag = 1;                 // 左电机停止运行
   Right_Motor_Flag = 0;          // 右电机运行
   Time0_Count = 0;
   Key_Flag = 1;
}
  else
    { if(Time0_Count>=Key_Stop_Time)
     { Left_Motor_Flag = 0;                 // 左电机运行
       Right_Motor_Flag = 0;          // 右电机运行
          Time0_Count = 0;
       Key_Flag = 0;
     }
    }
  Key = 0;
}
void car_PWM_int(void) interrupt 12  using 1  
{ PWMD = Char_PWM[PWM_Vx+2];         // PWM输出实时更新
  PWMCON &= Bin(11111101);      // 清除 PWM 周期计数器溢出标志 PWMIF
}     
void  car_motor_dir(void) interrupt 0  using 1
{ if(PWM_Vx > 0)     // 如果 PWM_Vx值 > 0, 电机正转
{ if(Left_Motor_Flag == 0)         
     Left_Motor_Forward()       // 左电机标记值=0, -->左电机正转
   else
  Left_Motor_Stop()      // 左电机标记值=1, -->左电机停止
      if(Right_Motor_Flag == 0)           
     Right_Motor_Forward()      // 右电机标记值=0, -->右电机正转
   else
     Right_Motor_Stop()       // 右电机标记值=1, -->右电机停止
}
  else if(PWM_Vx < 0)    // 如果 PWM_Vx值 < 0, 电机反转
{ if(Left_Motor_Flag == 0)         
     Left_Motor_Reverse()        // 左电机标记值=0, -->左电机反转
   else
  Left_Motor_Stop()      // 左电机标记值=1, -->左电机停止
      if(Right_Motor_Flag == 0)         
     Right_Motor_Reverse()       // 右电机标记值=0, -->右电机反转
   else
     Right_Motor_Stop()       // 右电机标记值=1, -->右电机停止
}
  else         // 如果 PWM_Vx值 = 0, 电机停止   
{ Left_Motor_Stop();      //  -->左电机停止
   Right_Motor_Stop();      //  -->右电机停止
}         
}     
void init(void)
{
  P1   = Bin(11111111);      
  P3   = Bin(01011011);        // 置 MA,MB,MC,MD,C1,C2 输出为L,关闭L293输出   
  P4   = Bin(00000000);      
//-----------------------------------
// PxM0n  PxM1n    说 明
//   0      0       准双向
//   0      1       推挽输出
//   1      0       输入(高阻)
//   1      1       开漏输出
  P1M0 = Bin(00000000);     
  P1M1 = Bin(00000000);  
  P3M0 = Bin(00000000);        // 设置 MA,MB,MC,MD,C1为推挽输出, C2为准双向   
  P3M1 = Bin(10100000);   
  P4M0 = Bin(00000000);      
  P4M1 = Bin(00000111);     
  P3  |= Bin(00000100);        // 置C2(INT0)为H,以便使用INT0下降沿中断触发
  CLKCON = Bin(00001100);      // Fsys = Foscs,使用片内16.6MHz片内RC振荡器   
  TCON1 = Bin(00000000);    // 设置系统时钟12分频作为T0的时钟源,系统时钟12分频作为T1的时钟源
  TMOD  = Bin(00100001);       // 设定T0的工作模式为1, 16位向上计数计数器/定时器,
                               // 设定T1的工作模式为2,8位自动重载向上计数计数器/定时器
  TL0    = LO_BYTE(Tsmp_T0);   // 装入T0定时器的初值, 延时20ms
  TH0    = HI_BYTE(Tsmp_T0);   // T0 16位向上计数计数器/定时器, 使用片内16.6MHz片内RC振荡器, 12分频
  TL1    = 138; //Tsmp_T1;            // 装入T1定时器的初值, 延时100us
  TH1    = 138; //Tsmp_T1;            // 8位自动重装入, 使用片内16.6MHz片内RC振荡器, 12分频
  PWMD   = 0x00;
  PWMP   = 0xff;
  PWMCON = Bin(10110001);      // 设置 PWM 输出
  IT0    = 1;                  // INT0 下降沿触发方式
  PT1L   = 1;       // 设置 T1定时器为高级中断
  PX0L   = 1;       // 设置 INT0为高级中断
  IPL1 |= Bin(00100000);    // 设置 PPWML为高级中断
  IEN1  |= Bin(00100000);      // PWM 允许中断
  EX0    = 1;                  // INT0 充许中断
  ET0    = 1;                  // 定时器0允许中断
  ET1    = 1;                  // 定时器1允许中断
  TR0    = 1;       // 启动定时器0
  TR1    = 1;                  // 启动定时器1
  EA     = 1;                  // 开中断
}
void main(void)
{ init();        // 中断初始化
  while(1){ ; }
}

使用特权

评论回复
40
Cortex-M0|  楼主 | 2011-8-22 10:25 | 只看该作者
DEMO示范程序打包:

智能循迹小车.rar (8.5 KB)

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
zxcscm + 1
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则