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();
}
}
}
学过一段时间,学得头疼 我的程序设计:
定时器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位重新赋初值
}
红外解码是抄的范例,应该没有什么错。
/******************************************************************/
/* 外部中断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
}
我KAO,看晕了 我觉得红外没有无线来的简单,红外的通信数据格式处理复杂 你这个程序不完整吧?用于判断红外脉冲宽度的变量irtime都没看到在那里计数 maxchen 发表于 2013-4-8 12:26 static/image/common/back.gif
你这个程序不完整吧?用于判断红外脉冲宽度的变量irtime都没看到在那里计数 ...
为了大伙看的清楚,只是摘录了部分程序 没有看到程序的其他部分,除非其他部分有对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;
}
}
}
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();
}
}
}
所以,你的程序就有问题了。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%是正确的.*/
我做了一个红外控制调焦,也想做导星和电跟,无奈没机械,有个现成的赤道仪就好了:( maxchen 发表于 2013-4-8 18:59
所以,你的程序就有问题了。startflag是个静态局部变量,只有在中断内才能访问,而只有在startflag为真的时 ...
感谢大侠!
仔细比对标准程序,就是在那个中断处理部分多了两个大括号,导致无法进入处理程序。现在可以快进快退,马上可以成功了 一般这种DIY电跟成本高不?。。。我经济有限,主镜便宜 全套不到700,想弄个电跟,但是随便一个电跟价钱都和镜子差不多了。。这心里真不平衡,你说我主镜1000多2000的话,那倒是无所谓。所以想问问DIY大大,要不托您帮做个? 看LZ的方案应该不会跟贵把 有点基础的人玩玩还是不错的 用汇编更简单 啊,我之前用红外控制直流电机,红外是外部0,直流是用定时0,然后发现红外进不去,和你的问题一样,我也怀疑是中断优先级问题,也怀疑是不是那个静态变量搞鬼,最后无奈,我去掉定时0,把直流电机放到主函数才解决…你的问题出在哪里?我研究下你程序先! CLEO 发表于 2013-4-11 14:16 static/image/common/back.gif
啊,我之前用红外控制直流电机,红外是外部0,直流是用定时0,然后发现红外进不去,和你的问题一样,我也怀疑 ...
问题出在大侠指点的地方,静态变量始终为0,没有赋1操作。原因很简单,因为多了两个大括号,呵呵。
曾经出现过宕机情况,后来发现是char变量设置有问题,使用翻转~命令对char变量进行了翻转,程序就不知道跑哪里去了。
后来把所有需要翻转的char变量改为bit变量,问题就全部解决了 tbb1 发表于 2013-4-11 14:23 static/image/common/back.gif
问题出在大侠指点的地方,静态变量始终为0,没有赋1操作。原因很简单,因为多了两个大括号,呵呵。
曾经 ...
这样啊,我还是太急了,没认真研究程序就改掉了,我现在再弄一下....你现在只是电跟吗?没有导星?
页:
[1]