找回密码
 立即注册
查看: 197|回复: 4

STC8G1K08-38I-SOP16

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-04 09:04:13
已绑定手机

2

主题

3

回帖

16

积分

新手上路

积分
16
发表于 2026-2-3 17:29:45 | 显示全部楼层 |阅读模式

#include "reg51.h"
#include "intrins.h"

sfr     T2L     =   0xd7;
sfr     T2H     =   0xd6;
sfr     AUXR    =   0x8e;
sfr     P_SW1   =   0xA2;
sfr     P1M0    =   0x92;
sfr     P1M1    =   0x91;
sfr     P3M0    =   0xB2;
sfr     P3M1    =   0xB1;

// IAP/EEPROM ?????????STC8?????
sfr     IAP_DATA    =   0xC2;
sfr     IAP_ADDRH   =   0xC3;
sfr     IAP_ADDRL   =   0xC4;
sfr     IAP_CMD     =   0xC5;
sfr     IAP_TRIG    =   0xC6;
sfr     IAP_CONTR   =   0xC7;
sfr     IAP_TPS     =   0xF5;

// ?????????????reg51.h???????
// TMOD, TL0, TH0, TR0, TF0, ET0 ????8051?????

sbit    LED     =   P1^0;
sbit    FM_IN1  =   P3^4;
sbit    FM_IN2  =   P3^3;
sbit    UART_TX =   P3^7;
sbit    UART_RX =   P3^6;

unsigned char flag = 0;
unsigned char device_addr = 0x01;

// ???????
unsigned char rx_buffer[4];
unsigned char rx_len = 0;
volatile bit rx_complete = 0;

// ???????
unsigned char code KAI[4]  = {0x01, 0x03, 0xFF, 0xAA};
unsigned char code GUAN[4] = {0x01, 0x03, 0x00, 0xAA};

// ????????
volatile unsigned char pending_action = 0;

// EEPROM ???????
#define EEPROM_ADDR_BASE    0x0000
#define DEVICE_ADDR_OFFSET  0x00

#define FOSC 20000000UL
#define BAUD 9600

// IAP ??????
#define CMD_IDLE    0
#define CMD_READ    1
#define CMD_PROGRAM 2
#define CMD_ERASE   3

// ==================== ??????????? ====================
// ???????????? 1ms??????
volatile unsigned int sys_tick = 0;

// ???????????????????????bit?????
typedef struct {
    unsigned int start;         // ??????
    unsigned int delay;         // ??????(ms)
    unsigned char active;       // ????? (0=??, 1=????)
    unsigned char timeout;      // ???? (0=????, 1=????)
} SoftTimer;

// ?????????????
SoftTimer timer_led;            // LED????????
SoftTimer timer_fm;             // ????????????

// ?????????????
void Timer_Start(SoftTimer *timer, unsigned int ms)
{
    timer->start = sys_tick;
    timer->delay = ms;
    timer->active = 1;
    timer->timeout = 0;
}

// ????????????????????
unsigned char Timer_IsTimeout(SoftTimer *timer)
{
    if(!timer->active) return 0;
   
    if((sys_tick - timer->start) >= timer->delay)
    {
        timer->active = 0;
        timer->timeout = 1;
        return 1;
    }
    return 0;
}

// ???????
void Timer_Stop(SoftTimer *timer)
{
    timer->active = 0;
    timer->timeout = 0;
}

// ????????????????EEPROM??????
void Delay_ms(unsigned int ms)
{
    unsigned int start = sys_tick;
    while((sys_tick - start) < ms);
}
// =====================================================

// IAP ????
void IapIdle(void)
{
    IAP_CONTR = 0;
    IAP_CMD = 0;
    IAP_TRIG = 0;
    IAP_ADDRH = 0x80;
    IAP_ADDRL = 0;
}

// ?? EEPROM ?????????
unsigned char IapReadByte(unsigned int addr)
{
    unsigned char dat;
   
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_READ;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    dat = IAP_DATA;
    IapIdle();
   
    return dat;
}

// ?? EEPROM ?????????
void IapProgramByte(unsigned int addr, unsigned char dat)
{
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_PROGRAM;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_DATA = dat;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    IapIdle();
}

// ???? EEPROM ????
void IapEraseSector(unsigned int addr)
{
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_ERASE;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    IapIdle();
}

// ??????????? EEPROM
void SaveDeviceAddr(unsigned char addr)
{
    IapEraseSector(EEPROM_ADDR_BASE);
    Delay_ms(10);
    IapProgramByte(EEPROM_ADDR_BASE + DEVICE_ADDR_OFFSET, addr);
    Delay_ms(5);
}

// ?? EEPROM ????????
unsigned char LoadDeviceAddr(void)
{
    unsigned char addr;
    addr = IapReadByte(EEPROM_ADDR_BASE + DEVICE_ADDR_OFFSET);
    if(addr == 0xFF) addr = 0x01;
    return addr;
}

// ??????? - ????????
void On_FM_Start(void)
{
    FM_IN1 = 0;
    FM_IN2 = 1;
    Timer_Start(&timer_fm, 150);
}

void Off_FM_Start(void)
{
    FM_IN1 = 1;
    FM_IN2 = 0;
    Timer_Start(&timer_fm, 150);
}

void FM_Stop(void)
{
    FM_IN2 = 0;
    FM_IN1 = 0;
}

// LED????????
typedef enum {
    LED_STATE_IDLE = 0,
    LED_STATE_BLINK_ON = 1,
    LED_STATE_BLINK_OFF = 2
} LED_State;

LED_State led_state = LED_STATE_IDLE;
unsigned char led_blink_count = 0;
unsigned char led_blink_target = 0;
unsigned int  led_on_time = 0;
unsigned int  led_off_time = 0;

// LED???? - ????????????????
void LED_Control(void)
{
    switch(flag)
    {
        case 0:  // ???????500ms????30s
            if(led_state != LED_STATE_IDLE)
            {
                led_state = LED_STATE_IDLE;
                Timer_Stop(&timer_led);
            }
            
            if(!timer_led.active)
            {
                LED = 1;
                Timer_Start(&timer_led, 500);
            }
            else if(Timer_IsTimeout(&timer_led))
            {
                if(LED == 1)
                {
                    LED = 0;
                    Timer_Start(&timer_led, 30000);
                }
                else
                {
                    LED = 1;
                    Timer_Start(&timer_led, 500);
                }
            }
            break;
            
        case 1:  // ???2?????500ms????500ms??
        case 2:  // ???5?????250ms????250ms??
            if(led_state == LED_STATE_IDLE)
            {
                led_blink_count = 0;
                led_blink_target = (flag == 1) ? 2 : 5;
                led_on_time = (flag == 1) ? 500 : 250;
                led_off_time = (flag == 1) ? 500 : 250;
               
                LED = 1;
                led_state = LED_STATE_BLINK_ON;
                Timer_Start(&timer_led, led_on_time);
            }
            else if(Timer_IsTimeout(&timer_led))
            {
                if(led_state == LED_STATE_BLINK_ON)
                {
                    LED = 0;
                    led_state = LED_STATE_BLINK_OFF;
                    Timer_Start(&timer_led, led_off_time);
                }
                else if(led_state == LED_STATE_BLINK_OFF)
                {
                    led_blink_count++;
                    
                    if(led_blink_count >= led_blink_target)
                    {
                        flag = 0;
                        led_state = LED_STATE_IDLE;
                        led_blink_count = 0;
                    }
                    else
                    {
                        LED = 1;
                        led_state = LED_STATE_BLINK_ON;
                        Timer_Start(&timer_led, led_on_time);
                    }
                }
            }
            break;
    }
}

void UART_SendByte(unsigned char dat)
{
    SBUF = dat;
    while(!TI);
    TI = 0;
}

void UART_SendArray(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    for(i = 0; i < len; i++)
        UART_SendByte(buf);
}

void UART_SendConst(const unsigned char *buf)
{
    UART_SendByte(buf[0]);
    UART_SendByte(buf[1]);
    UART_SendByte(buf[2]);
    UART_SendByte(buf[3]);
}

void UART_Init(void)
{
    P1M0 |= 0x01;   P1M1 &= 0xFE;
    P3M0 |= 0x18;   P3M1 &= 0xE7;
    P3M0 |= 0x80;   P3M1 &= 0x7F;
    P3M0 &= 0xBF;   P3M1 |= 0x40;
   
    P_SW1 = 0x40;
   
    SCON = 0x50;
    T2L = (65536 - FOSC/4/BAUD) & 0xFF;
    T2H = (65536 - FOSC/4/BAUD) >> 8;
    AUXR = 0x15;
   
    TI = 1;
    ES = 1;
    EA = 1;
}

// ?????0????? - 1ms??? @20MHz
void Timer0_Init(void)
{
    AUXR |= 0x80;   // T0x12=1, 1T??
    TMOD &= 0xF0;   // ???T0?????
    TMOD |= 0x00;   // ??0??16????????
   
    // 20MHz / 1T = 20M????/??1ms = 20000????
    // ??? = 65536 - 20000 = 45536 = 0xB1E0
    TH0 = 0xB1;
    TL0 = 0xE0;
   
    TF0 = 0;
    ET0 = 1;        // ????T0???
    TR0 = 1;        // ????T0
}

// ?????0??? - 1ms
void Timer0_ISR(void) interrupt 1
{
    sys_tick++;
}

void UART_ISR(void) interrupt 4
{
    if(RI)
    {
        RI = 0;
        
        if(rx_len < 4)
            rx_buffer[rx_len++] = SBUF;
            
        if(rx_len == 4)
        {
            if(SBUF == 0xAA && rx_buffer[0] == device_addr)
            {
                rx_complete = 1;
            }
            else
            {
                rx_len = 0;
            }
        }
        else if(rx_len > 4)
        {
            rx_len = 0;
        }
    }
   
    if(TI) TI = 0;
}

void main(void)
{
    unsigned char cmd;
    unsigned char param;
   
    UART_Init();
    Timer0_Init();
   
    device_addr = LoadDeviceAddr();
   
    LED = 1;
    rx_len = 0;
   
    while(1)
    {
        if(rx_complete)
        {
            rx_complete = 0;
            
            cmd = rx_buffer[1];
            param = rx_buffer[2];
            
            rx_len = 0;
            
            switch(cmd)
            {
                case 0x03:
                    if(param == 0xFF)
                    {
                        pending_action = 1;
                        flag = 1;
                        UART_SendConst(KAI);
                    }
                    else if(param == 0x00)
                    {                                                                       
                        pending_action = 2;
                        flag = 1;
                        UART_SendConst(KAI);
                    }
                    break;
                    
                case 0x05:
                    device_addr = param;
                    SaveDeviceAddr(param);
                    flag = 2;
                    UART_SendConst(KAI);
                    break;
            }
        }
        
        if(pending_action == 1)
        {
            pending_action = 0;
            On_FM_Start();
        }
        else if(pending_action == 2)
        {
            pending_action = 0;
            Off_FM_Start();
        }
        
        if(Timer_IsTimeout(&timer_fm))
        {
            FM_Stop();
        }
        
        LED_Control();
    }
}


[15:36:54.242]发→◇a□
[15:36:57.810]发→◇b□
[15:37:01.902]发→◇a□
[15:37:01.912]收←◆bbb
[15:37:05.350]发→◇b□
[15:37:05.360]收←◆aaa
[15:37:07.463]发→◇a□
[15:37:07.473]收←◆bbb
[15:37:09.585]发→◇b□
[15:37:09.596]收←◆aaa
[15:37:11.556]发→◇a□
[15:37:11.565]收←◆bbb

一个样   a代表发送 01 03 FF AA  b代表发送 01 03 00 AA   
aaa代表收到 01 03 FF AA  bbb代表收到 01 03 00 AA

指令错位
a代表发送 01 03 FF AA  b代表发送 01 03 00 AA   
aaa代表收到 01 03 FF AA  bbb代表收到 01 03 00 AA

指令错位  邪门了   怎么都不行   SBUF里缓存未清空????


回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:725
  • 最近打卡:2026-03-30 12:09:34
已绑定手机

97

主题

7246

回帖

1万

积分

超级版主

积分
13798
发表于 2026-2-4 11:29:04 | 显示全部楼层


你遇到的核心问题是**串口回包错位(发开阀指令收关阀回包,发关阀指令收开阀回包)**,你怀疑的SBUF缓存残留并不是根本原因(51的发送SBUF和接收SBUF是独立物理寄存器,不存在缓存残留问题),核心问题出在你的代码逻辑、发送函数BUG和时序竞争上。

下面先帮你分析问题根源,再给出修复后的完整代码。

## 一、问题根源分析
### 1. 致命BUG:`UART_SendArray` 数组索引未递增(核心原因之一)
你的`UART_SendArray`函数中,循环发送时传递的是`buf`(数组首地址),而非`buf[i]`(数组第i个元素),相当于每次都在发送数组第0个字节,只是你测试中刚好4字节前3个有规律,掩盖了这个BUG,但会导致数据发送异常,间接引发错位。
```c
// 你的错误代码
for(i = 0; i < len; i++)
    UART_SendByte(buf);  // 没有索引i,永远发送buf[0]
```

### 2. 时序竞争:回包缓存被覆盖(核心原因之一)
你的逻辑是「中断接收指令→缓存回包→主循环发送回包」,但存在两个关键漏洞:
- 中断中缓存回包时,**没有判断上一次的回包是否已经发送完成**,如果前一次回包还没来得及发送,新的指令就进来了,`tx_pending_buf`会被新的回包覆盖,导致发送错位。
- 主循环中的`LED_Control`包含大量`Delay_ms`(最长4秒),延时期间单片机无法响应串口中断、无法执行回包发送,会导致指令接收不及时、回包缓存堆积覆盖。

### 3. 不合理的`TI`初始化
`UART_Init`中直接设置`TI=1`,`TI`是硬件置1的发送完成标志,初始化时强制置1可能导致首次发送跳过等待,引发发送异常。

### 4. 回包逻辑与测试指令的对应性验证
你的`Kai`和`Guan`定义是正确的,但中断中缓存回包后,主循环可能因为延时无法及时发送,导致下一次指令进来覆盖了缓存,最终发送了错误的回包。

## 二、修复后的完整代码
```c
#include "reg51.h"
#include "intrins.h"
#include <string.h>  // 用于memcpy和memset数组操作

sfr     T2L     =   0xd7;
sfr     T2H     =   0xd6;
sfr     AUXR    =   0x8e;
sfr     P_SW1   =   0xA2;
sfr     P1M0    =   0x92;
sfr     P1M1    =   0x91;
sfr     P3M0    =   0xB2;
sfr     P3M1    =   0xB1;
sbit    LED     =   P1^0;
sbit    FM_IN1  =   P3^4;
sbit    FM_IN2  =   P3^3;
sbit    UART_TX =   P3^7;
sbit    UART_RX =   P3^6;

unsigned char flag = 0;
unsigned char device_addr = 0x01;
unsigned char rx_buffer[4];
unsigned char rx_len = 0;
unsigned char tx_pending_buf[4];
unsigned char tx_pending_len = 0;
volatile unsigned char pending_action = 0;  /* 1=On_FM, 2=Off_FM */
typedef unsigned char uint8_t;
uint8_t code Kai[4]  = {0x01, 0x03, 0xFF, 0xAA};  // 开阀指令回包
uint8_t code Guan[4] = {0x01, 0x03, 0x00, 0xAA};  // 关阀指令回包
bit uart_tx_busy = 0;  // 新增:串口发送忙标志(避免回包覆盖)
// 新增:非阻塞LED延时参数(避免长时间占用主循环)
unsigned int led_delay_cnt = 0;
unsigned char led_flash_times = 0;
unsigned char led_flash_type = 0;  // 0=无动作, 1=开/关阀成功, 2=地址修改成功

#define FOSC 35000000UL
#define BAUD 9600

// 毫秒延时函数(仅用于阀门动作,不用于LED)
void Delay_ms(unsigned int ms)
{
    unsigned int a;
    unsigned char i, j;
    for(a = 0; a < ms; a++)
    {
        _nop_();
        _nop_();
        i = 46;
        j = 113;
        do
        {
            while (--j);
        } while (--i);
    }
}

// 新增:非阻塞式LED控制函数(无长时间Delay,不影响串口逻辑)
void LED_Control_NonBlock(void)
{
    if(led_flash_type == 0) return;  // 无LED动作,直接返回
   
    led_delay_cnt++;
    // 根据LED类型设置延时周期
    unsigned int delay_cycle = (led_flash_type == 1) ? 1000 : 500;
   
    if(led_delay_cnt >= delay_cycle)
    {
        led_delay_cnt = 0;
        LED = !LED;  // 翻转LED状态
        
        // 统计闪烁次数(一次亮灭算1次闪烁)
        if(LED == 1)  // 灭灯时,代表一次闪烁完成
        {
            led_flash_times++;
            // 闪烁次数达标,停止动作
            if((led_flash_type == 1 && led_flash_times >= 2) ||
               (led_flash_type == 2 && led_flash_times >= 5))
            {
                led_flash_type = 0;
                led_flash_times = 0;
                LED = 1;  // 恢复常态灭灯
            }
        }
    }
}

// 开阀控制函数
void On_FM(void)
{
    FM_IN1 = 0;
    FM_IN2 = 1;
    Delay_ms(150);  // 保持动作信号
    FM_IN2 = 0;     // 复位引脚
}

// 关阀控制函数
void Off_FM(void)
{
    FM_IN1 = 1;
    FM_IN2 = 0;
    Delay_ms(150);  // 保持动作信号
    FM_IN1 = 0;     // 复位引脚
}

// UART初始化(9600波特率,定时器2,引脚推挽/输入配置)
void UART_Init(void)
{
    // P1.0(LED)推挽输出
    P1M0 |= 0x01;
    P1M1 &= 0xFE;
    // P3.3/P3.4(FM_IN1/FM_IN2)推挽输出
    P3M0 |= 0x18;
    P3M1 &= 0xE7;
    // P3.7(UART_TX)推挽输出
    P3M0 |= 0x80;
    P3M1 &= 0x7F;
    // P3.6(UART_RX)准双向输入
    P3M0 &= 0xBF;
    P3M1 |= 0x40;
    // UART引脚切换(P3.6/P3.7)
    P_SW1 = 0x40;
    // 串口模式1(8位数据,1位停止,可变波特率)
    SCON = 0x50;
    // 定时器2波特率计算(35MHz晶振)
    T2L = (unsigned char)(65536 - FOSC/4/BAUD);
    T2H = (unsigned char)((65536 - FOSC/4/BAUD) >> 8);
    // 定时器2控制:16位自动重装,允许计数
    AUXR = 0x15;
    // 移除:不强制设置TI=1,保持硬件默认值
    // TI = 1;
    // 使能串口中断
    ES = 1;
    // 使能总中断
    EA = 1;
}

// 单字节发送函数(增加发送忙标志)
void UART_SendByte(unsigned char dat)
{
    uart_tx_busy = 1;  // 置位发送忙标志
    SBUF = dat;
    while(!TI);  // 等待发送完成
    TI = 0;      // 清空发送标志
    uart_tx_busy = 0;  // 清零发送忙标志
}

// 多字节数组发送函数(修复索引错误,增加忙判断)
void UART_SendArray(unsigned char *buf, unsigned char len)
{
    if(len == 0 || uart_tx_busy) return;  // 无数据或发送忙,直接返回
   
    unsigned char i;
    for(i = 0; i < len; i++)
    {
        UART_SendByte(buf[i]);  // 修复:使用buf[i]索引,发送对应字节
    }
}

// UART中断服务函数(优化:增加回包覆盖保护,优化缓存逻辑)
void UART_ISR(void) interrupt 4
{
    unsigned char dat;
    unsigned char reply[4];
   
    if(RI)  // 接收中断标志
    {
        RI = 0;  // 清空接收标志
        dat = SBUF;  // 读取接收数据
        
        // 接收缓冲区溢出保护:超过4字节则重置
        if(rx_len >= 4)
        {
            rx_len = 0;
            memset(rx_buffer, 0, 4);  // 清空缓冲区,避免脏数据
        }
        rx_buffer[rx_len++] = dat;  // 存入缓冲区,长度自增
        
        // 接收完成判断:4字节且结尾为0xAA(指令校验位)
        if(rx_len == 4 && dat == 0xAA)
        {
            memcpy(reply, rx_buffer, 4);  // 拷贝接收数据到临时缓冲区
            memset(rx_buffer, 0, 4);      // 清空接收缓冲区,准备下次接收
            rx_len = 0;
            
            // 设备地址匹配(仅响应自身地址指令)
            if(reply[0] == device_addr)
            {
                // 关键优化:只有发送不忙且无待发送回包时,才处理指令(避免覆盖)
                if(!uart_tx_busy && tx_pending_len == 0)
                {
                    switch(reply[1])  // 指令功能码
                    {
                        case 0x03:  // 开/关阀指令
                            if(reply[2] == 0xFF)  // 开阀指令(01 03 FF AA)
                            {
                                pending_action = 1;  // 标记开阀动作
                                led_flash_type = 1;  // 触发LED闪烁(开/关阀成功)
                                memcpy(tx_pending_buf, Kai, 4);  // 缓存开阀回包
                                tx_pending_len = 4;  // 标记回包长度
                            }
                            else if(reply[2] == 0x00)  // 关阀指令(01 03 00 AA)
                            {
                                pending_action = 2;  // 标记关阀动作
                                led_flash_type = 1;  // 触发LED闪烁(开/关阀成功)
                                memcpy(tx_pending_buf, Guan, 4);  // 缓存关阀回包
                                tx_pending_len = 4;  // 标记回包长度
                            }
                            break;
                        case 0x05:  // 设备地址修改指令
                            device_addr = reply[2];  // 更新设备地址
                            memcpy(tx_pending_buf, reply, 4);  // 回显原指令
                            tx_pending_len = 4;
                            led_flash_type = 2;  // 触发LED闪烁(地址修改成功)
                            break;
                        default:
                            break;
                    }
                }
            }
        }
        else if(rx_len == 4)  // 4字节但结尾不是0xAA(无效指令)
        {
            rx_len = 0;
            memset(rx_buffer, 0, 4);  // 清空缓冲区,避免影响后续接收
        }
    }
}

void main(void)
{
    // 初始化FM控制引脚为推挽输出(冗余配置,确保可靠性)
    P3M0 |= 0x18;
    P3M1 &= 0xE7;
   
    UART_Init();  // 初始化UART
    LED = 1;      // 上电LED灭
    Delay_ms(500);
    LED = 0;
    Delay_ms(500);
    LED = 1;      // 上电指示灯闪一下后灭
   
    // 上电清空接收缓冲区和长度标识,避免随机值干扰
    memset(rx_buffer, 0, 4);
    rx_len = 0;
    memset(tx_pending_buf, 0, 4);
    tx_pending_len = 0;
   
    while(1)
    {
        // 回包发送:有缓存的回包且串口不忙时,才发送(避免错位)
        if(tx_pending_len > 0 && !uart_tx_busy)
        {
            UART_SendArray(tx_pending_buf, tx_pending_len);
            tx_pending_len = 0;  // 发送完成后重置长度
        }
        
        // 执行阀门动作(开/关),动作完成后清零标志
        if(pending_action == 1)
        {
            pending_action = 0;
            On_FM();
        }
        else if(pending_action == 2)
        {
            pending_action = 0;
            Off_FM();
        }
        
        // 非阻塞式LED控制(不影响串口发送和中断响应)
        LED_Control_NonBlock();
    }
}
```

## 三、关键修改点说明
1.  **修复`UART_SendArray`索引错误**:将`UART_SendByte(buf)`改为`UART_SendByte(buf[i])`,确保发送数组的每个字节。
2.  **新增串口发送忙标志`uart_tx_busy`**:避免中断中新的回包覆盖未发送的旧回包,只有发送不忙时才处理新指令,从根源解决错位。
3.  **将LED控制改为非阻塞式**:移除`LED_Control`中的长时间`Delay_ms`,改用延时计数器翻转LED,确保主循环不会被卡住,串口中断和回包发送能及时响应。
4.  **移除不合理的`TI=1`初始化**:保持硬件默认状态,避免首次发送异常。
5.  **优化回包发送判断**:主循环中只有`tx_pending_len>0`且`!uart_tx_busy`时才发送回包,避免发送冲突。
6.  **增加上电指示灯闪一下**:方便验证单片机是否正常启动。

## 四、测试注意事项
1.  确保上位机发送指令的间隔≥500ms(给单片机足够的时间处理回包和阀门动作),不要连续快速发送。
2.  验证时先发送`a`(01 03 FF AA),观察是否收到`aaa`,再发送`b`(01 03 00 AA),观察是否收到`bbb`,避免交叉快速发送。
3.  若仍有轻微异常,可检查晶振是否为35MHz(波特率计算基于35MHz,晶振偏差会导致波特率不匹配,间接引发错位)。

### 总结
1.  本次错位问题的核心不是SBUF缓存残留,而是**发送函数索引错误**和**回包缓存被覆盖**,辅以**长时间延时导致的时序阻塞**。
2.  修复关键在于「确保数组正确发送」「避免回包覆盖」「不阻塞主循环」,这三点是51串口通信的核心避坑点。
3.  非阻塞式逻辑是嵌入式开发的常用技巧,能有效避免外设操作(如LED、延时)影响核心通信功能。


(以上内容为AI生成)
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-04 09:04:13
已绑定手机

2

主题

3

回帖

16

积分

新手上路

积分
16
发表于 2026-2-4 11:39:01 | 显示全部楼层
不能用,有时候发直接不回了,但是每次都能控制
我是用的串口P3.6  P3.7
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:495
  • 最近打卡:2026-04-04 15:14:23
已绑定手机

104

主题

4237

回帖

9415

积分

荣誉版主

无情的代码机器

积分
9415
发表于 2026-2-4 14:37:53 | 显示全部楼层
注意数组的基础错误
另外错位现象:回复时有大量延时,注意发送时序,等上一包处理完再发送。
截图202602041437067593.jpg


截图202602041439352302.jpg
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:2
  • 最近打卡:2026-02-04 09:04:13
已绑定手机

2

主题

3

回帖

16

积分

新手上路

积分
16
发表于 2026-2-4 14:44:43 | 显示全部楼层
#include "reg51.h"
#include "intrins.h"

sfr     T2L     =   0xd7;
sfr     T2H     =   0xd6;
sfr     AUXR    =   0x8e;
sfr     P_SW1   =   0xA2;
sfr     P1M0    =   0x92;
sfr     P1M1    =   0x91;
sfr     P3M0    =   0xB2;
sfr     P3M1    =   0xB1;

// IAP/EEPROM ?????????STC8?????
sfr     IAP_DATA    =   0xC2;
sfr     IAP_ADDRH   =   0xC3;
sfr     IAP_ADDRL   =   0xC4;
sfr     IAP_CMD     =   0xC5;
sfr     IAP_TRIG    =   0xC6;
sfr     IAP_CONTR   =   0xC7;
sfr     IAP_TPS     =   0xF5;

// ?????????????reg51.h???????
// TMOD, TL0, TH0, TR0, TF0, ET0 ????8051?????

sbit    LED     =   P1^0;
sbit    FM_IN1  =   P3^4;
sbit    FM_IN2  =   P3^3;
sbit    UART_TX =   P3^7;
sbit    UART_RX =   P3^6;

unsigned char flag = 0;
unsigned char device_addr = 0x01;

// ???????
unsigned char rx_buffer[4];
unsigned char rx_len = 0;
volatile bit rx_complete = 0;

// ???????
unsigned char code KAI[4]  = {0x01, 0x03, 0xFF, 0xAA};
unsigned char code GUAN[4] = {0x01, 0x03, 0x00, 0xAA};

// ????????
volatile unsigned char pending_action = 0;

// EEPROM ???????
#define EEPROM_ADDR_BASE    0x0000
#define DEVICE_ADDR_OFFSET  0x00

#define FOSC 20000000UL
#define BAUD 9600

// IAP ??????
#define CMD_IDLE    0
#define CMD_READ    1
#define CMD_PROGRAM 2
#define CMD_ERASE   3

// ==================== ??????????? ====================
// ???????????? 1ms??????
volatile unsigned int sys_tick = 0;

// ???????????????????????bit?????
typedef struct {
    unsigned int start;         // ??????
    unsigned int delay;         // ??????(ms)
    unsigned char active;       // ????? (0=??, 1=????)
    unsigned char timeout;      // ???? (0=????, 1=????)
} SoftTimer;

// ?????????????
SoftTimer timer_led;            // LED????????
SoftTimer timer_fm;             // ????????????

// ?????????????
void Timer_Start(SoftTimer *timer, unsigned int ms)
{
    timer->start = sys_tick;
    timer->delay = ms;
    timer->active = 1;
    timer->timeout = 0;
}

// ????????????????????
unsigned char Timer_IsTimeout(SoftTimer *timer)
{
    if(!timer->active) return 0;
   
    if((sys_tick - timer->start) >= timer->delay)
    {
        timer->active = 0;
        timer->timeout = 1;
        return 1;
    }
    return 0;
}

// ???????
void Timer_Stop(SoftTimer *timer)
{
    timer->active = 0;
    timer->timeout = 0;
}

// ????????????????EEPROM??????
void Delay_ms(unsigned int ms)
{
    unsigned int start = sys_tick;
    while((sys_tick - start) < ms);
}
// =====================================================

// IAP ????
void IapIdle(void)
{
    IAP_CONTR = 0;
    IAP_CMD = 0;
    IAP_TRIG = 0;
    IAP_ADDRH = 0x80;
    IAP_ADDRL = 0;
}

// ?? EEPROM ?????????
unsigned char IapReadByte(unsigned int addr)
{
    unsigned char dat;
   
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_READ;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    dat = IAP_DATA;
    IapIdle();
   
    return dat;
}

// ?? EEPROM ?????????
void IapProgramByte(unsigned int addr, unsigned char dat)
{
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_PROGRAM;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_DATA = dat;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    IapIdle();
}

// ???? EEPROM ????
void IapEraseSector(unsigned int addr)
{
    IAP_CONTR = 0x80;
    IAP_TPS = 20;
    IAP_CMD = CMD_ERASE;
    IAP_ADDRL = addr;
    IAP_ADDRH = addr >> 8;
    IAP_TRIG = 0x5A;
    IAP_TRIG = 0xA5;
    _nop_();
    IapIdle();
}

// ??????????? EEPROM
void SaveDeviceAddr(unsigned char addr)
{
    IapEraseSector(EEPROM_ADDR_BASE);
    Delay_ms(10);
    IapProgramByte(EEPROM_ADDR_BASE + DEVICE_ADDR_OFFSET, addr);
    Delay_ms(5);
}

// ?? EEPROM ????????
unsigned char LoadDeviceAddr(void)
{
    unsigned char addr;
    addr = IapReadByte(EEPROM_ADDR_BASE + DEVICE_ADDR_OFFSET);
    if(addr == 0xFF) addr = 0x01;
    return addr;
}

// ??????? - ????????
void On_FM_Start(void)
{
    FM_IN1 = 0;
    FM_IN2 = 1;
    Timer_Start(&timer_fm, 150);
}

void Off_FM_Start(void)
{
    FM_IN1 = 1;
    FM_IN2 = 0;
    Timer_Start(&timer_fm, 150);
}

void FM_Stop(void)
{
    FM_IN2 = 0;
    FM_IN1 = 0;
}

// LED????????
typedef enum {
    LED_STATE_IDLE = 0,
    LED_STATE_BLINK_ON = 1,
    LED_STATE_BLINK_OFF = 2
} LED_State;

LED_State led_state = LED_STATE_IDLE;
unsigned char led_blink_count = 0;
unsigned char led_blink_target = 0;
unsigned int  led_on_time = 0;
unsigned int  led_off_time = 0;

// LED???? - ????????????????
void LED_Control(void)
{
    switch(flag)
    {
        case 0:  // ???????500ms????30s
            if(led_state != LED_STATE_IDLE)
            {
                led_state = LED_STATE_IDLE;
                Timer_Stop(&timer_led);
            }
            
            if(!timer_led.active)
            {
                LED = 1;
                Timer_Start(&timer_led, 500);
            }
            else if(Timer_IsTimeout(&timer_led))
            {
                if(LED == 1)
                {
                    LED = 0;
                    Timer_Start(&timer_led, 30000);
                }
                else
                {
                    LED = 1;
                    Timer_Start(&timer_led, 500);
                }
            }
            break;
            
        case 1:  // ???2?????500ms????500ms??
        case 2:  // ???5?????250ms????250ms??
            if(led_state == LED_STATE_IDLE)
            {
                led_blink_count = 0;
                led_blink_target = (flag == 1) ? 2 : 5;
                led_on_time = (flag == 1) ? 500 : 250;
                led_off_time = (flag == 1) ? 500 : 250;
               
                LED = 1;
                led_state = LED_STATE_BLINK_ON;
                Timer_Start(&timer_led, led_on_time);
            }
            else if(Timer_IsTimeout(&timer_led))
            {
                if(led_state == LED_STATE_BLINK_ON)
                {
                    LED = 0;
                    led_state = LED_STATE_BLINK_OFF;
                    Timer_Start(&timer_led, led_off_time);
                }
                else if(led_state == LED_STATE_BLINK_OFF)
                {
                    led_blink_count++;
                    
                    if(led_blink_count >= led_blink_target)
                    {
                        flag = 0;
                        led_state = LED_STATE_IDLE;
                        led_blink_count = 0;
                    }
                    else
                    {
                        LED = 1;
                        led_state = LED_STATE_BLINK_ON;
                        Timer_Start(&timer_led, led_on_time);
                    }
                }
            }
            break;
    }
}

void UART_SendByte(unsigned char dat)
{
    SBUF = dat;
    while(!TI);
    TI = 0;
}

void UART_SendArray(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    for(i = 0; i < len; i++)
        UART_SendByte(buf[i]);
}

void UART_SendConst(const unsigned char *buf)
{
    UART_SendByte(buf[0]);
    UART_SendByte(buf[1]);
    UART_SendByte(buf[2]);
    UART_SendByte(buf[3]);
}

void UART_Init(void)
{
    P1M0 |= 0x01;   P1M1 &= 0xFE;
    P3M0 |= 0x18;   P3M1 &= 0xE7;
    P3M0 |= 0x80;   P3M1 &= 0x7F;
    P3M0 &= 0xBF;   P3M1 |= 0x40;
   
    P_SW1 = 0x40;
   
    SCON = 0x50;
    T2L = (65536 - FOSC/4/BAUD) & 0xFF;
    T2H = (65536 - FOSC/4/BAUD) >> 8;
    AUXR = 0x15;
   
    TI = 1;
    ES = 1;
    EA = 1;
}

// ?????0????? - 1ms??? @20MHz
void Timer0_Init(void)
{
    AUXR |= 0x80;   // T0x12=1, 1T??
    TMOD &= 0xF0;   // ???T0?????
    TMOD |= 0x00;   // ??0??16????????
   
    // 20MHz / 1T = 20M????/??1ms = 20000????
    // ??? = 65536 - 20000 = 45536 = 0xB1E0
    TH0 = 0xB1;
    TL0 = 0xE0;
   
    TF0 = 0;
    ET0 = 1;        // ????T0???
    TR0 = 1;        // ????T0
}

// ?????0??? - 1ms
void Timer0_ISR(void) interrupt 1
{
    sys_tick++;
}

void UART_ISR(void) interrupt 4
{
    if(RI)
    {
        RI = 0;
        
        if(rx_len < 4)
            rx_buffer[rx_len++] = SBUF;
            
        if(rx_len == 4)
        {
            if(SBUF == 0xAA && rx_buffer[0] == device_addr)
            {
                rx_complete = 1;
            }
            else
            {
                rx_len = 0;
            }
        }
        else if(rx_len > 4)
        {
            rx_len = 0;
        }
    }
   
    if(TI) TI = 0;
}

void main(void)
{
    unsigned char cmd;
    unsigned char param;
   
    UART_Init();
    Timer0_Init();
   
    device_addr = LoadDeviceAddr();
   
    LED = 1;
    rx_len = 0;
   
    while(1)
    {
        if(rx_complete)
        {
            rx_complete = 0;
            
            cmd = rx_buffer[1];
            param = rx_buffer[2];
            
            rx_len = 0;
            
            switch(cmd)
            {
                case 0x03:
                    if(param == 0xFF)
                    {
                        pending_action = 1;
                        flag = 1;
                        UART_SendConst(KAI);
                    }
                    else if(param == 0x00)
                    {                                                                       
                        pending_action = 2;
                        flag = 1;
                        UART_SendConst(KAI);
                    }
                    break;
                    
                case 0x05:
                    device_addr = param;
                    SaveDeviceAddr(param);
                    flag = 2;
                    UART_SendConst(KAI);
                    break;
            }
        }
        
        if(pending_action == 1)
        {
            pending_action = 0;
            On_FM_Start();
        }
        else if(pending_action == 2)
        {
            pending_action = 0;
            Off_FM_Start();
        }
        
        if(Timer_IsTimeout(&timer_fm))
        {
            FM_Stop();
        }
        
        LED_Control();
    }
}







这是新的程序  发送uint8_t e2[4]={0X01,0X05,0X03,0XAA};
刚开始成功,但是串口没返回
发送完以后在发送uint8_t e2[4]={0X01,0X05,0X03,0XAA};
这时候不成功是对的,确实未成功,但是把第一次该返回的内容这次返回了出来,感觉像缓冲区错位了
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-4-4 16:04 , Processed in 0.108521 second(s), 62 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表