tbb1 发表于 2013-4-7 21:48

51单片机驱动单轴电跟初步成功,有问题请教大神们

精确计算后,得到的脉冲数据可以做到5毫米目镜200倍下亮星10分钟在视野内。
但是距离商用还有很大改进空间。
现在是用定时器1作为脉冲输出的。
定时器0和外部中断用于红外遥控器的控制输入,希望做到可以遥控启动停止、快进、快退。
DEBUG下定时器0也启动了,但是无法接收遥控器信号或是接收了没有处理。
在编程上,同时使用两个定时器和3个中断,如何安排逻辑呢?

下面的程序(节选)是否有问题?
void Ircontrol(void)//红外码值处理函数
{
unsigned char l,m;
if(irok)                        //如果接收好了进行红外处理
   {   
    Ircordpro();
   if (Mode==1) //单倍模式
      {
   SingleModel: // 单倍电跟状态
   if (IRcord==0x44)   //如果按下启动键,则启动定时器1,脉冲输出开始,步进电机运行
   {
   Direct=0;
   Status=~Status;    //启动/停止翻转
   }      

。。。。


void main(void)
{
EX0init(); //初始化外部中断
TIMinit(Status,Speed);//初始化定时器
P2=0x00;//1位数码管全部显示
while(1)//主循环
   {
    if(irok)                        //如果接收好了进行红外处理
   {   
    Ircordpro();
    irok=0;
   }
    if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
   {
      Ircontrol();
   TIMinit(Status,Speed);//初始化定时器
   Ir_work();
   }
}
}



火星蒙面侠 发表于 2013-4-7 22:02

学过一段时间,学得头疼

tbb1 发表于 2013-4-7 22:16

我的程序设计:
定时器1带有速度Speed参数,
while(1)里运行红外编解码程序,当红外中断进入解码完毕后,将Speed参数相应调整,进而改变定时器1的输出频率。
问题来了:
如果红外成功解码,则while(1)里的Speed参数如何被输入到定时器1的初值里去呢?
函数功能:脉冲输出,定时器T1的中断服务程序
**************************************************************/
void Time1(void) interrupt 3 using 3 //"interrupt"声明函数为中断服务函数
               //其后的3为定时器T1的中断编号;3表示使用第2组工作寄存器
{
    CLK=~CLK;//按位取反操作,将P1.0引脚输出电平取反
        TH1=256-Speed; //(65536-Speed)/256; //定时器T1的高8位重新赋初值
        TL1=14; //(65536-Speed)%256; //定时器T1的高8位重新赋初值
}



tbb1 发表于 2013-4-7 22:24

红外解码是抄的范例,应该没有什么错。

/******************************************************************/
/*                  外部中断0函数    --红外接收,优先级最高   */
/******************************************************************/
void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
static unsigned chari;             //接收红外信号处理
static bit startflag;                //是否开始处理标志位

if(startflag)                        
       {
   
    if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms
       {    i=0;
                    irdata=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
                    irtime=0;
                    i++;
                          if(i==33)
                              {
                                 irok=1;
                               i=0;
                                  }
          }
       
       else
                {irtime=0;startflag=1;}
        }
}

/******************************************************************/
/*                   定时器0初始化                              */
/******************************************************************/
void TIMinit(unsigned char Sta,uint Speed)//定时器0初始化
{

TMOD=0x02;//定时器0工作方式2,定时器1工作方式0.TH0是重装值,TL0是初值
TH0=0x00; //重载值
TL0=0x00; //初始化值
        TH1=256-Speed; //(65536-Speed)/256; //定时器T1的高8位赋初值
        TL1=14;// (65536-Speed)%256; //定时器T1的高8位赋初值
ET0=1;    //开中断
TR0=1;   
        ET1=Sta;               //定时器T1中断允许         
        TR1=1;               //启动定时器T1
}
/******************************************************************/
/*                   外部中断初始化                               */
/******************************************************************/
void EX0init(void)
{
IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
EX0 = 1;   //使能外部中断
EA = 1;    //开总中断
}
/******************************************************************/
/*                  红外键值处理                              */
/******************************************************************/

void Ir_work(void)//红外键值散转程序
{
       switch(IRcord)//判断第三个数码值
                 {
                       case 0x0c:P0=dofly;break;//1 显示相应的按键值
                       case 0x18:P0=dofly;break;//2
                       case 0x5e:P0=dofly;break;//3
                       case 0x08:P0=dofly;break;//4
                       case 0x1c:P0=dofly;break;//5
                       case 0x5a:P0=dofly;break;//6
                       case 0x42:P0=dofly;break;//7
                       case 0x52:P0=dofly;break;//8
                       case 0x4a:P0=dofly;break;//9

                       }

                  irpro_ok=0;//处理完成标志

}

/******************************************************************/
/*                  红外解码函数处理                            */
/******************************************************************/
void Ircordpro(void)//红外码值处理函数
{
unsigned char i, j, k;
unsigned char cord,value;

k=1;
for(i=0;i<4;i++)      //处理4个字节
   {
      for(j=1;j<=8;j++) //处理1个字节8位
         {
          cord=irdata;
          if(cord>7)//大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
                  {
             value=value|0x80;
                        }
          else
                  {
             value=value;
                        }
          if(j<8)
                  {
                       value=value>>1;
                        }
         k++;
         }
   IRcord=value;
   value=0;   
   } irpro_ok=1;//处理完毕标志位置1
   
}

a125278748 发表于 2013-4-7 22:31

我KAO,看晕了

鑫鑫点灯 发表于 2013-4-7 22:50

我觉得红外没有无线来的简单,红外的通信数据格式处理复杂

maxchen 发表于 2013-4-8 12:26

你这个程序不完整吧?用于判断红外脉冲宽度的变量irtime都没看到在那里计数

tbb1 发表于 2013-4-8 14:41

maxchen 发表于 2013-4-8 12:26 static/image/common/back.gif
你这个程序不完整吧?用于判断红外脉冲宽度的变量irtime都没看到在那里计数 ...

为了大伙看的清楚,只是摘录了部分程序

maxchen 发表于 2013-4-8 16:56

没有看到程序的其他部分,除非其他部分有对startflag赋值,不然,中断里的那个if进不去
/******************************************************************/
/*                  外部中断0函数    --红外接收,优先级最高   */
/******************************************************************/
void ex0_isr(void) interrupt 0 using 0
{ //外部中断0服务函数
    static unsigned chari;             //接收红外信号处理

/* 没有初始化startflag,所以默认startflag==0 */
    static bit startflag;                //是否开始处理标志位

    if(startflag) {      /*除非外部有对startflag操作,不然永远也进不去 */
      if(irtime < 63 && irtime >= 33) { //引导码 TC9012的头码,9ms+4.5ms
            i = 0;
            irdata = irtime; //存储每个电平的持续时间,用于以后判断是0还是1
            irtime = 0;
            i++;
            if(i == 33) {
                irok = 1;
                i = 0;
            }
      } else {
            irtime = 0;
            startflag = 1;
      }
    }
}

tbb1 发表于 2013-4-8 18:00

maxchen 发表于 2013-4-8 16:56 static/image/common/back.gif
没有看到程序的其他部分,除非其他部分有对startflag赋值,不然,中断里的那个if进不去 ...

多谢提点。
下面是全程序:
/*-----------------------------------------------
名称:遥控器红外解码数码管显示
公司:上海浩豚电子科技有限公司
编写:师访
日期:2009.5
修改:无
内容:按配套遥控器上1-9会在数码管上对应显示
------------------------------------------------*/
#include<AT89X51.h> //<reg52.h>    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<stdio.h>
#include<intrins.h>
//#include<reg51.h>//包含51单片机寄存器定义的头文件
#define TURE 1
#define FALSE 0

/*-----------------------------------------步进电机控制-----------------------------------------

   P0数码管显示 P2.1~3 数码管选位P1--LED灯,控制步进电机
   P3红外遥控器    (独立键盘P3.0~P3.2不用)
数码管:第一位--模式:1--电跟模式,0--自由模式
第2位--方向:1--逆时针,0--顺时针
第3、4位--目前速度:10为1X地球自转速度,20为2X自转速度。。。
第5、6位--电跟基础速度:50为1X地球自转速度
               
-----------------------------------------我还是分割线-----------------------------------------*/

/******************************************************************/
/*                  变量声明                                    */
/******************************************************************/
#define uchar unsigned char
#define uint unsigned int
sbit CLK=P1^0;//P1.0引脚为脉冲输出
sbit EN=P1^1;//P1.1引脚为使能
sbit Direct=P1^2;//P1.2引脚为方向,1-反转,0-正转?
uint Speed=101; //设置1X速度定时器1初值:256-(3250/32)=256-101=145   65536-3250=62286
uint Status=1; //启动状态初始为0,停止状态
uint Mode=1; //工作模式。1--单倍电跟状态,0--自由控制状态
//uint Direct=0;//转动方向初值
uchar zx,k,sudu;
int n=0,m,bu,l;
sbit IR=P3^2;//红外接口标志
unsigned char const dofly[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};//数码管显示编码
unsigned charirtime;//红外用全局变量
bit irpro_ok,irok;
unsigned char IRcord;
unsigned char   irdata;
/******************************************************************/
/*                  函数声明                                    */
/******************************************************************/
void Delay(unsigned char mS);//延时子函数
void Ir_work(void);
void Ircordpro(void);
void Ircontrol(void);
/******************************************************************/
/*                  定时器0中断服务函数--红外接收               */
/******************************************************************/
void tim0_isr (void) interrupt 1 using 1//定时器0中断服务函数
{
irtime++;                           //用于计数2个下降沿之间的时间
}
/**************************************************************
函数功能:脉冲输出,定时器T1的中断服务程序
**************************************************************/
void Time1(void) interrupt 3 using 3 //"interrupt"声明函数为中断服务函数
               //其后的3为定时器T1的中断编号;3表示使用第2组工作寄存器
{
    CLK=~CLK;//按位取反操作,将P1.0引脚输出电平取反
   TH1=256-Speed; //(65536-Speed)/256; //定时器T1的高8位重新赋初值
TL1=14; //(65536-Speed)%256; //定时器T1的高8位重新赋初值
}

/******************************************************************/
/*                  外部中断0函数    --红外接收,优先级最高   */
/******************************************************************/
void ex0_isr (void) interrupt 0 using 0//外部中断0服务函数
{
static unsigned chari;             //接收红外信号处理
static bit startflag;                //是否开始处理标志位
if(startflag)                        
{
    if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms
       {    i=0;
      irdata=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
      irtime=0;
      i++;
       if(i==33)
         {
       irok=1;
   i=0;
      }
          }

    else
{irtime=0;startflag=1;}
}
}
/******************************************************************/
/*                   定时器初始化                              */
/******************************************************************/
void TIMinit(void)//定时器0初始化
{
TMOD=0x02;//定时器0工作方式2,定时器1工作方式0.TH0是重装值,TL0是初值
TH0=0x00; //重载值
TL0=0x00; //初始化值
TH1=256-Speed; //(65536-Speed)/256; //定时器T1的高8位赋初值
TL1=14;// (65536-Speed)%256; //定时器T1的高8位赋初值
ET0=1;    //开中断
TR0=1;   
ET1=Status;               //定时器T1中断允许         
TR1=1;               //启动定时器T1
}
/******************************************************************/
/*                   外部中断初始化                               */
/******************************************************************/
void EX0init(void)
{
IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
EX0 = 1;   //使能外部中断
EA = 1;    //开总中断
}
/******************************************************************/
/*                  红外键值处理                              */
/******************************************************************/
void Ir_work(void)//红外键值散转程序
{
       switch(IRcord)//判断第三个数码值
          {
    case 0x0c:P0=dofly;break;//1 显示相应的按键值
    case 0x18:P0=dofly;break;//2
    case 0x5e:P0=dofly;break;//3
    case 0x08:P0=dofly;break;//4
    case 0x1c:P0=dofly;break;//5
    case 0x5a:P0=dofly;break;//6
    case 0x42:P0=dofly;break;//7
    case 0x52:P0=dofly;break;//8
    case 0x4a:P0=dofly;break;//9
    }
    irpro_ok=0;//处理完成标志
}
/******************************************************************/
/*                  红外解码函数处理                            */
/******************************************************************/
void Ircordpro(void)//红外码值处理函数
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;
for(i=0;i<4;i++)      //处理4个字节
   {
      for(j=1;j<=8;j++) //处理1个字节8位
         {
          cord=irdata;
          if(cord>7)//大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
      {
             value=value|0x80;
   }
          else
      {
             value=value;
   }
          if(j<8)
      {
    value=value>>1;
   }
         k++;
         }
   IRcord=value;
   value=0;   
   } irpro_ok=1;//处理完毕标志位置1
   
}
/******************************************************************/
/*                  红外控制处理程序                            */
/******************************************************************/
void Ircontrol(void)//红外码值处理函数
{
unsigned char l,m;
      if (Mode) //单倍模式
      {
//   SingleModel: // 单倍电跟状态
    if (Direct)//如果处于反转下,先停止,再启动
      {
       ET1=0;    //如处于反转状态,先停
       for (l=1;100;l++) //低速启动延时
         {
         for (m=1;50;m++)
          {
          }
         }
          Direct=0;
      }
   if (IRcord==0x44)   //如果按下启动键,则启动定时器1,脉冲输出开始,步进电机运行
   {
   Direct=0;
   Status=~Status;    //启动/停止翻转
   }      
    if (IRcord==0x43) //快进按钮按下
   {
      Direct=0;
      Speed=Speed+50;
   }
      
    if (IRcord==0x40) //快退按钮按下
   {
      Direct=1;
      Speed=Speed-50;
   }
      
    if (IRcord==0x18) //选择自由模式
      {
      Mode=0;
   }
      }
else
   {
//      FreeModel: // 自由状态
         if (IRcord==0x44)   //如果按下启动键,则启动定时器1,脉冲输出开始,步进电机运行
   {
   ET1=0;//先停止,关闭定时器1
   for (l=1;100;l++) //停止延时
      {
      for (m=1;100;m++)
       {
       }
      }
   Direct=0;
   Speed=150;//加速
   Status=~Status;    //启动/停止翻转
   ET1=1;
   }      
    if (IRcord==0x43) //快进按钮按下
   {
      if (Direct)//如果处于反转下,先停止,再启动
      {
       ET1=0;    //如处于反转状态,先停
       for (l=1;100;l++) //低速启动延时
         {
         for (m=1;50;m++)
          {
          }
         }
          Direct=0;
      }
      Speed=Speed+20;
      if (Speed>=220) Speed=220;
   if (!ET1) ET1=1; //启动
   }
    if (IRcord==0x40) //快退按钮按下
   {
   if (!Direct)//如果处于正转下,先停止,再启动
      {
       ET1=0;//先停止,关闭定时器1
       for (l=1;100;l++) //停止延时
      {
      for (m=1;100;m++)
         {
         }
      }
      }
   Direct=1;
   Speed=Speed+20;
   if (Speed>=220) Speed=220;
   if (!ET1) ET1=1;
   }
    if (IRcord==0x0c) //选择单倍模式
      {
      Mode=1;
   }
      } //else对应
}
/////////////////////////////////////////////////////////////////
void main(void)
{
EX0init(); //初始化外部中断
TIMinit();//初始化定时器
P2=0x00;//1位数码管全部显示
Direct=0;
while(1)//主循环
   {
    if(irok)                        //如果接收好了进行红外处理
   {   
    Ircordpro();
    irok=0;
   }
    if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
   {
Ircontrol();
   Ir_work();
   }
}
}

maxchen 发表于 2013-4-8 18:59

所以,你的程序就有问题了。startflag是个静态局部变量,只有在中断内才能访问,而只有在startflag为真的时候才给startflag赋值1,所以startflag永远也等于0,所以红外解码肯定不正常

我的程序是在STM8上用TIM2进行输入捕获来解码的,所以就没必要给你参考了。建议先研究清楚红外接收管输出的波形,给个网上找的程序你参考吧。
sbit IR_IO = P1^6;          // IR管脚 任意IO

//定时器初始化为125uS中断一次
void IR_decode_init(void)
{
   TMOD |= 0x12;                     // T1定时方式2
//--------------设定中断时间------------------------
   TH0 = (-125);TL0 = (-125); // 定时125us 12M晶振
    ET0 = 1;      TR0 = 1;      // 启动T1
    EA = 1;                              // 总中断允许
}
//解码的相关数据            
bit Irprot_LastState = 0;   // 端口状态位
uchar codeCnt = 0;          // 数据码位计数
uchar irTime;                   // 码时间,用于以125us时间计时
uchar IR_data;            // 接收数据缓存

//下面为解码的关键部分,大家自己去分析。主思路就是计算下降沿间隔,其余什么高电平多少时间,低电平多少时间都不关心,因此代码比较精简。
//125us执行中断程序一次
void Timer0(void) interrupt 1                                                            
{   
   irTime++;
   if(irTime==240) {irTime--;codeCnt=0x3f;} // ir解码后码值存放时间, 240*125us = 30ms
   if(IR_IO)   Irprot_LastState=1; // 记录IO状态
   else if(Irprot_LastState)       // 有下降沿
   {
      Irprot_LastState = 0;      // 下降沿后IO状态记录为0
      if(irTime<24)                // 小于24*125us=3ms的间隔才进行处理
      {
         codeCnt++;codeCnt &= 0x1f;
         IR_data <<= 1;
         if( irTime>15 )   IR_data++;// 大于15*125us=1.875ms的间隔为数据1
      }
      irTime = 0;                  // 下降沿处理完成,将时间清0
   }
}
/*
使用时只需查询codeCnt的值是否等于31(如果解码完成30ms后才去判断codeCnt==31,codeCnt将不会再是31,可以在程序中修改该标志的存活时间),是表示解码完成,解码数据放于IR_data[]数组中; 因为该解码的核心思想是检测两个下降沿相隔的时间,所以只要两个下降沿间隔符合,不管高低电平时间都会进行解码,所以如果要提高准确性,需把IR_data[]中的数据进行检验,
也就是看是否IR_data==IR_data,如果是,99%是正确的.*/

CLEO 发表于 2013-4-9 09:23

我做了一个红外控制调焦,也想做导星和电跟,无奈没机械,有个现成的赤道仪就好了:(

tbb1 发表于 2013-4-9 10:03

maxchen 发表于 2013-4-8 18:59
所以,你的程序就有问题了。startflag是个静态局部变量,只有在中断内才能访问,而只有在startflag为真的时 ...

感谢大侠!
仔细比对标准程序,就是在那个中断处理部分多了两个大括号,导致无法进入处理程序。现在可以快进快退,马上可以成功了

sherryzx 发表于 2013-4-9 11:31

一般这种DIY电跟成本高不?。。。我经济有限,主镜便宜 全套不到700,想弄个电跟,但是随便一个电跟价钱都和镜子差不多了。。这心里真不平衡,你说我主镜1000多2000的话,那倒是无所谓。所以想问问DIY大大,要不托您帮做个?

天秤星座 发表于 2013-4-9 13:05

看LZ的方案应该不会跟贵把 有点基础的人玩玩还是不错的

c360 发表于 2013-4-9 17:15

用汇编更简单

CLEO 发表于 2013-4-11 14:16

啊,我之前用红外控制直流电机,红外是外部0,直流是用定时0,然后发现红外进不去,和你的问题一样,我也怀疑是中断优先级问题,也怀疑是不是那个静态变量搞鬼,最后无奈,我去掉定时0,把直流电机放到主函数才解决…你的问题出在哪里?我研究下你程序先!

tbb1 发表于 2013-4-11 14:23

CLEO 发表于 2013-4-11 14:16 static/image/common/back.gif
啊,我之前用红外控制直流电机,红外是外部0,直流是用定时0,然后发现红外进不去,和你的问题一样,我也怀疑 ...

问题出在大侠指点的地方,静态变量始终为0,没有赋1操作。原因很简单,因为多了两个大括号,呵呵。
曾经出现过宕机情况,后来发现是char变量设置有问题,使用翻转~命令对char变量进行了翻转,程序就不知道跑哪里去了。
后来把所有需要翻转的char变量改为bit变量,问题就全部解决了

CLEO 发表于 2013-4-11 14:30

tbb1 发表于 2013-4-11 14:23 static/image/common/back.gif
问题出在大侠指点的地方,静态变量始终为0,没有赋1操作。原因很简单,因为多了两个大括号,呵呵。
曾经 ...

这样啊,我还是太急了,没认真研究程序就改掉了,我现在再弄一下....你现在只是电跟吗?没有导星?
页: [1]
查看完整版本: 51单片机驱动单轴电跟初步成功,有问题请教大神们