51单片机中用中断方式实现串口数据发送与接收

本文介绍了一种利用51单片机通过串口进行数据收发的方法,采用中断方式进行数据发送,并展示了初始化串口、设置波特率、接收及发送数据的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*

Description:用中断方式实现串口数据发送

Author:Jcy

Date:2012-5-2

*/
#include<reg52.h>
#define uint  unsigned int
#define uchar unsigned char

uchar receive_ser;     //串口接收到的数据
uchar flag=0;

uchar receivebuf[ ]="Jcy";
uchar i=0;
uchar j;
void init_ser()
{ 
    TMOD=0X20;//定时器1工作在方式2  
    TH1=0XFD;
    TL1=0XFD;  //波特率9600,51单片机大多用这个
    TR1=1;  //定时器/计数器1启动
    EA=1;    //开放总中断
    SM0=0;
    SM1=1;   //串行口方式1
    REN=1;//允许串口接收
    ES=1;//开串口 中断
}

void delay(uint z)   
{
    uint x,y;
    for(x=z;x>0;x--)
        for(y=110;y>0;y--);                  
}


void ser_int() interrupt 4     //中断函数不用声明  
{
    if(RI==1)
    {
        RI=0;
        receive_ser=SBUF;
            if(receive_ser!='\0')
            {
                receivebuf[i]=receive_ser;
                i++;
                if(i==12)
                {
                    i=0;
                    flag=1;
                }    

            }          
    }
        
}

void main()
{
    init_ser();
    while(1)
    {
        if(flag==1)
        {
            ES=0;  //关闭中断
            flag=0;   //重置
            for(j=0;j<12;j++)
            {
                SBUF=receivebuf[j];   //发送
                while(!TI);  //如果一直没发送完毕
                TI=0;       //为下次发送做准备
                delay(10);   //此处可以不用延迟
            }
            ES=1;
        }
    }   
}


<think>嗯,用户的问题是关于51单片机串口在未经授权情况下发送数据的问题。从引用内容看,用户可能遇到了串口自发发送异常数据的情况,这在实际开发中确实是个棘手问题。 用户提供的两份参考资料很有价值。第一份详细说明了SCON寄存器中TI和RI标志位的特性——它们必须由软件清零,否则会持续触发中断。第二份汇编代码展示了标准串口中断处理流程,特别是JBC RI, LOOP这条关键指令,它同时检测标志位并清零。 让我深入思考可能的原因。首先想到的是硬件干扰:静电或电源波动可能导致TXD引脚电平异常。其次是软件缺陷:如果TI标志未被及时清除,串口控制器会误认为发送缓冲区空闲,从而不断触发发送中断。另外,DMA配置错误也可能导致内存数据被意外发送。 用户可能正在调试一个已投产的设备,所以需要非侵入式的检测方案。除了示波器观察TXD引脚,还可以在中断服务程序里添加调试代码,记录发送触发次数。对于关键系统,建议在物理层增加光耦隔离,同时在软件层设置发送使能标志位,只有通过安全认证的数据才允许加载到SBUF寄存器。 突然意识到还有个隐蔽的风险点:如果程序跑飞后执行了MOV SBUF, A这样的指令,哪怕A寄存器是随机值也会引发发送。这种情况需要检查看门狗定时器和堆栈溢出保护机制。</think>针对51单片机串口"未经允许发送数据"的问题,常见原因和解决方案如下,结合引用内容分析: --- ### **原因分析** 1. **TI标志未及时清除(关键原因)** - 根据引用[1]:**发送中断标志TI** 在数据发送完成后由硬件自动置"1"。 - **问题**:若未在中断服务程序(ISR)中用软件清除TI(`CLR TI`),后续可能因TI持续为1,导致串口控制器误判为"需要发送数据",从而触发自发发送。 - 引用[2]代码示例:中断服务程序中明确包含 `CLR TI` 和 `JBC RI, LOOP`(检测并清除RI/TI)。 2. **中断配置错误** - **ES(串口中断允许位)** 或 **EA(总中断允许位)** 意外开启,且未正确处理中断逻辑(引用[1]的IE寄存器说明)。 3. **程序跑飞或堆栈溢出** - 程序异常跳转到发送函数(如 `MOV SBUF, A`),或内存数据覆盖导致SBUF寄存器被意外写入。 4. **硬件干扰** - 电源波动、电磁干扰导致TXD引脚电平异常,被接收端误判为数据。 --- ### **解决方案** #### 1. **严格清除中断标志** - **在串口中断服务程序中** 必须区分发送/接收中断并清除对应标志: ```assembly BREAK: JBC RI, RECEIVE_INT ; 若RI=1则跳转并清除RI CLR TI ; 清除发送中断标志 RETI RECEIVE_INT: ... ; 接收处理 RETI ``` - **C语言示例**: ```c void UART_ISR() interrupt 4 { if (RI) { RI = 0; // 清除接收标志 // 处理接收数据 } if (TI) { TI = 0; // 清除发送标志 // 停止发送或准备下一字节 } } ``` #### 2. **控制发送使能** - 添加**发送使能标志位**,确保只有主动发送时才能写入SBUF: ```c bit send_enable = 0; // 发送使能标志 void SendData(uint8_t dat) { send_enable = 1; // 允许发送 SBUF = dat; // 触发发送 } // 中断服务中 if (TI) { TI = 0; if (!send_enable) return; // 非主动发送则退出 // ...继续发送后续数据 } ``` #### 3. **检查硬件初始化** - **电源滤波**:增加电容稳压,避免电压波动。 - **引脚配置**:确认TXD引脚未其他电路短路。 - **初始化序列**:复位后关闭串口中断,待配置完成再开启: ```assembly MOV SCON, #50H ; 模式1,允许接收 MOV IE, #00H ; 关闭所有中断 ; ...其他初始化 SETB EA ; 完成初始化后开启总中断 SETB ES ; 开启串口中断 ``` #### 4. **程序健壮性设计** - **看门狗定时器**:启用硬件看门狗(WDT),防止程序跑飞。 - **堆栈深度检查**:确保中断嵌套不会导致堆栈溢出。 - **未使用中断入口**:在未使用的中断向量处放置跳转或空操作,防止意外进入。 --- ### **验证步骤** 1. **示波器检测**:观察TXD引脚是否有异常电平跳变。 2. **中断监控**:在中断服务程序入口添加调试代码(如LED翻转),确认中断触发频率。 3. **内存保护**:在关键变量(如SBUF)周围添加数据校验(如CRC),检测是否被意外修改。 > **关键点总结**:**TI标志未清除是最常见原因**,必须确保每次发送后及时清除TI。同时,通过硬件抗干扰和软件容错设计,可显著降低异常发送概率[^1][^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值