[STC单片机] 可以在子函数中调用中断函数吗?

[复制链接]
9528|40
McuPlayer 发表于 2013-10-23 15:58 | 显示全部楼层
你可以中断来调用函数(主程序不调用此函数),而不用函数调用中断

你的目标是协议级的事件驱动
 楼主| cellagent 发表于 2013-10-23 16:32 | 显示全部楼层
McuPlayer 发表于 2013-10-23 15:58
你可以中断来调用函数(主程序不调用此函数),而不用函数调用中断

你的目标是协议级的事件驱动

你好,我把程序贴出来了。

/////wireless.h 用法发送一段完整的波形
#include <stc12c5a60s2.h>
#define uchar unsigned char

//IO口定义
sbit TRX=P2^0;//遥控器信号输出,(数据输出)

//变量定义
uchar TH0_12a=0xfa;
uchar TL0_12a=0xe2;           //12a 宽脉冲         1310 t=1424.4092us  proteus测1.46ms
uchar TH0_4a=0xfe;
uchar TL0_4a=0x3e;           //4a         窄脉冲         450  t=488.28125us  proteus测0.52ms
uchar TH0_124a=0xcb;
uchar TL0_124a=0x12;   //124a 同步头 13550 t=14702.691us proteus测14.75ms

/*void init()
{         
TMOD=0x10;        //定时器T1工作于方式1,16位计数器
TH0=0x00;
TL0=0x00;
ET1=1;                //定时器1中断允许
EA=1;               
} */

void time1_interrupt() interrupt 1   //         TF1=1,定时器1溢出产生中断
{
TR0=0; //关定时器
}

void bit_1()        //1                12a低,4a高,12a低,4a高
{
TRX=0;
TH0=TH0_12a;
TL0=TL0_12a;
TR0=1;  
while(TR0);                //中断返回时TR0=0
TRX=1;
TH0=TH0_4a;
TL0=TL0_4a;
TR0=1;  
while(TR0);

TRX=0;
TH0=TH0_12a;
TL0=TL0_12a;
TR0=1;  
while(TR0);                //中断返回时TR0=0
TRX=1;
TH0=TH0_4a;
TL0=TL0_4a;
TR0=1;  
while(TR0);
}

void bit_0()        //0                12a高,4a低,12a高,4a低
{
TRX=0;
TH0=TH0_4a;
TL0=TL0_4a;
TR0=1;  
while(TR0);
TRX=1;
TH0=TH0_12a;
TL0=TL0_12a;
TR0=1;  
while(TR0);

TRX=0;
TH0=TH0_4a;
TL0=TL0_4a;
TR0=1;  
while(TR0);
TRX=1;
TH0=TH0_12a;
TL0=TL0_12a;
TR0=1;  
while(TR0);
}

void bit_syn()         //同步码  4a低,124a高
{
TRX=0;
TH0=TH0_4a;
TL0=TL0_4a;
TR0=1;  
while(TR0);
TRX=1;
TH0=TH0_124a;
TL0=TL0_124a;
TR0=1;  
while(TR0);
}

void trans_proc(uchar *mydata,uchar n)
{  
uchar i,j,temp,temp_temp;
bit_syn();
for(i=0;i<n;i++)         
{  
        temp=mydata;
        for(j=0;j<8;j++)
        {
                temp_temp=temp;
                temp_temp &=0x80;
                if(temp_temp==0x80)
                {
                        bit_1();
                }       
                else
                {
                        bit_0();
                }
                temp=temp <<1;
        }
}
EA = 0;           //防止不断发送而不能进行函数返回
}

////main.c 先通过串口接收一个字符,如果字符是'a',则发送一段波形
#include "wireless.h"
#define   FOSC    11059200L
#define   BAUD    9600

BYTE command;

////初始化函数将串口的初始和定时器0的初始化合在一起,定时器0与定时器1应该能分别独立工作吧?
void InitUart()
{
          SCON = 0x5a;                        //8 bit data ,no parity bit
      TMOD = 0x21;                        //T0 as 8-bit auto reload
      TH1 = TL1 = -(FOSC/12/32/BAUD);    //Set Uart baudrate
          TH0 = TL0 = 0x00;
          ET0 = 1;
          TR1 = 1;
}

void RecvData(void)          //查询方式接收命令
{
while(!RI);
        RI=0;
command =SBUF;
}

void SendData(BYTE d)                  //发送一个字节的数据,形参d即为待发送数据。
{
while(!TI);
        TI=0;
SBUF=d; //将数据写入到串口缓冲
}

void main()
{
InitUart();
while(1)
{
RecvData();
if(command == 'a')
        {
        SendData('a');
        EA = 1;///我的理解是此时完全进入到发送波形的过程
        trans_proc(0xd6,1);///EA=0,会让程序发送完一段波形就返回
        }
if(command == 'b')
        {
        SendData('b');
        }
}
}
以上程序运行的结果是,串口能够正常显示字符,但是不能进行无线通信,即另一块单片机收不到数据。不用串口而直接用wireless.h发送时,另一块单片机能够收到数据。是什么原因呢?


 楼主| cellagent 发表于 2013-10-23 16:32 | 显示全部楼层
怎么后面的字体都变了。不知能不能看清楚?
puppet21 发表于 2013-10-23 16:40 | 显示全部楼层
可以是可以,但是你这样会导致函数重入。你触发一次事件,但执行了两次中断程序。除非你分开函数写,但觉得……没必要啊……
 楼主| cellagent 发表于 2013-10-23 16:49 | 显示全部楼层
puppet21 发表于 2013-10-23 16:40
可以是可以,但是你这样会导致函数重入。你触发一次事件,但执行了两次中断程序。除非你分开函数写,但觉得 ...

谢谢你的回复。可以详细说说你的建议吗?
16777216 发表于 2013-10-23 16:59 | 显示全部楼层
STC应该不可以 但是STM好像可以用事件触发完成你的要求 软件的事件触发
异域意 发表于 2013-10-23 17:00 | 显示全部楼层
16777216 发表于 2013-10-23 17:02 | 显示全部楼层
再写一个函数与中断一样不就好了么 或者这样 做一个定时器中断的开关  主函数打开定时器开关.定时器调用函数
 楼主| cellagent 发表于 2013-10-23 18:01 | 显示全部楼层
16777216 发表于 2013-10-23 17:02
再写一个函数与中断一样不就好了么 或者这样 做一个定时器中断的开关  主函数打开定时器开关. ...

谢谢你的回复。简单的中断开关那种我测试过,行得通,现在是我想在串口收到'a'后发送一段波形,波形的脉冲的宽度是用定时器控制的。我尝试波形发送完后给一个完成标志。发送波形的过程应该可以看作是一个子函数吧,只不过其中包含中断,我尝试过发送完波形后关闭所有的中断,但是还是达不到效果。
16777216 发表于 2013-10-23 20:15 | 显示全部楼层
cellagent 发表于 2013-10-23 18:01
谢谢你的回复。简单的中断开关那种我测试过,行得通,现在是我想在串口收到'a'后发送一段波形,波形的脉 ...

如果波形是确定的话直接用延时做不是很好么
McuPlayer 发表于 2013-10-24 00:28 | 显示全部楼层
中断ISR中:
把收到的串口数据写入变量 command = SBUF;


主程序的主循环加入:
switch(command)
{
case 'a':
    break;
case 'b':
    break;
case 'c':
    break;
}
command = 0;
 楼主| cellagent 发表于 2013-10-24 08:22 | 显示全部楼层
16777216 发表于 2013-10-23 20:15
如果波形是确定的话直接用延时做不是很好么

是的,我后来用延时产生波形,在proteus中看两种波形是一样的,但是接收端只能收到定时器的波形数据,而收不到延时的波形数据。没有示波器,我想应该是延时中间的指令占用时间导致波形发生了变化。
 楼主| cellagent 发表于 2013-10-24 08:29 | 显示全部楼层
cellagent 发表于 2013-10-24 08:22
是的,我后来用延时产生波形,在proteus中看两种波形是一样的,但是接收端只能收到定时器的波形数据,而 ...

将发送波形作为一个子函数,收到字符'a'就发送一次或几次波形,过程很明了。看不到波形,很纠结。
nuaabob 发表于 2013-10-24 09:35 | 显示全部楼层
ayb_ice 发表于 2013-10-23 09:40
中断是硬件行为,不要去人为调用,可以设定中断标志触发中断

这位同学正解,中断是硬件行为,我们能做的只是通过编写中断程序指定当该中断发生时单片机如何去处理相应的事件。
xiaoliping1945 发表于 2013-10-29 19:47 | 显示全部楼层
中断时硬件内部触发的,也几十说,你设置好中断后,控制要不要启动中断,而不是调用中断函数,中断函数是没法调用的,
 楼主| cellagent 发表于 2013-10-30 10:56 | 显示全部楼层
nuaabob 发表于 2013-10-24 09:35
这位同学正解,中断是硬件行为,我们能做的只是通过编写中断程序指定当该中断发生时单片机如何去处理相应 ...

谢谢你的回复。是的,中断只能由主函数去调用。
 楼主| cellagent 发表于 2013-10-30 10:58 | 显示全部楼层
xiaoliping1945 发表于 2013-10-29 19:47
中断时硬件内部触发的,也几十说,你设置好中断后,控制要不要启动中断,而不是调用中断函数,中断函数是没 ...

谢谢你的回复。我现在对中断的理解灵活一点了,需要用的话就置位中断标志,不用就清除中断标志。
nuaabob 发表于 2013-10-30 19:19 | 显示全部楼层
本帖最后由 nuaabob 于 2013-10-30 19:21 编辑
cellagent 发表于 2013-10-30 10:56
谢谢你的回复。是的,中断只能由主函数去调用。


上面有同学提到STM32,这个我不懂,但是STC是增强型51单片机,这个我还是比较了解的,中断事件的发生跟任何函数无关,只能由硬件自动触发,譬如定时器中断,一旦“计数容器”THx、TLx计满溢出,单片机会自动将TFx由0翻转为1状态,并向CPU申请中断,如果在初始化程序中开启了该定时/计数器x的中断,CPU就会响应并进入中断服务程序,所以中断服务程序(函数)不是由哪个函数调用,而是由硬件自动触发,我们写中断服务程序只是相当于做了个“填空题”,充实了中断服务函数的内容而已。这个过程如果是学过汇编的就会很清楚,C51把很多底层的问题屏蔽起来了。
所以,“中断只能由主函数去调用”这句话是错误的。
 楼主| cellagent 发表于 2013-10-31 08:09 | 显示全部楼层
nuaabob 发表于 2013-10-30 19:19
上面有同学提到STM32,这个我不懂,但是STC是增强型51单片机,这个我还是比较了解的,中断事件的发生跟任 ...

谢谢你的回复。很到位,让我对中断的认识又加深了。我记得某书上说过,“中断只能由系统去调用”,我想它指的是,系统做好了中断的初始化,设置了中断标志吧,就如你说的“填空题”,当中断产生时,系统暂时停止当前的任务去做中断任务。
outstanding 发表于 2013-10-31 08:32 | 显示全部楼层
调用中断,这样用比较危险吧,可以用标志变量
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部