{echo} 2025-12-26 10:45 采纳率: 0%
浏览 11

485通信问题,求解答

用485进不去串口中断,但是用串口就可以进去。串口调试的话,我发一个指令就会回我一个,但是我用usb转485发送指令,不会回我指令

#include <STC8G.H>
#include "SHT30.h"
#include "uart.h"
#include "delay.h"
#include "Timer0.h"
#include "modbus.h"

int T, H;
unsigned int crc_res;
unsigned char tx_buf[10];
volatile unsigned char RX_flag=0;
volatile unsigned char Time_count=0;
volatile unsigned char RX_count=0;
unsigned char RX_buff[MAX_count];

void main()
{  
UartInit();   // 串口初始化
SHT30_Init();  // SHT30引脚初始化
RS485_Init();
Timer0_Init();    
EA=1;
Delayms(100);
    while(1)
    {
        SHT30_ReadData(&T, &H);
        if (RX_flag)
         {
                      ES=0;//关闭串口中断
            // 收到指令后,首先屏蔽定时器判定,防止处理期间被重置
            // 校验地址和功能码
            if (RX_buff[0] == 0x01 && RX_buff[1] == 0x03)
            {
                tx_buf[0] = 0x01;
                tx_buf[1] = 0x03;
                tx_buf[2] = 0x04;
                tx_buf[3] = (unsigned char)(T>> 8);   // 取高8位
                tx_buf[4] = (unsigned char)(T& 0xFF); // 取低8位
                tx_buf[5] = (unsigned char)(H >> 8);   // 湿度高8位
                tx_buf[6] = (unsigned char)(H & 0xFF); // 湿度低8位
                crc_res = Modbus_CRC16(tx_buf, 7);
                tx_buf[7] = crc_res & 0xFF; 
                tx_buf[8] = crc_res >> 8;
                RS485_Send(tx_buf, 9);
            }
                        Delayms(5);
                        RX_count = 0; 
            RX_flag = 0;
                    ES=1;
          }
         }
                
//UartInit();   // 串口初始化
//SHT30_Init();  // SHT30引脚初始化
//    Uart_SendString("System Start...\r\n");
//    while (1) {
//        if (SHT30_ReadData(&T, &H)) {
//            // 打印温度
//            Uart_PrintResult("Temp: ", T);
//            Uart_SendString(" C  ");
//            
//            // 打印湿度
//            Uart_PrintResult("Humi: ", H);
//            Uart_SendString(" %\r\n");
//        } else {
//            Uart_SendString("SHT30 Error!\r\n");
//        }

//        Delayms(1000);; // 每秒测量一次
//    }
    
}

void UART_ISR() interrupt 4 
{
    if(RI) 
        {
            RI=0;
            if(RX_count<MAX_count)
            {
                RX_buff[RX_count]=SBUF;//接受发过来的数据
                RX_count++;
            }
       Time_count=0;
    }
}

void Timer0_ISP() interrupt 1
{
    if(RX_count>0)//接收到了数据
    {
        Time_count++;
        if(Time_count>5)//超时
        {
            RX_flag=1;//接受完成标志位
            Time_count=0;
        }
    }
}
#include "uart.h"

void UartInit(void)        //9600bps@11.0592MHz
{
    PCON &= 0x7F;        //波特率不倍速
    SCON = 0x50;        //8位数据,可变波特率
    AUXR &= 0xBF;        //定时器时钟12T模式
    AUXR &= 0xFE;        //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;        //设置定时器模式
    TMOD |= 0x20;        //设置定时器模式
    TL1 = 0xFD;        //设置定时初始值
    TH1 = 0xFD;        //设置定时重载值
    ET1 = 0;        //禁止定时器%d中断
    TR1 = 1;        //定时器1开始计时
    ES=1;      //打开串口中断
}


// 发送单个字节
void Uart_SendByte(u8 dat) {
    SBUF = dat;
    while (!TI);    // 等待发送完成
    TI = 0;         // 清除发送标志
}

// 发送字符串
void Uart_SendString(char *s) {
    while (*s) {
        Uart_SendByte(*s++);
    }
}
// 将整数拆分并打印成 x.x 的形式
// 例如:val = 256 -> 打印 "25.6"
void Uart_PrintResult(char *label, int val) {
    u8 buf[6];
    u8 i = 0;
    u8 is_neg = 0;
    u8 decimal;

    Uart_SendString(label); // 打印标签如 "Temp: "

    if (val < 0) {
        is_neg = 1;
        val = -val;
    }

    decimal = (u8)(val % 10); // 取小数位
    val /= 10;                // 取整数部分

    // 转换整数部分到字符串
    if (val == 0) {
        buf[i++] = '0';
    } else {
        while (val > 0) {
            buf[i++] = (val % 10) + '0';
            val /= 10;
        }
    }

    if (is_neg) Uart_SendByte('-');

    // 倒序打印整数部分
    while (i > 0) {
        Uart_SendByte(buf[--i]);
    }

    // 打印小数点和第一位小数
    Uart_SendByte('.');
    Uart_SendByte(decimal + '0');
}

//串口重定向,用printf打印
char putchar(char c)//必需的写putchar,不能分开写put_char
{
    Uart_SendByte(c);
    return c;
}

#include "Timer0.h"

void Timer0_Init(void)        // 1毫秒@11.0592MHz (STC8G)
{
    AUXR &= 0x7F;        // 定时器时钟12T模式
    TMOD &= 0xF0;        // 设置定时器模式
    TL0 = 0x71;            // 设置定时初始值
    TH0 = 0xF9;            // 设置定时初始值
    TF0 = 0;            // 清除TF0标志
    TR0 = 1;            // 定时器0开始计时
    ET0 = 1;     // 开启定时器0中断
}
#include "modbus.h"

//modbusCRC校验
unsigned int Modbus_CRC16(unsigned char *buf, unsigned char len) 
{
    unsigned int crc = 0xFFFF;
    unsigned char i, j;
    
    for(i = 0; i < len; i++) {
        crc ^= buf[i];
        for(j = 0; j < 8; j++) {
            if(crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

void RS485_Init(void)
{
    P3M1 &= ~0x08; P3M0 |= 0x08;//P3.3 推挽输出 (RS485控制)
    RS485_DIR=0;//接收模式
}

void RS485_Send(unsigned char *p, unsigned char len)
{
    RS485_DIR = 1; // 发送模式
    while (len--)
    {
        SBUF = *p++;
        while (!TI); 
        TI = 0;
    }
    Delayms(2);
    RS485_DIR = 0; // 接收模式
}
  • 写回答

2条回答 默认 最新

  • 关注

    你这问题核心就3个点,按优先级排雷:

    1. 485收发切换是头号坑
      先确认RS485_DIR宏定义是不是真的对应P3.3!很多人宏定义写错引脚,等于白切。另外发送完延迟2ms可能不够,改成5ms试试,别还没切回接收模式,应答指令就丢了。
    2. A/B线别接反!
      这是485调试最容易犯的错,接反了数据直接乱码,MCU收不到有效字节,RI标志位不置1,自然进不了串口中断。
    3. 硬件匹配要到位
      USB转485模块波特率必须设成9600、8N1,和你程序一致。多设备或远距离通信时,记得接120Ω终端电阻,不然信号衰减也收不到数据。

    快速验证法
    把485模块的A/B线对调,或者临时把RS485_DIR直接拉低(强制接收模式),发指令看能不能进中断——能进就是切换逻辑问题,不能进就是硬件或接线问题。

    评论

报告相同问题?

问题事件

  • 创建了问题 12月26日